// // Copyright (C) Pixar. All rights reserved. // // This license governs use of the accompanying software. If you // use the software, you accept this license. If you do not accept // the license, do not use the software. // // 1. Definitions // The terms "reproduce," "reproduction," "derivative works," and // "distribution" have the same meaning here as under U.S. // copyright law. A "contribution" is the original software, or // any additions or changes to the software. // A "contributor" is any person or entity that distributes its // contribution under this license. // "Licensed patents" are a contributor's patent claims that read // directly on its contribution. // // 2. Grant of Rights // (A) Copyright Grant- Subject to the terms of this license, // including the license conditions and limitations in section 3, // each contributor grants you a non-exclusive, worldwide, // royalty-free copyright license to reproduce its contribution, // prepare derivative works of its contribution, and distribute // its contribution or any derivative works that you create. // (B) Patent Grant- Subject to the terms of this license, // including the license conditions and limitations in section 3, // each contributor grants you a non-exclusive, worldwide, // royalty-free license under its licensed patents to make, have // made, use, sell, offer for sale, import, and/or otherwise // dispose of its contribution in the software or derivative works // of the contribution in the software. // // 3. Conditions and Limitations // (A) No Trademark License- This license does not grant you // rights to use any contributor's name, logo, or trademarks. // (B) If you bring a patent claim against any contributor over // patents that you claim are infringed by the software, your // patent license from such contributor to the software ends // automatically. // (C) If you distribute any portion of the software, you must // retain all copyright, patent, trademark, and attribution // notices that are present in the software. // (D) If you distribute any portion of the software in source // code form, you may do so only under this license by including a // complete copy of this license with your distribution. If you // distribute any portion of the software in compiled or object // code form, you may only do so under a license that complies // with this license. // (E) The software is licensed "as-is." You bear the risk of // using it. The contributors give no express warranties, // guarantees or conditions. You may have additional consumer // rights under your local laws which this license cannot change. // To the extent permitted under your local laws, the contributors // exclude the implied warranties of merchantability, fitness for // a particular purpose and non-infringement. // #ifndef FAR_SUBDIVISION_TABLES_H #define FAR_SUBDIVISION_TABLES_H #include #include #include #include "../version.h" template class HbrFace; template class HbrHalfedge; template class HbrVertex; template class HbrMesh; namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { template class FarMesh; template class FarMeshFactory; // Catmull-Clark tables store the indexing tables required in order to compute // the refined positions of a mesh without the help of a hierarchical data // structure. The advantage of this representation is its ability to be executed // in a massively parallel environment without data dependencies. // // The vertex indexing tables require the vertex buffer to be sorted based on the // nature of the parent of a given vertex : either a face, an edge, or a vertex. // // [...Child of a Face...]|[... Child of an Edge ...]|[... Child of a Vertex ...] // // Each segment of the buffer is associated the following tables ( is the type): // __IT : indices of all the adjacent vertices required by the compute kernels // __W : fractional weight of the vertex (based on sharpness & topology) // __ITa : codex for the two previous tables // For more details see : "Feature Adaptive GPU Rendering of Catmull-Clark // Subdivision Surfaces" p.3 - par. 3.2 template class FarSubdivisionTables { public: // Destructor virtual ~FarSubdivisionTables() {} // Return the highest level of subdivision possible with these tables int GetMaxLevel() const { return (int)(_vertsOffsets.size()); } // Memory required to store the indexing tables virtual int GetMemoryUsed() const; // Compute the positions of refined vertices using the specified kernels virtual void Refine( int level, void * clientdata=0 ) const=0; // Pointer back to the mesh owning the table FarMesh * GetMesh() { return _mesh; } // The index of the first vertex that belongs to the level of subdivision // represented by this set of FarCatmarkSubdivisionTables int GetFirstVertexOffset( int level ) const; // Number of vertices children of a face at a given level (always 0 for Loop) int GetNumFaceVertices( int level ) const; // Number of vertices children of an edge at a given level int GetNumEdgeVertices( int level ) const; // Number of vertices children of a vertex at a given level int GetNumVertexVertices( int level ) const; // Total number of vertices at a given level int GetNumVertices( int level ) const; // Indexing tables accessors // Generic multi-level indexing table : the indices across all the subdivision // levels are stored in a single std::vector. The table class holds a sequence // of markers pointing to the first index at the beginning of the sequence // describing a given level (note that "level 1" vertices are obtained by using // the indices starting at "level 0" of the tables) template class Table { std::vector _data; // table data std::vector _markers; // pointers to the first datum at each level public: // Returns the memory required to store the data in this table. int GetMemoryUsed() const { return (int)_data.size() * sizeof(Type); } void SetMarker(int level, Type * marker) { _markers[level] = marker; } void Resize(int size) { _data.resize(size); _markers[0] = &_data[0]; } Table(int maxlevel) : _markers(maxlevel) { } Type * operator[](int level) { assert(level>=0 and level<(int)_markers.size()); return _markers[level]; } const Type * operator[](int level) const { return const_cast(this)->operator[](level); } }; Table const & Get_E_IT() const { return _E_IT; } Table const & Get_E_W() const { return _E_W; } Table const & Get_V_ITa() const { return _V_ITa; } Table const & Get_V_IT() const { return _V_IT; } Table const & Get_V_W() const { return _V_W; } protected: friend class FarMeshFactory; FarSubdivisionTables( FarMesh * mesh, int maxlevel ); // Returns an integer based on the order in which the kernels are applied static int getMaskRanking( unsigned char mask0, unsigned char mask1 ); // Compares to vertices based on the ranking of their hbr masks combination static bool compareVertices( HbrVertex const * x, HbrVertex const * y ); struct VertexKernelBatch { int kernelF; int kernelE; std::pair kernelB; std::pair kernelA1; std::pair kernelA2; VertexKernelBatch() : kernelF(0), kernelE(0) { } void InitVertexKernels(int a, int b) { kernelB.first = kernelA1.first = kernelA2.first = a; kernelB.second = kernelA1.second = kernelA2.second = b; } void AddVertex( int index, int rank ) { // expand the range of kernel batches based on vertex index and rank if (rank<7) { if (index < kernelB.first) kernelB.first=index; if (index > kernelB.second) kernelB.second=index; } if ((rank>2) and (rank<8)) { if (index < kernelA2.first) kernelA2.first=index; if (index > kernelA2.second) kernelA2.second=index; } if (rank>6) { if (index < kernelA1.first) kernelA1.first=index; if (index > kernelA1.second) kernelA1.second=index; } } }; // Returns the range of vertex indices of each of the 3 batches of VertexPoint // compute Kernels (kernel application order is : B / A / A) std::vector & getKernelBatches() const { return _batches; } protected: // mesh that owns this subdivisionTable FarMesh * _mesh; Table _E_IT; // vertices from edge refinement Table _E_W; // weigths Table _V_ITa; // vertices from vertex refinement Table _V_IT; // indices of adjacent vertices Table _V_W; // weights std::vector _batches; std::vector _vertsOffsets; // offset to the first vertex of each level private: }; template FarSubdivisionTables::FarSubdivisionTables( FarMesh * mesh, int maxlevel ) : _mesh(mesh), _E_IT(maxlevel+1), _E_W(maxlevel+1), _V_ITa(maxlevel+1), _V_IT(maxlevel+1), _V_W(maxlevel+1), _batches(maxlevel), _vertsOffsets(maxlevel+1,0) { assert( maxlevel > 0 ); } // The ranking matrix defines the order of execution for the various combinations // of Corner, Crease, Dart and Smooth topological configurations. This matrix is // somewhat arbitrary as it is possible to perform some permutations in the // ordering without adverse effects, but it does try to minimize kernel switching // during the exececution of Refine(). This table is identical for both the Loop // and Catmull-Clark schemes. // // The matrix is derived from this table : // Rules +----+----+----+----+----+----+----+----+----+----+ // Pass 0 | Dt | Sm | Sm | Dt | Sm | Dt | Sm | Cr | Co | Cr | // Pass 1 | | | | Co | Co | Cr | Cr | Co | | | // Kernel +----+----+----+----+----+----+----+----+----+----+ // Pass 0 | B | B | B | B | B | B | B | A | A | A | // Pass 1 | | | | A | A | A | A | A | | | // +----+----+----+----+----+----+----+----+----+----+ // Rank | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | // +----+----+----+----+----+----+----+----+----+----+ // with : // - A : compute kernel applying k_Crease / k_Corner rules // - B : compute kernel applying k_Smooth / k_Dart rules template int FarSubdivisionTables::getMaskRanking( unsigned char mask0, unsigned char mask1 ) { static short masks[4][4] = { { 0, 1, 6, 4 }, { 0xFF, 2, 5, 3 }, { 0xFF, 0xFF, 9, 7 }, { 0xFF, 0xFF, 0xFF, 8 } }; return masks[mask0][mask1]; } // Compare the weight masks of 2 vertices using the following ordering table. // // Assuming 2 computer kernels : // - A handles the k_Crease and K_Corner rules // - B handles the K_Smooth and K_Dart rules // The vertices should be sorted so as to minimize the number execution calls of // these kernels to match the 2 pass interpolation scheme used in Hbr. template bool FarSubdivisionTables::compareVertices( HbrVertex const * x, HbrVertex const * y ) { // Masks of the parent vertex decide for the current vertex. HbrVertex * px=x->GetParentVertex(), * py=y->GetParentVertex(); assert( (getMaskRanking(px->GetMask(false), px->GetMask(true) )!=0xFF) and (getMaskRanking(py->GetMask(false), py->GetMask(true) )!=0xFF) ); return getMaskRanking(px->GetMask(false), px->GetMask(true) ) < getMaskRanking(py->GetMask(false), py->GetMask(true) ); } template int FarSubdivisionTables::GetFirstVertexOffset( int level ) const { assert(level>=0 and level<=(int)_vertsOffsets.size()); return _vertsOffsets[level]; } template int FarSubdivisionTables::GetNumFaceVertices( int level ) const { assert(level>=0 and level<=(int)_batches.size()); return _batches[level-1].kernelF; } template int FarSubdivisionTables::GetNumEdgeVertices( int level ) const { assert(level>=0 and level<=(int)_batches.size()); return _batches[level-1].kernelE; } template int FarSubdivisionTables::GetNumVertexVertices( int level ) const { assert(level>=0 and level<=(int)_batches.size()); if (level==0) return _mesh->GetNumCoarseVertices(); else return std::max( _batches[level-1].kernelB.second, std::max(_batches[level-1].kernelA1.second, _batches[level-1].kernelA2.second)); } template int FarSubdivisionTables::GetNumVertices( int level ) const { assert(level>=0 and level<=(int)_batches.size()); if (level==0) return GetNumVertexVertices(0); else return GetNumFaceVertices(level)+ GetNumEdgeVertices(level)+ GetNumVertexVertices(level); } template int FarSubdivisionTables::GetMemoryUsed() const { return _E_IT.GetMemoryUsed()+ _E_W.GetMemoryUsed()+ _V_ITa.GetMemoryUsed()+ _V_IT.GetMemoryUsed()+ _V_W.GetMemoryUsed(); } } // end namespace OPENSUBDIV_VERSION using namespace OPENSUBDIV_VERSION; } // end namespace OpenSubdiv #endif /* FAR_SUBDIVISION_TABLES_H */