// // 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/gregoryBasis.h" #include "../far/endCapGregoryBasisPatchFactory.h" #include "../far/error.h" #include "../far/stencilTableFactory.h" #include "../far/topologyRefiner.h" #include #include #include namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Far { // // EndCapGregoryBasisPatchFactory for Vertex StencilTable // EndCapGregoryBasisPatchFactory::EndCapGregoryBasisPatchFactory( TopologyRefiner const & refiner, StencilTable * vertexStencils, StencilTable * varyingStencils, bool shareBoundaryVertices) : _vertexStencils(vertexStencils), _varyingStencils(varyingStencils), _refiner(&refiner), _shareBoundaryVertices(shareBoundaryVertices), _numGregoryBasisVertices(0), _numGregoryBasisPatches(0) { // Sanity check: the mesh must be adaptively refined assert(not refiner.IsUniform()); // Reserve the patch point stencils. Ideally topology refiner // would have an API to return how many endcap patches will be required. // Instead we conservatively estimate by the number of patches at the // finest level. int numMaxLevelFaces = refiner.GetLevel(refiner.GetMaxLevel()).GetNumFaces(); int numPatchPointsExpected = numMaxLevelFaces * 20; // limits to 100M (=800M bytes) entries for the reserved size. int numStencilsExpected = std::min(numPatchPointsExpected * 16, 100*1024*1024); _vertexStencils->reserve(numPatchPointsExpected, numStencilsExpected); // varying stencils use only 1 index with weight=1.0 _varyingStencils->reserve(numPatchPointsExpected, numPatchPointsExpected); } // // Stateless EndCapGregoryBasisPatchFactory // GregoryBasis const * EndCapGregoryBasisPatchFactory::Create(TopologyRefiner const & refiner, Index faceIndex, int fvarChannel) { // Gregory patches are end-caps: they only exist on max-level Vtr::internal::Level const & level = refiner.getLevel(refiner.GetMaxLevel()); GregoryBasis::ProtoBasis basis(level, faceIndex, 0, fvarChannel); GregoryBasis * result = new GregoryBasis; basis.Copy(result); // note: this function doesn't create varying stencils. return result; } bool EndCapGregoryBasisPatchFactory::addPatchBasis(Index faceIndex, bool verticesMask[4][5], int levelVertOffset) { // Gregory patches only exist on the hight Vtr::internal::Level const & level = _refiner->getLevel(_refiner->GetMaxLevel()); // Gather the CVs that influence the Gregory patch and their relative // weights in a basis GregoryBasis::ProtoBasis basis(level, faceIndex, levelVertOffset, -1); for (int i = 0; i < 4; ++i) { if (verticesMask[i][0]) { GregoryBasis::AppendToStencilTable(basis.P[i], _vertexStencils); GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils); } if (verticesMask[i][1]) { GregoryBasis::AppendToStencilTable(basis.Ep[i], _vertexStencils); GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils); } if (verticesMask[i][2]) { GregoryBasis::AppendToStencilTable(basis.Em[i], _vertexStencils); GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils); } if (verticesMask[i][3]) { GregoryBasis::AppendToStencilTable(basis.Fp[i], _vertexStencils); GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils); } if (verticesMask[i][4]) { GregoryBasis::AppendToStencilTable(basis.Fm[i], _vertexStencils); GregoryBasis::AppendToStencilTable(basis.varyingIndex[i], _varyingStencils); } } return true; } // // Populates the topology table used by Gregory-basis patches // // Note : 'faceIndex' values are expected to be sorted in ascending order !!! // Note 2: this code attempts to identify basis vertices shared along // gregory patch edges ConstIndexArray EndCapGregoryBasisPatchFactory::GetPatchPoints( Vtr::internal::Level const * level, Index faceIndex, PatchTableFactory::PatchFaceTag const * levelPatchTags, int levelVertOffset) { // allocate indices (awkward) // assert(Vtr::INDEX_INVALID==0xFFFFFFFF); for (int i = 0; i < 20; ++i) { _patchPoints.push_back(Vtr::INDEX_INVALID); } Index * dest = &_patchPoints[_numGregoryBasisPatches * 20]; int gregoryVertexOffset = _refiner->GetNumVerticesTotal(); if (_shareBoundaryVertices) { ConstIndexArray fedges = level->getFaceEdges(faceIndex); assert(fedges.size()==4); for (int i=0; i<4; ++i) { Index edge = fedges[i], adjface = 0; { // Gather adjacent faces ConstIndexArray adjfaces = level->getEdgeFaces(edge); for (int j=0; jgetFaceEdges(adjface); int aedge = aedges.FindIndexIn4Tuple(edge); assert(aedge!=Vtr::INDEX_INVALID); // Find index of basis in the list of basis already generated struct compare { static int op(void const * a, void const * b) { return *(Index const*)a - *(Index const*)b; } }; Index * ptr = (Index *)std::bsearch(&adjface, &_faceIndices[0], _faceIndices.size(), sizeof(Index), compare::op); int srcBasisIdx = (int)(ptr - &_faceIndices[0]); if (!ptr) { // if the adjface is hole, it won't be found break; } assert(ptr and srcBasisIdx>=0 and srcBasisIdx<(int)_faceIndices.size()); // Copy the indices of CVs from the face on the other side of the // shared edge static int const gregoryEdgeVerts[4][4] = { { 0, 1, 7, 5}, { 5, 6, 12, 10}, {10, 11, 17, 15}, {15, 16, 2, 0} }; Index * src = &_patchPoints[srcBasisIdx*20]; for (int j=0; j<4; ++j) { // invert direction // note that src indices have already been offsetted. dest[gregoryEdgeVerts[i][3-j]] = src[gregoryEdgeVerts[aedge][j]]; } } } } bool newVerticesMask[4][5]; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 5; ++j) { if (dest[i*5+j]==Vtr::INDEX_INVALID) { // assign new vertex dest[i*5+j] = _numGregoryBasisVertices + gregoryVertexOffset; ++_numGregoryBasisVertices; newVerticesMask[i][j] = true; } else { // share vertex newVerticesMask[i][j] = false; } } } _faceIndices.push_back(faceIndex); // add basis addPatchBasis(faceIndex, newVerticesMask, levelVertOffset); ++_numGregoryBasisPatches; // return cvs; return ConstIndexArray(dest, 20); } } // end namespace Far } // end namespace OPENSUBDIV_VERSION } // end namespace OpenSubdiv