// // Copyright 2014 DreamWorks Animation LLC. // // 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. // #ifndef VTR_LEVEL_H #define VTR_LEVEL_H #include "../version.h" #include "../sdc/types.h" #include "../sdc/crease.h" #include "../sdc/options.h" #include "../vtr/types.h" #include #include #include #include namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { // Forward declarations for friends: namespace Far { template class TopologyRefinerFactory; class TopologyRefinerFactoryBase; class TopologyRefiner; class PatchTablesFactory; } namespace Vtr { class Refinement; class QuadRefinement; class TriRefinement; class FVarRefinement; class FVarLevel; // // Level: // A refinement level includes a vectorized representation of the topology // for a particular subdivision level. The topology is "complete" in that any // level can be used as the base level of another subdivision hierarchy and can // be considered a complete mesh independent of its ancestors. It currently // does contain a "depth" member -- as some inferences can then be made about // the topology (i.e. all quads or all tris if not level 0) but that is still // under consideration (e.g. a "regular" flag would serve the same purpose, and // level 0 may even be regular). // // This class is intended for private use within the library. So really its // interface should be fully protected and only those library classes that need // it will be declared as friends, e.g. Refinement. // // The represenation of topology here is to store six topological relationships // in tables of integers. Each is stored in its own array(s) so the result is // a SOA representation of the topology. The six relations are: // // - face-verts: vertices incident/comprising a face // - face-edges: edges incident a face // - edge-verts: vertices incident/comprising an edge // - edge-faces: faces incident an edge // - vert-faces: faces incident a vertex // - vert-edges: edges incident a vertex // // There is some redundancy here but the intent is not that this be a minimal // represenation, the intent is that it be amenable to refinement. Classes in // the Far layer essentially store 5 of these 6 in a permuted form -- we add // the face-edges here to simplify refinement. // // Notes/limitations/stuff to do -- much of this code still reflects the early days // when it was being prototyped and so it does not conform to OSD standards in many // ways: // - superficial stylistic issues: // . replacing "m" prefix with "_" on member variables // - done // . replace "access" and "modify" prefixes on Array methods with "get" // - done // - replace use of "...Count" with "GetNum..." // - use of Vertex vs Vert in non-local (or any?) methods // - review public/protected/friend accessibility // // Most are more relevant to the refinement, which used to be part of this class: // - short cuts that need revisiting: // - support for face-vert counts > 4 // - support for edge-face counts > 2 // - some neighborhood searches avoidable with more "local indexing" // - identify (informally) where scheme-specific code will be needed, so far: // - topological splitting and associated marking // - really the only variable here is whether to generate tris or // quads from non-quads // - interpolation // - potentially not part of the pre-processing required for FarMesh // and where it appears *not* to be needed: // - subdivision of sharpness values // - classification of vertex type/mask // - apply classification of vertices (computing Rules or masks) // - apply to base/course level on conversion // - apply to child level after subdivision of sharpness // - keep in mind desired similarity with FarMesh tables for ease of transfer // (contradicts previous point to some degree) // class Level { public: // // Simple nested types to hold the tags for each component type -- some of // which are user-specified features (e.g. whether a face is a hole or not) // while others indicate the topological nature of the component, how it // is affected by creasing in its neighborhood, etc. // // Most of these properties are passed down to child components during // refinement, but some -- notably the designation of a component as semi- // sharp -- require re-determination as sharpnes values are reduced at each // level. // struct VTag { typedef unsigned short VTagSize; VTag() { } VTagSize _nonManifold : 1; // fixed VTagSize _xordinary : 1; // fixed VTagSize _boundary : 1; // fixed VTagSize _infSharp : 1; // fixed VTagSize _semiSharp : 1; // variable VTagSize _rule : 4; // variable when _semiSharp VTagSize _incomplete : 1; // variable for sparse refinement // On deck -- coming soon... //VTagSize _constSharp : 1; // variable when _semiSharp //VTagSize _hasEdits : 1; // variable //VTagSize _editsApplied : 1; // variable }; struct ETag { typedef unsigned char ETagSize; ETag() { } ETagSize _nonManifold : 1; // fixed ETagSize _boundary : 1; // fixed ETagSize _infSharp : 1; // fixed ETagSize _semiSharp : 1; // variable }; struct FTag { typedef unsigned char FTagSize; FTag() { } FTagSize _hole : 1; // fixed // On deck -- coming soon... //FTagSize _hasEdits : 1; // variable }; VTag getFaceCompositeVTag(ConstIndexArray & faceVerts) const; ETag getFaceCompositeETag(ConstIndexArray & faceEdges) const; public: Level(); ~Level(); // Simple accessors: int getDepth() const { return _depth; } int getNumVertices() const { return _vertCount; } int getNumFaces() const { return _faceCount; } int getNumEdges() const { return _edgeCount; } // More global sizes may prove useful... int getNumFaceVerticesTotal() const { return (int) _faceVertIndices.size(); } int getNumFaceEdgesTotal() const { return (int) _faceEdgeIndices.size(); } int getNumEdgeVerticesTotal() const { return (int) _edgeVertIndices.size(); } int getNumEdgeFacesTotal() const { return (int) _edgeFaceIndices.size(); } int getNumVertexFacesTotal() const { return (int) _vertFaceIndices.size(); } int getNumVertexEdgesTotal() const { return (int) _vertEdgeIndices.size(); } int getMaxValence() const { return _maxValence; } int getMaxEdgeFaces() const { return _maxEdgeFaces; } // Methods to access the relation tables/indices -- note that for some relations // we store an additional "local index", e.g. for the case of vert-faces if one // of the faces F[i] is incident a vertex V, then L[i] is the "local index" in // F[i] of vertex V. Once have only quads (or tris), this local index need only // occupy two bits and could conceivably be packed into the same integer as the // face index, but for now, given the need to support faces of potentially high // valence we'll us an 8- or 16-bit integer. // // Methods to access the six topological relations: ConstIndexArray getFaceVertices(Index faceIndex) const; ConstIndexArray getFaceEdges(Index faceIndex) const; ConstIndexArray getEdgeVertices(Index edgeIndex) const; ConstIndexArray getEdgeFaces(Index edgeIndex) const; ConstIndexArray getVertexFaces(Index vertIndex) const; ConstIndexArray getVertexEdges(Index vertIndex) const; ConstLocalIndexArray getVertexFaceLocalIndices(Index vertIndex) const; ConstLocalIndexArray getVertexEdgeLocalIndices(Index vertIndex) const; // Replace these with access to sharpness buffers/arrays rather than elements: float getEdgeSharpness(Index edgeIndex) const; float getVertexSharpness(Index vertIndex) const; Sdc::Crease::Rule getVertexRule(Index vertIndex) const; Index findEdge(Index v0Index, Index v1Index) const; // Holes void setHole(Index faceIndex, bool b); bool isHole(Index faceIndex) const; // Manifold/non-manifold tags: void setEdgeNonManifold(Index edgeIndex, bool b); bool isEdgeNonManifold(Index edgeIndex) const; void setVertexNonManifold(Index vertIndex, bool b); bool isVertexNonManifold(Index vertIndex) const; public: // Debugging aides -- unclear what will persist... enum TopologyError { TOPOLOGY_MISSING_EDGE_FACES=0, TOPOLOGY_MISSING_EDGE_VERTS, TOPOLOGY_MISSING_FACE_EDGES, TOPOLOGY_MISSING_FACE_VERTS, TOPOLOGY_MISSING_VERT_FACES, TOPOLOGY_MISSING_VERT_EDGES, TOPOLOGY_FAILED_CORRELATION_EDGE_FACE, TOPOLOGY_FAILED_CORRELATION_FACE_VERT, TOPOLOGY_FAILED_CORRELATION_FACE_EDGE, TOPOLOGY_FAILED_ORIENTATION_INCIDENT_EDGE, TOPOLOGY_FAILED_ORIENTATION_INCIDENT_FACE, TOPOLOGY_FAILED_ORIENTATION_INCIDENT_FACES_EDGES, TOPOLOGY_DEGENERATE_EDGE, TOPOLOGY_NON_MANIFOLD_EDGE, TOPOLOGY_INVALID_CREASE_EDGE, TOPOLOGY_INVALID_CREASE_VERT }; static char const * getTopologyErrorString(TopologyError errCode); typedef void (* ValidationCallback)(TopologyError errCode, char const * msg, void const * clientData); bool validateTopology(ValidationCallback callback=0, void const * clientData=0) const; void print(const Refinement* parentRefinement = 0) const; public: // High-level topology queries -- these are likely to be moved elsewhere, but here // is the best place for them for now... bool isSingleCreasePatch(Index face, float* sharpnessOut=NULL, int* rotationOut=NULL) const; int gatherManifoldVertexRingFromIncidentQuads(Index vIndex, int vOffset, int ringVerts[]) const; // // When gathering "patch points" we may want the indices of the vertices or the corresponding // FVar values for a particular channel. Both are represented and equally accessible within // the faces, so we allow all to be returned through these methods. Setting the optional FVar // channel to -1 will retrieve indices of vertices instead of FVar values: // int gatherQuadRegularInteriorPatchPoints(Index fIndex, Index patchPoints[], int rotation = 0, int fvarChannel = -1) const; int gatherQuadRegularBoundaryPatchPoints(Index fIndex, Index patchPoints[], int boundaryEdgeInFace, int fvarChannel = -1) const; int gatherQuadRegularCornerPatchPoints( Index fIndex, Index patchPoints[], int cornerVertInFace, int fvarChannel = -1) const; int gatherQuadRegularRingAroundVertex(Index vIndex, Index ringPoints[], int fvarChannel = -1) const; // WIP -- for future use, need to extend for face-varying... int gatherTriRegularInteriorPatchPoints( Index fIndex, Index patchVerts[], int rotation = 0) const; int gatherTriRegularBoundaryVertexPatchPoints(Index fIndex, Index patchVerts[], int boundaryVertInFace) const; int gatherTriRegularBoundaryEdgePatchPoints( Index fIndex, Index patchVerts[], int boundaryEdgeInFace) const; int gatherTriRegularCornerVertexPatchPoints( Index fIndex, Index patchVerts[], int cornerVertInFace) const; int gatherTriRegularCornerEdgePatchPoints( Index fIndex, Index patchVerts[], int cornerEdgeInFace) const; protected: friend class Refinement; friend class QuadRefinement; friend class TriRefinement; friend class FVarRefinement; friend class FVarLevel; template friend class Far::TopologyRefinerFactory; friend class Far::TopologyRefinerFactoryBase; friend class Far::TopologyRefiner; friend class Far::PatchTablesFactory; // Sizing methods used to construct a level to populate: void resizeFaces( int numFaces); void resizeFaceVertices(int numFaceVertsTotal); void resizeFaceEdges( int numFaceEdgesTotal); void resizeEdges( int numEdges); void resizeEdgeVertices(); // always 2*edgeCount void resizeEdgeFaces(int numEdgeFacesTotal); void resizeVertices( int numVertices); void resizeVertexFaces(int numVertexFacesTotal); void resizeVertexEdges(int numVertexEdgesTotal); // Modifiers to populate the relations for each component: IndexArray getFaceVertices(Index faceIndex); IndexArray getFaceEdges(Index faceIndex); IndexArray getEdgeVertices(Index edgeIndex); IndexArray getEdgeFaces(Index edgeIndex); IndexArray getVertexFaces( Index vertIndex); LocalIndexArray getVertexFaceLocalIndices(Index vertIndex); IndexArray getVertexEdges( Index vertIndex); LocalIndexArray getVertexEdgeLocalIndices(Index vertIndex); // Replace these with access to sharpness buffers/arrays rather than elements: float& getEdgeSharpness(Index edgeIndex); float& getVertexSharpness(Index vertIndex); // Create, destroy and populate face-varying channels: int createFVarChannel(int fvarValueCount, Sdc::Options const& options); void destroyFVarChannel(int channel = 0); int getNumFVarChannels() const { return (int) _fvarChannels.size(); } int getNumFVarValues(int channel = 0) const; ConstIndexArray getFVarFaceValues(Index faceIndex, int channel = 0) const; IndexArray getFVarFaceValues(Index faceIndex, int channel = 0); void completeFVarChannelTopology(int channel, int regBoundaryValence); // Counts and offsets for all relation types: // - these may be unwarranted if we let Refinement access members directly... int getNumFaceVertices( Index faceIndex) const { return _faceVertCountsAndOffsets[2*faceIndex]; } int getOffsetOfFaceVertices(Index faceIndex) const { return _faceVertCountsAndOffsets[2*faceIndex + 1]; } int getNumFaceEdges( Index faceIndex) const { return getNumFaceVertices(faceIndex); } int getOffsetOfFaceEdges(Index faceIndex) const { return getOffsetOfFaceVertices(faceIndex); } int getNumEdgeVertices( Index ) const { return 2; } int getOffsetOfEdgeVertices(Index edgeIndex) const { return 2 * edgeIndex; } int getNumEdgeFaces( Index edgeIndex) const { return _edgeFaceCountsAndOffsets[2*edgeIndex]; } int getOffsetOfEdgeFaces(Index edgeIndex) const { return _edgeFaceCountsAndOffsets[2*edgeIndex + 1]; } int getNumVertexFaces( Index vertIndex) const { return _vertFaceCountsAndOffsets[2*vertIndex]; } int getOffsetOfVertexFaces(Index vertIndex) const { return _vertFaceCountsAndOffsets[2*vertIndex + 1]; } int getNumVertexEdges( Index vertIndex) const { return _vertEdgeCountsAndOffsets[2*vertIndex]; } int getOffsetOfVertexEdges(Index vertIndex) const { return _vertEdgeCountsAndOffsets[2*vertIndex + 1]; } // // Note that for some relations, the size of the relations for a child component // can vary radically from its parent due to the sparsity of the refinement. So // in these cases a few additional utilities are provided to help define the set // of incident components. Assuming adequate memory has been allocated, the // "resize" methods here initialize the set of incident components by setting // both the size and the appropriate offset, while "trim" is use to quickly lower // the size from an upper bound and nothing else. // void resizeFaceVertices(Index FaceIndex, int count); void resizeEdgeFaces(Index edgeIndex, int count); void trimEdgeFaces( Index edgeIndex, int count); void resizeVertexFaces(Index vertIndex, int count); void trimVertexFaces( Index vertIndex, int count); void resizeVertexEdges(Index vertIndex, int count); void trimVertexEdges( Index vertIndex, int count); protected: // // Plans where to have a few specific friend classes properly construct the topology, // e.g. the Refinement class. There is now clearly a need to have some class // construct full topology given only a simple face-vertex list. That can be done // externally (either a Factory outside Vtr or another Vtr construction helper), but // until we decide where, the required implementation is defined here. // void completeTopologyFromFaceVertices(); Index findEdge(Index v0, Index v1, ConstIndexArray v0Edges) const; // Methods supporting the above: void orientIncidentComponents(); bool orderVertexFacesAndEdges(Index vIndex, Index* vFaces, Index* vEdges) const; bool orderVertexFacesAndEdges(Index vIndex); void populateLocalIndices(); IndexArray shareFaceVertCountsAndOffsets() const; protected: // // A Level is independent of subdivision scheme or options. While it may have been // affected by them in its construction, they are not associated with it -- a Level // is pure topology and any subdivision parameters are external. // // Simple members for inventory, etc. int _faceCount; int _edgeCount; int _vertCount; // TBD - "depth" is clearly useful in both the topological splitting and the // stencil queries so could be valuable in both. As face-vert valence becomes // constant there is no need to store face-vert and face-edge counts so it has // value in Level, though perhaps specified as something other than "depth" int _depth; int _maxEdgeFaces; int _maxValence; // // Topology vectors: // Note that of all of these, only data for the face-edge relation is not // stored in the osd::FarTables in any form. The FarTable vectors combine // the edge-vert and edge-face relations. The eventual goal is that this // data be part of the osd::Far classes and be a superset of the FarTable // vectors, i.e. no data duplication or conversion. The fact that FarTable // already stores 5 of the 6 possible relations should make the topology // storage as a whole a non-issue. // // The vert-face-child and vert-edge-child indices are also arguably not // a topology relation but more one for parent/child relations. But it is // a topological relationship, and if named differently would not likely // raise this. It has been named with "child" in the name as it does play // a more significant role during subdivision in mapping between parent // and child components, and so has been named to reflect that more clearly. // // Per-face: std::vector _faceVertCountsAndOffsets; // 2 per face, redundant after level 0 std::vector _faceVertIndices; // 3 or 4 per face, variable at level 0 std::vector _faceEdgeIndices; // matches face-vert indices std::vector _faceTags; // 1 per face: includes "hole" tag // Per-edge: std::vector _edgeVertIndices; // 2 per edge std::vector _edgeFaceCountsAndOffsets; // 2 per edge std::vector _edgeFaceIndices; // varies with faces per edge std::vector _edgeSharpness; // 1 per edge std::vector _edgeTags; // 1 per edge: manifold, boundary, etc. // Per-vertex: std::vector _vertFaceCountsAndOffsets; // 2 per vertex std::vector _vertFaceIndices; // varies with valence std::vector _vertFaceLocalIndices; // varies with valence, 8-bit for now std::vector _vertEdgeCountsAndOffsets; // 2 per vertex std::vector _vertEdgeIndices; // varies with valence std::vector _vertEdgeLocalIndices; // varies with valence, 8-bit for now std::vector _vertSharpness; // 1 per vertex std::vector _vertTags; // 1 per vertex: manifold, Sdc::Rule, etc. // Face-varying channels: std::vector _fvarChannels; }; // // Access/modify the vertices indicent a given face: // inline ConstIndexArray Level::getFaceVertices(Index faceIndex) const { return ConstIndexArray(&_faceVertIndices[_faceVertCountsAndOffsets[faceIndex*2+1]], _faceVertCountsAndOffsets[faceIndex*2]); } inline IndexArray Level::getFaceVertices(Index faceIndex) { return IndexArray(&_faceVertIndices[_faceVertCountsAndOffsets[faceIndex*2+1]], _faceVertCountsAndOffsets[faceIndex*2]); } inline void Level::resizeFaceVertices(Index faceIndex, int count) { assert(count < 256); int* countOffsetPair = &_faceVertCountsAndOffsets[faceIndex*2]; countOffsetPair[0] = count; countOffsetPair[1] = (faceIndex == 0) ? 0 : (countOffsetPair[-2] + countOffsetPair[-1]); _maxValence = std::max(_maxValence, count); } // // Access/modify the edges indicent a given face: // inline ConstIndexArray Level::getFaceEdges(Index faceIndex) const { return ConstIndexArray(&_faceEdgeIndices[_faceVertCountsAndOffsets[faceIndex*2+1]], _faceVertCountsAndOffsets[faceIndex*2]); } inline IndexArray Level::getFaceEdges(Index faceIndex) { return IndexArray(&_faceEdgeIndices[_faceVertCountsAndOffsets[faceIndex*2+1]], _faceVertCountsAndOffsets[faceIndex*2]); } // // Access/modify the faces indicent a given vertex: // inline ConstIndexArray Level::getVertexFaces(Index vertIndex) const { return ConstIndexArray(&_vertFaceIndices[_vertFaceCountsAndOffsets[vertIndex*2+1]], _vertFaceCountsAndOffsets[vertIndex*2]); } inline IndexArray Level::getVertexFaces(Index vertIndex) { return IndexArray(&_vertFaceIndices[_vertFaceCountsAndOffsets[vertIndex*2+1]], _vertFaceCountsAndOffsets[vertIndex*2]); } inline ConstLocalIndexArray Level::getVertexFaceLocalIndices(Index vertIndex) const { return ConstLocalIndexArray(&_vertFaceLocalIndices[_vertFaceCountsAndOffsets[vertIndex*2+1]], _vertFaceCountsAndOffsets[vertIndex*2]); } inline LocalIndexArray Level::getVertexFaceLocalIndices(Index vertIndex) { return LocalIndexArray(&_vertFaceLocalIndices[_vertFaceCountsAndOffsets[vertIndex*2+1]], _vertFaceCountsAndOffsets[vertIndex*2]); } inline void Level::resizeVertexFaces(Index vertIndex, int count) { int* countOffsetPair = &_vertFaceCountsAndOffsets[vertIndex*2]; countOffsetPair[0] = count; countOffsetPair[1] = (vertIndex == 0) ? 0 : (countOffsetPair[-2] + countOffsetPair[-1]); } inline void Level::trimVertexFaces(Index vertIndex, int count) { _vertFaceCountsAndOffsets[vertIndex*2] = count; } // // Access/modify the edges indicent a given vertex: // inline ConstIndexArray Level::getVertexEdges(Index vertIndex) const { return ConstIndexArray(&_vertEdgeIndices[_vertEdgeCountsAndOffsets[vertIndex*2+1]], _vertEdgeCountsAndOffsets[vertIndex*2]); } inline IndexArray Level::getVertexEdges(Index vertIndex) { return IndexArray(&_vertEdgeIndices[_vertEdgeCountsAndOffsets[vertIndex*2+1]], _vertEdgeCountsAndOffsets[vertIndex*2]); } inline ConstLocalIndexArray Level::getVertexEdgeLocalIndices(Index vertIndex) const { return ConstLocalIndexArray(&_vertEdgeLocalIndices[_vertEdgeCountsAndOffsets[vertIndex*2+1]], _vertEdgeCountsAndOffsets[vertIndex*2]); } inline LocalIndexArray Level::getVertexEdgeLocalIndices(Index vertIndex) { return LocalIndexArray(&_vertEdgeLocalIndices[_vertEdgeCountsAndOffsets[vertIndex*2+1]], _vertEdgeCountsAndOffsets[vertIndex*2]); } inline void Level::resizeVertexEdges(Index vertIndex, int count) { int* countOffsetPair = &_vertEdgeCountsAndOffsets[vertIndex*2]; countOffsetPair[0] = count; countOffsetPair[1] = (vertIndex == 0) ? 0 : (countOffsetPair[-2] + countOffsetPair[-1]); _maxValence = std::max(_maxValence, count); } inline void Level::trimVertexEdges(Index vertIndex, int count) { _vertEdgeCountsAndOffsets[vertIndex*2] = count; } // // Access/modify the vertices indicent a given edge: // inline ConstIndexArray Level::getEdgeVertices(Index edgeIndex) const { return ConstIndexArray(&_edgeVertIndices[edgeIndex*2], 2); } inline IndexArray Level::getEdgeVertices(Index edgeIndex) { return IndexArray(&_edgeVertIndices[edgeIndex*2], 2); } // // Access/modify the faces indicent a given edge: // inline ConstIndexArray Level::getEdgeFaces(Index edgeIndex) const { return ConstIndexArray(&_edgeFaceIndices[_edgeFaceCountsAndOffsets[edgeIndex*2+1]], _edgeFaceCountsAndOffsets[edgeIndex*2]); } inline IndexArray Level::getEdgeFaces(Index edgeIndex) { return IndexArray(&_edgeFaceIndices[_edgeFaceCountsAndOffsets[edgeIndex*2+1]], _edgeFaceCountsAndOffsets[edgeIndex*2]); } inline void Level::resizeEdgeFaces(Index edgeIndex, int count) { int* countOffsetPair = &_edgeFaceCountsAndOffsets[edgeIndex*2]; countOffsetPair[0] = count; countOffsetPair[1] = (edgeIndex == 0) ? 0 : (countOffsetPair[-2] + countOffsetPair[-1]); _maxEdgeFaces = std::max(_maxEdgeFaces, count); } inline void Level::trimEdgeFaces(Index edgeIndex, int count) { _edgeFaceCountsAndOffsets[edgeIndex*2] = count; } // // Access/modify sharpness values: // inline float Level::getEdgeSharpness(Index edgeIndex) const { return _edgeSharpness[edgeIndex]; } inline float& Level::getEdgeSharpness(Index edgeIndex) { return _edgeSharpness[edgeIndex]; } inline float Level::getVertexSharpness(Index vertIndex) const { return _vertSharpness[vertIndex]; } inline float& Level::getVertexSharpness(Index vertIndex) { return _vertSharpness[vertIndex]; } inline Sdc::Crease::Rule Level::getVertexRule(Index vertIndex) const { return (Sdc::Crease::Rule) _vertTags[vertIndex]._rule; } // // Access/modify hole tag: // inline void Level::setHole(Index faceIndex, bool b) { _faceTags[faceIndex]._hole = b; } inline bool Level::isHole(Index faceIndex) const { return _faceTags[faceIndex]._hole; } // // Access/modify non-manifold tags: // inline void Level::setEdgeNonManifold(Index edgeIndex, bool b) { _edgeTags[edgeIndex]._nonManifold = b; } inline bool Level::isEdgeNonManifold(Index edgeIndex) const { return _edgeTags[edgeIndex]._nonManifold; } inline void Level::setVertexNonManifold(Index vertIndex, bool b) { _vertTags[vertIndex]._nonManifold = b; } inline bool Level::isVertexNonManifold(Index vertIndex) const { return _vertTags[vertIndex]._nonManifold; } // // Sizing methods to allocate space: // inline void Level::resizeFaces(int faceCount) { _faceCount = faceCount; _faceVertCountsAndOffsets.resize(2 * faceCount); _faceTags.resize(faceCount); std::memset(&_faceTags[0], 0, _faceCount * sizeof(FTag)); } inline void Level::resizeFaceVertices(int totalFaceVertCount) { _faceVertIndices.resize(totalFaceVertCount); } inline void Level::resizeFaceEdges(int totalFaceEdgeCount) { _faceEdgeIndices.resize(totalFaceEdgeCount); } inline void Level::resizeEdges(int edgeCount) { _edgeCount = edgeCount; _edgeFaceCountsAndOffsets.resize(2 * edgeCount); _edgeSharpness.resize(edgeCount); _edgeTags.resize(edgeCount); if (edgeCount>0) { std::memset(&_edgeTags[0], 0, _edgeCount * sizeof(ETag)); } } inline void Level::resizeEdgeVertices() { _edgeVertIndices.resize(2 * _edgeCount); } inline void Level::resizeEdgeFaces(int totalEdgeFaceCount) { _edgeFaceIndices.resize(totalEdgeFaceCount); } inline void Level::resizeVertices(int vertCount) { _vertCount = vertCount; _vertFaceCountsAndOffsets.resize(2 * vertCount); _vertEdgeCountsAndOffsets.resize(2 * vertCount); _vertSharpness.resize(vertCount); _vertTags.resize(vertCount); std::memset(&_vertTags[0], 0, _vertCount * sizeof(VTag)); } inline void Level::resizeVertexFaces(int totalVertFaceCount) { _vertFaceIndices.resize(totalVertFaceCount); _vertFaceLocalIndices.resize(totalVertFaceCount); } inline void Level::resizeVertexEdges(int totalVertEdgeCount) { _vertEdgeIndices.resize(totalVertEdgeCount); _vertEdgeLocalIndices.resize(totalVertEdgeCount); } inline IndexArray Level::shareFaceVertCountsAndOffsets() const { // XXXX manuelk we have to force const casting here (classes don't 'share' // members usually...) return IndexArray(const_cast(&_faceVertCountsAndOffsets[0]), (int)_faceVertCountsAndOffsets.size()); } } // end namespace Vtr } // end namespace OPENSUBDIV_VERSION using namespace OPENSUBDIV_VERSION; } // end namespace OpenSubdiv #endif /* VTR_LEVEL_H */