// // 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. // #ifndef FAR_PATCH_TABLES_H #define FAR_PATCH_TABLES_H #include "../version.h" #include "../far/patchParam.h" #include #include #include #include #include namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { /// \brief Container for patch vertex indices tables /// /// FarPatchTables contain the lists of vertices for each patch of an adaptive /// mesh representation. /// class FarPatchTables { public: typedef std::vector PTable; typedef std::vector VertexValenceTable; typedef std::vector QuadOffsetTable; typedef std::vector PatchParamTable; typedef std::vector FVarDataTable; enum Type { NON_PATCH = 0, ///< undefined POINTS, ///< points (useful for cage drawing) LINES, ///< lines (useful for cage drawing) QUADS, ///< bilinear quads-only patches TRIANGLES, ///< bilinear triangles-only mesh LOOP, ///< Loop patch (unsupported) REGULAR, ///< feature-adaptive bicubic patches BOUNDARY, CORNER, GREGORY, GREGORY_BOUNDARY }; enum TransitionPattern { NON_TRANSITION = 0, PATTERN0, PATTERN1, PATTERN2, PATTERN3, PATTERN4, }; /// \brief Describes the type of a patch /// /// Uniquely identifies all the types of patches in a mesh : /// /// * Raw polygon meshes are identified as POLYGONS and can contain faces /// with arbitrary number of vertices /// /// * Uniformly subdivided meshes contain bilinear patches of either QUADS /// or TRIANGLES /// /// * Adaptively subdivided meshes contain bicubic patches of types REGULAR, /// BOUNDARY, CORNER, GREGORY, GREGORY_BOUNDARY. These bicubic patches are /// also further distinguished by a transition pattern as well as a rotational /// orientation. /// /// An iterator class is provided as a convenience to enumerate over the set /// of valid feature adaptive patch descriptors. /// class Descriptor { public: /// \brief Default constructor. Descriptor() : _type(NON_PATCH), _pattern(NON_TRANSITION), _rotation(0) {} /// \brief Constructor Descriptor(int type, int pattern, unsigned char rotation) : _type(type), _pattern(pattern), _rotation(rotation) { } /// \brief Copy Constructor Descriptor( Descriptor const & d ) : _type(d.GetType()), _pattern(d.GetPattern()), _rotation(d.GetRotation()) { } /// \brief Returns the type of the patch Type GetType() const { return (Type)_type; } /// \brief Returns the transition pattern of the patch if any (5 types) TransitionPattern GetPattern() const { return (TransitionPattern)_pattern; } /// \brief Returns the rotation of the patch (4 rotations) unsigned char GetRotation() const { return _rotation; } /// \brief Returns the number of control vertices expected for a patch of the /// type described static short GetNumControlVertices( Type t ); /// \brief Returns the number of control vertices expected for a patch of the /// type described short GetNumControlVertices() const { return GetNumControlVertices( this->GetType() ); } /// Returns a vector of all the legal patch descriptors static std::vector const & GetAllValidDescriptors(); /// \brief Allows ordering of patches by type bool operator < ( Descriptor const other ) const; /// \brief True if the descriptors are identical bool operator == ( Descriptor const other ) const; /// \brief Descriptor Iterator /// Iterates through the patches in the following preset order /// /// Order: /// /// NON_TRANSITION ( REGULAR /// BOUNDARY /// CORNER /// GREGORY /// GREGORY_BOUNDARY ) /// /// PATTERN0 ( REGULAR /// BOUNDARY ROT0 ROT1 ROT2 ROT3 /// CORNER ROT0 ROT1 ROT2 ROT3 ) /// /// PATTERN1 ( REGULAR /// BOUNDARY ROT0 ROT1 ROT2 ROT3 /// CORNER ROT0 ROT1 ROT2 ROT3 ) /// ... /// /// NON_TRANSITION NON_PATCH ROT0 (end) /// class iterator; /// \brief Returns an iterator to the first type of patch (REGULAR NON_TRANSITION ROT0) static iterator begin(); /// \brief Returns an iterator to the end of the list of patch types (NON_PATCH) static iterator end(); private: template friend class FarPatchTablesFactory; friend class iterator; unsigned int _type:4; unsigned int _pattern:3; unsigned int _rotation:2; }; /// \brief Describes an array of patches of the same type class PatchArray { public: /// \brief Constructor. /// /// @param desc descriptor information for the patches in /// the array /// /// @param vertIndex absolute index to the first control vertex /// of the first patch in the PTable /// /// @param patchIndex absolute index of the first patch in the /// array /// /// @param npatches number of patches in the array /// /// @param quadOffsetIndex absolute index of the first quad offset /// entry /// PatchArray( Descriptor desc, unsigned int vertIndex, unsigned int patchIndex, unsigned int npatches, unsigned int quadOffsetIndex ) : _desc(desc), _range(vertIndex, patchIndex, npatches, quadOffsetIndex) { } /// Returns a patch descriptor defining the type of patches in the array Descriptor GetDescriptor() const { return _desc; } /// \brief Describes the range of patches in a PatchArray struct ArrayRange { /// \brief Constructor /// /// @param vertIndex absolute index to the first control vertex /// of the first patch in the PTable /// /// @param patchIndex absolute index of the first patch in the /// array /// /// @param npatches number of patches in the array /// /// @param quadOffsetIndex absolute index of the first quad offset /// entry /// ArrayRange( unsigned int vertIndex, unsigned int patchIndex, unsigned int npatches, unsigned int quadOffsetIndex ) : vertIndex(vertIndex), patchIndex(patchIndex), npatches(npatches), quadOffsetIndex(quadOffsetIndex) { } unsigned int vertIndex, // absolute index to the first control vertex of the first patch in the PTable patchIndex, // absolute index of the first patch in the array npatches, // number of patches in the array quadOffsetIndex; // absolute index of the first quad offset entry }; /// \brief Returns a array range struct ArrayRange const & GetArrayRange() const { return _range; } /// \brief Returns the index of the first control vertex of the first patch /// of this array in the global PTable unsigned int GetVertIndex() const { return _range.vertIndex; } /// \brief Returns the global index of the first patch in this array (Used to /// access param / fvar table data) unsigned int GetPatchIndex() const { return _range.patchIndex; } /// \brief Returns the number of patches in the array unsigned int GetNumPatches() const { return _range.npatches; } /// \brief Returns the index to the first entry in the QuadOffsetTable unsigned int GetQuadOffsetIndex() const { return _range.quadOffsetIndex; } private: template friend class FarPatchTablesFactory; Descriptor _desc; // type of patches in the array ArrayRange _range; // index locators in the array }; typedef std::vector PatchArrayVector; /// \brief Constructor /// /// @param patchArrays Vector of descriptors and ranges for arrays of patches /// /// @param patches Indices of the control vertices of the patches /// /// @param vertexValences Vertex valance table /// /// @param quadOffsets Quad offset table /// /// @param patchParams Local patch parameterization /// /// @param fvarData Face varying data table /// /// @param maxValence Highest vertex valence allowed in the mesh /// FarPatchTables(PatchArrayVector const & patchArrays, PTable const & patches, VertexValenceTable const * vertexValences, QuadOffsetTable const * quadOffsets, PatchParamTable const * patchParams, FVarDataTable const * fvarData, int maxValence); /// \brief Get the table of patch control vertices PTable const & GetPatchTable() const { return _patches; } /// \brief Returns a pointer to the array of patches matching the descriptor PatchArray const * GetPatchArray( Descriptor desc ) const { return const_cast(this)->findPatchArray( desc ); } /// \brief Returns all arrays of patches PatchArrayVector const & GetPatchArrayVector() const { return _patchArrays; } /// \brief Returns a pointer to the vertex indices of uniformly subdivided faces /// /// In uniform mode the FarPatchTablesFactory can be set to generate either a /// patch array containing the faces at the highest level of subdivision, or /// a range of arrays, corresponding to multiple successive levels of subdivision. /// /// Note : level '0' is not the coarse mesh. Currently there is no path in the /// factories to convert the coarse mesh to FarPatchTables. /// /// @param level the level of subdivision of the faces (returns the highest /// level by default) /// /// @return a pointer to the first vertex index or NULL if the mesh /// is not uniformly subdivided or the level cannot be found. /// unsigned int const * GetFaceVertices(int level=0) const; /// \brief Returns the number of faces in a uniformly subdivided mesh at a given level /// /// In uniform mode the FarPatchTablesFactory can be set to generate either a /// patch array containing the faces at the highest level of subdivision, or /// a range of arrays, corresponding to multiple successive levels of subdivision. /// /// Note : level '0' is not the coarse mesh. Currently there is no path in the /// factories to convert the coarse mesh to FarPatchTables. /// /// @param level the level of subdivision of the faces (returns the highest /// level by default) /// /// @return the number of faces in the mesh given the subdivision level /// or -1 if the mesh is not uniform or the level is incorrect. /// int GetNumFaces(int level=0) const; /// \brief Returns a vertex valence table used by Gregory patches VertexValenceTable const & GetVertexValenceTable() const { return _vertexValenceTable; } /// \brief Returns a quad offsets table used by Gregory patches QuadOffsetTable const & GetQuadOffsetTable() const { return _quadOffsetTable; } /// \brief Returns a PatchParamTable for each type of patch PatchParamTable const & GetPatchParamTable() const { return _paramTable; } /// \brief Returns an FVarDataTable for each type of patch /// The data is stored as a run of totalFVarWidth floats per-vertex per-face /// e.g.: for UV data it has the structure of float[p][4][2] where /// p=primitiveID and totalFVarWidth=2: /// [ [ uv uv uv uv ] [ uv uv uv uv ] [ ... ] ] /// prim 0 prim 1 FVarDataTable const & GetFVarDataTable() const { return _fvarTable; } /// \brief Ringsize of Regular Patches in table. static int GetRegularPatchRingsize() { return 16; } /// \brief Ringsize of Boundary Patches in table. static int GetBoundaryPatchRingsize() { return 12; } /// \brief Ringsize of Boundary Patches in table. static int GetCornerPatchRingsize() { return 9; } /// \brief Ringsize of Gregory (and Gregory Boundary) Patches in table. static int GetGregoryPatchRingsize() { return 4; } /// \brief Returns the total number of patches stored in the tables int GetNumPatches() const; /// \brief Returns the total number of control vertex indices in the tables int GetNumControlVertices() const; /// \brief Returns max vertex valence int GetMaxValence() const { return _maxValence; } /// \brief True if the patches are of feature adaptive types bool IsFeatureAdaptive() const; private: template friend class FarPatchTablesFactory; template friend class FarMultiMeshFactory; // Returns the array of patches of type "desc", or NULL if there aren't any in the primitive PatchArray * findPatchArray( Descriptor desc ); // Private constructor FarPatchTables( int maxvalence ) : _maxValence(maxvalence) { } PatchArrayVector _patchArrays; // Vector of descriptors for arrays of patches PTable _patches; // Indices of the control vertices of the patches VertexValenceTable _vertexValenceTable; // vertex valence table (for Gregory patches) QuadOffsetTable _quadOffsetTable; // quad offsets table (for Gregory patches) PatchParamTable _paramTable; FVarDataTable _fvarTable; // highest vertex valence allowed in the mesh (used for Gregory // vertexValance & quadOffset tables) int _maxValence; }; /// \brief Descriptor iterator class class FarPatchTables::Descriptor::iterator { public: /// Constructor iterator() : _pos(-1) {} /// Copy Constructor iterator(Descriptor desc); /// Iteration increment operator iterator & operator ++ (); /// True of the two descriptors are identical bool operator == ( iterator const & other ) const { return (_pos==other._pos); } /// True if the two descriptors are different bool operator != ( iterator const & other ) const { return not (*this==other); } /// Dereferencing operator Descriptor const * operator -> () const { return getValue(); } /// Dereferencing operator Descriptor const & operator * () const { return *getValue(); } private: Descriptor const * getValue() const; int _pos; }; // Iterator constructor inline FarPatchTables::Descriptor::iterator::iterator(Descriptor desc) { _pos = -1; std::vector const & descs = Descriptor::GetAllValidDescriptors(); for (int i=0; i<(int)descs.size(); ++i) { if (descs[i] == desc) { _pos = i; break; } } } // Iteration increment operator inline FarPatchTables::Descriptor::iterator & FarPatchTables::Descriptor::iterator::operator ++ () { if (++_pos>=(int)Descriptor::GetAllValidDescriptors().size()) { _pos = -1; } return *this; } inline FarPatchTables::Descriptor const * FarPatchTables::Descriptor::iterator::getValue() const { static Descriptor _nonpatch; std::vector const & descs = Descriptor::GetAllValidDescriptors(); if (_pos>=0 and _pos<(int)descs.size()) { return &descs[_pos]; } return &_nonpatch; } inline std::vector const & FarPatchTables::Descriptor::GetAllValidDescriptors() { static std::vector _descriptors; if (_descriptors.empty()) { _descriptors.reserve(50); // non-transition patches for (int i=REGULAR; i<=GREGORY_BOUNDARY; ++i) { _descriptors.push_back( Descriptor(i, NON_TRANSITION, 0) ); } // transition patches for (int i=PATTERN0; i<=PATTERN4; ++i) { _descriptors.push_back( Descriptor(REGULAR, i, 0) ); // 4 rotations for boundary & corner patches for (int j=0; j<4; ++j) { _descriptors.push_back( Descriptor(BOUNDARY, i, j) ); } for (int j=0; j<4; ++j) { _descriptors.push_back( Descriptor(CORNER, i, j) ); } } } return _descriptors; } // Returns an iterator to the first type of patch (REGULAR NON_TRANSITION ROT0) inline FarPatchTables::Descriptor::iterator FarPatchTables::Descriptor::begin() { return iterator( Descriptor(REGULAR, NON_TRANSITION, 0) ); } // Returns an iterator to the end of the list of patch types (NON_PATCH) inline FarPatchTables::Descriptor::iterator FarPatchTables::Descriptor::end() { return iterator( Descriptor() ); } // Constructor inline FarPatchTables::FarPatchTables(PatchArrayVector const & patchArrays, PTable const & patches, VertexValenceTable const * vertexValences, QuadOffsetTable const * quadOffsets, PatchParamTable const * patchParams, FVarDataTable const * fvarData, int maxValence) : _patchArrays(patchArrays), _patches(patches), _maxValence(maxValence) { // copy other tables if exist if (vertexValences) _vertexValenceTable = *vertexValences; if (quadOffsets) _quadOffsetTable = *quadOffsets; if (patchParams) _paramTable = *patchParams; if (fvarData) _fvarTable = *fvarData; } inline bool FarPatchTables::IsFeatureAdaptive() const { // the vertex valence table is only used by Gregory patches, so the PatchTables // contain feature adaptive patches if this is not empty. if (not _vertexValenceTable.empty()) return true; PatchArrayVector const & parrays = GetPatchArrayVector(); // otherwise, we have to check each patch array for (int i=0; i<(int)parrays.size(); ++i) { if (parrays[i].GetDescriptor().GetType() >= REGULAR and parrays[i].GetDescriptor().GetType() <= GREGORY_BOUNDARY) return true; } return false; } // Returns the number of control vertices expected for a patch of this type inline short FarPatchTables::Descriptor::GetNumControlVertices( FarPatchTables::Type type ) { switch (type) { case REGULAR : return FarPatchTables::GetRegularPatchRingsize(); case QUADS : return 4; case GREGORY : case GREGORY_BOUNDARY : return FarPatchTables::GetGregoryPatchRingsize(); case BOUNDARY : return FarPatchTables::GetBoundaryPatchRingsize(); case CORNER : return FarPatchTables::GetCornerPatchRingsize(); case TRIANGLES : return 3; case LINES : return 2; case POINTS : return 1; default : return -1; } } // Returns a pointer to the vertex indices of uniformly subdivided faces inline unsigned int const * FarPatchTables::GetFaceVertices(int level) const { if (IsFeatureAdaptive()) return NULL; PatchArrayVector const & parrays = GetPatchArrayVector(); if (parrays.empty()) return NULL; if (level < 1) { return &GetPatchTable()[ parrays.rbegin()->GetVertIndex() ]; } else if ((level-1) < (int)parrays.size() ) { return &GetPatchTable()[ parrays[level-1].GetVertIndex() ]; } return NULL; } // Returns the number of faces in a uniformly subdivided mesh at a given level inline int FarPatchTables::GetNumFaces(int level) const { if (IsFeatureAdaptive()) return -1; PatchArrayVector const & parrays = GetPatchArrayVector(); if (parrays.empty()) return -1; if (level < 1) { return parrays.rbegin()->GetNumPatches(); } else if ( (level-1) < (int)parrays.size() ) { return parrays[level-1].GetNumPatches(); } return -1; } // Allows ordering of patches by type inline bool FarPatchTables::Descriptor::operator < ( Descriptor const other ) const { return _pattern < other._pattern or ((_pattern == other._pattern) and (_type < other._type or ((_type == other._type) and (_rotation < other._rotation)))); } // True if the descriptors are identical inline bool FarPatchTables::Descriptor::operator == ( Descriptor const other ) const { return _pattern == other._pattern and _type == other._type and _rotation == other._rotation; } // Returns a pointer to the array of patches matching the descriptor inline FarPatchTables::PatchArray * FarPatchTables::findPatchArray( FarPatchTables::Descriptor desc ) { for (int i=0; i<(int)_patchArrays.size(); ++i) { if (_patchArrays[i].GetDescriptor()==desc) return &_patchArrays[i]; } return 0; } // Returns the total number of patches stored in the tables inline int FarPatchTables::GetNumPatches() const { // there is one PatchParam record for each patch in the mesh return (int)GetPatchParamTable().size(); } // Returns the total number of control vertex indices in the tables inline int FarPatchTables::GetNumControlVertices() const { int result=0; for (int i=0; i<(int)_patchArrays.size(); ++i) { result += _patchArrays[i].GetDescriptor().GetNumControlVertices() * _patchArrays[i].GetNumPatches(); } return result; } } // end namespace OPENSUBDIV_VERSION using namespace OPENSUBDIV_VERSION; } // end namespace OpenSubdiv #endif /* FAR_PATCH_TABLES */