mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-27 05:50:05 +00:00
358 lines
14 KiB
C++
358 lines
14 KiB
C++
//
|
|
// 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 <assert.h>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "../version.h"
|
|
|
|
template <class T> class HbrFace;
|
|
template <class T> class HbrHalfedge;
|
|
template <class T> class HbrVertex;
|
|
template <class T> class HbrMesh;
|
|
|
|
namespace OpenSubdiv {
|
|
namespace OPENSUBDIV_VERSION {
|
|
|
|
template <class T, class U> class FarMesh;
|
|
template <class T, class U> 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 (<T> is the type):
|
|
// _<T>_IT : indices of all the adjacent vertices required by the compute kernels
|
|
// _<T>_W : fractional weight of the vertex (based on sharpness & topology)
|
|
// _<T>_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 T, class U=T> class FarSubdivisionTables {
|
|
public:
|
|
|
|
// Destructor
|
|
virtual ~FarSubdivisionTables<T,U>() {}
|
|
|
|
// 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<T,U> * 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 <typename Type> class Table {
|
|
std::vector<Type> _data; // table data
|
|
std::vector<Type *> _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<Table *>(this)->operator[](level);
|
|
}
|
|
};
|
|
|
|
Table<unsigned int> const & Get_E_IT() const { return _E_IT; }
|
|
|
|
Table<float> const & Get_E_W() const { return _E_W; }
|
|
|
|
Table<int> const & Get_V_ITa() const { return _V_ITa; }
|
|
|
|
Table<unsigned int> const & Get_V_IT() const { return _V_IT; }
|
|
|
|
Table<float> const & Get_V_W() const { return _V_W; }
|
|
|
|
protected:
|
|
friend class FarMeshFactory<T,U>;
|
|
|
|
FarSubdivisionTables<T,U>( FarMesh<T,U> * 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<T> const * x, HbrVertex<T> const * y );
|
|
|
|
struct VertexKernelBatch {
|
|
int kernelF;
|
|
int kernelE;
|
|
|
|
std::pair<int,int> kernelB;
|
|
std::pair<int,int> kernelA1;
|
|
std::pair<int,int> 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<VertexKernelBatch> & getKernelBatches() const { return _batches; }
|
|
|
|
protected:
|
|
// mesh that owns this subdivisionTable
|
|
FarMesh<T,U> * _mesh;
|
|
|
|
Table<unsigned int> _E_IT; // vertices from edge refinement
|
|
Table<float> _E_W; // weigths
|
|
|
|
Table<int> _V_ITa; // vertices from vertex refinement
|
|
Table<unsigned int> _V_IT; // indices of adjacent vertices
|
|
Table<float> _V_W; // weights
|
|
|
|
std::vector<VertexKernelBatch> _batches;
|
|
|
|
std::vector<int> _vertsOffsets; // offset to the first vertex of each level
|
|
private:
|
|
};
|
|
|
|
template <class T, class U>
|
|
FarSubdivisionTables<T,U>::FarSubdivisionTables( FarMesh<T,U> * 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 <class T, class U> int
|
|
FarSubdivisionTables<T,U>::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 <class T, class U> bool
|
|
FarSubdivisionTables<T,U>::compareVertices( HbrVertex<T> const * x, HbrVertex<T> const * y ) {
|
|
|
|
// Masks of the parent vertex decide for the current vertex.
|
|
HbrVertex<T> * 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 <class T, class U> int
|
|
FarSubdivisionTables<T,U>::GetFirstVertexOffset( int level ) const {
|
|
assert(level>=0 and level<=(int)_vertsOffsets.size());
|
|
return _vertsOffsets[level];
|
|
}
|
|
|
|
template <class T, class U> int
|
|
FarSubdivisionTables<T,U>::GetNumFaceVertices( int level ) const {
|
|
assert(level>=0 and level<=(int)_batches.size());
|
|
return _batches[level-1].kernelF;
|
|
}
|
|
|
|
template <class T, class U> int
|
|
FarSubdivisionTables<T,U>::GetNumEdgeVertices( int level ) const {
|
|
assert(level>=0 and level<=(int)_batches.size());
|
|
return _batches[level-1].kernelE;
|
|
}
|
|
|
|
template <class T, class U> int
|
|
FarSubdivisionTables<T,U>::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 <class T, class U> int
|
|
FarSubdivisionTables<T,U>::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 <class T, class U> int
|
|
FarSubdivisionTables<T,U>::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 */
|