Skip to content

Instantly share code, notes, and snippets.

@davidgyu
Created February 5, 2013 20:48

Revisions

  1. davidgyu created this gist Feb 5, 2013.
    380 changes: 380 additions & 0 deletions displayOsdFVarCoord.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,380 @@
    //
    // This is a simple example that uses face-varying u,v data
    // with uniform catmull-clark subdivision using OpenSubdiv
    //
    // c++ -o displayOsdFVarCoord displayOsdFVarCoord.cpp -I$OPENSUBDIV/include -L$OPENSUBDIV/lib -losdCPU -lglut -lGL
    //

    #if defined(__APPLE__)
    #include <GLUT/glut.h>
    #else
    #include <stdlib.h>
    #include <GL/glew.h>
    #if defined(WIN32)
    #include <GL/wglew.h>
    #endif
    #include <GL/glut.h>
    #endif

    #include <osd/error.h>
    #include <osd/vertex.h>

    #include <far/mesh.h>
    #include <far/meshFactory.h>

    #include <hbr/mesh.h>

    #include <osd/cpuDispatcher.h>
    #include <osd/cpuVertexBuffer.h>
    #include <osd/cpuComputeContext.h>
    #include <osd/cpuComputeController.h>

    #include <iostream>
    #include <vector>

    std::vector<float> vertexBufferData;
    std::vector<int> indexBufferData;
    std::vector<float> uvBufferData;

    typedef OpenSubdiv::HbrMesh<OpenSubdiv::OsdVertex> OsdHbrMesh;
    typedef OpenSubdiv::HbrVertex<OpenSubdiv::OsdVertex> OsdHbrVertex;
    typedef OpenSubdiv::HbrFace<OpenSubdiv::OsdVertex> OsdHbrFace;
    typedef OpenSubdiv::HbrHalfedge<OpenSubdiv::OsdVertex> OsdHbrHalfedge;
    typedef OpenSubdiv::HbrFVarData<OpenSubdiv::OsdVertex> OsdHbrFVarData;

    typedef OpenSubdiv::FarMeshFactory<OpenSubdiv::OsdVertex> OsdFarMeshFactory;
    typedef OpenSubdiv::FarMesh<OpenSubdiv::OsdVertex> OsdFarMesh;

    static OsdFarMesh *
    buildMesh(const float *vertexData, int numVertices,
    const int *indexData, int numIndices,
    const int *faceData, int numFaces,
    const float *uvData = NULL)
    {
    // Build HbrMesh to specify mesh topology
    static OpenSubdiv::HbrCatmarkSubdivision<OpenSubdiv::OsdVertex> _catmark;
    OsdHbrMesh *hbrMesh = NULL;
    if (uvData) {
    // This set of descriptors describes u,v per face vert
    static const int uvFVarCount = 2;
    static const int uvFVarIndices[] = { 0, 1 };
    static const int uvFVarWidths[] = { 1, 1 };
    static const int uvFVarTotalWidth = 2;
    hbrMesh = new OsdHbrMesh(&_catmark,
    uvFVarCount,
    uvFVarIndices,
    uvFVarWidths,
    uvFVarTotalWidth);
    } else {
    hbrMesh = new OsdHbrMesh(&_catmark);
    }

    // This example has boundary edges.
    hbrMesh->SetInterpolateBoundaryMethod(
    OsdHbrMesh::k_InterpolateBoundaryEdgeAndCorner);

    OpenSubdiv::OsdVertex v;
    for (int i = 0; i < numVertices; ++i) {
    hbrMesh->NewVertex(i, v);
    }

    std::vector<int> faceVerts;
    int faceDataOffset = 0;
    int ptexFaceIndex = 0;

    for (int fi = 0; fi<numFaces; ++fi) {
    int numFaceVerts = faceData[fi];

    bool valid = true;
    faceVerts.resize(numFaceVerts);
    for (int fvi = 0; fvi < numFaceVerts; ++fvi) {
    int v0 = indexData[fvi + faceDataOffset];
    int v1 = indexData[((fvi+1) % numFaceVerts) + faceDataOffset];

    faceVerts[fvi] = v0;

    OsdHbrVertex * origin = hbrMesh->GetVertex(v0);
    OsdHbrVertex * destination = hbrMesh->GetVertex(v1);
    if (!origin || !destination) {
    std::cerr << "topology error: non-existent vertex\n";
    valid = false;
    }

    if (origin == destination) {
    std::cerr << "topology error: vertex connected to itself\n";
    valid = false;
    }

    OsdHbrHalfedge * opposite = destination->GetEdge(origin);
    if (opposite && opposite->GetOpposite()) {
    std::cerr << "topology error: non-manifold edge\n";
    valid = false;
    }

    if (origin->GetEdge(destination)) {
    std::cerr << "topology error: duplicate edge\n";
    valid = false;
    }
    }

    if (valid) {
    OsdHbrFace *face = hbrMesh->NewFace(numFaceVerts, &faceVerts[0], 0);

    face->SetPtexIndex(ptexFaceIndex);
    ptexFaceIndex += (numFaceVerts == 4) ? 1 : numFaceVerts;

    if (uvData) {
    int fvarWidth = hbrMesh->GetTotalFVarWidth();
    const float *fvarFaceData = &uvData[faceDataOffset*fvarWidth];

    for(int fvi=0; fvi<numFaceVerts; ++fvi) {
    OsdHbrVertex *v = hbrMesh->GetVertex( faceVerts[fvi] );
    OsdHbrFVarData& fvarData = v->GetFVarData(face);

    if ( ! fvarData.IsInitialized() ) {
    fvarData.SetAllData(fvarWidth, fvarFaceData);
    } else
    if (!fvarData.CompareAll(fvarWidth, fvarFaceData)) {
    OsdHbrFVarData& fvarData = v->NewFVarData(face);
    fvarData.SetAllData(fvarWidth, fvarFaceData);
    }

    fvarFaceData += fvarWidth;
    }

    }
    }

    faceDataOffset += numFaceVerts;
    }

    hbrMesh->Finish();

    int level = 1;

    OsdFarMeshFactory meshFactory(hbrMesh, level, false /*uniform*/);
    OsdFarMesh * farMesh = meshFactory.Create(true /*ptex*/, true /*fvar*/);

    delete hbrMesh;

    std::cerr << "==== vertices ====\n";

    OpenSubdiv::OsdCpuComputeContext *
    computeContext = OpenSubdiv::OsdCpuComputeContext::Create(farMesh);
    OpenSubdiv::OsdCpuComputeController *
    computeController = new OpenSubdiv::OsdCpuComputeController();

    OpenSubdiv::OsdCpuVertexBuffer * vertexBuffer =
    OpenSubdiv::OsdCpuVertexBuffer::Create(3, farMesh->GetNumVertices());
    vertexBuffer->UpdateData(vertexData, numVertices);

    computeController->Refine(computeContext, vertexBuffer);

    const float *vbuffer = vertexBuffer->BindCpuBuffer();
    vertexBufferData.assign(vbuffer,
    vbuffer+vertexBuffer->GetNumVertices() *
    vertexBuffer->GetNumElements());
    for (int i=0; i<vertexBuffer->GetNumVertices(); ++i) {
    std::cerr << "(" << vbuffer[i*3+0] << ", "
    << vbuffer[i*3+1] << ", "
    << vbuffer[i*3+2] << ")\n";
    }

    std::cerr << "==== indices ====\n";

    const std::vector<int> &ibuffer = farMesh->GetFaceVertices(level);
    indexBufferData = ibuffer;
    for (int i=0; i<ibuffer.size(); i+=4) {
    std::cerr << "[" << ibuffer[i+0] << " "
    << ibuffer[i+1] << " "
    << ibuffer[i+2] << " "
    << ibuffer[i+3] << "]\n";
    }

    std::cerr << "==== ptex coords data ====\n";

    std::vector<int> const &
    ptexCoords = farMesh->GetPtexCoordinates(level);
    for (int i=0; i<ptexCoords.size(); i+=2) {
    const int *p = &ptexCoords[i];

    int faceIndex = i / 2;

    int ptexFaceIndex = p[0];
    int u = (p[1] >> 16) & 0xffff;
    int v = (p[1] & 0xffff);

    std::cerr << faceIndex << ": ";
    std::cerr << " ptex face: " << ptexFaceIndex;
    std::cerr << " uvoffset: ("
    << (float)u/(1<<level) << ", " << (float)v/(1<<level)
    << ")";
    if (faceIndex < 0) {
    std::cerr << " non-quad coarse face";
    }
    std::cerr << "\n";
    }

    std::cerr << "==== fvar coords data ====\n";

    if (uvData) {
    std::vector<float> const & fvarCoords = farMesh->GetFVarData(level);
    uvBufferData = fvarCoords;
    for (int i=0; i<fvarCoords.size(); i+=4*2) {
    const float *uv = &fvarCoords[i];
    int faceIndex = i / (4*2);

    std::cerr << faceIndex << ":";
    std::cerr << " (" << uv[0*2+0] << "," << uv[0*2+1] << ")";
    std::cerr << " (" << uv[1*2+0] << "," << uv[1*2+1] << ")";
    std::cerr << " (" << uv[2*2+0] << "," << uv[2*2+1] << ")";
    std::cerr << " (" << uv[3*2+0] << "," << uv[3*2+1] << ")";
    std::cerr << "\n";
    }
    }

    return farMesh;
    }

    static void
    buildCylinder()
    {
    float vertexData[] = {
    1.0,-1.0,-1.0,
    1.0, 1.0,-1.0,
    -1.0,-1.0,-1.0,
    -1.0, 1.0,-1.0,
    -1.0,-1.0, 1.0,
    -1.0, 1.0, 1.0,
    1.0,-1.0, 1.0,
    1.0, 1.0, 1.0,
    };
    int numVertices = (sizeof(vertexData) / sizeof(vertexData[0])) / 3;

    int indexData[] = {
    0, 1, 3, 2,
    2, 3, 5, 4,
    4, 5, 7, 6,
    6, 7, 1, 0,
    };
    int numIndices = sizeof(indexData) / sizeof(indexData[0]);

    int faceData[] = {
    4, 4, 4, 4,
    };
    int numFaces = sizeof(faceData) / sizeof(faceData[0]);

    float uvData[] = {
    0.0,0.0, 0.0,1.0, 0.25,1.0, 0.25,0.0,
    0.25,0.0, 0.25,1.0, 0.5,1.0, 0.5,0.0,
    0.5,0.0, 0.5,1.0, 0.75,1.0, 0.75,0.0,
    0.75,0.0, 0.75,1.0, 1.0,1.0, 1.0,0.0,
    };

    buildMesh(vertexData, numVertices,
    indexData, numIndices,
    faceData, numFaces, uvData);
    }

    int vpWidth = 512, vpHeight = 512;
    bool pressed = false;
    int prevX = 0, prevY = 0;
    float rotX = 0, rotY = 0;

    void
    reshape(int width, int height)
    {
    vpWidth = width;
    vpHeight = height;
    glutPostRedisplay();
    }

    void
    display()
    {
    glClearColor(0.1, 0.1, 0.1, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glEnable(GL_DEPTH_TEST);

    glViewport(0, 0, vpWidth, vpHeight);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-1, 1, -1, 1, 1, 10);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0, 0, -3);

    glRotatef(rotX, 1, 0, 0);
    glRotatef(rotY, 0, 1, 0);

    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    glBegin(GL_QUADS);
    int numQuads = indexBufferData.size() / 4;
    for (int face=0; face<numQuads; ++face) {
    for (int vert=0; vert<4; ++vert) {
    const float *uv0 = &uvBufferData[(face*4+vert)*2];
    glColor3f(uv0[0], uv0[1], 0.0);
    glVertex3fv(&vertexBufferData[indexBufferData[face*4+vert]*3]);
    }
    }
    glEnd();

    glutSwapBuffers();
    }

    void
    mouse(int button, int state, int x, int y)
    {
    if (button == GLUT_LEFT_BUTTON and state == GLUT_DOWN) {
    pressed = true;
    prevX = x;
    prevY = y;
    } else if (button == GLUT_LEFT_BUTTON and state == GLUT_UP) {
    pressed = false;
    }
    }

    void
    motion(int x, int y)
    {
    if (pressed) {
    rotX += float(y - prevY) / vpHeight * 360.0f;
    rotY += float(x - prevX) / vpHeight * 360.0f;
    prevX = x;
    prevY = y;
    }
    glutPostRedisplay();
    }

    void
    keyboard(unsigned char key, int, int)
    {
    switch (key) {
    case 27:
    case 'q':
    exit(1);
    default:
    break;
    }
    }

    int
    main(int argc, char **argv)
    {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
    glutInitWindowSize(vpWidth, vpHeight);
    glutCreateWindow("Test");

    buildCylinder();

    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    }