Example #1
0
inline bool
TopologyRefinerFactory<PXR_NS::Converter>::assignComponentTopology(
    Far::TopologyRefiner & refiner, PXR_NS::Converter const & converter) {

    PXR_NAMESPACE_USING_DIRECTIVE

    PxOsdMeshTopology const topology = converter.topology;
    int const * vertIndices = topology.GetFaceVertexIndices().cdata();
    bool flip = (topology.GetOrientation() != PxOsdOpenSubdivTokens->rightHanded);

    for (int face=0, idx=0; face<refiner.GetLevel(0).GetNumFaces(); ++face) {

        IndexArray dstFaceVerts = getBaseFaceVertices(refiner, face);

        if (flip) {
            dstFaceVerts[0] = vertIndices[idx++];
            for (int vert=dstFaceVerts.size()-1; vert > 0; --vert) {
                dstFaceVerts[vert] = vertIndices[idx++];
            }
        } else {
            for (int vert=0; vert<dstFaceVerts.size(); ++vert) {

                dstFaceVerts[vert] = vertIndices[idx++];
            }
        }
    }

    return true;
}
Example #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;
}
Example #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;
}
Example #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;
}
Example #5
0
inline bool
TopologyRefinerFactory<PXR_NS::Converter>::assignComponentTags(
    Far::TopologyRefiner & refiner, PXR_NS::Converter const & converter) {

    PXR_NAMESPACE_USING_DIRECTIVE

    PxOsdMeshTopology const & topology = converter.topology;

    PxOsdSubdivTags const & tags = topology.GetSubdivTags();

    //
    // creases
    //

    // The sharpnesses can be defined either per-crease or per-edge.
    VtIntArray const creaseIndices = tags.GetCreaseIndices(),
                     creaseLengths = tags.GetCreaseLengths();
    VtFloatArray const creaseWeights = tags.GetCreaseWeights();

    size_t numCreaseSets = creaseLengths.size();
    bool perEdgeCrease = creaseWeights.size() != numCreaseSets;

    if (perEdgeCrease) {
        // validate per-edge crease.
        int numEdges = 0;
        for (size_t i = 0; i < numCreaseSets; ++i) {
            numEdges += creaseLengths[i] - 1;
        }
        if (creaseWeights.size() != static_cast<size_t>(numEdges)) {
            TF_WARN("Invalid length of crease sharpnesses (%s)\n",
                converter.name.GetText());
            numCreaseSets = 0;
        }
    }
    for (size_t i=0, cindex=0, sindex=0; i < numCreaseSets; ++i) {

        int numSegments = creaseLengths[i] - 1;

        for (int j = 0; j < numSegments; ++j) {
            int v0 = creaseIndices[cindex+j],
                v1 = creaseIndices[cindex+j+1];

            OpenSubdiv::Vtr::Index edge = refiner.GetLevel(0).FindEdge(v0, v1);
            if (edge==OpenSubdiv::Vtr::INDEX_INVALID) {
                TF_WARN("Set edge sharpness cannot find edge (%d-%d) (%s)",
                        v0, v1, converter.name.GetText());
            } else {
                setBaseEdgeSharpness(refiner,
                    edge, std::max(0.0f, creaseWeights[sindex]));
            }

            if (perEdgeCrease) ++sindex;
        }
        if (!perEdgeCrease) ++sindex;
        cindex += creaseLengths[i];
    }

    //
    // corners
    //

    VtIntArray const cornerIndices = tags.GetCornerIndices();
    VtFloatArray const cornerWeights = tags.GetCornerWeights();

    size_t numCorners = cornerIndices.size();

    if (cornerWeights.size() != numCorners) {
        TF_WARN("Invalid length of corner sharpnesses at prim %s\n",
            converter.name.GetText());
        numCorners = 0;
    }
    for (size_t i=0; i < numCorners; ++i) {
        int vert = cornerIndices[i];
        if (vert >= 0 && vert < refiner.GetLevel(0).GetNumVertices()) {
            setBaseVertexSharpness(refiner,
                vert, std::max(0.0f, cornerWeights[i]));
        } else {
            TF_WARN("Set vertex sharpness cannot find vertex (%d) (%s)",
                vert, converter.name.GetText());
        }
    }

    //
    // holes
    //

    VtIntArray const holeIndices = tags.GetHoleIndices();

    int numHoles = holeIndices.size();

    for (int i=0; i < numHoles; ++i) {
        int face = holeIndices[i];
        if (face >= 0 && face < refiner.GetLevel(0).GetNumFaces()) {
            setBaseFaceHole(refiner, face, true);
        } else {
            TF_WARN("Set hole cannot find face (%d) (%s)",
                face, converter.name.GetText());
        }
    }

    return true;
}
Example #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;
}