// // Copyright 2013 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #include "../far/stencilTableFactory.h" #include "../far/stencilBuilder.h" #include "../far/patchTable.h" #include "../far/patchTableFactory.h" #include "../far/patchMap.h" #include "../far/topologyRefiner.h" #include "../far/primvarRefiner.h" #include #include #include namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Far { using internal::StencilBuilder; namespace { #ifdef __INTEL_COMPILER #pragma warning (push) #pragma warning disable 1572 #endif template inline bool isWeightZero(REAL w) { return (w == (REAL) 0.0); } #ifdef __INTEL_COMPILER #pragma warning (pop) #endif } //------------------------------------------------------------------------------ template void StencilTableFactoryReal::generateControlVertStencils( int numControlVerts, StencilReal & dst) { // Control vertices contribute a single index with a weight of 1.0 for (int i=0; i StencilTableReal const * StencilTableFactoryReal::Create(TopologyRefiner const & refiner, Options options) { bool interpolateVertex = options.interpolationMode==INTERPOLATE_VERTEX; bool interpolateVarying = options.interpolationMode==INTERPOLATE_VARYING; bool interpolateFaceVarying = options.interpolationMode==INTERPOLATE_FACE_VARYING; int numControlVertices = !interpolateFaceVarying ? refiner.GetLevel(0).GetNumVertices() : refiner.GetLevel(0).GetNumFVarValues(options.fvarChannel); int maxlevel = std::min(int(options.maxLevel), refiner.GetMaxLevel()); if (maxlevel==0 && (! options.generateControlVerts)) { StencilTableReal * result = new StencilTableReal; result->_numControlVertices = numControlVertices; return result; } StencilBuilder builder(numControlVertices, /*genControlVerts*/ true, /*compactWeights*/ true); // // Interpolate stencils for each refinement level // PrimvarRefinerReal primvarRefiner(refiner); typename StencilBuilder::Index srcIndex(&builder, 0); typename StencilBuilder::Index dstIndex(&builder, numControlVertices); for (int level=1; level<=maxlevel; ++level) { if (interpolateVertex) { primvarRefiner.Interpolate(level, srcIndex, dstIndex); } else if (interpolateVarying) { primvarRefiner.InterpolateVarying(level, srcIndex, dstIndex); } else { primvarRefiner.InterpolateFaceVarying(level, srcIndex, dstIndex, options.fvarChannel); } if (options.factorizeIntermediateLevels) { srcIndex = dstIndex; } int dstVertex = !interpolateFaceVarying ? refiner.GetLevel(level).GetNumVertices() : refiner.GetLevel(level).GetNumFVarValues(options.fvarChannel); dstIndex = dstIndex[dstVertex]; if (! options.factorizeIntermediateLevels) { // All previous verts are considered as coarse verts, as a // result, we don't update the srcIndex and update the coarse // vertex count. builder.SetCoarseVertCount(dstIndex.GetOffset()); } } size_t firstOffset = numControlVertices; if (! options.generateIntermediateLevels) firstOffset = srcIndex.GetOffset(); // Copy stencils from the StencilBuilder into the StencilTable. // Always initialize numControlVertices (useful for torus case) StencilTableReal * result = new StencilTableReal(numControlVertices, builder.GetStencilOffsets(), builder.GetStencilSizes(), builder.GetStencilSources(), builder.GetStencilWeights(), options.generateControlVerts, firstOffset); return result; } //------------------------------------------------------------------------------ template StencilTableReal const * StencilTableFactoryReal::Create(int numTables, StencilTableReal const ** tables) { // XXXtakahito: // This function returns NULL for empty inputs or erroneous condition. // It's convenient for skipping varying stencils etc, however, // other Create() API returns an empty stencil instead of NULL. // They need to be consistent. if ( (numTables<=0) || (! tables)) { return NULL; } int ncvs = -1, nstencils = 0, nelems = 0; for (int i=0; i const * st = tables[i]; // allow the tables could have a null entry. if (!st) continue; if (ncvs >= 0 && st->GetNumControlVertices() != ncvs) { return NULL; } ncvs = st->GetNumControlVertices(); nstencils += st->GetNumStencils(); nelems += (int)st->GetControlIndices().size(); } if (ncvs == -1) { return NULL; } StencilTableReal * result = new StencilTableReal; result->resize(nstencils, nelems); int * sizes = &result->_sizes[0]; Index * indices = &result->_indices[0]; REAL * weights = &result->_weights[0]; for (int i=0; i const * st = tables[i]; if (!st) continue; int st_nstencils = st->GetNumStencils(), st_nelems = (int)st->_indices.size(); memcpy(sizes, &st->_sizes[0], st_nstencils*sizeof(int)); memcpy(indices, &st->_indices[0], st_nelems*sizeof(Index)); memcpy(weights, &st->_weights[0], st_nelems*sizeof(REAL)); sizes += st_nstencils; indices += st_nelems; weights += st_nelems; } result->_numControlVertices = ncvs; // have to re-generate offsets from scratch result->generateOffsets(); return result; } //------------------------------------------------------------------------------ template StencilTableReal const * StencilTableFactoryReal::AppendLocalPointStencilTable( TopologyRefiner const &refiner, StencilTableReal const * baseStencilTable, StencilTableReal const * localPointStencilTable, bool factorize) { return appendLocalPointStencilTable( refiner, baseStencilTable, localPointStencilTable, /*channel*/-1, factorize); } template StencilTableReal const * StencilTableFactoryReal::AppendLocalPointStencilTableFaceVarying( TopologyRefiner const &refiner, StencilTableReal const * baseStencilTable, StencilTableReal const * localPointStencilTable, int channel, bool factorize) { return appendLocalPointStencilTable( refiner, baseStencilTable, localPointStencilTable, channel, factorize); } template StencilTableReal const * StencilTableFactoryReal::appendLocalPointStencilTable( TopologyRefiner const &refiner, StencilTableReal const * baseStencilTable, StencilTableReal const * localPointStencilTable, int channel, bool factorize) { // require the local point stencils exist and be non-empty if ((localPointStencilTable == NULL) || (localPointStencilTable->GetNumStencils() == 0)) { return NULL; } int nControlVerts = channel < 0 ? refiner.GetLevel(0).GetNumVertices() : refiner.GetLevel(0).GetNumFVarValues(channel); // if no base stencils or empty, return copy of local point stencils if ((baseStencilTable == NULL) || (baseStencilTable->GetNumStencils() == 0)) { StencilTableReal * result = new StencilTableReal(*localPointStencilTable); result->_numControlVertices = nControlVerts; return result; } // baseStencilTable can be built with or without singular stencils // (single weight of 1.0f) as place-holders for coarse mesh vertices. int controlVertsIndexOffset = 0; int nBaseStencils = baseStencilTable->GetNumStencils(); int nBaseStencilsElements = (int)baseStencilTable->_indices.size(); { int nverts = channel < 0 ? refiner.GetNumVerticesTotal() : refiner.GetNumFVarValuesTotal(channel); if (nBaseStencils == nverts) { // the table contains stencils for the control vertices // // <----------------- nverts ------------------> // // +---------------+----------------------------+-----------------+ // | control verts | refined verts : (max lv) | local points | // +---------------+----------------------------+-----------------+ // | base stencil table | LP stencils | // +--------------------------------------------+-----------------+ // ^ / // \_________________________/ // // controlVertsIndexOffset = 0; } else if (nBaseStencils == (nverts - nControlVerts)) { // the table does not contain stencils for the control vertices // // <----------------- nverts ------------------> // <------ nBaseStencils -------> // +---------------+----------------------------+-----------------+ // | control verts | refined verts : (max lv) | local points | // +---------------+----------------------------+-----------------+ // | base stencil table | LP stencils | // +----------------------------+-----------------+ // ^ / // \_________________/ // <--------------> // controlVertsIndexOffset // controlVertsIndexOffset = nControlVerts; } else { // these are not the stencils you are looking for. assert(0); return NULL; } } // copy all local point stencils to proto stencils, and factorize if needed. int nLocalPointStencils = localPointStencilTable->GetNumStencils(); int nLocalPointStencilsElements = 0; StencilBuilder builder(nControlVerts, /*genControlVerts*/ false, /*compactWeights*/ factorize); typename StencilBuilder::Index origin(&builder, 0); typename StencilBuilder::Index dst = origin; typename StencilBuilder::Index srcIdx = origin; for (int i = 0 ; i < nLocalPointStencils; ++i) { StencilReal src = localPointStencilTable->GetStencil(i); dst = origin[i]; for (int j = 0; j < src.GetSize(); ++j) { Index index = src.GetVertexIndices()[j]; REAL weight = src.GetWeights()[j]; if (isWeightZero(weight)) continue; if (factorize) { dst.AddWithWeight( // subtracting controlVertsIndex if the baseStencil doesn't // include control vertices (see above diagram) // since currently local point stencils are created with // absolute indices including control (level=0) vertices. baseStencilTable->GetStencil(index - controlVertsIndexOffset), weight); } else { srcIdx = origin[index + controlVertsIndexOffset]; dst.AddWithWeight(srcIdx, weight); } } nLocalPointStencilsElements += builder.GetNumVertsInStencil(i); } // create new stencil table StencilTableReal * result = new StencilTableReal; result->_numControlVertices = nControlVerts; result->resize(nBaseStencils + nLocalPointStencils, nBaseStencilsElements + nLocalPointStencilsElements); int* sizes = &result->_sizes[0]; Index * indices = &result->_indices[0]; REAL * weights = &result->_weights[0]; // put base stencils first memcpy(sizes, &baseStencilTable->_sizes[0], nBaseStencils*sizeof(int)); memcpy(indices, &baseStencilTable->_indices[0], nBaseStencilsElements*sizeof(Index)); memcpy(weights, &baseStencilTable->_weights[0], nBaseStencilsElements*sizeof(REAL)); sizes += nBaseStencils; indices += nBaseStencilsElements; weights += nBaseStencilsElements; // endcap stencils second for (int i = 0 ; i < nLocalPointStencils; ++i) { int size = builder.GetNumVertsInStencil(i); int idx = builder.GetStencilOffsets()[i]; for (int j = 0; j < size; ++j) { *indices++ = builder.GetStencilSources()[idx+j]; *weights++ = builder.GetStencilWeights()[idx+j]; } *sizes++ = size; } // have to re-generate offsets from scratch result->generateOffsets(); return result; } //------------------------------------------------------------------------------ template LimitStencilTableReal const * LimitStencilTableFactoryReal::Create(TopologyRefiner const & refiner, LocationArrayVec const & locationArrays, StencilTableReal 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(); bool interpolateVertex = (options.interpolationMode == INTERPOLATE_VERTEX); bool interpolateVarying = (options.interpolationMode == INTERPOLATE_VARYING); bool interpolateFaceVarying = (options.interpolationMode == INTERPOLATE_FACE_VARYING); int fvarChannel = options.fvarChannel; // // Quick sanity checks for given PatchTable and/or StencilTables: // int nRefinedStencils = 0; if (uniform) { // Uniform stencils must include at least the last level points: nRefinedStencils = interpolateFaceVarying ? refiner.GetLevel(maxlevel).GetNumFVarValues(fvarChannel) : refiner.GetLevel(maxlevel).GetNumVertices(); } else { // Adaptive stencils must include at least all refined points: nRefinedStencils = interpolateFaceVarying ? refiner.GetNumFVarValuesTotal(fvarChannel) : refiner.GetNumVerticesTotal(); } if (cvStencilsIn && (cvStencilsIn->GetNumStencils() < nRefinedStencils)) { // Too few stencils in given StencilTable return 0; } if (patchTableIn && (patchTableIn->IsFeatureAdaptive() == uniform)) { // Adaptive/uniform mismatch with given PatchTable and refiner return 0; } // If an appropriate StencilTable was given, use it, otherwise, create a new one StencilTableReal 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 // typename StencilTableFactoryReal::Options stencilTableOptions; stencilTableOptions.generateIntermediateLevels = uniform ? false :true; stencilTableOptions.generateControlVerts = true; stencilTableOptions.generateOffsets = true; stencilTableOptions.interpolationMode = options.interpolationMode; stencilTableOptions.fvarChannel = options.fvarChannel; cvstencils = StencilTableFactoryReal::Create(refiner, stencilTableOptions); } // If an appropriate PatchTable was given, use it, otherwise, create a new one PatchTable const * patchtable = patchTableIn; if (! patchtable) { // // Ideally we could create a sparse PatchTable here for the given // Locations, but that requires inverting the ptex/base-face relation. // so the caller must deal with that and provide such a PatchTable // PatchTableFactory::Options patchTableOptions; patchTableOptions.SetPatchPrecision(); patchTableOptions.includeBaseLevelIndices = true; patchTableOptions.generateVaryingTables = interpolateVarying; patchTableOptions.generateFVarTables = interpolateFaceVarying; if (interpolateFaceVarying) { patchTableOptions.includeFVarBaseLevelIndices = true; patchTableOptions.numFVarChannels = 1; patchTableOptions.fvarChannelIndices = &fvarChannel; patchTableOptions.generateFVarLegacyLinearPatches = uniform || !refiner.GetAdaptiveOptions().considerFVarChannels; } patchTableOptions.SetEndCapType( Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS); patchTableOptions.useInfSharpPatch = !uniform && refiner.GetAdaptiveOptions().useInfSharpPatch; patchtable = PatchTableFactory::Create(refiner, patchTableOptions); } // Append local point stencils and further verfiy size of given StencilTable: StencilTableReal const * localstencils = 0; if (interpolateVertex) { localstencils = patchtable->GetLocalPointStencilTable(); } else if (interpolateFaceVarying) { localstencils = patchtable->GetLocalPointFaceVaryingStencilTable(fvarChannel); } else { localstencils = patchtable->GetLocalPointVaryingStencilTable(); } if (localstencils && (cvstencils->GetNumStencils() == nRefinedStencils)) { StencilTableReal const *refinedstencils = cvstencils; if (interpolateFaceVarying) { cvstencils = StencilTableFactoryReal::AppendLocalPointStencilTableFaceVarying( refiner, refinedstencils, localstencils, fvarChannel); } else { cvstencils = StencilTableFactoryReal::AppendLocalPointStencilTable( refiner, refinedstencils, localstencils); } if (!cvStencilsIn) delete refinedstencils; } assert(patchtable && cvstencils); // Create a patch-map to locate sub-patches faster PatchMap patchmap( *patchtable ); // // Generate limit stencils for locations // int nControlVertices = interpolateFaceVarying ? refiner.GetLevel(0).GetNumFVarValues(fvarChannel) : refiner.GetLevel(0).GetNumVertices(); StencilBuilder builder(nControlVertices, /*genControlVerts*/ false, /*compactWeights*/ true); typename StencilBuilder::Index origin(&builder, 0); typename StencilBuilder::Index dst = origin; // // Generally use the patches corresponding to the interpolation mode, but Uniform // PatchTables do not have varying patches -- use the equivalent linear vertex // patches in this case: // bool useVertexPatches = interpolateVertex || (interpolateVarying && uniform); bool useFVarPatches = interpolateFaceVarying; REAL wP[20], wDs[20], wDt[20], wDss[20], wDst[20], wDtt[20]; for (size_t i=0; i=0); for (int j=0; jGetPatchVertices(*handle); } else if (useFVarPatches) { cvs = patchtable->GetPatchFVarValues(*handle, fvarChannel); } else { cvs = patchtable->GetPatchVaryingVertices(*handle); } StencilTableReal const & src = *cvstencils; dst = origin[numLimitStencils]; if (options.generate2ndDerivatives) { if (useVertexPatches) { patchtable->EvaluateBasis( *handle, s, t, wP, wDs, wDt, wDss, wDst, wDtt); } else if (useFVarPatches) { patchtable->EvaluateBasisFaceVarying( *handle, s, t, wP, wDs, wDt, wDss, wDst, wDtt, fvarChannel); } else { patchtable->EvaluateBasisVarying( *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) { if (useVertexPatches) { patchtable->EvaluateBasis( *handle, s, t, wP, wDs, wDt); } else if (useFVarPatches) { patchtable->EvaluateBasisFaceVarying( *handle, s, t, wP, wDs, wDt, 0, 0, 0, fvarChannel); } else { patchtable->EvaluateBasisVarying( *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 { if (useVertexPatches) { patchtable->EvaluateBasis( *handle, s, t, wP); } else if (useFVarPatches) { patchtable->EvaluateBasisFaceVarying( *handle, s, t, wP, 0, 0, 0, 0, 0, fvarChannel); } else { patchtable->EvaluateBasisVarying( *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 // LimitStencilTableReal * result = new LimitStencilTableReal( nControlVertices, builder.GetStencilOffsets(), builder.GetStencilSizes(), builder.GetStencilSources(), builder.GetStencilWeights(), builder.GetStencilDuWeights(), builder.GetStencilDvWeights(), builder.GetStencilDuuWeights(), builder.GetStencilDuvWeights(), builder.GetStencilDvvWeights(), /*ctrlVerts*/false, /*fristOffset*/0); return result; } // // Explicit instantiation for float and double: // template class StencilTableFactoryReal; template class StencilTableFactoryReal; template class LimitStencilTableFactoryReal; template class LimitStencilTableFactoryReal; } // end namespace Far } // end namespace OPENSUBDIV_VERSION } // end namespace OpenSubdiv