OpenSubdiv/opensubdiv/far/meshFactory.h
Dirk Van Gelder 0925fe5a4b Fix for crash in new mesh/refiner code in OsdUtil. Need to
set HBR_ADAPTIVE before including hbr code.  Also use an ifndef in
far/meshFactory.h so that code can be included where someone else has
already defined HBR_ADAPTIVE.
2013-11-01 22:17:11 -07:00

834 lines
27 KiB
C++

//
// 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_MESH_FACTORY_H
#define FAR_MESH_FACTORY_H
#include "../version.h"
// Activate Hbr feature adaptive tagging : in order to process the HbrMesh
// adaptively, some tag data is added to HbrFace, HbrVertex and HbrHalfedge.
// While small, these tags incur some performance costs and are by default
// disabled.
#ifndef HBR_ADAPTIVE
#define HBR_ADAPTIVE
#endif
#include "../hbr/mesh.h"
#include "../hbr/bilinear.h"
#include "../hbr/catmark.h"
#include "../hbr/loop.h"
#include "../far/mesh.h"
#include "../far/dispatcher.h"
#include "../far/bilinearSubdivisionTablesFactory.h"
#include "../far/catmarkSubdivisionTablesFactory.h"
#include "../far/loopSubdivisionTablesFactory.h"
#include "../far/patchTablesFactory.h"
#include "../far/vertexEditTablesFactory.h"
#include <typeinfo>
#include <set>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
/// \brief Instantiates a FarMesh from an HbrMesh.
///
/// FarMeshFactory requires a 2 steps process :
/// 1. Instantiate a FarMeshFactory object from an HbrMesh
/// 2. Call "Create" to obtain the FarMesh instance
///
/// This tiered factory approach offers client-code the opportunity to access
/// useful transient information tied to the lifespan of the factory instance.
/// Specifically, regression code needs to access the remapping tables that
/// tie HbrMesh vertices to their FarMesh counterparts for comparison.
///
template <class T, class U=T> class FarMeshFactory {
public:
/// \brief Constructor for the factory.
/// Analyzes the HbrMesh and stores transient data used to create the
/// adaptive patch representation. Once the new rep has been instantiated
/// with 'Create', this factory object can be deleted safely.
///
/// @param mesh The HbrMesh describing the topology (this mesh *WILL* be
/// modified by this factory).
///
/// @param maxlevel In uniform subdivision mode : number of levels of
/// subdivision. In feature adaptive mode : maximum
/// level of isolation around extraordinary topological
/// features.
///
/// @param firstLevel First level of subdivision to use when building the
/// FarMesh. The default -1 only generates a single patch
/// array for the highest level of subdivision)
/// Note : firstLevel is only applicable if adaptive is false
///
/// @param adaptive Switch between uniform and feature adaptive mode
///
FarMeshFactory(HbrMesh<T> * mesh, int maxlevel, bool adaptive=false, int firstLevel=-1);
/// \brief Create a table-based mesh representation
///
/// @param requireFVarData create a face-varying table
///
/// @return a pointer to the FarMesh created
///
FarMesh<U> * Create( bool requireFVarData=false );
/// \brief Computes the minimum number of adaptive feature isolation levels required
/// in order for the limit surface to be an accurate representation of the
/// shape given all the tags and edits.
///
/// @param mesh The HbrMesh describing the topology
///
/// @param nfaces The number of faces in the HbrMesh
///
/// @param cornerIsolate The level of isolation desired for patch corners
///
/// @return The minimum level of isolation of extraordinary
/// topological features.
///
static int ComputeMinIsolation( HbrMesh<T> const * mesh, int nfaces, int cornerIsolate=5 );
/// \brief The Hbr mesh that this factory is converting
HbrMesh<T> const * GetHbrMesh() const { return _hbrMesh; }
/// \brief Maximum level of subidivision supported by this factory
int GetMaxLevel() const { return _maxlevel; }
/// \brief The number of coarse vertices found in the HbrMesh before refinement
///
/// @return The number of coarse vertices
///
int GetNumCoarseVertices() const { return _numCoarseVertices; }
/// \brief Total number of faces up to a given level of subdivision
///
/// @param level The number of faces up to 'level' of subdivision
///
/// @return The summation of the number of faces
///
int GetNumFacesTotal(int level) const {
return sumList<HbrFace<T> *>(_facesList, level);
}
/// \brief Returns the corresponding index of the HbrVertex<T> in the new
/// FarMesh
///
/// @param v the vertex
///
/// @return the remapped index of the vertex in the FarMesh
///
int GetVertexID( HbrVertex<T> * v );
/// \brief Returns a the mapping between HbrVertex<T>->GetID() and Far
/// vertices indices
///
/// @return the table that maps HbrMesh to FarMesh vertex indices
///
std::vector<int> const & GetRemappingTable( ) const { return _remapTable; }
private:
friend class FarBilinearSubdivisionTablesFactory<T,U>;
friend class FarCatmarkSubdivisionTablesFactory<T,U>;
friend class FarLoopSubdivisionTablesFactory<T,U>;
friend class FarSubdivisionTablesFactory<T,U>;
friend class FarVertexEditTablesFactory<T,U>;
friend class FarPatchTablesFactory<T>;
template <class X> struct VertCompare {
bool operator()(HbrVertex<X> const * v1, HbrVertex<X> const * v2 ) const {
//return v1->GetID() < v2->GetID();
return (void*)(v1) < (void*)(v2);
}
};
// Non-copyable, so these are not implemented:
FarMeshFactory( FarMeshFactory const & );
FarMeshFactory<T,U> & operator=(FarMeshFactory<T,U> const &);
// True if the HbrMesh applies the bilinear subdivision scheme
static bool isBilinear(HbrMesh<T> const * mesh);
// True if the HbrMesh applies the Catmull-Clark subdivision scheme
static bool isCatmark(HbrMesh<T> const * mesh);
// True if the HbrMesh applies the Loop subdivision scheme
static bool isLoop(HbrMesh<T> const * mesh);
// True if the factory is refining adaptively
bool isAdaptive() { return _adaptive; }
// False if v prevents a face from being represented with a BSpline
static bool vertexIsBSpline( HbrVertex<T> * v, bool next );
// True if a vertex is a regular boundary
static bool vertexIsRegularBoundary( HbrVertex<T> * v );
// Non-const accessor to the remapping table
std::vector<int> & getRemappingTable( ) { return _remapTable; }
template <class Type> static int sumList( std::vector<std::vector<Type> > const & list, int level );
// Calls Hbr to refines the neighbors of v
static void refineVertexNeighbors(HbrVertex<T> * v);
// Uniformly refine the Hbr mesh
static void refine( HbrMesh<T> * mesh, int maxlevel );
// Adaptively refine the Hbr mesh
int refineAdaptive( HbrMesh<T> * mesh, int maxIsolate );
typedef std::vector<std::vector< HbrFace<T> *> > FacesList;
// Returns sorted vectors of HbrFace<T> pointers sorted by level
FacesList const & GetFaceList() const { return _facesList; }
private:
HbrMesh<T> * _hbrMesh;
bool _adaptive;
int _maxlevel,
_firstlevel,
_numVertices,
_numCoarseVertices,
_numFaces,
_maxValence,
_numPtexFaces;
// remapping table to translate vertex ID's between Hbr indices and the
// order of the same vertices in the tables
std::vector<int> _remapTable;
FacesList _facesList;
};
template <class T, class U>
template <class Type> int
FarMeshFactory<T,U>::sumList( std::vector<std::vector<Type> > const & list, int level) {
level = std::min(level, (int)list.size()-1);
int total = 0;
for (int i=0; i<=level; ++i)
total += (int)list[i].size();
return total;
}
// Refines non-adaptively an Hbr mesh
template <class T, class U> void
FarMeshFactory<T,U>::refine( HbrMesh<T> * mesh, int maxlevel ) {
for (int level=0, firstface=0; level<maxlevel; ++level ) {
int nfaces = mesh->GetNumFaces();
for (int i=firstface; i<nfaces; ++i) {
HbrFace<T> * f = mesh->GetFace(i);
if (f->GetDepth()==level) {
if (not f->IsHole()) {
f->Refine();
} else {
// Hole faces need to maintain the 1-ring of vertices so we
// have to create an extra row of children faces around the
// hole.
HbrHalfedge<T> * e = f->GetFirstEdge();
for (int i=0; i<f->GetNumVertices(); ++i) {
assert(e);
if (e->GetRightFace() and (not e->GetRightFace()->IsHole())) {
// RefineFaceAtVertex only creates a single child face
// centered on the passed vertex
HbrSubdivision<T> * s = mesh->GetSubdivision();
s->RefineFaceAtVertex(mesh,f,e->GetOrgVertex());
s->RefineFaceAtVertex(mesh,f,e->GetDestVertex());
}
e = e->GetNext();
}
}
}
}
// Hbr allocates faces sequentially, so there is no need to iterate over
// faces that have already been refined.
firstface = nfaces;
}
mesh->SetSubdivisionMethod(HbrMesh<T>::k_SubdivisionMethodUniform);
}
// Scan the faces of a mesh and compute the max level of subdivision required
template <class T, class U> int
FarMeshFactory<T,U>::ComputeMinIsolation( HbrMesh<T> const * mesh, int nfaces, int cornerIsolate ) {
assert(mesh);
int editmax=0;
float sharpmax=0.0f;
float cornerSharp=0.0;
if (mesh->GetInterpolateBoundaryMethod()<HbrMesh<T>::k_InterpolateBoundaryEdgeAndCorner)
cornerSharp = (float) cornerIsolate;
// Check vertex sharpness
int nverts = mesh->GetNumVertices();
for (int i=0; i<nverts; ++i) {
HbrVertex<T> * v = mesh->GetVertex(i);
if (not v->OnBoundary())
sharpmax = std::max( sharpmax, v->GetSharpness() );
else {
sharpmax = std::max( sharpmax, cornerSharp );
}
}
// Check edge sharpness and hierarchical edits
for (int i=0 ; i<nfaces ; ++i) {
HbrFace<T> * f = mesh->GetFace(i);
// We don't need to check non-coarse faces
if (not f->IsCoarse())
continue;
// Check for edits
if (f->HasVertexEdits()) {
HbrVertexEdit<T> ** edits = (HbrVertexEdit<T>**)f->GetHierarchicalEdits();
while (HbrVertexEdit<T> * edit = *edits++) {
editmax = std::max( editmax , edit->GetNSubfaces() );
}
}
// Check for sharpness
int nv = f->GetNumVertices();
for (int j=0; j<nv; ++j) {
HbrHalfedge<T> * e = f->GetEdge(j);
if (not e->IsBoundary())
sharpmax = std::max( sharpmax, f->GetEdge(j)->GetSharpness() );
}
}
int result = std::max( (int)ceil(sharpmax)+1, editmax+1 );
// Cap the result to "infinitely sharp" (10)
return std::min( result, (int)HbrHalfedge<T>::k_InfinitelySharp );
}
// True if a vertex is a regular boundary
template <class T, class U> bool
FarMeshFactory<T,U>::vertexIsRegularBoundary( HbrVertex<T> * v ) {
int valence = v->GetValence();
return (v->OnBoundary() and (valence==2 or valence==3));
}
// True if the vertex can be incorporated into a B-spline patch
template <class T, class U> bool
FarMeshFactory<T,U>::vertexIsBSpline( HbrVertex<T> * v, bool next ) {
int valence = v->GetValence();
bool isRegBoundary = v->OnBoundary() and (valence==3);
// Extraordinary vertices that are not on a regular boundary
if (v->IsExtraordinary() and not isRegBoundary )
return false;
// Irregular boundary vertices (high valence)
if (v->OnBoundary() and (valence>3))
return false;
// Creased vertices that aren't corner / boundaries
if (v->IsSharp(next) and not v->OnBoundary())
return false;
return true;
}
// Calls Hbr to refines the neighbors of v
template <class T, class U> void
FarMeshFactory<T,U>::refineVertexNeighbors(HbrVertex<T> * v) {
assert(v);
HbrHalfedge<T> * start = v->GetIncidentEdge(),
* next=start;
do {
HbrFace<T> * lft = next->GetLeftFace(),
* rgt = next->GetRightFace();
if (not ((lft and lft->IsHole()) and
(rgt and rgt->IsHole()) ) ) {
if (rgt)
rgt->_adaptiveFlags.isTagged=true;
if (lft)
lft->_adaptiveFlags.isTagged=true;
HbrHalfedge<T> * istart = next,
* inext = istart;
do {
if (not inext->IsInsideHole() )
inext->GetOrgVertex()->Refine();
inext = inext->GetNext();
} while (istart != inext);
}
next = v->GetNextEdge( next );
} while (next and next!=start);
}
// Refines an Hbr Catmark mesh adaptively around extraordinary features
template <class T, class U> int
FarMeshFactory<T,U>::refineAdaptive( HbrMesh<T> * mesh, int maxIsolate ) {
int ncoarsefaces = mesh->GetNumCoarseFaces(),
ncoarseverts = mesh->GetNumVertices();
int maxlevel = maxIsolate+1;
// First pass : tag coarse vertices & faces that need refinement
typedef std::set<HbrVertex<T> *,VertCompare<T> > VertSet;
VertSet verts, nextverts;
for (int i=0; i<ncoarseverts; ++i) {
HbrVertex<T> * v = mesh->GetVertex(i);
// Non manifold topology may leave un-connected vertices that need to be skipped
if (not v->IsConnected()) {
continue;
}
// Tag non-BSpline vertices for refinement
if (not vertexIsBSpline(v, false)) {
v->_adaptiveFlags.isTagged=true;
nextverts.insert(v);
}
}
for (int i=0; i<ncoarsefaces; ++i) {
HbrFace<T> * f = mesh->GetFace(i);
if (f->IsHole())
continue;
bool extraordinary = mesh->GetSubdivision()->FaceIsExtraordinary(mesh,f);
int nv = f->GetNumVertices();
for (int j=0; j<nv; ++j) {
HbrHalfedge<T> * e = f->GetEdge(j);
assert(e);
// Tag sharp edges for refinement
if (e->IsSharp(true) and (not e->IsBoundary())) {
nextverts.insert(e->GetOrgVertex());
nextverts.insert(e->GetDestVertex());
e->GetOrgVertex()->_adaptiveFlags.isTagged=true;
e->GetDestVertex()->_adaptiveFlags.isTagged=true;
}
// Tag extraordinary (non-quad) faces for refinement
if (extraordinary or f->HasVertexEdits()) {
HbrVertex<T> * v = f->GetVertex(j);
v->_adaptiveFlags.isTagged=true;
nextverts.insert(v);
}
// Quad-faces with 2 non-consecutive boundaries need to be flagged
// for refinement as boundary patches.
//
// o ........ o ........ o ........ o
// . | | . ... b.undary edge
// . | needs | .
// . | flag | . --- regular edge
// . | | .
// o ........ o ........ o ........ o
//
if ( e->IsBoundary() and (not f->_adaptiveFlags.isTagged) and nv==4 ) {
if (e->GetPrev() and (not e->GetPrev()->IsBoundary()) and
e->GetNext() and (not e->GetNext()->IsBoundary()) and
e->GetNext() and e->GetNext()->GetNext() and e->GetNext()->GetNext()->IsBoundary()) {
// Tag the face so that we don't check for this again
f->_adaptiveFlags.isTagged=true;
// Tag all 4 vertices of the face to make sure 4 boundary
// sub-patches are generated
for (int k=0; k<4; ++k) {
HbrVertex<T> * v = f->GetVertex(j);
v->_adaptiveFlags.isTagged=true;
nextverts.insert(v);
}
}
}
}
_maxValence = std::max(_maxValence, nv);
}
// Second pass : refine adaptively around singularities
for (int level=0; level<maxlevel-1; ++level) {
verts = nextverts;
nextverts.clear();
// Refine vertices
for (typename VertSet::iterator i=verts.begin(); i!=verts.end(); ++i) {
HbrVertex<T> * v = *i;
assert(v);
if (level>0)
v->_adaptiveFlags.isTagged=true;
else
v->_adaptiveFlags.wasTagged=true;
refineVertexNeighbors(v);
// Tag non-BSpline vertices for refinement
if (not vertexIsBSpline(v, true))
nextverts.insert(v->Subdivide());
// Refine edges with creases or edits
int valence = v->GetValence();
_maxValence = std::max(_maxValence, valence);
HbrHalfedge<T> * e = v->GetIncidentEdge();
for (int j=0; j<valence; ++j) {
// Skip edges that have already been processed (HasChild())
if ((not e->HasChild()) and e->IsSharp(false) and (not e->IsBoundary())) {
if (not e->IsInsideHole()) {
nextverts.insert( e->Subdivide() );
nextverts.insert( e->GetOrgVertex()->Subdivide() );
nextverts.insert( e->GetDestVertex()->Subdivide() );
}
}
HbrHalfedge<T> * next = v->GetNextEdge(e);
e = next ? next : e->GetPrev();
}
// Flag verts with hierarchical edits for neighbor refinement at the next level
HbrVertex<T> * childvert = v->Subdivide();
HbrHalfedge<T> * childedge = childvert->GetIncidentEdge();
assert( childvert->GetValence()==valence);
for (int j=0; j<valence; ++j) {
HbrFace<T> * f = childedge->GetFace();
if (f->HasVertexEdits()) {
int nv = f->GetNumVertices();
for (int k=0; k<nv; ++k)
nextverts.insert( f->GetVertex(k) );
}
if ((childedge = childvert->GetNextEdge(childedge)) == NULL)
break;
}
}
// Add coarse verts from extraordinary faces
if (level==0) {
for (int i=0; i<ncoarsefaces; ++i) {
HbrFace<T> * f = mesh->GetFace(i);
assert (f->IsCoarse());
if (mesh->GetSubdivision()->FaceIsExtraordinary(mesh,f))
nextverts.insert( f->Subdivide() );
}
}
}
mesh->SetSubdivisionMethod(HbrMesh<T>::k_SubdivisionMethodFeatureAdaptive);
return maxlevel-1;
}
// Assumption : the order of the vertices in the HbrMesh could be set in any
// random order, so the builder runs 2 passes over the entire vertex list to
// gather the counters needed to generate the indexing tables.
template <class T, class U>
FarMeshFactory<T,U>::FarMeshFactory( HbrMesh<T> * mesh, int maxlevel, bool adaptive, int firstlevel ) :
_hbrMesh(mesh),
_adaptive(adaptive),
_maxlevel(maxlevel),
_firstlevel(firstlevel),
_numVertices(-1),
_numCoarseVertices(-1),
_numFaces(-1),
_maxValence(3),
_numPtexFaces(-1),
_facesList(maxlevel+1)
{
_numCoarseVertices = mesh->GetNumVertices();
_numPtexFaces = getNumPtexFaces(mesh);
// Subdivide the Hbr mesh up to maxlevel.
//
// Note : using a placeholder vertex class 'T' can greatly speed up the
// topological analysis if the interpolation results are not used.
if (adaptive)
_maxlevel=refineAdaptive( mesh, maxlevel );
else
refine( mesh, maxlevel);
_numFaces = mesh->GetNumFaces();
_numVertices = mesh->GetNumVertices();
if (not adaptive) {
// Populate the face lists
int fsize=0;
for (int i=0; i<_numFaces; ++i) {
HbrFace<T> * f = mesh->GetFace(i);
assert(f);
if (f->GetDepth()==0 and (not f->IsHole()))
fsize += mesh->GetSubdivision()->GetFaceChildrenCount( f->GetNumVertices() );
}
_facesList[0].reserve(mesh->GetNumCoarseFaces());
_facesList[1].reserve(fsize);
for (int l=2; l<=maxlevel; ++l)
_facesList[l].reserve( _facesList[l-1].capacity()*4 );
for (int i=0; i<_numFaces; ++i) {
HbrFace<T> * f = mesh->GetFace(i);
if (f->GetDepth()<=maxlevel and (not f->IsHole()))
_facesList[ f->GetDepth() ].push_back(f);
}
}
}
template <class T, class U> bool
FarMeshFactory<T,U>::isBilinear(HbrMesh<T> const * mesh) {
return typeid(*(mesh->GetSubdivision()))==typeid(HbrBilinearSubdivision<T>);
}
template <class T, class U> bool
FarMeshFactory<T,U>::isCatmark(HbrMesh<T> const * mesh) {
return typeid(*(mesh->GetSubdivision()))==typeid(HbrCatmarkSubdivision<T>);
}
template <class T, class U> bool
FarMeshFactory<T,U>::isLoop(HbrMesh<T> const * mesh) {
return typeid(*(mesh->GetSubdivision()))==typeid(HbrLoopSubdivision<T>);
}
template <class T, class U> void
copyVertex( T & dest, U const & src ) {
}
template <class T> void
copyVertex( T & dest, T const & src ) {
dest = src;
}
template <class T> int
getNumPtexFaces(HbrMesh<T> const * hmesh) {
HbrFace<T> * lastface = hmesh->GetFace(hmesh->GetNumFaces()-1);
assert(lastface);
int result = lastface->GetPtexIndex();
result += (hmesh->GetSubdivision()->FaceIsExtraordinary(hmesh, lastface) ?
lastface->GetNumVertices() : 1);
return result;
}
// Computes per-face or per-patch local ptex texture coordinates.
template <class T> FarPatchParam *
computePatchParam(HbrFace<T> const *f, FarPatchParam *coord) {
short u,v;
unsigned short ofs = 1;
unsigned char depth;
bool nonquad = false;
if (coord == NULL) return NULL;
// 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();
for ( u=v=depth=0; p!=NULL; depth++ ) {
int nverts = p->GetNumVertices();
if ( nverts != 4 ) { // non-quad coarse face : stop accumulating offsets
nonquad = true; // set non-quad bit
break;
}
for (unsigned char i=0; i<nverts; ++i) {
if ( p->GetChild( i )==f ) {
switch ( i ) {
case 0 : break;
case 1 : { u+=ofs; } break;
case 2 : { u+=ofs; v+=ofs; } break;
case 3 : { v+=ofs; } break;
}
break;
}
}
ofs = ofs << 1;
f = p;
p = f->GetParent();
}
coord->Set( f->GetPtexIndex(), u, v, rots, depth, nonquad );
return ++coord;
}
template <class T> float *
computeFVarData(HbrFace<T> const *f, const int width, float *coord, bool isAdaptive) {
if (coord == NULL) return NULL;
if (isAdaptive) {
int rots = f->_adaptiveFlags.rots;
int nverts = f->GetNumVertices();
assert(nverts==4);
for ( int j=0; j < nverts; ++j ) {
HbrVertex<T> *v = f->GetVertex((j+rots)%4);
float *fvdata = v->GetFVarData(f).GetData(0);
for ( int k=0; k<width; ++k ) {
(*coord++) = fvdata[k];
}
}
} else {
// for each face vertex copy face-varying data into coord pointer
int nverts = f->GetNumVertices();
for ( int j=0; j < nverts; ++j ) {
HbrVertex<T> *v = f->GetVertex(j);
float *fvdata = v->GetFVarData(f).GetData(0);
for ( int k=0; k<width; ++k ) {
(*coord++) = fvdata[k];
}
}
}
// pass back pointer to next destination
return coord;
}
template <class T, class U> FarMesh<U> *
FarMeshFactory<T,U>::Create( bool requireFVarData ) {
assert( GetHbrMesh() );
// Note : we cannot create a Far rep of level 0 (coarse mesh)
if (GetMaxLevel()<1)
return 0;
FarMesh<U> * result = new FarMesh<U>();
if ( isBilinear( GetHbrMesh() ) ) {
result->_subdivisionTables = FarBilinearSubdivisionTablesFactory<T,U>::Create(this, result, &result->_batches);
} else if ( isCatmark( GetHbrMesh() ) ) {
result->_subdivisionTables = FarCatmarkSubdivisionTablesFactory<T,U>::Create(this, result, &result->_batches);
} else if ( isLoop(GetHbrMesh()) ) {
result->_subdivisionTables = FarLoopSubdivisionTablesFactory<T,U>::Create(this, result, &result->_batches);
} else
assert(0);
assert(result->_subdivisionTables);
// If the vertex classes aren't place-holders, copy the data of the coarse
// vertices into the vertex buffer.
if (sizeof(U)>1) {
result->_vertices.resize( _numVertices );
for (int i=0; i<GetNumCoarseVertices(); ++i)
copyVertex(result->_vertices[i], GetHbrMesh()->GetVertex(i)->GetData());
}
// Create the element indices tables (patches for adaptive, quads for non-adaptive)
if (isAdaptive()) {
FarPatchTablesFactory<T> factory(GetHbrMesh(), _numFaces, _remapTable);
// XXXX: currently PatchGregory shader supports up to 29 valence
result->_patchTables = factory.Create(GetMaxLevel()+1, _maxValence, requireFVarData);
} else {
result->_patchTables = FarPatchTablesFactory<T>::Create(GetHbrMesh(), _facesList, _remapTable, _firstlevel, requireFVarData );
}
assert( result->_patchTables );
result->_numPtexFaces = _numPtexFaces;
if (requireFVarData) {
result->_totalFVarWidth = _hbrMesh->GetTotalFVarWidth();
} else {
result->_totalFVarWidth = 0;
}
// Create VertexEditTables if necessary
if (GetHbrMesh()->HasVertexEdits()) {
result->_vertexEditTables = FarVertexEditTablesFactory<T,U>::Create( this, result, &result->_batches, GetMaxLevel() );
assert(result->_vertexEditTables);
}
return result;
}
template <class T, class U> int
FarMeshFactory<T,U>::GetVertexID( HbrVertex<T> * v ) {
assert( v and (v->GetID() < _remapTable.size()) );
return _remapTable[ v->GetID() ];
}
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* FAR_MESH_FACTORY_H */