We need to leverage our per-patch ptex indexing scheme in the EvalLimit API.

- replace ptex indexing with the FarPtexCoord structure as a way to pass per-patch
  ptex data to the shaders.

  We are replacing a vector<int> arranged as :
  int[0] : ptex face index
  int[1] : (u,v) as 16 bits encoding the log2 coordinate of the top left corner

  Instead we are now using a struct arranged as :
  int[0] : ptex face index
  int[1] : is a bit-field containing u,v, rotation, depth and non-quad

  The u,v coordinates have been reduced to 10 bits instead of 16, which still
  gives us a lot of margin.

- Replace OsdVertexBufferDescriptor with something more adequate for general
  primvar representation (this name will probably eventually change...)

- Improve OsdPatchDescriptor
    - add a "loop" boolean (true if the patch is of loop type)
    - add a GetPatchSize() accessor

- OsdPatchArray :
    - remove some redundant elements (still more to do there)

- Fix all shader / examples / regressions & stuff to make this all work.

fixes #143
This commit is contained in:
manuelk 2013-03-22 18:20:50 -07:00
parent 86c805fd67
commit e6e7c96a52
19 changed files with 307 additions and 147 deletions

View File

@ -912,7 +912,7 @@ display()
if (g_mesh->GetDrawContext()->IsAdaptive()) {
switch (patch.patchSize) {
switch (patch.desc.GetPatchSize()) {
case 4:
topology = D3D11_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST;
break;

View File

@ -1290,7 +1290,7 @@ display() {
if (g_mesh->GetDrawContext()->IsAdaptive()) {
#if defined(GL_ARB_tessellation_shader) || defined(GL_VERSION_4_0)
primType = GL_PATCHES;
glPatchParameteri(GL_PATCH_VERTICES, patch.patchSize);
glPatchParameteri(GL_PATCH_VERTICES, patch.desc.GetPatchSize());
#endif
} else {
if (g_scheme == kLoop) {
@ -1324,7 +1324,7 @@ display() {
for (size_t j = 0; j < drawRanges.size(); ++j) {
int primitiveOffset = (drawRanges[j].firstIndex - patch.firstIndex)/patch.patchSize;
int primitiveOffset = (drawRanges[j].firstIndex - patch.firstIndex)/patch.desc.GetPatchSize();
if (patch.desc.type == OpenSubdiv::kGregory || patch.desc.type == OpenSubdiv::kBoundaryGregory){
glProgramUniform1i(program, uniformGregoryQuadOffset, patch.gregoryQuadOffsetBase + primitiveOffset*4);
}

View File

@ -1242,13 +1242,13 @@ display() {
if (patch.desc.subpatch == 0) {
if (patchType == OpenSubdiv::kTransitionRegular)
transitionPatchTypeCount[0][patchPattern][patchRotation] += patch.numIndices / patch.patchSize;
transitionPatchTypeCount[0][patchPattern][patchRotation] += patch.numIndices / patch.desc.GetPatchSize();
else if (patchType == OpenSubdiv::kTransitionBoundary)
transitionPatchTypeCount[1][patchPattern][patchRotation] += patch.numIndices / patch.patchSize;
transitionPatchTypeCount[1][patchPattern][patchRotation] += patch.numIndices / patch.desc.GetPatchSize();
else if (patchType == OpenSubdiv::kTransitionBoundary)
transitionPatchTypeCount[2][patchPattern][patchRotation] += patch.numIndices / patch.patchSize;
transitionPatchTypeCount[2][patchPattern][patchRotation] += patch.numIndices / patch.desc.GetPatchSize();
else
patchTypeCount[patchType] += patch.numIndices / patch.patchSize;
patchTypeCount[patchType] += patch.numIndices / patch.desc.GetPatchSize();
}
GLenum primType;
@ -1256,7 +1256,7 @@ display() {
if (g_mesh->GetDrawContext()->IsAdaptive()) {
#if defined(GL_ARB_tessellation_shader) || defined(GL_VERSION_4_0)
primType = GL_PATCHES;
glPatchParameteri(GL_PATCH_VERTICES, patch.patchSize);
glPatchParameteri(GL_PATCH_VERTICES, patch.desc.GetPatchSize());
#endif
} else {

View File

@ -767,7 +767,7 @@ OpenSubdivPtexShader::draw(const MHWRender::MDrawContext &mDrawContext,
GLint surfaceProgram = bindProgram(mDrawContext, osdDrawContext, patch);
if (patch.desc.type != OpenSubdiv::kNonPatch) {
glPatchParameteri(GL_PATCH_VERTICES, patch.patchSize);
glPatchParameteri(GL_PATCH_VERTICES, patch.desc.GetPatchSize());
if (osdDrawContext->vertexTextureBuffer) {
glActiveTexture(GL_TEXTURE0);

View File

@ -681,7 +681,7 @@ OpenSubdivShader::draw(const MHWRender::MDrawContext &mDrawContext,
bindProgram(mDrawContext, osdDrawContext, patch);
if (patch.desc.type != OpenSubdiv::kNonPatch) {
glPatchParameteri(GL_PATCH_VERTICES, patch.patchSize);
glPatchParameteri(GL_PATCH_VERTICES, patch.desc.GetPatchSize());
glDrawElements(GL_PATCHES,
patch.numIndices, GL_UNSIGNED_INT,

View File

@ -802,7 +802,7 @@ display() {
OpenSubdiv::OsdPatchArray const & patch = patches[i];
GLenum primType = GL_PATCHES;
glPatchParameteri(GL_PATCH_VERTICES, patch.patchSize);
glPatchParameteri(GL_PATCH_VERTICES, patch.desc.GetPatchSize());
Effect effect;
effect.color = g_displayColor;
@ -973,7 +973,7 @@ drawStroke(int x, int y)
OpenSubdiv::OsdPatchArray const & patch = patches[i];
GLenum primType = GL_PATCHES;
glPatchParameteri(GL_PATCH_VERTICES, patch.patchSize);
glPatchParameteri(GL_PATCH_VERTICES, patch.desc.GetPatchSize());
Effect effect;
effect.color = 0;

View File

@ -66,15 +66,14 @@ uniform float bumpScale = 1.0;
vec4 GeneratePatchCoord(vec2 localUV) // for non-adpative
{
ivec2 ptexIndex = texelFetch(g_ptexIndicesBuffer, gl_PrimitiveID).xy;
int faceID = abs(ptexIndex.x);
int lv = 1 << nonAdaptiveLevel;
if (ptexIndex.x < 0) lv >>= 1;
int u = ptexIndex.y >> 16;
int v = (ptexIndex.y & 0xffff);
ivec2 ptexIndex = texelFetchBuffer(g_ptexIndicesBuffer, gl_PrimitiveID).xy;
int faceID = ptexIndex.x;
int lv = 1 << (ptexIndex.y & 0xf);
int u = (ptexIndex.y >> 17) & 0x3ff;
int v = (ptexIndex.y >> 7) & 0x3ff;
vec2 uv = localUV;
uv = (uv * vec2(1.0)/lv) + vec2(u, v)/lv;
return vec4(uv.x, uv.y, lv+0.5, faceID+0.5);
}

View File

@ -1407,7 +1407,7 @@ drawModel() {
if (g_mesh->GetDrawContext()->IsAdaptive()) {
primType = GL_PATCHES;
glPatchParameteri(GL_PATCH_VERTICES, patch.patchSize);
glPatchParameteri(GL_PATCH_VERTICES, patch.desc.GetPatchSize());
if (g_mesh->GetDrawContext()->vertexTextureBuffer) {
glActiveTexture(GL_TEXTURE0);

View File

@ -97,7 +97,7 @@ public:
/// Returns the ptex coordinates for each face at a given level. The coordinates
/// are stored as : (int) faceindex / (ushort) u_index / (ushort) v_index
std::vector<int> const & GetPtexCoordinates(int level) const;
std::vector<FarPtexCoord> const & GetPtexCoordinates(int level) const;
/// Returns the fvar data for each face at a given level. The data
/// is stored as a run of totalFVarWidth floats per-vertex per-face
@ -117,6 +117,9 @@ public:
/// Returns the total number of vertices in the mesh across across all depths
int GetNumVertices() const { return (int)(_vertices.size()); }
/// True if the mesh tables support the feature-adaptive mode.
bool SupportsFeatureAdaptive() const { return _patchTables!=NULL; }
/// Returns an ordered vector of batches of compute kernels. The kernels
/// describe the sequence of computations required to apply the subdivision
/// scheme to the vertices in the mesh.
@ -153,7 +156,7 @@ private:
std::vector< std::vector<int> > _faceverts;
// ptex coordinates for each face
std::vector< std::vector<int> > _ptexcoordinates;
std::vector< std::vector<FarPtexCoord> > _ptexcoordinates;
// fvar data for each face
std::vector< std::vector<float> > _fvarData;
@ -175,7 +178,7 @@ FarMesh<U>::GetFaceVertices(int level) const {
return _faceverts[0];
}
template <class U> std::vector<int> const &
template <class U> std::vector<FarPtexCoord> const &
FarMesh<U>::GetPtexCoordinates(int level) const {
if ( (level>=0) and (level<(int)_faceverts.size()) )
return _ptexcoordinates[level];

View File

@ -187,7 +187,7 @@ private:
int refineAdaptive( HbrMesh<T> * mesh, int maxIsolate );
// Generates local sub-face coordinates for Ptex textures
void generatePtexCoordinates( std::vector<int> & vec, int level );
void generatePtexCoordinates( std::vector<FarPtexCoord> & vec, int level );
// Generates local sub-face face-varying UV coordinates
void generateFVarData( std::vector<float> & vec, int level );
@ -628,8 +628,8 @@ copyVertex( T & dest, T const & src ) {
// int 2 :
// [ u (16 bits) ] [ v (16 bits) ]
//
template <class T> int *
computePtexCoordinate(HbrFace<T> const *f, int *coord, bool isAdaptive) {
template <class T> FarPtexCoord *
computePtexCoordinate(HbrFace<T> const *f, FarPtexCoord *coord) {
short u,v;
unsigned short ofs = 1, depth;
@ -637,7 +637,8 @@ computePtexCoordinate(HbrFace<T> const *f, int *coord, bool isAdaptive) {
if (coord == NULL) return NULL;
int rots = f->_adaptiveFlags.rots;
// save the rotation state of the coarse face
unsigned char rots = f->_adaptiveFlags.rots;
// track upwards towards coarse parent face, accumulating u,v indices
HbrFace<T> const * p = f->GetParent();
@ -665,37 +666,30 @@ computePtexCoordinate(HbrFace<T> const *f, int *coord, bool isAdaptive) {
p = f->GetParent();
}
// bit0 : non-quad bit
// bit1,2 : rotation bit
if (isAdaptive)
coord[0] = (f->GetPtexIndex() << 3) | (rots << 1) | (nonquad ? 1 : 0);
else
coord[0] = nonquad ? -f->GetPtexIndex() : f->GetPtexIndex();
coord[1] = (int)u << 16;
coord[1] += v;
coord->Set( f->GetPtexIndex(), u, v, rots, depth, nonquad );
return coord+2;
return ++coord;
}
// This currently only supports the Catmark / Bilinear schemes. Loop
template <class T, class U> void
FarMeshFactory<T,U>::generatePtexCoordinates( std::vector<int> & vec, int level ) {
FarMeshFactory<T,U>::generatePtexCoordinates( std::vector<FarPtexCoord> & vec, int level ) {
assert( _hbrMesh );
if (_facesList[0].empty() or _facesList[level][0]->GetPtexIndex() == -1)
return;
vec.resize( _facesList[level].size()*2, -1 );
vec.resize( _facesList[level].size() );
int *p = &vec[0];
FarPtexCoord * p = &vec[0];
for (int i=0; i<(int)_facesList[level].size(); ++i) {
HbrFace<T> const * f = _facesList[level][i];
assert(f);
p = computePtexCoordinate(f, p, /*isAdaptive=*/false);
p = computePtexCoordinate(f, p);
}
}

View File

@ -55,8 +55,8 @@
// a particular purpose and non-infringement.
//
#ifndef FAR_PTACH_TABLES_H
#define FAR_PTACH_TABLES_H
#ifndef FAR_PATCH_TABLES_H
#define FAR_PATCH_TABLES_H
#include "../version.h"
#include <vector>
@ -64,6 +64,55 @@
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
/// \brief Flattened ptex coordinates indexing system
///
/// Bitfield layout :
///
/// level:4 - the subdivision level of the patch
/// nonquad:1; - whether the patch is the child of a non-quad face
/// rotation:2; - patch rotations necessary to match CCW face-winding
/// v:10; - log2 value of u parameter at first patch corner
/// u:10; - log2 value of v parameter at first patch corner
/// reserved1:5; - padding
///
/// Note : the bitfield is not expanded in the struct due to differences in how
/// compilers pack bit-fields and endian-ness.
///
struct FarPtexCoord {
unsigned int faceIndex:32; // Ptex face index
unsigned int bitField:32; // Patch description bits
/// Sets teh values of the bit fields
///
/// @param faceid ptex face index
///
/// @param u value of the u parameter for the first corner of the face
/// @param v value of the v parameter for the first corner of the face
///
/// @params rots rotations required to reproduce CCW face-winding
/// @params depth subdivision level of the patch
/// @params nonquad true if the root face is not a quad
///
void Set( unsigned int faceid,
short u, short v,
unsigned char rots, unsigned char depth, bool nonquad ) {
faceIndex = faceid;
bitField = (u << 17) |
(v << 7) |
(rots << 5) |
((nonquad ? 1:0) << 4) |
(nonquad ? depth+1 : depth);
}
/// Resets the values to 0
void Clear() {
faceIndex = bitField = 0;
}
};
/// \brief Indices for multi-mesh patch arrays
// XXXX manuelk : we should probably derive FarMultiPatchTables for multi-meshes
struct FarPatchCount {
int nonPatch; // reserved for uniform and loop
int regular;
@ -75,6 +124,7 @@ struct FarPatchCount {
int transitionBoundary[5][4];
int transitionCorner[5][4];
/// Constructor.
FarPatchCount() {
nonPatch = regular = boundary = corner = gregory = boundaryGregory = 0;
for (int i = 0; i < 5; ++i) {
@ -86,6 +136,7 @@ struct FarPatchCount {
}
}
/// Adds the indices from another patchTable.
void Append(FarPatchCount const &p) {
nonPatch += p.nonPatch;
regular += p.regular;
@ -100,7 +151,7 @@ struct FarPatchCount {
transitionCorner[i][j] += p.transitionCorner[i][j];
}
}
}
}
};
typedef std::vector<FarPatchCount> FarPatchCountVector;
@ -113,13 +164,16 @@ typedef std::vector<FarPatchCount> FarPatchCountVector;
class FarPatchTables {
public:
typedef std::pair<std::vector<unsigned int>,
std::vector<unsigned char> > PTable; // index table - level table pair
/// Patch table : (vert indices, patch level) pairs
typedef std::pair<std::vector<unsigned int>,
std::vector<unsigned char> > PTable;
typedef std::vector<int> VertexValenceTable;
typedef std::vector<unsigned int> QuadOffsetTable;
typedef std::vector<int> PtexCoordinateTable;
typedef std::vector<FarPtexCoord> PtexCoordinateTable;
typedef std::vector<float> FVarDataTable;
@ -164,7 +218,7 @@ public:
/// Ringsize of Boundary Patches in table.
static int GetCornerPatchRingsize() { return 9; }
/// Ringsize of Gregory Patches in table.
/// Ringsize of Gregory (and Gregory Boundary) Patches in table.
static int GetGregoryPatchRingsize() { return 4; }
@ -202,6 +256,12 @@ public:
FVarDataTable const & GetTransitionCornerFVarData(unsigned char pattern, unsigned char rot) const { return _transition[pattern]._C_FVD[rot]; }
/// Returns the total number of patches stored in the tables
size_t GetNumPatches() const;
/// Returns the total number of control vertex indices in the tables
size_t GetNumControlVertices() const;
/// Returns max vertex valence
int GetMaxValence() const { return _maxValence; }
@ -218,19 +278,19 @@ private:
// FarTables for full / end patches
struct Patches {
PTable _R_IT, // regular patches
_B_IT, // boundary patches
_C_IT, // corner patches
_G_IT, // gregory patches
_G_B_IT; // gregory boundary patches
PTable _R_IT, // regular patches vertex indices table
_B_IT, // boundary
_C_IT, // corner
_G_IT, // gregory
_G_B_IT; // gregory
PtexCoordinateTable _R_PTX,
PtexCoordinateTable _R_PTX, // regular patches ptex indices table
_B_PTX,
_C_PTX,
_G_PTX,
_G_B_PTX;
FVarDataTable _R_FVD,
FVarDataTable _R_FVD, // regular patches face-varying indices table
_B_FVD,
_C_FVD,
_G_FVD,
@ -252,22 +312,77 @@ private:
_C_FVD[4];
};
Patches _full;
Patches _full; // full patches tables
TPatches _transition[5];
TPatches _transition[5]; // transition patches tables
VertexValenceTable _vertexValenceTable;
// XXXX manuelk : Greg. patch tables need to be localized to Gregory CVs only.
QuadOffsetTable _quadOffsetTable;
// vertex valence table (for Gregory patches)
VertexValenceTable _vertexValenceTable;
// quad offsets table (for Gregory patches)
QuadOffsetTable _quadOffsetTable;
// highest vertex valence allowed in the mesh (used for Gregory
// vertexValance & quadOffset talbes)
int _maxValence;
FarPatchCountVector _patchCounts;
// vector of counters for aggregated patch tables used by multi-meshes
FarPatchCountVector _patchCounts;
};
// Returns the total number of patches stored in the tables
inline size_t
FarPatchTables::GetNumPatches() const {
// We can use directly the size of the levels table ("second") because
// there is 1 value per patch
size_t count = _full._R_IT.second.size() +
_full._B_IT.second.size() +
_full._C_IT.second.size() +
_full._G_IT.second.size() +
_full._G_B_IT.second.size();
for (int i = 0; i < 5; ++i) {
count += _transition[i]._R_IT.second.size();
for (int j = 0; j < 4; ++j) {
count += _transition[i]._B_IT[j].second.size()+
_transition[i]._C_IT[j].second.size();
}
}
return count;
}
// Returns the total number of control vertex indices in the tables
inline size_t
FarPatchTables::GetNumControlVertices() const {
// The "first" table of a PTable contains the vertex indices of each
// patch, so we can directly use those to tally our count.
size_t count = _full._R_IT.first.size() +
_full._B_IT.first.size() +
_full._C_IT.first.size() +
_full._G_IT.first.size() +
_full._G_B_IT.first.size();
for (int i = 0; i < 5; ++i) {
count += _transition[i]._R_IT.first.size();
for (int j = 0; j < 4; ++j) {
count += _transition[i]._B_IT[j].first.size()+
_transition[i]._C_IT[j].first.size();
}
}
return count;
}
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* FAR_VERTEX_EDIT_TABLES_H */
#endif /* FAR_PATCH_TABLES */

View File

@ -55,8 +55,8 @@
// a particular purpose and non-infringement.
//
#ifndef FAR_PTACH_TABLES_FACTORY_H
#define FAR_PTACH_TABLES_FACTORY_H
#ifndef FAR_PATCH_TABLES_FACTORY_H
#define FAR_PATCH_TABLES_FACTORY_H
#include "../version.h"
@ -125,7 +125,7 @@ private:
typedef Pointers<unsigned int*> IndexPointers;
typedef Pointers<unsigned char*> LevelPointers;
typedef Pointers<int *> PtexPointers;
typedef Pointers<FarPtexCoord *> PtexPointers;
typedef Pointers<float *> FVarPointers;
struct Counters {
@ -137,8 +137,8 @@ private:
Counters() { memset(this, 0, sizeof(Counters)); }
};
Counters _fullCtr,
_transitionCtr[5];
Counters _fullCtr, // counters for full patches
_transitionCtr[5]; // counters for transition patches
HbrMesh<T> const * _mesh;
@ -543,30 +543,30 @@ FarPatchTablesFactory<T>::Create( int maxlevel, int maxvalence, bool requirePtex
// Allocate ptex coordinate table if necessary
if (requirePtexCoordinate) {
result->_full._R_PTX.resize(_fullCtr.R_C*2);
result->_full._R_PTX.resize(_fullCtr.R_C);
fptrsPtx.R_P = &result->_full._R_PTX[0];
result->_full._B_PTX.resize(_fullCtr.B_C[0]*2);
result->_full._B_PTX.resize(_fullCtr.B_C[0]);
fptrsPtx.B_P[0] = &result->_full._B_PTX[0];
result->_full._C_PTX.resize(_fullCtr.C_C[0]*2);
result->_full._C_PTX.resize(_fullCtr.C_C[0]);
fptrsPtx.C_P[0] = &result->_full._C_PTX[0];
result->_full._G_PTX.resize(_fullCtr.G_C[0]*2);
result->_full._G_PTX.resize(_fullCtr.G_C[0]);
fptrsPtx.G_P[0] = &result->_full._G_PTX[0];
result->_full._G_B_PTX.resize(_fullCtr.G_C[1]*2);
result->_full._G_B_PTX.resize(_fullCtr.G_C[1]);
fptrsPtx.G_P[1] = &result->_full._G_B_PTX[0];
for (int i=0; i < 5; ++i) {
result->_transition[i]._R_PTX.resize(_transitionCtr[i].R_C*2);
result->_transition[i]._R_PTX.resize(_transitionCtr[i].R_C);
tptrsPtx[i].R_P = &result->_transition[i]._R_PTX[0];
for (int j=0; j < 4; ++j) {
result->_transition[i]._B_PTX[j].resize(_transitionCtr[i].B_C[j]*2);
result->_transition[i]._B_PTX[j].resize(_transitionCtr[i].B_C[j]);
tptrsPtx[i].B_P[j] = &result->_transition[i]._B_PTX[j][0];
result->_transition[i]._C_PTX[j].resize(_transitionCtr[i].C_C[j]*2);
result->_transition[i]._C_PTX[j].resize(_transitionCtr[i].C_C[j]);
tptrsPtx[i].C_P[j] = &result->_transition[i]._C_PTX[j][0];
}
}
@ -631,7 +631,7 @@ FarPatchTablesFactory<T>::Create( int maxlevel, int maxvalence, bool requirePtex
getOneRing(f, 16, remapRegular, fptrs.R_P);
fptrs.R_P+=16;
*fptrsLv.R_P++ = depth;
fptrsPtx.R_P = computePtexCoordinate(f, fptrsPtx.R_P, /*isAdaptive=*/true);
fptrsPtx.R_P = computePtexCoordinate(f, fptrsPtx.R_P);
fptrsFvd.R_P = computeFVarData(f, fvarWidth, fptrsFvd.R_P, /*isAdaptive=*/true);
} break;
@ -640,7 +640,7 @@ FarPatchTablesFactory<T>::Create( int maxlevel, int maxvalence, bool requirePtex
getOneRing(f, 12, remapRegularBoundary, fptrs.B_P[0]);
fptrs.B_P[0]+=12;
*fptrsLv.B_P[0]++ = depth;
fptrsPtx.B_P[0] = computePtexCoordinate(f, fptrsPtx.B_P[0], /*isAdaptive=*/true);
fptrsPtx.B_P[0] = computePtexCoordinate(f, fptrsPtx.B_P[0]);
fptrsFvd.B_P[0] = computeFVarData(f, fvarWidth, fptrsFvd.B_P[0], /*isAdaptive=*/true);
} break;
@ -649,7 +649,7 @@ FarPatchTablesFactory<T>::Create( int maxlevel, int maxvalence, bool requirePtex
getOneRing(f, 9, remapRegularCorner, fptrs.C_P[0]);
fptrs.C_P[0]+=9;
*fptrsLv.C_P[0]++ = depth;
fptrsPtx.C_P[0] = computePtexCoordinate(f, fptrsPtx.C_P[0], /*isAdaptive=*/true);
fptrsPtx.C_P[0] = computePtexCoordinate(f, fptrsPtx.C_P[0]);
fptrsFvd.C_P[0] = computeFVarData(f, fvarWidth, fptrsFvd.C_P[0], /*isAdaptive=*/true);
} break;
@ -667,7 +667,7 @@ FarPatchTablesFactory<T>::Create( int maxlevel, int maxvalence, bool requirePtex
*fptrsLv.G_P[0]++ = depth;
getQuadOffsets(f, quad_G_C0_P);
quad_G_C0_P += 4;
fptrsPtx.G_P[0] = computePtexCoordinate(f, fptrsPtx.G_P[0], /*isAdaptive=*/true);
fptrsPtx.G_P[0] = computePtexCoordinate(f, fptrsPtx.G_P[0]);
fptrsFvd.G_P[0] = computeFVarData(f, fvarWidth, fptrsFvd.G_P[0], /*isAdaptive=*/true);
} else {
@ -678,7 +678,7 @@ FarPatchTablesFactory<T>::Create( int maxlevel, int maxvalence, bool requirePtex
*fptrsLv.G_P[1]++ = depth;
getQuadOffsets(f, quad_G_C1_P);
quad_G_C1_P += 4;
fptrsPtx.G_P[1] = computePtexCoordinate(f, fptrsPtx.G_P[1], /*isAdaptive=*/true);
fptrsPtx.G_P[1] = computePtexCoordinate(f, fptrsPtx.G_P[1]);
fptrsFvd.G_P[1] = computeFVarData(f, fvarWidth, fptrsFvd.G_P[1], /*isAdaptive=*/true);
}
} else {
@ -698,7 +698,7 @@ FarPatchTablesFactory<T>::Create( int maxlevel, int maxvalence, bool requirePtex
getOneRing(f, 16, remapRegular, tptrs[tcase].R_P);
tptrs[tcase].R_P+=16;
*tptrsLv[tcase].R_P++ = depth;
tptrsPtx[tcase].R_P = computePtexCoordinate(f, tptrsPtx[tcase].R_P, /*isAdaptive=*/true);
tptrsPtx[tcase].R_P = computePtexCoordinate(f, tptrsPtx[tcase].R_P);
tptrsFvd[tcase].R_P = computeFVarData(f, fvarWidth, tptrsFvd[tcase].R_P, /*isAdaptive=*/true);
} break;
@ -707,7 +707,7 @@ FarPatchTablesFactory<T>::Create( int maxlevel, int maxvalence, bool requirePtex
getOneRing(f, 12, remapRegularBoundary, tptrs[tcase].B_P[rot]);
tptrs[tcase].B_P[rot]+=12;
*tptrsLv[tcase].B_P[rot]++ = depth;
tptrsPtx[tcase].B_P[rot] = computePtexCoordinate(f, tptrsPtx[tcase].B_P[rot], /*isAdaptive=*/true);
tptrsPtx[tcase].B_P[rot] = computePtexCoordinate(f, tptrsPtx[tcase].B_P[rot]);
tptrsFvd[tcase].B_P[rot] = computeFVarData(f, fvarWidth, tptrsFvd[tcase].B_P[rot], /*isAdaptive=*/true);
} break;
@ -716,7 +716,7 @@ FarPatchTablesFactory<T>::Create( int maxlevel, int maxvalence, bool requirePtex
getOneRing(f, 9, remapRegularCorner, tptrs[tcase].C_P[rot]);
tptrs[tcase].C_P[rot]+=9;
*tptrsLv[tcase].C_P[rot]++ = depth;
tptrsPtx[tcase].C_P[rot] = computePtexCoordinate(f, tptrsPtx[tcase].C_P[rot], /*isAdaptive=*/true);
tptrsPtx[tcase].C_P[rot] = computePtexCoordinate(f, tptrsPtx[tcase].C_P[rot]);
tptrsFvd[tcase].C_P[rot] = computeFVarData(f, fvarWidth, tptrsFvd[tcase].C_P[rot], /*isAdaptive=*/true);
} break;
}
@ -1030,4 +1030,4 @@ using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* FAR_VERTEX_EDIT_TABLES_H */
#endif /* FAR_PATCH_TABLES_FACTORY_H */

View File

@ -116,11 +116,6 @@ OsdD3D11DrawContext::allocate(FarMesh<OsdVertex> *farMesh,
int level = tables->GetMaxLevel();
const std::vector<int> &indices = farMesh->GetFaceVertices(level-1);
// XXX: farmesh or FarSubdivisionTables should have a virtual method
// to determine loop or not
bool loop =
dynamic_cast<const FarLoopSubdivisionTables<OsdVertex>*>(tables) != NULL;
int numIndices = (int)indices.size();
// Allocate and fill index buffer.
@ -140,7 +135,7 @@ OsdD3D11DrawContext::allocate(FarMesh<OsdVertex> *farMesh,
OsdPatchArray array;
array.desc.type = kNonPatch;
array.patchSize = loop ? 3 : 4;
array.desc.loop = dynamic_cast<const FarLoopSubdivisionTables<OsdVertex>*>(tables) != NULL;
array.firstIndex = 0;
array.numIndices = numIndices;
@ -239,7 +234,6 @@ OsdD3D11DrawContext::allocate(FarMesh<OsdVertex> *farMesh,
_AppendPatchArray(indexBuffer, &indexBase,
levelBuffer, &levelBase,
patchTables->GetFullRegularPatches(),
patchTables->GetRegularPatchRingsize(),
patchTables->GetFullRegularPtexCoordinates(),
patchTables->GetFullRegularFVarData(),
farMesh->GetTotalFVarWidth(),
@ -247,7 +241,6 @@ OsdD3D11DrawContext::allocate(FarMesh<OsdVertex> *farMesh,
_AppendPatchArray(indexBuffer, &indexBase,
levelBuffer, &levelBase,
patchTables->GetFullBoundaryPatches(),
patchTables->GetBoundaryPatchRingsize(),
patchTables->GetFullBoundaryPtexCoordinates(),
patchTables->GetFullBoundaryFVarData(),
farMesh->GetTotalFVarWidth(),
@ -255,7 +248,6 @@ OsdD3D11DrawContext::allocate(FarMesh<OsdVertex> *farMesh,
_AppendPatchArray(indexBuffer, &indexBase,
levelBuffer, &levelBase,
patchTables->GetFullCornerPatches(),
patchTables->GetCornerPatchRingsize(),
patchTables->GetFullCornerPtexCoordinates(),
patchTables->GetFullCornerFVarData(),
farMesh->GetTotalFVarWidth(),
@ -263,7 +255,6 @@ OsdD3D11DrawContext::allocate(FarMesh<OsdVertex> *farMesh,
_AppendPatchArray(indexBuffer, &indexBase,
levelBuffer, &levelBase,
patchTables->GetFullGregoryPatches(),
patchTables->GetGregoryPatchRingsize(),
patchTables->GetFullGregoryPtexCoordinates(),
patchTables->GetFullGregoryFVarData(),
farMesh->GetTotalFVarWidth(),
@ -272,7 +263,6 @@ OsdD3D11DrawContext::allocate(FarMesh<OsdVertex> *farMesh,
_AppendPatchArray(indexBuffer, &indexBase,
levelBuffer, &levelBase,
patchTables->GetFullBoundaryGregoryPatches(),
patchTables->GetGregoryPatchRingsize(),
patchTables->GetFullBoundaryGregoryPtexCoordinates(),
patchTables->GetFullBoundaryGregoryFVarData(),
farMesh->GetTotalFVarWidth(),
@ -284,7 +274,6 @@ OsdD3D11DrawContext::allocate(FarMesh<OsdVertex> *farMesh,
_AppendPatchArray(indexBuffer, &indexBase,
levelBuffer, &levelBase,
patchTables->GetTransitionRegularPatches(p),
patchTables->GetRegularPatchRingsize(),
patchTables->GetTransitionRegularPtexCoordinates(p),
patchTables->GetTransitionRegularFVarData(p),
farMesh->GetTotalFVarWidth(),
@ -293,7 +282,6 @@ OsdD3D11DrawContext::allocate(FarMesh<OsdVertex> *farMesh,
_AppendPatchArray(indexBuffer, &indexBase,
levelBuffer, &levelBase,
patchTables->GetTransitionBoundaryPatches(p, r),
patchTables->GetBoundaryPatchRingsize(),
patchTables->GetTransitionBoundaryPtexCoordinates(p, r),
patchTables->GetTransitionBoundaryFVarData(p, r),
farMesh->GetTotalFVarWidth(),
@ -301,7 +289,6 @@ OsdD3D11DrawContext::allocate(FarMesh<OsdVertex> *farMesh,
_AppendPatchArray(indexBuffer, &indexBase,
levelBuffer, &levelBase,
patchTables->GetTransitionCornerPatches(p, r),
patchTables->GetCornerPatchRingsize(),
patchTables->GetTransitionCornerPtexCoordinates(p, r),
patchTables->GetTransitionCornerFVarData(p, r),
farMesh->GetTotalFVarWidth(),
@ -390,7 +377,7 @@ void
OsdD3D11DrawContext::_AppendPatchArray(
unsigned int *indexBuffer, int *indexBase,
unsigned int *levelBuffer, int *levelBase,
FarPatchTables::PTable const & ptable, int patchSize,
FarPatchTables::PTable const & ptable,
FarPatchTables::PtexCoordinateTable const & ptexTable,
FarPatchTables::FVarDataTable const & fvarTable, int fvarDataWidth,
OsdPatchDescriptor const & desc,
@ -402,7 +389,6 @@ OsdD3D11DrawContext::_AppendPatchArray(
OsdPatchArray array;
array.desc = desc;
array.patchSize = patchSize;
array.firstIndex = *indexBase;
array.numIndices = (int)ptable.first.size();
array.levelBase = *levelBase;
@ -425,7 +411,7 @@ OsdD3D11DrawContext::_AppendPatchArray(
&ptable.first[0], array.numIndices * sizeof(unsigned int));
*indexBase += array.numIndices;
int numElements = array.numIndices/array.patchSize;
int numElements = array.numIndices/array.desc.GetPatchSize();
assert(numElements == (int)ptable.second.size());
memcpy(levelBuffer + array.levelBase,

View File

@ -123,11 +123,6 @@ OsdGLDrawContext::allocate(FarMesh<OsdVertex> *farMesh,
int level = tables->GetMaxLevel();
const std::vector<int> &indices = farMesh->GetFaceVertices(level-1);
// XXX: farmesh or FarSubdivisionTables should have a virtual method
// to determine loop or not
bool loop =
dynamic_cast<const FarLoopSubdivisionTables<OsdVertex>*>(tables) != NULL;
int numIndices = (int)indices.size();
// Allocate and fill index buffer.
@ -166,7 +161,7 @@ OsdGLDrawContext::allocate(FarMesh<OsdVertex> *farMesh,
OsdPatchArray array;
array.desc.type = kNonPatch;
array.patchSize = loop ? 3 : 4;
array.desc.loop = dynamic_cast<const FarLoopSubdivisionTables<OsdVertex>*>(tables) != NULL;
array.firstIndex = 0;
array.numIndices = numIndices;
@ -180,9 +175,9 @@ OsdGLDrawContext::allocate(FarMesh<OsdVertex> *farMesh,
glGenBuffers(1, &ptexCoordinateBuffer);
glBindBuffer(GL_TEXTURE_BUFFER, ptexCoordinateBuffer);
const std::vector<int> &ptexCoordinates =
const std::vector<FarPtexCoord> &ptexCoordinates =
farMesh->GetPtexCoordinates(level-1);
int size = (int)ptexCoordinates.size() * sizeof(GLint);
int size = (int)ptexCoordinates.size() * sizeof(FarPtexCoord);
glBufferData(GL_TEXTURE_BUFFER, size, &(ptexCoordinates[0]), GL_STATIC_DRAW);
@ -276,7 +271,7 @@ OsdGLDrawContext::allocate(FarMesh<OsdVertex> *farMesh,
glGenBuffers(1, &ptexCoordinateBuffer);
glBindBuffer(GL_ARRAY_BUFFER, ptexCoordinateBuffer);
glBufferData(GL_ARRAY_BUFFER,
totalPatchLevels * sizeof(int) * 2, NULL, GL_STATIC_DRAW);
totalPatchLevels * sizeof(FarPtexCoord), NULL, GL_STATIC_DRAW);
#endif
}
@ -298,28 +293,24 @@ OsdGLDrawContext::allocate(FarMesh<OsdVertex> *farMesh,
_AppendPatchArray(&indexBase, &levelBase,
patchTables->GetFullRegularPatches(),
patchTables->GetRegularPatchRingsize(),
patchTables->GetFullRegularPtexCoordinates(),
patchTables->GetFullRegularFVarData(),
farMesh->GetTotalFVarWidth(),
OsdPatchDescriptor(kRegular, 0, 0, 0, 0), 0);
_AppendPatchArray(&indexBase, &levelBase,
patchTables->GetFullBoundaryPatches(),
patchTables->GetBoundaryPatchRingsize(),
patchTables->GetFullBoundaryPtexCoordinates(),
patchTables->GetFullBoundaryFVarData(),
farMesh->GetTotalFVarWidth(),
OsdPatchDescriptor(kBoundary, 0, 0, 0, 0), 0);
_AppendPatchArray(&indexBase, &levelBase,
patchTables->GetFullCornerPatches(),
patchTables->GetCornerPatchRingsize(),
patchTables->GetFullCornerPtexCoordinates(),
patchTables->GetFullCornerFVarData(),
farMesh->GetTotalFVarWidth(),
OsdPatchDescriptor(kCorner, 0, 0, 0, 0), 0);
_AppendPatchArray(&indexBase, &levelBase,
patchTables->GetFullGregoryPatches(),
patchTables->GetGregoryPatchRingsize(),
patchTables->GetFullGregoryPtexCoordinates(),
patchTables->GetFullGregoryFVarData(),
farMesh->GetTotalFVarWidth(),
@ -328,7 +319,6 @@ OsdGLDrawContext::allocate(FarMesh<OsdVertex> *farMesh,
0);
_AppendPatchArray(&indexBase, &levelBase,
patchTables->GetFullBoundaryGregoryPatches(),
patchTables->GetGregoryPatchRingsize(),
patchTables->GetFullBoundaryGregoryPtexCoordinates(),
patchTables->GetFullBoundaryGregoryFVarData(),
farMesh->GetTotalFVarWidth(),
@ -339,7 +329,6 @@ OsdGLDrawContext::allocate(FarMesh<OsdVertex> *farMesh,
for (unsigned char p=0; p<5; ++p) {
_AppendPatchArray(&indexBase, &levelBase,
patchTables->GetTransitionRegularPatches(p),
patchTables->GetRegularPatchRingsize(),
patchTables->GetTransitionRegularPtexCoordinates(p),
patchTables->GetTransitionRegularFVarData(p),
farMesh->GetTotalFVarWidth(),
@ -347,14 +336,12 @@ OsdGLDrawContext::allocate(FarMesh<OsdVertex> *farMesh,
for (unsigned char r=0; r<4; ++r) {
_AppendPatchArray(&indexBase, &levelBase,
patchTables->GetTransitionBoundaryPatches(p, r),
patchTables->GetBoundaryPatchRingsize(),
patchTables->GetTransitionBoundaryPtexCoordinates(p, r),
patchTables->GetTransitionBoundaryFVarData(p, r),
farMesh->GetTotalFVarWidth(),
OsdPatchDescriptor(kTransitionBoundary, p, r, 0, 0), 0);
_AppendPatchArray(&indexBase, &levelBase,
patchTables->GetTransitionCornerPatches(p, r),
patchTables->GetCornerPatchRingsize(),
patchTables->GetTransitionCornerPtexCoordinates(p, r),
patchTables->GetTransitionCornerFVarData(p, r),
farMesh->GetTotalFVarWidth(),
@ -443,7 +430,7 @@ OsdGLDrawContext::allocate(FarMesh<OsdVertex> *farMesh,
void
OsdGLDrawContext::_AppendPatchArray(
int *indexBase, int *levelBase,
FarPatchTables::PTable const & ptable, int patchSize,
FarPatchTables::PTable const & ptable,
FarPatchTables::PtexCoordinateTable const & ptexTable,
FarPatchTables::FVarDataTable const & fvarTable, int fvarDataWidth,
OsdPatchDescriptor const & desc, int gregoryQuadOffsetBase)
@ -454,7 +441,6 @@ OsdGLDrawContext::_AppendPatchArray(
OsdPatchArray array;
array.desc = desc;
array.patchSize = patchSize;
array.firstIndex = *indexBase;
array.numIndices = (int)ptable.first.size();
array.levelBase = *levelBase;
@ -464,7 +450,7 @@ OsdGLDrawContext::_AppendPatchArray(
if (desc.type == OpenSubdiv::kTransitionRegular or
desc.type == OpenSubdiv::kTransitionBoundary or
desc.type == OpenSubdiv::kTransitionCorner) {
int subPatchCounts[] = { 3, 4, 4, 4, 2 };
static int subPatchCounts[] = { 3, 4, 4, 4, 2 };
numSubPatches = subPatchCounts[desc.pattern];
}
@ -480,7 +466,7 @@ OsdGLDrawContext::_AppendPatchArray(
*indexBase += array.numIndices;
#if defined(GL_ARB_texture_buffer_object) || defined(GL_VERSION_3_1)
int numElements = array.numIndices/array.patchSize;
int numElements = array.numIndices/array.desc.GetPatchSize();
assert(numElements == (int)ptable.second.size());
glBufferSubData(GL_TEXTURE_BUFFER,
array.levelBase * sizeof(unsigned char),
@ -491,12 +477,12 @@ OsdGLDrawContext::_AppendPatchArray(
if (ptexCoordinateTextureBuffer) {
#if defined(GL_ARB_texture_buffer_object) || defined(GL_VERSION_3_1)
assert((int)ptexTable.size()/2 == numElements);
assert((int)ptexTable.size() == numElements);
// populate ptex coordinates
glBufferSubData(GL_ARRAY_BUFFER,
array.levelBase * sizeof(int) * 2,
(int)ptexTable.size() * sizeof(int),
array.levelBase * sizeof(FarPtexCoord),
(int)ptexTable.size() * sizeof(FarPtexCoord),
&ptexTable[0]);
#endif
}

View File

@ -131,7 +131,7 @@ private:
void _AppendPatchArray(
int *indexBase, int *levelBase,
FarPatchTables::PTable const & ptable, int patchSize,
FarPatchTables::PTable const & ptable,
FarPatchTables::PtexCoordinateTable const & ptexTable,
FarPatchTables::FVarDataTable const & fvarTable, int fvarDataWidth,
OsdPatchDescriptor const & desc,

View File

@ -171,11 +171,11 @@ float TessAdaptive(vec3 p0, vec3 p1, int patchLevel)
{ \
ivec2 ptexIndex = texelFetchBuffer(g_ptexIndicesBuffer, \
gl_PrimitiveID + LevelBase).xy; \
int lv = 1 << (patchLevel - int(ptexIndex.x & 1)); \
int faceID = ptexIndex.x >> 3; \
int u = ptexIndex.y >> 16; \
int v = (ptexIndex.y & 0xffff); \
int rotation = (ptexIndex.x >> 1) & 0x3; \
int faceID = ptexIndex.x; \
int lv = 1 << (ptexIndex.y & 0xf); \
int u = (ptexIndex.y >> 17) & 0x3ff; \
int v = (ptexIndex.y >> 7) & 0x3ff; \
int rotation = (ptexIndex.y >> 5) & 0x3; \
output[ID].v.patchCoord.w = faceID+0.5; \
output[ID].v.ptexInfo = ivec4(u, v, lv, rotation); \
}

View File

@ -168,14 +168,14 @@ float TessAdaptive(float3 p0, float3 p1, int patchLevel)
#define OSD_DECLARE_PTEX_INDICES_BUFFER Buffer<int2> g_ptexIndicesBuffer : register( t4 );
#define OSD_COMPUTE_PTEX_COORD_HULL_SHADER \
#define OSD_COMPUTE_PTEX_COORD_TESSCONTROL_SHADER \
{ \
int2 ptexIndex = g_ptexIndicesBuffer[ID + LevelBase].xy; \
int lv = 1 << (patchLevel - int(ptexIndex.x & 1)); \
int faceID = ptexIndex.x >> 3; \
int u = ptexIndex.y >> 16; \
int v = (ptexIndex.y & 0xffff); \
int rotation = (ptexIndex.x >> 1) & 0x3; \
int faceID = ptexIndex.x; \
int lv = 1 << (ptexIndex.y & 0xf); \
int u = (ptexIndex.y >> 17) & 0x3ff; \
int v = (ptexIndex.y >> 7) & 0x3ff; \
int rotation = (ptexIndex.y >> 5) & 0x3; \
output.patchCoord.w = faceID+0.5; \
output.ptexInfo = int4(u, v, lv, rotation); \
}

View File

@ -91,7 +91,28 @@ struct OsdPatchDescriptor {
type(type), pattern(pattern), rotation(rotation), subpatch(0),
maxValence(maxValence), numElements(numElements) {}
short GetPatchSize() const {
switch (type) {
case kNonPatch : return (loop ? 3:4);
case kRegular :
case kTransitionRegular : return 16;
case kBoundary :
case kTransitionBoundary : return 12;
case kCorner :
case kTransitionCorner : return 9;
case kGregory :
case kBoundaryGregory : return 4;
default : return -1;
}
}
OsdPatchType type:4; // 0-8
unsigned char loop:1; // 0-1
unsigned char pattern:3; // 0-4
unsigned char rotation:2; // 0-3
unsigned char subpatch:2; // 0-3
@ -104,11 +125,11 @@ bool operator< (OsdPatchDescriptor const & a,
struct OsdPatchArray {
OsdPatchDescriptor desc;
int patchSize;
int firstIndex;
int numIndices;
int levelBase;
int firstIndex; // index of first vertex in patch indices array
int numIndices; // number of vertex indices in indices array
int levelBase; // XXX ???
int gregoryQuadOffsetBase;
};

View File

@ -68,6 +68,17 @@ struct OsdVertexDescriptor {
: numVertexElements(numVertexElem),
numVaryingElements(numVaryingElem) { }
/// Resets the contents of vertex & varying primvar data buffers for a given
/// vertex.
///
/// @param vertex The float array containing the vertex-interpolated primvar
/// data that needs to be reset.
///
/// @param varying The float array containing the varying-interpolated primvar
/// data that needs to be reset.
///
/// @param index Vertex index in the buffer.
///
void Clear(float *vertex, float *varying, int index) const {
if (vertex) {
for (int i = 0; i < numVertexElements; ++i)
@ -79,12 +90,34 @@ struct OsdVertexDescriptor {
varying[index*numVaryingElements+i] = 0.0f;
}
}
/// Applies "dst += src*weight" to "vertex" primvar data in a vertex buffer.
///
/// @param vertex The VertexData buffer
///
/// @param dstIndex Index of the destination vertex.
///
/// @param srcIndex Index of the origin vertex.
///
/// @param weight Weight applied to the primvar data.
///
void AddWithWeight(float *vertex, int dstIndex, int srcIndex, float weight) const {
int d = dstIndex * numVertexElements;
int s = srcIndex * numVertexElements;
for (int i = 0; i < numVertexElements; ++i)
vertex[d++] += vertex[s++] * weight;
}
/// Applies "dst += src*weight" to "varying" primvar data in a vertex buffer.
///
/// @param vertex The VaryingData buffer
///
/// @param dstIndex Index of the destination vertex.
///
/// @param srcIndex Index of the source vertex.
///
/// @param weight Weight applied to the primvar data.
///
void AddVaryingWithWeight(float *varying, int dstIndex, int srcIndex, float weight) const {
int d = dstIndex * numVaryingElements;
int s = srcIndex * numVaryingElements;
@ -92,6 +125,18 @@ struct OsdVertexDescriptor {
varying[d++] += varying[s++] * weight;
}
/// Applies an "add" vertex edit
///
/// @param vertex The primvar data buffer.
///
/// @param primVarOffset Offset to the primvar datum.
///
/// @param primVarWidth Length of the primvar datum.
///
/// @param editIndex The location of the vertex in the buffer.
///
/// @param editValues The values to add to the primvar datum.
///
void ApplyVertexEditAdd(float *vertex, int primVarOffset, int primVarWidth, int editIndex, const float *editValues) const {
int d = editIndex * numVertexElements + primVarOffset;
for (int i = 0; i < primVarWidth; ++i) {
@ -99,6 +144,18 @@ struct OsdVertexDescriptor {
}
}
/// Applies a "set" vertex edit
///
/// @param vertex The primvar data buffer.
///
/// @param primVarOffset Offset to the primvar datum.
///
/// @param primVarWidth Length of the primvar datum.
///
/// @param editIndex The location of the vertex in the buffer.
///
/// @param editValues The values to add to the primvar datum.
///
void ApplyVertexEditSet(float *vertex, int primVarOffset, int primVarWidth, int editIndex, const float *editValues) const {
int d = editIndex * numVertexElements + primVarOffset;
for (int i = 0; i < primVarWidth; ++i) {
@ -111,15 +168,14 @@ struct OsdVertexDescriptor {
};
struct OsdVertexBufferDescriptor {
/// Default Constructor
OsdVertexBufferDescriptor()
: vertexOffset(0), stride(0), elementOffset(0) { }
: offset(0), length(0), stride(0) { }
OsdVertexBufferDescriptor(int vertexOffset_, int stride_, int elementOffset_)
: vertexOffset(vertexOffset_), stride(stride_), elementOffset(elementOffset_) { }
int vertexOffset;
int stride;
int elementOffset;
int offset; // offset to desired element data
int length; // number or length of the data
int stride; // stride to the next element
};
} // end namespace OPENSUBDIV_VERSION