// // 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), _vertexStencilTable(NULL), _varyingStencilTable(NULL) { } // 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), _vertexStencilTable(NULL), _varyingStencilTable(NULL), _fvarChannels(src._fvarChannels), _sharpnessIndices(src._sharpnessIndices), _sharpnessValues(src._sharpnessValues) { if (src._vertexStencilTable) { _vertexStencilTable = new StencilTable(*src._vertexStencilTable); } if (src._varyingStencilTable) { _varyingStencilTable = new StencilTable(*src._varyingStencilTable); } } PatchTable::~PatchTable() { delete _vertexStencilTable; delete _varyingStencilTable; } // // 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, // 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" PatchTable, there are no "transition" patterns required // for face-varying patches. // // - No transition patterns means vertex indices of face-varying patches can // be pre-rotated in the factory, so we do not store patch rotation // // - Face-varying patches still special variants for boundary and corner cases // // - 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 { // Channel interpolation mode Sdc::Options::FVarLinearInterpolation interpolation; // Patch type // // Note : in bilinear interpolation modes, all patches are of the same type, // so we only need a single type (patchesType). In bi-cubic modes, each // patch requires its own type (patchTypes). PatchDescriptor::Type patchesType; std::vector patchTypes; // Patch points values std::vector patchValuesOffsets; // offset to the first value of each patch std::vector patchValues; // point values for each patch }; inline PatchTable::FVarPatchChannel & PatchTable::getFVarPatchChannel(int channel) { assert(channel<(int)_fvarChannels.size()); return _fvarChannels[channel]; } inline PatchTable::FVarPatchChannel const & PatchTable::getFVarPatchChannel(int channel) const { assert(channel<(int)_fvarChannels.size()); return _fvarChannels[channel]; } void PatchTable::allocateFVarPatchChannels(int numChannels) { _fvarChannels.resize(numChannels); } void PatchTable::allocateChannelValues(int channel, int numPatches, int numVerticesTotal) { FVarPatchChannel & c = getFVarPatchChannel(channel); if (c.interpolation==Sdc::Options::FVAR_LINEAR_ALL) { // Allocate bi-linear channels (allows uniform topology to be populated // in a single traversal) c.patchValues.resize(numVerticesTotal); } else { // Allocate per-patch type and offset vectors for bi-cubic patches // // Note : c.patchValues cannot be allocated pre-emptively since we do // not know the type (and size) of each patch yet. These channels // require an extra step to compact the value indices and generate // offsets c.patchesType = PatchDescriptor::NON_PATCH; c.patchTypes.resize(numPatches); } } void PatchTable::setFVarPatchChannelLinearInterpolation(int channel, Sdc::Options::FVarLinearInterpolation interpolation) { FVarPatchChannel & c = getFVarPatchChannel(channel); c.interpolation = interpolation; } void PatchTable::setFVarPatchChannelPatchesType(int channel, PatchDescriptor::Type type) { FVarPatchChannel & c = getFVarPatchChannel(channel); c.patchesType = type; } void PatchTable::setBicubicFVarPatchChannelValues(int channel, int patchSize, std::vector const & values) { // This method populates the sparse array of values held in the patch // table from a non-sparse array of value indices generated during // the second traversal of an adaptive TopologyRefiner. // It is assumed that the patch types have been stored in the channel's // 'patchTypes' vector during the first traversal. FVarPatchChannel & c = getFVarPatchChannel(channel); assert(c.interpolation!=Sdc::Options::FVAR_LINEAR_ALL and c.patchTypes.size()*patchSize==values.size()); int npatches = (int)c.patchTypes.size(), nverts = 0; // Generate offsets and count vertices c.patchValuesOffsets.resize(npatches); for (int patch=0; patch0) { _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(&_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 and desc.GetType()<=PatchDescriptor::GREGORY_BASIS) { return true; } } return false; } int PatchTable::GetNumFVarChannels() const { return (int)_fvarChannels.size(); } Sdc::Options::FVarLinearInterpolation PatchTable::GetFVarChannelLinearInterpolation(int channel) const { FVarPatchChannel const & c = getFVarPatchChannel(channel); return c.interpolation; } Vtr::Array PatchTable::getFVarPatchTypes(int channel) { FVarPatchChannel & c = getFVarPatchChannel(channel); return Vtr::Array(&c.patchTypes[0], (int)c.patchTypes.size()); } Vtr::ConstArray PatchTable::GetFVarPatchTypes(int channel) const { FVarPatchChannel const & c = getFVarPatchChannel(channel); if (c.patchesType!=PatchDescriptor::NON_PATCH) { return Vtr::ConstArray(&c.patchesType, 1); } else { return Vtr::ConstArray(&c.patchTypes[0], (int)c.patchTypes.size()); } } ConstIndexArray PatchTable::GetFVarPatchesValues(int channel) const { FVarPatchChannel const & c = getFVarPatchChannel(channel); return ConstIndexArray(&c.patchValues[0], (int)c.patchValues.size()); } IndexArray PatchTable::getFVarPatchesValues(int channel) { FVarPatchChannel & c = getFVarPatchChannel(channel); return IndexArray(&c.patchValues[0], (int)c.patchValues.size()); } PatchDescriptor::Type PatchTable::getFVarPatchType(int channel, int patch) const { FVarPatchChannel const & c = getFVarPatchChannel(channel); PatchDescriptor::Type type; if (c.patchesType!=PatchDescriptor::NON_PATCH) { assert(c.patchTypes.empty()); type = c.patchesType; } else { assert(patch<(int)c.patchTypes.size()); type = c.patchTypes[patch]; } return type; } PatchDescriptor::Type PatchTable::GetFVarPatchType(int channel, PatchHandle const & handle) const { return getFVarPatchType(channel, handle.patchIndex); } PatchDescriptor::Type PatchTable::GetFVarPatchType(int channel, int arrayIndex, int patchIndex) const { return getFVarPatchType(channel, getPatchIndex(arrayIndex, patchIndex)); } ConstIndexArray PatchTable::getFVarPatchValues(int channel, int patch) const { FVarPatchChannel const & c = getFVarPatchChannel(channel); if (c.patchValuesOffsets.empty()) { int ncvs = PatchDescriptor::GetNumFVarControlVertices(c.patchesType); return ConstIndexArray(&c.patchValues[patch * ncvs], ncvs); } else { assert(patch<(int)c.patchValuesOffsets.size() and patch<(int)c.patchTypes.size()); return ConstIndexArray(&c.patchValues[c.patchValuesOffsets[patch]], PatchDescriptor::GetNumFVarControlVertices(c.patchTypes[patch])); } } ConstIndexArray PatchTable::GetFVarPatchValues(int channel, PatchHandle const & handle) const { return getFVarPatchValues(channel, handle.patchIndex); } ConstIndexArray PatchTable::GetFVarPatchValues(int channel, int arrayIndex, int patchIndex) const { return getFVarPatchValues(channel, getPatchIndex(arrayIndex, patchIndex)); } void PatchTable::print() const { printf("patchTable (0x%p)\n", this); printf(" numPatches = %d\n", GetNumPatchesTotal()); for (int i=0; i