//------------------------------------------------------------------------------
static Far::TopologyRefiner const *
createTopologyRefiner(int maxlevel) {

    // Populate a topology descriptor with our raw data

    typedef Far::TopologyRefinerFactoryBase::TopologyDescriptor Descriptor;

    Sdc::Type type = OpenSubdiv::Sdc::TYPE_CATMARK;

    Sdc::Options options;
    options.SetVVarBoundaryInterpolation(Sdc::Options::VVAR_BOUNDARY_EDGE_ONLY);

    Descriptor desc;
    desc.numVertices  = g_nverts;
    desc.numFaces     = g_nfaces;
    desc.vertsPerFace = g_vertsperface;
    desc.vertIndices  = g_vertIndices;

    // Instantiate a FarTopologyRefiner from the descriptor
    Far::TopologyRefiner * refiner =
        Far::TopologyRefinerFactory<Descriptor>::Create(type, options, desc);

    // Uniformly refine the topolgy up to 'maxlevel'
    refiner->RefineUniform( maxlevel );

    return refiner;
}
Exemplo n.º 2
0
//------------------------------------------------------------------------------
int main(int, char **) {

    // Generate some FarTopologyRefiner (see far_tutorial_0 for details).
    Far::TopologyRefiner * refiner = createTopologyRefiner();

    // Uniformly refine the topolgy up to 'maxlevel'.
    int maxlevel = 4;
    refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel));

    // Use the FarStencilTable factory to create cascading stencil table
    // note: we want stencils for the each refinement level
    //       "cascade" mode is achieved by setting "factorizeIntermediateLevels"
    //       to false
    Far::StencilTableFactory::Options options;
    options.generateIntermediateLevels=true;
    options.factorizeIntermediateLevels=false;
    options.generateOffsets=true;

    Far::StencilTable const * stencilTable =
        Far::StencilTableFactory::Create(*refiner, options);

    std::vector<Vertex> vertexBuffer(refiner->GetNumVerticesTotal()-g_nverts);

    Vertex * destVerts = &vertexBuffer[0];

    int start = 0, end = 0; // stencils batches for each level of subdivision
    for (int level=0; level<maxlevel; ++level) {

        int nverts = refiner->GetLevel(level+1).GetNumVertices();

        Vertex const * srcVerts = reinterpret_cast<Vertex *>(g_verts);
        if (level>0) {
             srcVerts = &vertexBuffer[start];
        }

        start = end;
        end += nverts;

        stencilTable->UpdateValues(srcVerts, destVerts, start, end);
        
        // apply 2 hierarchical edits on level 1 vertices
        if (level==1) {
            float * pos = destVerts[start+5].GetPosition();
            pos[1] += 0.5f;            

            pos = destVerts[start+20].GetPosition();
            pos[0] += 0.25f;
        }
    }


    { // Output OBJ of the highest level refined -----------

        Vertex * verts = &vertexBuffer[0];

        // Print vertex positions
        for (int level=1, firstvert=0; level<=maxlevel; ++level) {

            Far::TopologyLevel const & refLevel = refiner->GetLevel(level);

            printf("g level_%d\n", level);

            int nverts = refLevel.GetNumVertices();
            for (int vert=0; vert<nverts; ++vert) {
                float const * pos = verts[vert].GetPosition();
                printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
            }
            verts += nverts;
 
            // Print faces
            for (int face=0; face<refLevel.GetNumFaces(); ++face) {

                Far::ConstIndexArray fverts = refLevel.GetFaceVertices(face);

                // all refined Catmark faces should be quads
                assert(fverts.size()==4);

                printf("f ");
                for (int vert=0; vert<fverts.size(); ++vert) {
                    printf("%d ", fverts[vert]+firstvert+1); // OBJ uses 1-based arrays...
                }
                printf("\n");
            }
            firstvert+=nverts;
        }
    }

    delete refiner;
    delete stencilTable;
}
Exemplo n.º 3
0
//------------------------------------------------------------------------------
static void
createFarGLMesh(Shape * shape, int maxlevel) {

    Stopwatch s;
    s.Start();

    using namespace OpenSubdiv;

    // create Far mesh (topology)
    Sdc::SchemeType sdctype = GetSdcType(*shape);
    Sdc::Options    sdcoptions = GetSdcOptions(*shape);

    sdcoptions.SetFVarLinearInterpolation(g_fvarInterpolation);

    Far::TopologyRefiner * refiner =
        Far::TopologyRefinerFactory<Shape>::Create(*shape,
            Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions));

    if (g_Adaptive) {
        Far::TopologyRefiner::AdaptiveOptions options(maxlevel);
        options.useSingleCreasePatch = false;
        refiner->RefineAdaptive(options);
    } else {
        Far::TopologyRefiner::UniformOptions options(maxlevel);
        options.fullTopologyInLastLevel = true;
        refiner->RefineUniform(options);
    }

    int numTotalVerts = refiner->GetNumVerticesTotal();

    //
    // Patch table
    //
    std::vector<Vertex> fvarBuffer;
    Far::PatchTable * patchTable = 0;
    bool createFVarWire = g_FarDrawFVarPatches or g_FarDrawFVarVerts;

    if (g_Adaptive) {
        Far::PatchTableFactory::Options options;
        options.generateFVarTables = createFVarWire;
        options.shareEndCapPatchPoints = false;

        patchTable =
            Far::PatchTableFactory::Create(*refiner, options);

        // increase vertex buffer for the additional local points
        if (patchTable->GetLocalPointStencilTable()) {
            numTotalVerts += patchTable->GetLocalPointStencilTable()->GetNumStencils();
        }

        g_numPatches = patchTable->GetNumPatchesTotal();
        g_maxValence = patchTable->GetMaxValence();

        if (createFVarWire) {

            // interpolate fvar values

            int channel = 0;

            // XXXX should use a (u,v) vertex class
            fvarBuffer.resize(refiner->GetNumFVarValuesTotal(channel), 0);
            Vertex * values = &fvarBuffer[0];

            int nCoarseValues = refiner->GetLevel(0).GetNumFVarValues(channel);

            for (int i=0; i<nCoarseValues; ++i) {
                float const * ptr = &shape->uvs[i*2];
                values[i].SetPosition(ptr[0],  ptr[1], 0.0f);
            }

            int lastLevel = refiner->GetMaxLevel();
            Vertex * src = values;
            for (int level = 1; level <= lastLevel; ++level) {
                Vertex * dst = src + refiner->GetLevel(level-1).GetNumFVarValues(channel);
                Far::PrimvarRefiner(*refiner).InterpolateFaceVarying(level, src, dst, channel);
                src = dst;
            }
        }
    }

    //
    // interpolate vertices
    //

    // create vertex primvar data buffer
    std::vector<Vertex> vertexBuffer(numTotalVerts);
    Vertex * verts = &vertexBuffer[0];

    // copy coarse vertices positions
    int ncoarseverts = shape->GetNumVertices();
    for (int i=0; i<ncoarseverts; ++i) {
        float * ptr = &shape->verts[i*3];
        verts[i].SetPosition(ptr[0], ptr[1], ptr[2]);
    }

    s.Start();
    if (g_useStencils) {
        //
        // Stencil interpolation
        //
        Far::StencilTable const * stencilTable = 0;
        Far::StencilTableFactory::Options options;
        options.generateOffsets=true;
        options.generateIntermediateLevels=true;
        stencilTable = Far::StencilTableFactory::Create(*refiner, options);

        // append local point stencils if needed
        if (patchTable and patchTable->GetLocalPointStencilTable()) {
            if (Far::StencilTable const * stencilTableWithLocalPoints =
                Far::StencilTableFactory::AppendLocalPointStencilTable(
                    *refiner, stencilTable,
                    patchTable->GetLocalPointStencilTable())) {
                delete stencilTable;
                stencilTable = stencilTableWithLocalPoints;
            }
        }

        //
        // apply stencils
        //
        stencilTable->UpdateValues(verts, verts + ncoarseverts);

        delete stencilTable;
    } else {
        //
        // TopologyRefiner interpolation
        //
        // populate buffer with Far interpolated vertex data
        int lastLevel = refiner->GetMaxLevel();
        Vertex * src = verts;
        for (int level = 1; level <= lastLevel; ++level) {
            Vertex * dst = src + refiner->GetLevel(level-1).GetNumVertices();
            Far::PrimvarRefiner(*refiner).Interpolate(level, src, dst);
            src = dst;
        }
        //printf("          %f ms (interpolate)\n", float(s.GetElapsed())*1000.0f);
        //printf("          %f ms (total)\n", float(s.GetTotalElapsed())*1000.0f);

        // TODO: endpatch basis conversion comes here
    }
    s.Stop();

    //
    // Misc display
    //

    //printf("Far time: %f ms (topology)\n", float(s.GetElapsed())*1000.0f);

    if (g_FarDrawVertIDs) {
        createVertNumbers(*refiner, vertexBuffer);
    }

    if (g_FarDrawFaceIDs) {
        createFaceNumbers(*refiner, vertexBuffer);
    }

    if (g_FarDrawPtexIDs and patchTable) {
        createPtexNumbers(*patchTable, vertexBuffer);
    }

    if (g_Adaptive) {
        createPatchNumbers(*patchTable, vertexBuffer);
    }

    if (g_Adaptive and g_FarDrawGregogyBasis) {
        createGregoryBasis(*patchTable, vertexBuffer);
    }

    if (g_Adaptive and createFVarWire) {
        createFVarPatches(*refiner, *patchTable, fvarBuffer);
        createFVarPatchNumbers(*patchTable, fvarBuffer);
    }

    createEdgeNumbers(*refiner, vertexBuffer, g_FarDrawEdgeIDs!=0, g_FarDrawEdgeSharpness!=0);

    GLMesh::Options options;
    options.vertColorMode=g_Adaptive ? GLMesh::VERTCOLOR_BY_LEVEL : GLMesh::VERTCOLOR_BY_SHARPNESS;
    options.edgeColorMode=g_Adaptive ? GLMesh::EDGECOLOR_BY_PATCHTYPE : GLMesh::EDGECOLOR_BY_SHARPNESS;
    options.faceColorMode=g_Adaptive ? GLMesh::FACECOLOR_BY_PATCHTYPE :GLMesh::FACECOLOR_SOLID;

    g_far_glmesh.Initialize(options, *refiner, patchTable, (float *)&verts[0]);
    if (g_Adaptive) {
        g_far_glmesh.SetDiffuseColor(1.0f, 1.0f, 1.0f, 1.0f);
    } else {
        g_far_glmesh.SetDiffuseColor(0.75f, 0.9f, 1.0f, 1.0f);
    }


    //setFaceColors(*refiner);

    g_far_glmesh.InitializeDeviceBuffers();

    // save coarse topology (used for control mesh display)
    g_controlMeshDisplay.SetTopology(refiner->GetLevel(0));

    // save coarse points in a GPU buffer (used for control mesh display)
    if (not g_controlMeshDisplayVBO) {
        glGenBuffers(1, &g_controlMeshDisplayVBO);
    }
    glBindBuffer(GL_ARRAY_BUFFER, g_controlMeshDisplayVBO);
    glBufferData(GL_ARRAY_BUFFER,
                 3*sizeof(float)*vertexBuffer.size(), (GLfloat*)&vertexBuffer[0],
                 GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // compute model bounds
    float min[3] = { FLT_MAX,  FLT_MAX,  FLT_MAX};
    float max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
    for (size_t i=0; i <vertexBuffer.size(); ++i) {
        for(int j=0; j<3; ++j) {
            float v = vertexBuffer[i].GetPos()[j];
            min[j] = std::min(min[j], v);
            max[j] = std::max(max[j], v);
        }
    }
    for (int j=0; j<3; ++j) {
        g_center[j] = (min[j] + max[j]) * 0.5f;
        g_size += (max[j]-min[j])*(max[j]-min[j]);
    }
    g_size = sqrtf(g_size);

    delete refiner;
    delete patchTable;
}
Exemplo n.º 4
0
//------------------------------------------------------------------------------
int main(int, char **) {

    // Generate some FarTopologyRefiner (see far_tutorial_0 for details).
    Far::TopologyRefiner * refiner = createTopologyRefiner();


    // Uniformly refine the topolgy up to 'maxlevel'.
    int maxlevel = 4;
    refiner->RefineUniform(Far::TopologyRefiner::UniformOptions(maxlevel));

    int nverts = refiner->GetLevel(maxlevel).GetNumVertices();

    // Use the Far::StencilTable factory to create discrete stencil table
    Far::StencilTableFactory::Options options;
    options.generateIntermediateLevels=false; // only the highest refinement level.
    options.generateOffsets=true;

    //
    // Vertex primvar data
    //

        // Create stencils table for 'vertex' interpolation
        options.interpolationMode=Far::StencilTableFactory::INTERPOLATE_VERTEX;

        Far::StencilTable const * vertexStencils =
            Far::StencilTableFactory::Create(*refiner, options);
        assert(nverts==vertexStencils->GetNumStencils());

        // Allocate vertex primvar buffer (1 stencil for each vertex)
        std::vector<Vertex> vertexBuffer(vertexStencils->GetNumStencils());

        // Use the cube vertex positions as 'vertex' primvar data
        Vertex * vertexCVs = reinterpret_cast<Vertex *>(g_verts);

    //
    // Varying primvar data
    //

        // Create stencils table for 'varying' interpolation
        options.interpolationMode=Far::StencilTableFactory::INTERPOLATE_VARYING;

        Far::StencilTable const * varyingStencils =
            Far::StencilTableFactory::Create(*refiner, options);
        assert(nverts==varyingStencils->GetNumStencils());

        // Allocate varying primvar buffer (1 stencil for each vertex)
        std::vector<Vertex> varyingBuffer(varyingStencils->GetNumStencils());

        // Use the a per-vertex array of RGB colors as 'varying' primvar data
        Vertex * varyingCVs = reinterpret_cast<Vertex *>(g_colors);

    delete refiner;

    //
    // Apply stencils (in frame loop)
    //

    { // This section would be applied every frame after control vertices have
      // been moved.

        // Apply stencils on the control vertex data to update the primvar data
        // of the refined vertices.

        vertexStencils->UpdateValues(vertexCVs, &vertexBuffer[0]);

        varyingStencils->UpdateValues(varyingCVs, &varyingBuffer[0]);
    }

    { // Visualization with Maya : print a MEL script that generates particles
      // at the location of the refined vertices

        printf("particle ");
        for (int vert=0; vert<(int)nverts; ++vert) {
            float const * pos = vertexBuffer[vert].GetData();
            printf("-p %f %f %f\n", pos[0], pos[1], pos[2]);
        }
        printf("-c 1;\n");

        // Set particle point size (20 -- very large)
        printf("addAttr -is true -ln \"pointSize\" -at long -dv 20 particleShape1;\n");

        // Add per-particle color attribute ('rgbPP')
        printf("addAttr -ln \"rgbPP\" -dt vectorArray particleShape1;\n");

        // Set per-particle color values from our 'varying' primvar data
        printf("setAttr \"particleShape1.rgbPP\" -type \"vectorArray\" %d ", nverts);
        for (int vert=0; vert<nverts; ++vert) {
            float const * color = varyingBuffer[vert].GetData();
            printf("%f %f %f\n", color[0], color[1], color[2]);
        }
        printf(";\n");
    }

    delete vertexStencils;
    delete varyingStencils;
}
Exemplo n.º 5
0
//------------------------------------------------------------------------------
int main(int, char **) {

    int maxlevel = 3;

    typedef Far::TopologyRefinerFactoryBase::TopologyDescriptor Descriptor;

    Sdc::SchemeType type = OpenSubdiv::Sdc::SCHEME_CATMARK;

    Sdc::Options options;
    options.SetVtxBoundaryInterpolation(Sdc::Options::VTX_BOUNDARY_EDGE_ONLY);
    options.SetFVarLinearInterpolation(Sdc::Options::FVAR_LINEAR_NONE);

    // Populate a topology descriptor with our raw data
    Descriptor desc;
    desc.numVertices  = g_nverts;
    desc.numFaces     = g_nfaces;
    desc.numVertsPerFace = g_vertsperface;
    desc.vertIndicesPerFace  = g_vertIndices;

    // Create a face-varying channel descriptor
    Descriptor::FVarChannel uvs;
    uvs.numValues = g_nuvs;
    uvs.valueIndices = g_uvIndices;

    // Add the channel topology to the main descriptor
    desc.numFVarChannels = 1;
    desc.fvarChannels = & uvs;

    // Instantiate a FarTopologyRefiner from the descriptor
    Far::TopologyRefiner * refiner =
        Far::TopologyRefinerFactory<Descriptor>::Create(desc,
            Far::TopologyRefinerFactory<Descriptor>::Options(type, options));

    // Uniformly refine the topolgy up to 'maxlevel'
    // note: fullTopologyInLastLevel must be true to work with face-varying data
    {
        Far::TopologyRefiner::UniformOptions options(maxlevel);
        options.fullTopologyInLastLevel = true;
        refiner->RefineUniform(options);
    }

    // Allocate & interpolate the 'vertex' primvar data (see tutorial 2 for
    // more details).
    std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal());
    Vertex * verts = &vbuffer[0];

    int nCoarseVerts = g_nverts;
    for (int i=0; i<nCoarseVerts; ++i) {
        verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]);
    }

    refiner->Interpolate(verts, verts + nCoarseVerts);


    // Allocate & interpolate the 'face-varying' primvar data
    int channel = 0,
        nCoarseFVVerts = refiner->GetNumFVarValues(0, channel);

    std::vector<FVarVertex> fvBuffer(refiner->GetNumFVarValuesTotal(channel));
    FVarVertex * fvVerts = &fvBuffer[0];

    for (int i=0; i<g_nuvs; ++i) {
        fvVerts[i].u = g_uvs[i][0];
        fvVerts[i].v = g_uvs[i][1];
    }

    refiner->InterpolateFaceVarying(fvVerts, fvVerts + nCoarseFVVerts, channel);


    { // Output OBJ of the highest level refined -----------

        // Print vertex positions
        for (int level=0, firstVert=0; level<=maxlevel; ++level) {

            if (level==maxlevel) {
                for (int vert=0; vert<refiner->GetNumVertices(level); ++vert) {
                    float const * pos = verts[firstVert+vert].GetPosition();
                    printf("v %f %f %f\n", pos[0], pos[1], pos[2]);
                }
            } else {
                firstVert += refiner->GetNumVertices(level);
            }
        }

        // Print uvs
        for (int level=0, firstVert=0; level<=maxlevel; ++level) {

            if (level==maxlevel) {
                for (int vert=0; vert<refiner->GetNumFVarValues(level, channel); ++vert) {
                    FVarVertex const & uv = fvVerts[firstVert+vert];
                    printf("vt %f %f\n", uv.u, uv.v);
                }
            } else {
                firstVert += refiner->GetNumFVarValues(level, channel);
            }
        }


        // Print faces
        for (int face=0; face<refiner->GetNumFaces(maxlevel); ++face) {

            Far::ConstIndexArray fverts = refiner->GetFaceVertices(maxlevel, face),
                                 fvverts = refiner->GetFVarFaceValues(maxlevel, face, channel);

            // all refined Catmark faces should be quads
            assert(fverts.size()==4 and fvverts.size()==4);

            printf("f ");
            for (int vert=0; vert<fverts.size(); ++vert) {
                // OBJ uses 1-based arrays...
                printf("%d/%d ", fverts[vert]+1, fvverts[vert]+1);
            }
            printf("\n");
        }
    }
}
Exemplo n.º 6
0
//------------------------------------------------------------------------------
static void
createOsdMesh(ShapeDesc const & shapeDesc, int level) {

    Shape * shape = Shape::parseObj(shapeDesc.data.c_str(), shapeDesc.scheme);

    // create Far mesh (topology)
    OpenSubdiv::Sdc::SchemeType sdctype = GetSdcType(*shape);
    OpenSubdiv::Sdc::Options sdcoptions = GetSdcOptions(*shape);

    Far::TopologyRefiner *topologyRefiner =
        OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Create(*shape,
            OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions));

    g_orgPositions=shape->verts;
    g_positions.resize(g_orgPositions.size(), 0.0f);

    delete shape;

    float speed = g_particles ? g_particles->GetSpeed() : 0.2f;

    // save coarse topology (used for coarse mesh drawing)
    g_controlMeshDisplay.SetTopology(topologyRefiner->GetLevel(0));

    // create random varying color
    {
        int numCoarseVerts = topologyRefiner->GetLevel(0).GetNumVertices();
        g_varyingColors.resize(numCoarseVerts*3);
        createRandomColors(numCoarseVerts, 3, &g_varyingColors[0]);
    }

    Far::StencilTable const * vertexStencils = NULL;
    Far::StencilTable const * varyingStencils = NULL;
    int nverts=0;

    {
        bool adaptive = (sdctype == OpenSubdiv::Sdc::SCHEME_CATMARK);
        if (adaptive) {
            // Apply feature adaptive refinement to the mesh so that we can use the
            // limit evaluation API features.
            Far::TopologyRefiner::AdaptiveOptions options(level);
            topologyRefiner->RefineAdaptive(options);
        } else {
            Far::TopologyRefiner::UniformOptions options(level);
            topologyRefiner->RefineUniform(options);
        }

        // Generate stencil table to update the bi-cubic patches control
        // vertices after they have been re-posed (both for vertex & varying
        // interpolation)
        Far::StencilTableFactory::Options soptions;
        soptions.generateOffsets=true;
        soptions.generateIntermediateLevels=adaptive;

        vertexStencils =
            Far::StencilTableFactory::Create(*topologyRefiner, soptions);

        soptions.interpolationMode = Far::StencilTableFactory::INTERPOLATE_VARYING;

        varyingStencils =
            Far::StencilTableFactory::Create(*topologyRefiner, soptions);

        // Generate bi-cubic patch table for the limit surface
        Far::PatchTableFactory::Options poptions;
        if (g_endCap == kEndCapBSplineBasis) {
            poptions.SetEndCapType(
                Far::PatchTableFactory::Options::ENDCAP_BSPLINE_BASIS);
        } else {
            poptions.SetEndCapType(
                Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS);
        }

        Far::PatchTable const * patchTable =
            Far::PatchTableFactory::Create(*topologyRefiner, poptions);

        // append local points stencils
        if (Far::StencilTable const *localPointStencilTable =
            patchTable->GetLocalPointStencilTable()) {
            Far::StencilTable const *table =
                Far::StencilTableFactory::AppendLocalPointStencilTable(
                    *topologyRefiner, vertexStencils, localPointStencilTable);
            delete vertexStencils;
            vertexStencils = table;
        }
        if (Far::StencilTable const *localPointVaryingStencilTable =
            patchTable->GetLocalPointVaryingStencilTable()) {
            Far::StencilTable const *table =
                Far::StencilTableFactory::AppendLocalPointStencilTable(
                    *topologyRefiner,
                    varyingStencils, localPointVaryingStencilTable);
            delete varyingStencils;
            varyingStencils = table;
        }

        // total number of vertices = coarse verts + refined verts + gregory basis verts
        nverts = vertexStencils->GetNumControlVertices() +
            vertexStencils->GetNumStencils();

        if (g_patchTable) delete g_patchTable;
        g_patchTable = patchTable;
    }

    // note that for patch eval we need coarse+refined combined buffer.
    int nCoarseVertices = topologyRefiner->GetLevel(0).GetNumVertices();

    // In following template instantiations, same type of vertex buffers are
    // used for both source and destination (first and second template
    // parameters), since we'd like to draw control mesh wireframe too in
    // this example viewer.
    // If we don't need to draw the coarse control mesh, the src buffer doesn't
    // have to be interoperable to GL (it can be CpuVertexBuffer etc).

    delete g_evalOutput;
    if (g_kernel == kCPU) {
        g_evalOutput = new EvalOutput<Osd::CpuGLVertexBuffer,
                                      Osd::CpuGLVertexBuffer,
                                      Far::StencilTable,
                                      Osd::CpuPatchTable,
                                      Osd::CpuEvaluator>
            (vertexStencils, varyingStencils,
             nCoarseVertices, nverts, g_nParticles, g_patchTable);
#ifdef OPENSUBDIV_HAS_OPENMP
    } else if (g_kernel == kOPENMP) {
        g_evalOutput = new EvalOutput<Osd::CpuGLVertexBuffer,
                                      Osd::CpuGLVertexBuffer,
                                      Far::StencilTable,
                                      Osd::CpuPatchTable,
                                      Osd::OmpEvaluator>
            (vertexStencils, varyingStencils,
            nCoarseVertices, nverts, g_nParticles, g_patchTable);
#endif
#ifdef OPENSUBDIV_HAS_TBB
    } else if (g_kernel == kTBB) {
        g_evalOutput = new EvalOutput<Osd::CpuGLVertexBuffer,
                                      Osd::CpuGLVertexBuffer,
                                      Far::StencilTable,
                                      Osd::CpuPatchTable,
                                      Osd::TbbEvaluator>
            (vertexStencils, varyingStencils,
            nCoarseVertices, nverts, g_nParticles, g_patchTable);
#endif
#ifdef OPENSUBDIV_HAS_CUDA
    } else if (g_kernel == kCUDA) {
        g_evalOutput = new EvalOutput<Osd::CudaGLVertexBuffer,
                                      Osd::CudaGLVertexBuffer,
                                      Osd::CudaStencilTable,
                                      Osd::CudaPatchTable,
                                      Osd::CudaEvaluator>
            (vertexStencils, varyingStencils,
            nCoarseVertices, nverts, g_nParticles, g_patchTable);
#endif
#ifdef OPENSUBDIV_HAS_OPENCL
    } else if (g_kernel == kCL) {
        static Osd::EvaluatorCacheT<Osd::CLEvaluator> clEvaluatorCache;
        g_evalOutput = new EvalOutput<Osd::CLGLVertexBuffer,
                                      Osd::CLGLVertexBuffer,
                                      Osd::CLStencilTable,
                                      Osd::CLPatchTable,
                                      Osd::CLEvaluator,
                                      CLDeviceContext>
            (vertexStencils, varyingStencils,
            nCoarseVertices, nverts, g_nParticles, g_patchTable,
            &clEvaluatorCache, &g_clDeviceContext);
#endif
#ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
    } else if (g_kernel == kGLXFB) {
        static Osd::EvaluatorCacheT<Osd::GLXFBEvaluator> glXFBEvaluatorCache;
        g_evalOutput = new EvalOutput<Osd::GLVertexBuffer,
                                      Osd::GLVertexBuffer,
                                      Osd::GLStencilTableTBO,
                                      Osd::GLPatchTable,
                                      Osd::GLXFBEvaluator>
            (vertexStencils, varyingStencils,
             nCoarseVertices, nverts, g_nParticles, g_patchTable,
             &glXFBEvaluatorCache);
#endif
#ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
    } else if (g_kernel == kGLCompute) {
        static Osd::EvaluatorCacheT<Osd::GLComputeEvaluator> glComputeEvaluatorCache;
        g_evalOutput = new EvalOutput<Osd::GLVertexBuffer,
                                      Osd::GLVertexBuffer,
                                      Osd::GLStencilTableSSBO,
                                      Osd::GLPatchTable,
                                      Osd::GLComputeEvaluator>
            (vertexStencils, varyingStencils,
             nCoarseVertices, nverts, g_nParticles, g_patchTable,
             &glComputeEvaluatorCache);
#endif
    }

    // Create the 'uv particles' manager - this class manages the limit
    // location samples (ptex face index, (s,t) and updates them between frames.
    // Note: the number of limit locations can be entirely arbitrary
    delete g_particles;
    g_particles = new STParticles(*topologyRefiner, g_patchTable,
                                  g_nParticles, !g_randomStart);
    g_nParticles = g_particles->GetNumParticles();
    g_particles->SetSpeed(speed);

    g_prevTime = -1;
    g_currentTime = 0;

    updateGeom();

    delete topologyRefiner;
}
//------------------------------------------------------------------------------
int main(int, char **) {

    int maxlevel = 5;

    Far::TopologyRefiner * refiner = createFarTopologyRefiner();

    // Uniformly refine the topolgy up to 'maxlevel'
    refiner->RefineUniform( maxlevel );

    // Allocate a buffer for vertex primvar data. The buffer length is set to
    // be the sum of all children vertices up to the highest level of refinement.
    std::vector<Vertex> vbuffer(refiner->GetNumVerticesTotal());
    Vertex * verts = &vbuffer[0];

    // Initialize coarse mesh primvar data
    int nCoarseVerts = g_nverts;
    for (int i=0; i<nCoarseVerts; ++i) {

        verts[i].SetPosition(g_verts[i][0], g_verts[i][1], g_verts[i][2]);

        verts[i].SetColor(g_colors[i][0], g_colors[i][1], g_colors[i][2]);
    }

    // Interpolate all primvar data - not that this will perform both 'vertex' and
    // 'varying' interpolation at once by calling each specialized method in our
    // Vertex class with the appropriate weights.
    refiner->Interpolate(verts, verts + nCoarseVerts);



    { // Visualization with Maya : print a MEL script that generates colored
      // particles at the location of the refined vertices (don't forget to
      // turn shading on in the viewport to see the colors)

        int nverts = refiner->GetNumVertices(maxlevel);

        // Position the 'verts' pointer to the first vertex of our 'maxlevel' level
        for (int level=0; level<maxlevel; ++level) {
            verts += refiner->GetNumVertices(level);
        }

        // Output particle positions
        printf("particle ");
        for (int vert=0; vert<nverts; ++vert) {
            float const * pos = verts[vert].GetPosition();
            printf("-p %f %f %f\n", pos[0], pos[1], pos[2]);
        }
        printf(";\n");

        // Set particle point size (20 -- very large)
        printf("addAttr -is true -ln \"pointSize\" -at long -dv 20 particleShape1;\n");

        // Add per-particle color attribute ('rgbPP')
        printf("addAttr -ln \"rgbPP\" -dt vectorArray particleShape1;\n");

        // Set per-particle color values from our 'varying' primvar data
        printf("setAttr \"particleShape1.rgbPP\" -type \"vectorArray\" %d ", nverts);
        for (int vert=0; vert<nverts; ++vert) {
            float const * color = verts[vert].GetColor();
            printf("%f %f %f\n", color[0], color[1], color[2]);
        }
        printf(";\n");
    }
}