LimitStencilTables const * LimitStencilTablesFactory::Create(TopologyRefiner const & refiner, LocationArrayVec const & locationArrays, StencilTables const * cvStencils, PatchTables const * patchTables) { // Compute the total number of stencils to generate int numStencils=0, numLimitStencils=0; for (int i=0; i<(int)locationArrays.size(); ++i) { assert(locationArrays[i].numLocations>=0); numStencils += locationArrays[i].numLocations; } if (numStencils<=0) { return 0; } bool uniform = refiner.IsUniform(); int maxlevel = refiner.GetMaxLevel(), maxsize=17; StencilTables const * cvstencils = cvStencils; if (not cvstencils) { // Generate stencils for the control vertices - this is necessary to // properly factorize patches with control vertices at level 0 (natural // regular patches, such as in a torus) // note: the control vertices of the mesh are added as single-index // stencils of weight 1.0f StencilTablesFactory::Options options; options.generateIntermediateLevels = uniform ? false :true; options.generateControlVerts = true; options.generateOffsets = true; // XXXX (manuelk) We could potentially save some mem-copies by not // instanciating the stencil tables and work directly off the pool // allocators. cvstencils = StencilTablesFactory::Create(refiner, options); } else { // Sanity checks if (cvstencils->GetNumStencils() != (uniform ? refiner.GetNumVertices(maxlevel) : refiner.GetNumVerticesTotal())) { return 0; } } // If a stencil table was given, use it, otherwise, create a new one PatchTables const * patchtables = patchTables; if (not patchTables) { // XXXX (manuelk) If no patch-tables was passed, we should be able to // infer the patches fairly easily from the refiner. Once more tags // have been added to the refiner, maybe we can remove the need for the // patch tables. OpenSubdiv::Far::PatchTablesFactory::Options options; options.adaptiveStencilTables = cvstencils; patchtables = PatchTablesFactory::Create(refiner, options); } else { // Sanity checks if (patchTables->IsFeatureAdaptive()==uniform) { if (not cvStencils) { assert(cvstencils and cvstencils!=cvStencils); delete cvstencils; } return 0; } } assert(patchtables and cvstencils); // Create a patch-map to locate sub-patches faster PatchMap patchmap( *patchtables ); // // Generate limit stencils for locations // // Create a pool allocator to accumulate ProtoLimitStencils LimitStencilAllocator alloc(maxsize); alloc.Resize(numStencils); // XXXX (manuelk) we can make uniform (bilinear) stencils faster with a // dedicated code path that does not use PatchTables or the PatchMap for (int i=0, currentStencil=0; i<(int)locationArrays.size(); ++i) { LocationArray const & array = locationArrays[i]; assert(array.ptexIdx>=0); for (int j=0; j<array.numLocations; ++j, ++currentStencil) { float s = array.s[j], t = array.t[j]; PatchMap::Handle const * handle = patchmap.FindPatch(array.ptexIdx, s, t); if (handle) { ProtoLimitStencil dst = alloc[currentStencil]; if (uniform) { patchtables->Interpolate(*handle, s, t, *cvstencils, dst); } else { patchtables->Limit(*handle, s, t, *cvstencils, dst); } ++numLimitStencils; } } } if (not cvStencils) { delete cvstencils; } // // Copy the proto-stencils into the limit stencil tables // LimitStencilTables * result = new LimitStencilTables; int nelems = alloc.GetNumVerticesTotal(); if (nelems>0) { // Allocate result->resize(numLimitStencils, nelems); // Copy stencils LimitStencil dst(&result->_sizes.at(0), &result->_indices.at(0), &result->_weights.at(0), &result->_duWeights.at(0), &result->_dvWeights.at(0)); for (int i=0; i<alloc.GetNumStencils(); ++i) { *dst._size = alloc.CopyLimitStencil(i, dst._indices, dst._weights, dst._duWeights, dst._dvWeights); dst.Next(); } // XXXX manuelk should offset creation be optional ? result->generateOffsets(); } result->_numControlVertices = refiner.GetNumVertices(0); return result; }
//------------------------------------------------------------------------------ LimitStencilTable const * LimitStencilTableFactory::Create(TopologyRefiner const & refiner, LocationArrayVec const & locationArrays, StencilTable const * cvStencilsIn, PatchTable const * patchTableIn, Options options) { // Compute the total number of stencils to generate int numStencils=0, numLimitStencils=0; for (int i=0; i<(int)locationArrays.size(); ++i) { assert(locationArrays[i].numLocations>=0); numStencils += locationArrays[i].numLocations; } if (numStencils<=0) { return 0; } bool uniform = refiner.IsUniform(); int maxlevel = refiner.GetMaxLevel(); StencilTable const * cvstencils = cvStencilsIn; if (! cvstencils) { // Generate stencils for the control vertices - this is necessary to // properly factorize patches with control vertices at level 0 (natural // regular patches, such as in a torus) // note: the control vertices of the mesh are added as single-index // stencils of weight 1.0f StencilTableFactory::Options options; options.generateIntermediateLevels = uniform ? false :true; options.generateControlVerts = true; options.generateOffsets = true; // PERFORMANCE: We could potentially save some mem-copies by not // instantiating the stencil tables and work directly off the source // data. cvstencils = StencilTableFactory::Create(refiner, options); } else { // Sanity checks // // Note that the input cvStencils could be larger than the number of // refiner's vertices, due to the existence of the end cap stencils. if (cvstencils->GetNumStencils() < (uniform ? refiner.GetLevel(maxlevel).GetNumVertices() : refiner.GetNumVerticesTotal())) { return 0; } } // If a stencil table was given, use it, otherwise, create a new one PatchTable const * patchtable = patchTableIn; if (! patchtable) { // XXXX (manuelk) If no patch-table was passed, we should be able to // infer the patches fairly easily from the refiner. Once more tags // have been added to the refiner, maybe we can remove the need for the // patch table. PatchTableFactory::Options options; options.SetEndCapType( Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS); patchtable = PatchTableFactory::Create(refiner, options); if (! cvStencilsIn) { // if cvstencils is just created above, append endcap stencils if (StencilTable const *localPointStencilTable = patchtable->GetLocalPointStencilTable()) { StencilTable const *table = StencilTableFactory::AppendLocalPointStencilTable( refiner, cvstencils, localPointStencilTable); delete cvstencils; cvstencils = table; } } } else { // Sanity checks if (patchtable->IsFeatureAdaptive()==uniform) { if (! cvStencilsIn) { assert(cvstencils && cvstencils!=cvStencilsIn); delete cvstencils; } return 0; } } assert(patchtable && cvstencils); // Create a patch-map to locate sub-patches faster PatchMap patchmap( *patchtable ); // // Generate limit stencils for locations // internal::StencilBuilder builder(refiner.GetLevel(0).GetNumVertices(), /*genControlVerts*/ false, /*compactWeights*/ true); internal::StencilBuilder::Index origin(&builder, 0); internal::StencilBuilder::Index dst = origin; float wP[20], wDs[20], wDt[20], wDss[20], wDst[20], wDtt[20]; for (size_t i=0; i<locationArrays.size(); ++i) { LocationArray const & array = locationArrays[i]; assert(array.ptexIdx>=0); for (int j=0; j<array.numLocations; ++j) { // for each face we're working on float s = array.s[j], t = array.t[j]; // for each target (s,t) point on that face PatchMap::Handle const * handle = patchmap.FindPatch(array.ptexIdx, s, t); if (handle) { ConstIndexArray cvs = patchtable->GetPatchVertices(*handle); StencilTable const & src = *cvstencils; dst = origin[numLimitStencils]; if (options.generate2ndDerivatives) { patchtable->EvaluateBasis(*handle, s, t, wP, wDs, wDt, wDss, wDst, wDtt); dst.Clear(); for (int k = 0; k < cvs.size(); ++k) { dst.AddWithWeight(src[cvs[k]], wP[k], wDs[k], wDt[k], wDss[k], wDst[k], wDtt[k]); } } else if (options.generate1stDerivatives) { patchtable->EvaluateBasis(*handle, s, t, wP, wDs, wDt); dst.Clear(); for (int k = 0; k < cvs.size(); ++k) { dst.AddWithWeight(src[cvs[k]], wP[k], wDs[k], wDt[k]); } } else { patchtable->EvaluateBasis(*handle, s, t, wP); dst.Clear(); for (int k = 0; k < cvs.size(); ++k) { dst.AddWithWeight(src[cvs[k]], wP[k]); } } ++numLimitStencils; } } } if (! cvStencilsIn) { delete cvstencils; } if (! patchTableIn) { delete patchtable; } // // Copy the proto-stencils into the limit stencil table // LimitStencilTable * result = new LimitStencilTable( refiner.GetLevel(0).GetNumVertices(), builder.GetStencilOffsets(), builder.GetStencilSizes(), builder.GetStencilSources(), builder.GetStencilWeights(), builder.GetStencilDuWeights(), builder.GetStencilDvWeights(), builder.GetStencilDuuWeights(), builder.GetStencilDuvWeights(), builder.GetStencilDvvWeights(), /*ctrlVerts*/false, /*fristOffset*/0); return result; }