// // 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/patchTable.h" #include "../far/patchBasis.h" #include #include namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Far { PatchTable::PatchTable(int maxvalence) : _maxValence(maxvalence), _localPointStencils(), _localPointVaryingStencils(), _varyingDesc(Far::PatchDescriptor::QUADS), _vertexPrecisionIsDouble(false), _varyingPrecisionIsDouble(false), _faceVaryingPrecisionIsDouble(false) { } // Copy constructor // XXXX manuelk we need to eliminate this constructor (C++11 smart pointers) PatchTable::PatchTable(PatchTable const & src) : _maxValence(src._maxValence), _numPtexFaces(src._numPtexFaces), _patchArrays(src._patchArrays), _patchVerts(src._patchVerts), _paramTable(src._paramTable), _quadOffsetsTable(src._quadOffsetsTable), _vertexValenceTable(src._vertexValenceTable), _localPointStencils(src._localPointStencils), _localPointVaryingStencils(src._localPointVaryingStencils), _varyingDesc(src._varyingDesc), _fvarChannels(src._fvarChannels), _sharpnessIndices(src._sharpnessIndices), _sharpnessValues(src._sharpnessValues), _vertexPrecisionIsDouble(src._vertexPrecisionIsDouble), _varyingPrecisionIsDouble(src._varyingPrecisionIsDouble), _faceVaryingPrecisionIsDouble(src._faceVaryingPrecisionIsDouble) { if (src._localPointStencils.IsSet()) { _localPointStencils = src._localPointStencils.Clone(); } if (src._localPointVaryingStencils.IsSet()) { _localPointVaryingStencils = src._localPointVaryingStencils.Clone(); } if (! src._localPointFaceVaryingStencils.empty()) { _localPointFaceVaryingStencils.resize(src._localPointFaceVaryingStencils.size()); for (int fvc=0; fvc<(int)_localPointFaceVaryingStencils.size(); ++fvc) { _localPointFaceVaryingStencils[fvc] = src._localPointFaceVaryingStencils[fvc].Clone(); } } } PatchTable::~PatchTable() { _localPointStencils.Delete(); _localPointVaryingStencils.Delete(); for (int fvc=0; fvc<(int)_localPointFaceVaryingStencils.size(); ++fvc) { _localPointFaceVaryingStencils[fvc].Delete(); } } // // PatchArrays // struct PatchTable::PatchArray { PatchArray(PatchDescriptor d, int np, Index v, Index p, Index qo) : desc(d), numPatches(np), vertIndex(v), patchIndex(p), quadOffsetIndex (qo) { } void print() const; PatchDescriptor desc; // type of patches in the array int numPatches; // number of patches in the array Index vertIndex, // index to the first control vertex patchIndex, // absolute index of the first patch in the array quadOffsetIndex; // index of the first quad offset entry }; // debug helper void PatchTable::PatchArray::print() const { desc.print(); printf(" numPatches=%d vertIndex=%d patchIndex=%d " "quadOffsetIndex=%d\n", numPatches, vertIndex, patchIndex, quadOffsetIndex); } inline PatchTable::PatchArray & PatchTable::getPatchArray(Index arrayIndex) { assert(arrayIndex<(Index)GetNumPatchArrays()); return _patchArrays[arrayIndex]; } inline PatchTable::PatchArray const & PatchTable::getPatchArray(Index arrayIndex) const { assert(arrayIndex<(Index)GetNumPatchArrays()); return _patchArrays[arrayIndex]; } void PatchTable::reservePatchArrays(int numPatchArrays) { _patchArrays.reserve(numPatchArrays); } // // FVarPatchChannel // // Stores a record for each patch in the primitive : // // - Each patch in the PatchTable has a corresponding patch in each // face-varying patch channel. Patch vertex indices are sorted in the same // patch-type order as PatchTable::PTables. Face-varying data for a patch // can therefore be quickly accessed by using the patch primitive ID as // index into patchValueOffsets to locate the face-varying control vertex // indices. // // - Face-varying channels can have a different interpolation modes // // - Unlike "vertex" patches, there are no transition masks required // for face-varying patches. // // - Face-varying patches still require boundary edge masks. // // - currently most patches with sharp boundaries but smooth interiors have // to be isolated to level 10 : we need a special type of bicubic patch // similar to single-crease to resolve this condition without requiring // isolation if possible // struct PatchTable::FVarPatchChannel { Sdc::Options::FVarLinearInterpolation interpolation; PatchDescriptor desc; std::vector patchValues; std::vector patchParam; }; void PatchTable::allocateVaryingVertices( PatchDescriptor desc, int numPatches) { _varyingDesc = desc; _varyingVerts.resize(numPatches*desc.GetNumControlVertices()); } inline PatchTable::FVarPatchChannel & PatchTable::getFVarPatchChannel(int channel) { assert(channel>=0 && channel<(int)_fvarChannels.size()); return _fvarChannels[channel]; } inline PatchTable::FVarPatchChannel const & PatchTable::getFVarPatchChannel(int channel) const { assert(channel>=0 && channel<(int)_fvarChannels.size()); return _fvarChannels[channel]; } void PatchTable::allocateFVarPatchChannels(int numChannels) { _fvarChannels.resize(numChannels); } void PatchTable::allocateFVarPatchChannelValues( PatchDescriptor desc, int numPatches, int channel) { FVarPatchChannel & c = getFVarPatchChannel(channel); c.desc = desc; c.patchValues.resize(numPatches*desc.GetNumControlVertices()); c.patchParam.resize(numPatches); } void PatchTable::setFVarPatchChannelLinearInterpolation( Sdc::Options::FVarLinearInterpolation interpolation, int channel) { FVarPatchChannel & c = getFVarPatchChannel(channel); c.interpolation = interpolation; } // // PatchTable // inline int getPatchSize(PatchDescriptor desc) { return desc.GetNumControlVertices(); } void PatchTable::pushPatchArray(PatchDescriptor desc, int npatches, Index * vidx, Index * pidx, Index * qoidx) { if (npatches>0) { _patchArrays.push_back(PatchArray( desc, npatches, *vidx, *pidx, qoidx ? *qoidx : 0)); int nverts = getPatchSize(desc); *vidx += npatches * nverts; *pidx += npatches; if (qoidx) { *qoidx += (desc.GetType() == PatchDescriptor::GREGORY) ? npatches*nverts : 0; } } } int PatchTable::getPatchIndex(int arrayIndex, int patchIndex) const { PatchArray const & pa = getPatchArray(arrayIndex); assert(patchIndex=0 && channel<(int)_localPointFaceVaryingStencils.size()) { return _localPointFaceVaryingStencils[channel].IsSet() ? _localPointFaceVaryingStencils[channel].Size() : 0; } return 0; } PatchTable::ConstQuadOffsetsArray PatchTable::GetPatchQuadOffsets(PatchHandle const & handle) const { PatchArray const & pa = getPatchArray(handle.arrayIndex); return Vtr::ConstArray(&_quadOffsetsTable[pa.quadOffsetIndex + handle.vertIndex], 4); } bool PatchTable::IsFeatureAdaptive() const { // XXX: // revisit this function, since we'll add uniform cubic patches later. for (int i=0; i=PatchDescriptor::REGULAR && desc.GetType()<=PatchDescriptor::GREGORY_BASIS) { return true; } } return false; } PatchDescriptor PatchTable::GetVaryingPatchDescriptor() const { return _varyingDesc; } ConstIndexArray PatchTable::GetPatchVaryingVertices(PatchHandle const & handle) const { if (_varyingVerts.empty()) { return ConstIndexArray(); } int numVaryingCVs = _varyingDesc.GetNumControlVertices(); Index start = handle.patchIndex * numVaryingCVs; return ConstIndexArray(&_varyingVerts[start], numVaryingCVs); } ConstIndexArray PatchTable::GetPatchVaryingVertices(int array, int patch) const { if (_varyingVerts.empty()) { return ConstIndexArray(); } PatchArray const & pa = getPatchArray(array); int numVaryingCVs = _varyingDesc.GetNumControlVertices(); Index start = (pa.patchIndex + patch) * numVaryingCVs; return ConstIndexArray(&_varyingVerts[start], numVaryingCVs); } ConstIndexArray PatchTable::GetPatchArrayVaryingVertices(int array) const { if (_varyingVerts.empty()) { return ConstIndexArray(); } PatchArray const & pa = getPatchArray(array); int numVaryingCVs = _varyingDesc.GetNumControlVertices(); Index start = pa.patchIndex * numVaryingCVs; Index count = pa.numPatches * numVaryingCVs; return ConstIndexArray(&_varyingVerts[start], count); } ConstIndexArray PatchTable::GetVaryingVertices() const { if (_varyingVerts.empty()) { return ConstIndexArray(); } return ConstIndexArray(&_varyingVerts[0], (int)_varyingVerts.size()); } IndexArray PatchTable::getPatchArrayVaryingVertices(int arrayIndex) { PatchArray const & pa = getPatchArray(arrayIndex); int numVaryingCVs = _varyingDesc.GetNumControlVertices(); Index start = pa.patchIndex * numVaryingCVs; return IndexArray(&_varyingVerts[start], pa.numPatches * numVaryingCVs); } void PatchTable::populateVaryingVertices() { // In order to support evaluation of varying data we need to access // the varying values indexed by the zero ring vertices of the vertex // patch. This indexing is redundant for triangles and quads and // could be made redunant for other patch types if we reorganized // the vertex patch indices so that the zero ring indices always occured // first. This will also need to be updated when we add support for // triangle patches. int numVaryingCVs = _varyingDesc.GetNumControlVertices(); for (int arrayIndex=0; arrayIndex<(int)_patchArrays.size(); ++arrayIndex) { PatchArray const & pa = getPatchArray(arrayIndex); PatchDescriptor::Type patchType = pa.desc.GetType(); for (int patch=0; patch void PatchTable::EvaluateBasis( PatchHandle const & handle, REAL s, REAL t, REAL wP[], REAL wDs[], REAL wDt[], REAL wDss[], REAL wDst[], REAL wDtt[]) const { PatchDescriptor::Type patchType = GetPatchArrayDescriptor(handle.arrayIndex).GetType(); PatchParam const & param = _paramTable[handle.patchIndex]; if (patchType == PatchDescriptor::REGULAR) { internal::GetBSplineWeights(param, s, t, wP, wDs, wDt, wDss, wDst, wDtt); } else if (patchType == PatchDescriptor::GREGORY_BASIS) { internal::GetGregoryWeights(param, s, t, wP, wDs, wDt, wDss, wDst, wDtt); } else if (patchType == PatchDescriptor::QUADS) { internal::GetBilinearWeights(param, s, t, wP, wDs, wDt, wDss, wDst, wDtt); } else { assert(0); } } // // Evaluate basis functions for varying and derivatives at (s,t): // template void PatchTable::EvaluateBasisVarying( PatchHandle const & handle, REAL s, REAL t, REAL wP[], REAL wDs[], REAL wDt[], REAL wDss[], REAL wDst[], REAL wDtt[]) const { PatchParam const & param = _paramTable[handle.patchIndex]; internal::GetBilinearWeights(param, s, t, wP, wDs, wDt, wDss, wDst, wDtt); } // // Evaluate basis functions for face-varying and derivatives at (s,t): // template void PatchTable::EvaluateBasisFaceVarying( PatchHandle const & handle, REAL s, REAL t, REAL wP[], REAL wDs[], REAL wDt[], REAL wDss[], REAL wDst[], REAL wDtt[], int channel) const { PatchParam param = getPatchFVarPatchParam(handle.patchIndex, channel); PatchDescriptor::Type patchType = param.IsRegular() ? PatchDescriptor::REGULAR : GetFVarPatchDescriptor(channel).GetType(); if (patchType == PatchDescriptor::REGULAR) { internal::GetBSplineWeights(param, s, t, wP, wDs, wDt, wDss, wDst, wDtt); } else if (patchType == PatchDescriptor::GREGORY_BASIS) { internal::GetGregoryWeights(param, s, t, wP, wDs, wDt, wDss, wDst, wDtt); } else if (patchType == PatchDescriptor::QUADS) { internal::GetBilinearWeights(param, s, t, wP, wDs, wDt, wDss, wDst, wDtt); } else { assert(0); } } // // Explicit instantiation of EvaluateBasis...() methods for float and double: // template void PatchTable::EvaluateBasis(PatchHandle const & handle, float s, float t, float wP[], float wDs[], float wDt[], float wDss[], float wDst[], float wDtt[]) const; template void PatchTable::EvaluateBasisVarying(PatchHandle const & handle, float s, float t, float wP[], float wDs[], float wDt[], float wDss[], float wDst[], float wDtt[]) const; template void PatchTable::EvaluateBasisFaceVarying(PatchHandle const & handle, float s, float t, float wP[], float wDs[], float wDt[], float wDss[], float wDst[], float wDtt[], int channel) const; template void PatchTable::EvaluateBasis(PatchHandle const & handle, double s, double t, double wP[], double wDs[], double wDt[], double wDss[], double wDst[], double wDtt[]) const; template void PatchTable::EvaluateBasisVarying(PatchHandle const & handle, double s, double t, double wP[], double wDs[], double wDt[], double wDss[], double wDst[], double wDtt[]) const; template void PatchTable::EvaluateBasisFaceVarying(PatchHandle const & handle, double s, double t, double wP[], double wDs[], double wDt[], double wDss[], double wDst[], double wDtt[], int channel) const; } // end namespace Far } // end namespace OPENSUBDIV_VERSION } // end namespace OpenSubdiv