Move table splicing functions of FarMultiMeshFactory into factories,

in preparation for relocating MultiMesh to OsdUtil.
This commit is contained in:
Takahito Tejima 2014-03-20 14:52:42 -07:00
parent 76818e630b
commit d2fc86ba5e
8 changed files with 547 additions and 518 deletions

View File

@ -191,7 +191,7 @@ public:
private:
friend class FarKernelBatchFactory;
template <class X, class Y> friend class FarMultiMeshFactory;
template <class X, class Y> friend class FarSubdivisionTablesFactory;
int _kernelType;
int _level;

View File

@ -28,9 +28,8 @@
#include "../version.h"
#include "../far/mesh.h"
#include "../far/bilinearSubdivisionTablesFactory.h"
#include "../far/catmarkSubdivisionTablesFactory.h"
#include "../far/loopSubdivisionTablesFactory.h"
#include "../far/meshFactory.h"
#include "../far/patchTablesFactory.h"
#include "../far/vertexEditTablesFactory.h"
@ -66,35 +65,12 @@ public:
}
private:
// splice subdivision tables
FarSubdivisionTables * spliceSubdivisionTables(FarMesh<U> *farmesh, FarMeshVector const &meshes);
// splice patch tables
FarPatchTables * splicePatchTables(FarMeshVector const &meshes, bool hasFVarData);
// splice patch array
FarPatchTables::PTable::iterator splicePatch(FarPatchTables::Descriptor desc,
FarMeshVector const &meshes,
FarPatchTables::PatchArrayVector &result,
FarPatchTables::PTable::iterator dstIndexIt,
int *voffset, int *poffset, int *qoffset,
std::vector<int> const &vertexOffsets);
// splice hierarchical edit tables
FarVertexEditTables * spliceVertexEditTables(FarMeshVector const &meshes);
int _maxlevel;
int _maxvalence;
FarSubdivisionTables::Scheme _scheme;
// patch arrays for each mesh
std::vector<FarPatchTables::PatchArrayVector> _multiPatchArrays;
};
template <class T, class U>
FarMultiMeshFactory<T, U>::FarMultiMeshFactory()
: _maxlevel(0), _maxvalence(0), _scheme(FarSubdivisionTables::UNDEFINED) {
FarMultiMeshFactory<T, U>::FarMultiMeshFactory() {
}
template <class T, class U> FarMesh<U> *
@ -103,25 +79,17 @@ FarMultiMeshFactory<T, U>::Create(std::vector<FarMesh<U> const *> const &meshes)
if (meshes.empty()) return NULL;
int totalFVarWidth = meshes[0]->GetTotalFVarWidth();
_maxlevel = 0;
_maxvalence = 0;
_scheme = meshes[0]->GetSubdivisionTables()->GetScheme();
FarSubdivisionTables::Scheme scheme = meshes[0]->GetSubdivisionTables()->GetScheme();
for (size_t i = 0; i < meshes.size(); ++i) {
FarMesh<U> const *mesh = meshes[i];
// meshes have to have a same subdivision scheme
if (_scheme != mesh->GetSubdivisionTables()->GetScheme()) {
if (scheme != mesh->GetSubdivisionTables()->GetScheme()) {
assert(false);
return NULL;
}
_maxlevel = std::max(_maxlevel, mesh->GetSubdivisionTables()->GetMaxLevel()-1);
if (mesh->GetPatchTables()) {
_maxvalence = std::max(_maxvalence, mesh->GetPatchTables()->GetMaxValence());
}
// meshes have to have a same fvardata width
if (totalFVarWidth != mesh->GetTotalFVarWidth()) {
assert(false);
@ -132,13 +100,15 @@ FarMultiMeshFactory<T, U>::Create(std::vector<FarMesh<U> const *> const &meshes)
FarMesh<U> * result = new FarMesh<U>();
// splice subdivision tables
result->_subdivisionTables = spliceSubdivisionTables(result, meshes);
result->_subdivisionTables = FarSubdivisionTablesFactory<T, U>::Splice(meshes, &result->_batches);
// splice patch/quad index tables
result->_patchTables = splicePatchTables(meshes, totalFVarWidth > 0);
result->_patchTables = FarPatchTablesFactory<T>::Splice(meshes,
&_multiPatchArrays,
totalFVarWidth > 0);
// splice vertex edit tables
result->_vertexEditTables = spliceVertexEditTables(meshes);
result->_vertexEditTables = FarVertexEditTablesFactory<T, U>::Splice(meshes);
// count total num vertices, numptex faces
int numVertices = 0, numPtexFaces = 0;
@ -153,473 +123,6 @@ FarMultiMeshFactory<T, U>::Create(std::vector<FarMesh<U> const *> const &meshes)
return result;
}
template <typename V, typename IT> static IT
copyWithOffset(IT dst_iterator, V const &src, int offset) {
return std::transform(src.begin(), src.end(), dst_iterator,
std::bind2nd(std::plus<typename V::value_type>(), offset));
}
template <typename V, typename IT> static IT
copyWithOffset(IT dst_iterator, V const &src, int start, int count, int offset) {
return std::transform(src.begin()+start, src.begin()+start+count, dst_iterator,
std::bind2nd(std::plus<typename V::value_type>(), offset));
}
template <typename V, typename IT> static IT
copyWithPtexFaceOffset(IT dst_iterator, V const &src, int start, int count, int offset) {
for (typename V::const_iterator it = src.begin()+start; it != src.begin()+start+count; ++it) {
typename V::value_type ptexCoord = *it;
ptexCoord.faceIndex += offset;
*dst_iterator++ = ptexCoord;
}
return dst_iterator;
}
template <typename V, typename IT> static IT
copyWithOffsetF_ITa(IT dst_iterator, V const &src, int offset) {
for (typename V::const_iterator it = src.begin(); it != src.end();) {
*dst_iterator++ = *it++ + offset; // offset to F_IT
*dst_iterator++ = *it++; // valence
}
return dst_iterator;
}
template <typename V, typename IT> static IT
copyWithOffsetE_IT(IT dst_iterator, V const &src, int offset) {
for (typename V::const_iterator it = src.begin(); it != src.end(); ++it) {
*dst_iterator++ = (*it == -1) ? -1 : (*it + offset);
}
return dst_iterator;
}
template <typename V, typename IT> static IT
copyWithOffsetV_ITa(IT dst_iterator, V const &src, int tableOffset, int vertexOffset) {
for (typename V::const_iterator it = src.begin(); it != src.end();) {
*dst_iterator++ = *it++ + tableOffset; // offset to V_IT
*dst_iterator++ = *it++; // valence
*dst_iterator++ = (*it == -1) ? -1 : (*it + vertexOffset); ++it;
*dst_iterator++ = (*it == -1) ? -1 : (*it + vertexOffset); ++it;
*dst_iterator++ = (*it == -1) ? -1 : (*it + vertexOffset); ++it;
}
return dst_iterator;
}
template <typename V, typename IT> static IT
copyWithOffsetVertexValence(IT dst_iterator, V const &src, int srcMaxValence, int dstMaxValence, int offset) {
for (typename V::const_iterator it = src.begin(); it != src.end(); ) {
int valence = *it++;
*dst_iterator++ = valence;
valence = abs(valence);
for (int i = 0; i < 2*dstMaxValence; ++i) {
if (i < 2*srcMaxValence) {
*dst_iterator++ = (i < 2*valence) ? *it + offset : 0;
++it;
} else {
*dst_iterator++ = 0;
}
}
}
return dst_iterator;
}
template <class T, class U> FarSubdivisionTables *
FarMultiMeshFactory<T, U>::spliceSubdivisionTables(FarMesh<U> *farMesh, FarMeshVector const &meshes) {
// count total table size
size_t total_F_ITa = 0, total_F_IT = 0;
size_t total_E_IT = 0, total_E_W = 0;
size_t total_V_ITa = 0, total_V_IT = 0, total_V_W = 0;
for (size_t i = 0; i < meshes.size(); ++i) {
FarSubdivisionTables const * tables = meshes[i]->GetSubdivisionTables();
assert(tables);
total_F_ITa += tables->Get_F_ITa().size();
total_F_IT += tables->Get_F_IT().size();
total_E_IT += tables->Get_E_IT().size();
total_E_W += tables->Get_E_W().size();
total_V_ITa += tables->Get_V_ITa().size();
total_V_IT += tables->Get_V_IT().size();
total_V_W += tables->Get_V_W().size();
}
FarSubdivisionTables *result = new FarSubdivisionTables(_maxlevel, _scheme);
result->_F_ITa.resize(total_F_ITa);
result->_F_IT.resize(total_F_IT);
result->_E_IT.resize(total_E_IT);
result->_E_W.resize(total_E_W);
result->_V_ITa.resize(total_V_ITa);
result->_V_IT.resize(total_V_IT);
result->_V_W.resize(total_V_W);
// compute table offsets;
std::vector<int> vertexOffsets;
std::vector<int> fvOffsets;
std::vector<int> evOffsets;
std::vector<int> vvOffsets;
std::vector<int> F_IToffsets;
std::vector<int> V_IToffsets;
{
int vertexOffset = 0;
int F_IToffset = 0;
int V_IToffset = 0;
int fvOffset = 0;
int evOffset = 0;
int vvOffset = 0;
for (size_t i = 0; i < meshes.size(); ++i) {
FarSubdivisionTables const * tables = meshes[i]->GetSubdivisionTables();
assert(tables);
vertexOffsets.push_back(vertexOffset);
F_IToffsets.push_back(F_IToffset);
V_IToffsets.push_back(V_IToffset);
fvOffsets.push_back(fvOffset);
evOffsets.push_back(evOffset);
vvOffsets.push_back(vvOffset);
vertexOffset += meshes[i]->GetNumVertices();
F_IToffset += (int)tables->Get_F_IT().size();
fvOffset += (int)tables->Get_F_ITa().size()/2;
V_IToffset += (int)tables->Get_V_IT().size();
if (_scheme == FarSubdivisionTables::CATMARK or
_scheme == FarSubdivisionTables::LOOP) {
evOffset += (int)tables->Get_E_IT().size()/4;
vvOffset += (int)tables->Get_V_ITa().size()/5;
} else {
evOffset += (int)tables->Get_E_IT().size()/2;
vvOffset += (int)tables->Get_V_ITa().size();
}
}
}
// concat F_IT and V_IT
std::vector<unsigned int>::iterator F_IT = result->_F_IT.begin();
std::vector<unsigned int>::iterator V_IT = result->_V_IT.begin();
for (size_t i = 0; i < meshes.size(); ++i) {
FarSubdivisionTables const * tables = meshes[i]->GetSubdivisionTables();
int vertexOffset = vertexOffsets[i];
// remap F_IT, V_IT tables
F_IT = copyWithOffset(F_IT, tables->Get_F_IT(), vertexOffset);
V_IT = copyWithOffset(V_IT, tables->Get_V_IT(), vertexOffset);
}
// merge other tables
std::vector<int>::iterator F_ITa = result->_F_ITa.begin();
std::vector<int>::iterator E_IT = result->_E_IT.begin();
std::vector<float>::iterator E_W = result->_E_W.begin();
std::vector<float>::iterator V_W = result->_V_W.begin();
std::vector<int>::iterator V_ITa = result->_V_ITa.begin();
for (size_t i = 0; i < meshes.size(); ++i) {
FarSubdivisionTables const * tables = meshes[i]->GetSubdivisionTables();
// copy face tables
F_ITa = copyWithOffsetF_ITa(F_ITa, tables->Get_F_ITa(), F_IToffsets[i]);
// copy edge tables
E_IT = copyWithOffsetE_IT(E_IT, tables->Get_E_IT(), vertexOffsets[i]);
E_W = copyWithOffset(E_W, tables->Get_E_W(), 0);
// copy vert tables
if (_scheme == FarSubdivisionTables::CATMARK or
_scheme == FarSubdivisionTables::LOOP) {
V_ITa = copyWithOffsetV_ITa(V_ITa, tables->Get_V_ITa(), V_IToffsets[i], vertexOffsets[i]);
} else {
V_ITa = copyWithOffset(V_ITa, tables->Get_V_ITa(), vertexOffsets[i]);
}
V_W = copyWithOffset(V_W, tables->Get_V_W(), 0);
}
// merge batch, model by model
FarKernelBatchVector &batches = farMesh->_batches;
int editTableIndexOffset = 0;
for (int i = 0; i < (int)meshes.size(); ++i) {
for (int j = 0; j < (int)meshes[i]->_batches.size(); ++j) {
FarKernelBatch batch = meshes[i]->_batches[j];
batch._meshIndex = i;
batch._vertexOffset += vertexOffsets[i];
if (batch._kernelType == FarKernelBatch::CATMARK_FACE_VERTEX or
batch._kernelType == FarKernelBatch::BILINEAR_FACE_VERTEX) {
batch._tableOffset += fvOffsets[i];
} else if (batch._kernelType == FarKernelBatch::CATMARK_EDGE_VERTEX or
batch._kernelType == FarKernelBatch::LOOP_EDGE_VERTEX or
batch._kernelType == FarKernelBatch::BILINEAR_EDGE_VERTEX) {
batch._tableOffset += evOffsets[i];
} else if (batch._kernelType == FarKernelBatch::CATMARK_VERT_VERTEX_A1 or
batch._kernelType == FarKernelBatch::CATMARK_VERT_VERTEX_A2 or
batch._kernelType == FarKernelBatch::CATMARK_VERT_VERTEX_B or
batch._kernelType == FarKernelBatch::LOOP_VERT_VERTEX_A1 or
batch._kernelType == FarKernelBatch::LOOP_VERT_VERTEX_A2 or
batch._kernelType == FarKernelBatch::LOOP_VERT_VERTEX_B or
batch._kernelType == FarKernelBatch::BILINEAR_VERT_VERTEX) {
batch._tableOffset += vvOffsets[i];
} else if (batch._kernelType == FarKernelBatch::HIERARCHICAL_EDIT) {
batch._tableIndex += editTableIndexOffset;
}
batches.push_back(batch);
}
editTableIndexOffset += meshes[i]->_vertexEditTables ? meshes[i]->_vertexEditTables->GetNumBatches() : 0;
}
// count verts offsets
result->_vertsOffsets.resize(_maxlevel+2);
for (size_t i = 0; i < meshes.size(); ++i) {
FarSubdivisionTables const * tables = meshes[i]->GetSubdivisionTables();
for (size_t j = 0; j < tables->_vertsOffsets.size(); ++j) {
result->_vertsOffsets[j] += tables->_vertsOffsets[j];
}
}
return result;
}
template <class T, class U> FarPatchTables::PTable::iterator
FarMultiMeshFactory<T, U>::splicePatch(FarPatchTables::Descriptor desc,
FarMeshVector const &meshes,
FarPatchTables::PatchArrayVector &result,
FarPatchTables::PTable::iterator dstIndexIt,
int *voffset, int *poffset, int *qoffset,
std::vector<int> const &vertexOffsets)
{
for (size_t i = 0; i < meshes.size(); ++i) {
FarPatchTables const *patchTables = meshes[i]->GetPatchTables();
FarPatchTables::PatchArray const *srcPatchArray = patchTables->GetPatchArray(desc);
if (not srcPatchArray) continue;
// create new patcharray with offset
int vindex = srcPatchArray->GetVertIndex();
int npatch = srcPatchArray->GetNumPatches();
int nvertex = npatch * desc.GetNumControlVertices();
FarPatchTables::PatchArray patchArray(desc,
*voffset,
*poffset,
npatch,
*qoffset);
// append patch array
result.push_back(patchArray);
// also store into multiPatchArrays, will be used for partial drawing
// XXX: can be stored as indices. revisit here later
_multiPatchArrays[i].push_back(patchArray);
// increment offset
*voffset += nvertex;
*poffset += npatch;
*qoffset += (desc.GetType() == FarPatchTables::GREGORY ||
desc.GetType() == FarPatchTables::GREGORY_BOUNDARY) ? npatch * 4 : 0;
// copy index arrays [vindex, vindex+nvertex]
dstIndexIt = copyWithOffset(dstIndexIt,
patchTables->GetPatchTable(),
vindex,
nvertex,
vertexOffsets[i]);
}
return dstIndexIt;
}
template <class T, class U> FarPatchTables *
FarMultiMeshFactory<T, U>::splicePatchTables(FarMeshVector const &meshes, bool hasFVarData) {
FarPatchTables *result = new FarPatchTables(_maxvalence);
int totalQuadOffset0 = 0;
int totalQuadOffset1 = 0;
int totalFVarData = 0;
std::vector<int> vertexOffsets;
std::vector<int> gregoryQuadOffsets;
std::vector<int> numGregoryPatches;
int vertexOffset = 0;
int maxValence = 0;
int numTotalIndices = 0;
//result->_patchCounts.reserve(meshes.size());
//FarPatchCount totalCount;
typedef FarPatchTables::Descriptor Descriptor;
// note: see FarPatchTablesFactory<T>::Create
// feature adaptive refinement can generate un-connected face-vertices
// that have a valence of 0. The spliced vertex valence tables
// needs to be resized including such un-connected face-vertices.
int numVerticesInVertexValence = 0;
// count how many patches exist on each mesh
for (size_t i = 0; i < meshes.size(); ++i) {
const FarPatchTables *ptables = meshes[i]->GetPatchTables();
assert(ptables);
vertexOffsets.push_back(vertexOffset);
vertexOffset += meshes[i]->GetNumVertices();
// need to align maxvalence with the highest value
maxValence = std::max(maxValence, ptables->_maxValence);
FarPatchTables::PatchArray const *gregory = ptables->GetPatchArray(Descriptor(FarPatchTables::GREGORY, FarPatchTables::NON_TRANSITION, /*rot*/ 0));
FarPatchTables::PatchArray const *gregoryBoundary = ptables->GetPatchArray(Descriptor(FarPatchTables::GREGORY_BOUNDARY, FarPatchTables::NON_TRANSITION, /*rot*/ 0));
int nGregory = gregory ? gregory->GetNumPatches() : 0;
int nGregoryBoundary = gregoryBoundary ? gregoryBoundary->GetNumPatches() : 0;
totalQuadOffset0 += nGregory * 4;
totalQuadOffset1 += nGregoryBoundary * 4;
numGregoryPatches.push_back(nGregory);
gregoryQuadOffsets.push_back(totalQuadOffset0);
totalFVarData += (int)ptables->GetFVarDataTable().size();
numTotalIndices += ptables->GetNumControlVertices();
// note: some prims may not have vertex valence table, but still need a space
// in order to fill following prim's data at appropriate location.
numVerticesInVertexValence += ptables->_vertexValenceTable.empty()
? (int)meshes[i]->GetNumVertices()
: (int)ptables->_vertexValenceTable.size()/(2*ptables->_maxValence+1);
}
// Allocate full patches
result->_patches.resize(numTotalIndices);
// Allocate vertex valence table, quad offset table
if (totalQuadOffset0 + totalQuadOffset1 > 0) {
result->_vertexValenceTable.resize((2*maxValence+1) * numVerticesInVertexValence);
result->_quadOffsetTable.resize(totalQuadOffset0 + totalQuadOffset1);
}
// Allocate fvardata table
result->_fvarTable.resize(totalFVarData);
// splice tables
// assuming input farmeshes have dense patchtables
_multiPatchArrays.resize(meshes.size());
int voffset = 0, poffset = 0, qoffset = 0;
FarPatchTables::PTable::iterator dstIndexIt = result->_patches.begin();
// splice patches : iterate over all descriptors, including points, lines, quads, etc.
for (Descriptor::iterator it=Descriptor::begin(Descriptor::ANY); it!=Descriptor::end(); ++it) {
dstIndexIt = splicePatch(*it, meshes, result->_patchArrays, dstIndexIt, &voffset, &poffset, &qoffset, vertexOffsets);
}
// merge vertexvalence and quadoffset tables
FarPatchTables::QuadOffsetTable::iterator Q0_IT = result->_quadOffsetTable.begin();
FarPatchTables::QuadOffsetTable::iterator Q1_IT = Q0_IT + totalQuadOffset0;
FarPatchTables::VertexValenceTable::iterator VV_IT = result->_vertexValenceTable.begin();
for (size_t i = 0; i < meshes.size(); ++i) {
const FarPatchTables *ptables = meshes[i]->GetPatchTables();
// merge vertex valence
// note: some prims may not have vertex valence table, but still need a space
// in order to fill following prim's data at appropriate location.
copyWithOffsetVertexValence(VV_IT,
ptables->_vertexValenceTable,
ptables->_maxValence,
maxValence,
vertexOffsets[i]);
VV_IT += meshes[i]->GetNumVertices() * (2 * maxValence + 1);
// merge quad offsets
// int nGregoryQuads = (int)ptables->_full._G_IT.first.size();
int nGregoryQuads = numGregoryPatches[i] * 4;
if (nGregoryQuads > 0) {
Q0_IT = std::copy(ptables->_quadOffsetTable.begin(),
ptables->_quadOffsetTable.begin()+nGregoryQuads,
Q0_IT);
}
if (nGregoryQuads < (int)ptables->_quadOffsetTable.size()) {
Q1_IT = std::copy(ptables->_quadOffsetTable.begin()+nGregoryQuads,
ptables->_quadOffsetTable.end(),
Q1_IT);
}
}
// merge ptexCoord table
for (FarPatchTables::Descriptor::iterator it =
FarPatchTables::Descriptor::begin(FarPatchTables::Descriptor::ANY);
it != FarPatchTables::Descriptor::end(); ++it) {
int ptexFaceOffset = 0;
for (size_t i = 0; i < meshes.size(); ++i) {
FarPatchTables const *ptables = meshes[i]->GetPatchTables();
FarPatchTables::PatchArray const *parray = ptables->GetPatchArray(*it);
if (parray) {
copyWithPtexFaceOffset(std::back_inserter(result->_paramTable),
ptables->_paramTable,
parray->GetPatchIndex(),
parray->GetNumPatches(), ptexFaceOffset);
}
ptexFaceOffset += meshes[i]->GetNumPtexFaces();
}
}
// merge fvardata table
if (hasFVarData) {
FarPatchTables::FVarDataTable::iterator FV_IT = result->_fvarTable.begin();
for (FarPatchTables::Descriptor::iterator it =
FarPatchTables::Descriptor::begin(FarPatchTables::Descriptor::ANY);
it != FarPatchTables::Descriptor::end(); ++it) {
for (size_t i = 0; i < meshes.size(); ++i) {
FarPatchTables const *ptables = meshes[i]->GetPatchTables();
FarPatchTables::PatchArray const *parray = ptables->GetPatchArray(*it);
if (parray) {
int nv = (_scheme == FarSubdivisionTables::LOOP) ? 3 : 4;
int width = meshes[i]->GetTotalFVarWidth() * nv; // for each quads or tris
FarPatchTables::FVarDataTable::const_iterator begin =
ptables->_fvarTable.begin() + parray->GetPatchIndex() * width;
FarPatchTables::FVarDataTable::const_iterator end =
begin + parray->GetNumPatches() * width;
FV_IT = std::copy(begin, end, FV_IT);
}
}
}
}
return result;
}
template <class T, class U> FarVertexEditTables *
FarMultiMeshFactory<T, U>::spliceVertexEditTables(FarMeshVector const &meshes) {
FarVertexEditTables * result = new FarVertexEditTables();
// at this moment, don't merge vertex edit tables (separate batch)
for (size_t i = 0; i < meshes.size(); ++i) {
const FarVertexEditTables *vertexEditTables = meshes[i]->GetVertexEdit();
if (not vertexEditTables) continue;
// copy each edit batch XXX:inefficient copy
result->_batches.insert(result->_batches.end(),
vertexEditTables->_batches.begin(),
vertexEditTables->_batches.end());
}
if (result->_batches.empty()) {
delete result;
return NULL;
}
return result;
}
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;

View File

@ -408,7 +408,6 @@ public:
private:
template <class T> friend class FarPatchTablesFactory;
template <class T, class U> 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 );

View File

@ -41,6 +41,18 @@ namespace OPENSUBDIV_VERSION {
///
template <class T> class FarPatchTablesFactory {
public:
typedef std::vector<FarMesh<T> const *> FarMeshVector;
typedef std::vector<FarPatchTables::PatchArrayVector> MultiPatchArrayVector;
/// \brief Splices patch tables from multiple meshes.
/// if non-null multPatchArrays is given, it returns subsets of patcharrays such that
/// corresponding input meshes are separately expressed.
/// Client code is responsible for deallocation.
static FarPatchTables *Splice(FarMeshVector const &meshes,
MultiPatchArrayVector *multiPatchArrays,
bool hasFVarData);
protected:
template <class X, class Y> friend class FarMeshFactory;
@ -1195,6 +1207,259 @@ FarPatchTablesFactory<T>::computeFVarData(
return coord;
}
// splicing functions
template <typename V, typename IT> static IT
copyWithOffset(IT dst_iterator, V const &src, int start, int count, int offset) {
return std::transform(src.begin()+start, src.begin()+start+count, dst_iterator,
std::bind2nd(std::plus<typename V::value_type>(), offset));
}
template <typename V, typename IT> static IT
copyWithOffsetVertexValence(IT dst_iterator, V const &src, int srcMaxValence, int dstMaxValence, int offset) {
for (typename V::const_iterator it = src.begin(); it != src.end(); ) {
int valence = *it++;
*dst_iterator++ = valence;
valence = abs(valence);
for (int i = 0; i < 2*dstMaxValence; ++i) {
if (i < 2*srcMaxValence) {
*dst_iterator++ = (i < 2*valence) ? *it + offset : 0;
++it;
} else {
*dst_iterator++ = 0;
}
}
}
return dst_iterator;
}
template <class T> static FarPatchTables::PTable::iterator
splicePatch(FarPatchTables::Descriptor desc,
std::vector<FarMesh<T> const *> const &meshes,
FarPatchTables::PatchArrayVector &result,
std::vector<FarPatchTables::PatchArrayVector> *multiArrayResult,
FarPatchTables::PTable::iterator dstIndexIt,
int *voffset, int *poffset, int *qoffset,
std::vector<int> const &vertexOffsets) {
for (size_t i = 0; i < meshes.size(); ++i) {
FarPatchTables const *patchTables = meshes[i]->GetPatchTables();
FarPatchTables::PatchArray const *srcPatchArray = patchTables->GetPatchArray(desc);
if (not srcPatchArray) continue;
// create new patcharray with offset
int vindex = srcPatchArray->GetVertIndex();
int npatch = srcPatchArray->GetNumPatches();
int nvertex = npatch * desc.GetNumControlVertices();
FarPatchTables::PatchArray patchArray(desc,
*voffset,
*poffset,
npatch,
*qoffset);
// append patch array
result.push_back(patchArray);
// also store into multiPatchArrays, will be used for partial drawing
// XXX: can be stored as indices. revisit here later
if (multiArrayResult) {
(*multiArrayResult)[i].push_back(patchArray);
}
// increment offset
*voffset += nvertex;
*poffset += npatch;
*qoffset += (desc.GetType() == FarPatchTables::GREGORY ||
desc.GetType() == FarPatchTables::GREGORY_BOUNDARY) ? npatch * 4 : 0;
// copy index arrays [vindex, vindex+nvertex]
dstIndexIt = copyWithOffset(dstIndexIt,
patchTables->GetPatchTable(),
vindex,
nvertex,
vertexOffsets[i]);
}
return dstIndexIt;
}
template <class T> FarPatchTables *
FarPatchTablesFactory<T>::Splice(FarMeshVector const &meshes,
MultiPatchArrayVector *multiPatchArrays,
bool hasFVarData) {
int totalQuadOffset0 = 0;
int totalQuadOffset1 = 0;
int totalFVarData = 0;
std::vector<int> vertexOffsets;
std::vector<int> gregoryQuadOffsets;
std::vector<int> numGregoryPatches;
int vertexOffset = 0;
int maxValence = 0;
int numTotalIndices = 0;
//result->_patchCounts.reserve(meshes.size());
//FarPatchCount totalCount;
typedef FarPatchTables::Descriptor Descriptor;
// note: see FarPatchTablesFactory<T>::Create
// feature adaptive refinement can generate un-connected face-vertices
// that have a valence of 0. The spliced vertex valence tables
// needs to be resized including such un-connected face-vertices.
int numVerticesInVertexValence = 0;
// count how many patches exist on each mesh
for (size_t i = 0; i < meshes.size(); ++i) {
const FarPatchTables *ptables = meshes[i]->GetPatchTables();
assert(ptables);
vertexOffsets.push_back(vertexOffset);
vertexOffset += meshes[i]->GetNumVertices();
// need to align maxvalence with the highest value
maxValence = std::max(maxValence, ptables->_maxValence);
FarPatchTables::PatchArray const *gregory =
ptables->GetPatchArray(Descriptor(FarPatchTables::GREGORY,
FarPatchTables::NON_TRANSITION, /*rot*/ 0));
FarPatchTables::PatchArray const *gregoryBoundary =
ptables->GetPatchArray(Descriptor(FarPatchTables::GREGORY_BOUNDARY,
FarPatchTables::NON_TRANSITION, /*rot*/ 0));
int nGregory = gregory ? gregory->GetNumPatches() : 0;
int nGregoryBoundary = gregoryBoundary ? gregoryBoundary->GetNumPatches() : 0;
totalQuadOffset0 += nGregory * 4;
totalQuadOffset1 += nGregoryBoundary * 4;
numGregoryPatches.push_back(nGregory);
gregoryQuadOffsets.push_back(totalQuadOffset0);
totalFVarData += (int)ptables->GetFVarDataTable().size();
numTotalIndices += ptables->GetNumControlVertices();
// note: some prims may not have vertex valence table, but still need a space
// in order to fill following prim's data at appropriate location.
numVerticesInVertexValence += ptables->_vertexValenceTable.empty()
? (int)meshes[i]->GetNumVertices()
: (int)ptables->_vertexValenceTable.size()/(2*ptables->_maxValence+1);
}
FarPatchTables *result = new FarPatchTables(maxValence);
// Allocate full patches
result->_patches.resize(numTotalIndices);
// Allocate vertex valence table, quad offset table
if (totalQuadOffset0 + totalQuadOffset1 > 0) {
result->_vertexValenceTable.resize((2*maxValence+1) * numVerticesInVertexValence);
result->_quadOffsetTable.resize(totalQuadOffset0 + totalQuadOffset1);
}
// Allocate fvardata table
result->_fvarTable.resize(totalFVarData);
// splice tables
// assuming input farmeshes have dense patchtables
if (multiPatchArrays)
multiPatchArrays->resize(meshes.size());
int voffset = 0, poffset = 0, qoffset = 0;
FarPatchTables::PTable::iterator dstIndexIt = result->_patches.begin();
// splice patches : iterate over all descriptors, including points, lines, quads, etc.
for (Descriptor::iterator it=Descriptor::begin(Descriptor::ANY); it!=Descriptor::end(); ++it) {
dstIndexIt = splicePatch(*it,
meshes,
result->_patchArrays,
multiPatchArrays,
dstIndexIt,
&voffset,
&poffset,
&qoffset,
vertexOffsets);
}
// merge vertexvalence and quadoffset tables
FarPatchTables::QuadOffsetTable::iterator Q0_IT = result->_quadOffsetTable.begin();
FarPatchTables::QuadOffsetTable::iterator Q1_IT = Q0_IT + totalQuadOffset0;
FarPatchTables::VertexValenceTable::iterator VV_IT = result->_vertexValenceTable.begin();
for (size_t i = 0; i < meshes.size(); ++i) {
const FarPatchTables *ptables = meshes[i]->GetPatchTables();
// merge vertex valence
// note: some prims may not have vertex valence table, but still need a space
// in order to fill following prim's data at appropriate location.
copyWithOffsetVertexValence(VV_IT,
ptables->_vertexValenceTable,
ptables->_maxValence,
maxValence,
vertexOffsets[i]);
VV_IT += meshes[i]->GetNumVertices() * (2 * maxValence + 1);
// merge quad offsets
int nGregoryQuads = numGregoryPatches[i] * 4;
if (nGregoryQuads > 0) {
Q0_IT = std::copy(ptables->_quadOffsetTable.begin(),
ptables->_quadOffsetTable.begin()+nGregoryQuads,
Q0_IT);
}
if (nGregoryQuads < (int)ptables->_quadOffsetTable.size()) {
Q1_IT = std::copy(ptables->_quadOffsetTable.begin()+nGregoryQuads,
ptables->_quadOffsetTable.end(),
Q1_IT);
}
}
// merge ptexCoord table
for (FarPatchTables::Descriptor::iterator it =
FarPatchTables::Descriptor::begin(FarPatchTables::Descriptor::ANY);
it != FarPatchTables::Descriptor::end(); ++it) {
int ptexFaceOffset = 0;
for (size_t i = 0; i < meshes.size(); ++i) {
FarPatchTables const *ptables = meshes[i]->GetPatchTables();
FarPatchTables::PatchArray const *parray = ptables->GetPatchArray(*it);
if (parray) {
copyWithPtexFaceOffset(std::back_inserter(result->_paramTable),
ptables->_paramTable,
parray->GetPatchIndex(),
parray->GetNumPatches(), ptexFaceOffset);
}
ptexFaceOffset += meshes[i]->GetNumPtexFaces();
}
}
// merge fvardata table
if (hasFVarData) {
FarPatchTables::FVarDataTable::iterator FV_IT = result->_fvarTable.begin();
for (FarPatchTables::Descriptor::iterator it =
FarPatchTables::Descriptor::begin(FarPatchTables::Descriptor::ANY);
it != FarPatchTables::Descriptor::end(); ++it) {
for (size_t i = 0; i < meshes.size(); ++i) {
FarPatchTables const *ptables = meshes[i]->GetPatchTables();
FarPatchTables::PatchArray const *parray = ptables->GetPatchArray(*it);
FarSubdivisionTables::Scheme scheme = meshes[i]->GetSubdivisionTables()->GetScheme();
if (parray) {
int nv = (scheme == FarSubdivisionTables::LOOP) ? 3 : 4;
int width = meshes[i]->GetTotalFVarWidth() * nv; // for each quads or tris
FarPatchTables::FVarDataTable::const_iterator begin =
ptables->_fvarTable.begin() + parray->GetPatchIndex() * width;
FarPatchTables::FVarDataTable::const_iterator end =
begin + parray->GetNumPatches() * width;
FV_IT = std::copy(begin, end, FV_IT);
}
}
}
}
return result;
}
} // end namespace OPENSUBDIV_VERSION

View File

@ -195,10 +195,10 @@ public:
void computeLoopVertexPointsB(int offset,int level, int start, int end, U *vsrc) const;
protected:
template <class X, class Y> friend class FarMultiMeshFactory;
template <class X, class Y> friend class FarBilinearSubdivisionTablesFactory;
template <class X, class Y> friend class FarCatmarkSubdivisionTablesFactory;
template <class X, class Y> friend class FarLoopSubdivisionTablesFactory;
template <class X, class Y> friend class FarSubdivisionTablesFactory;
FarSubdivisionTables( int maxlevel, Scheme scheme );

View File

@ -27,8 +27,9 @@
#include "../version.h"
#include "../far/meshFactory.h"
// note: currently, this file has to be included from meshFactory.h
#include "../far/subdivisionTables.h"
#include "../far/kernelBatch.h"
#include <cassert>
#include <utility>
@ -47,6 +48,13 @@ template <class T, class U> class FarLoopSubdivisionTablesFactory;
///
template <class T, class U> class FarSubdivisionTablesFactory {
public:
typedef std::vector<FarMesh<U> const *> FarMeshVector;
/// \brief Splices subdivision tables and batches from multiple meshes and returns them
/// Client code is responsible for deallocation.
static FarSubdivisionTables *Splice(FarMeshVector const &meshes, FarKernelBatchVector *resultBatches);
protected:
friend class FarBilinearSubdivisionTablesFactory<T,U>;
friend class FarCatmarkSubdivisionTablesFactory<T,U>;
@ -350,6 +358,231 @@ FarSubdivisionTablesFactory<T,U>::compareVertices( HbrVertex<T> const * x, HbrVe
GetMaskRanking(py->GetMask(false), py->GetMask(true) );
}
// splice subdivision tables
template <typename V, typename IT> static IT
copyWithOffset(IT dst_iterator, V const &src, int offset) {
return std::transform(src.begin(), src.end(), dst_iterator,
std::bind2nd(std::plus<typename V::value_type>(), offset));
}
template <typename V, typename IT> static IT
copyWithPtexFaceOffset(IT dst_iterator, V const &src, int start, int count, int offset) {
for (typename V::const_iterator it = src.begin()+start; it != src.begin()+start+count; ++it) {
typename V::value_type ptexCoord = *it;
ptexCoord.faceIndex += offset;
*dst_iterator++ = ptexCoord;
}
return dst_iterator;
}
template <typename V, typename IT> static IT
copyWithOffsetF_ITa(IT dst_iterator, V const &src, int offset) {
for (typename V::const_iterator it = src.begin(); it != src.end();) {
*dst_iterator++ = *it++ + offset; // offset to F_IT
*dst_iterator++ = *it++; // valence
}
return dst_iterator;
}
template <typename V, typename IT> static IT
copyWithOffsetE_IT(IT dst_iterator, V const &src, int offset) {
for (typename V::const_iterator it = src.begin(); it != src.end(); ++it) {
*dst_iterator++ = (*it == -1) ? -1 : (*it + offset);
}
return dst_iterator;
}
template <typename V, typename IT> static IT
copyWithOffsetV_ITa(IT dst_iterator, V const &src, int tableOffset, int vertexOffset) {
for (typename V::const_iterator it = src.begin(); it != src.end();) {
*dst_iterator++ = *it++ + tableOffset; // offset to V_IT
*dst_iterator++ = *it++; // valence
*dst_iterator++ = (*it == -1) ? -1 : (*it + vertexOffset); ++it;
*dst_iterator++ = (*it == -1) ? -1 : (*it + vertexOffset); ++it;
*dst_iterator++ = (*it == -1) ? -1 : (*it + vertexOffset); ++it;
}
return dst_iterator;
}
template <class T, class U> FarSubdivisionTables*
FarSubdivisionTablesFactory<T,U>::Splice(FarMeshVector const &meshes, FarKernelBatchVector *batches ) {
// count total table size
size_t total_F_ITa = 0, total_F_IT = 0;
size_t total_E_IT = 0, total_E_W = 0;
size_t total_V_ITa = 0, total_V_IT = 0, total_V_W = 0;
FarSubdivisionTables::Scheme scheme = FarSubdivisionTables::UNDEFINED;
int maxLevel = 0;
for (size_t i = 0; i < meshes.size(); ++i) {
FarSubdivisionTables const * tables = meshes[i]->GetSubdivisionTables();
assert(tables);
total_F_ITa += tables->Get_F_ITa().size();
total_F_IT += tables->Get_F_IT().size();
total_E_IT += tables->Get_E_IT().size();
total_E_W += tables->Get_E_W().size();
total_V_ITa += tables->Get_V_ITa().size();
total_V_IT += tables->Get_V_IT().size();
total_V_W += tables->Get_V_W().size();
maxLevel = std::max(maxLevel, tables->GetMaxLevel()-1);
if (scheme == FarSubdivisionTables::UNDEFINED) {
scheme = tables->GetScheme();
} else {
assert(scheme == tables->GetScheme());
}
}
FarSubdivisionTables *result = new FarSubdivisionTables(maxLevel, scheme);
result->_F_ITa.resize(total_F_ITa);
result->_F_IT.resize(total_F_IT);
result->_E_IT.resize(total_E_IT);
result->_E_W.resize(total_E_W);
result->_V_ITa.resize(total_V_ITa);
result->_V_IT.resize(total_V_IT);
result->_V_W.resize(total_V_W);
// compute table offsets;
std::vector<int> vertexOffsets;
std::vector<int> fvOffsets;
std::vector<int> evOffsets;
std::vector<int> vvOffsets;
std::vector<int> F_IToffsets;
std::vector<int> V_IToffsets;
{
int vertexOffset = 0;
int F_IToffset = 0;
int V_IToffset = 0;
int fvOffset = 0;
int evOffset = 0;
int vvOffset = 0;
for (size_t i = 0; i < meshes.size(); ++i) {
FarSubdivisionTables const * tables = meshes[i]->GetSubdivisionTables();
assert(tables);
vertexOffsets.push_back(vertexOffset);
F_IToffsets.push_back(F_IToffset);
V_IToffsets.push_back(V_IToffset);
fvOffsets.push_back(fvOffset);
evOffsets.push_back(evOffset);
vvOffsets.push_back(vvOffset);
vertexOffset += meshes[i]->GetNumVertices();
F_IToffset += (int)tables->Get_F_IT().size();
fvOffset += (int)tables->Get_F_ITa().size()/2;
V_IToffset += (int)tables->Get_V_IT().size();
if (scheme == FarSubdivisionTables::CATMARK or
scheme == FarSubdivisionTables::LOOP) {
evOffset += (int)tables->Get_E_IT().size()/4;
vvOffset += (int)tables->Get_V_ITa().size()/5;
} else {
evOffset += (int)tables->Get_E_IT().size()/2;
vvOffset += (int)tables->Get_V_ITa().size();
}
}
}
// concat F_IT and V_IT
std::vector<unsigned int>::iterator F_IT = result->_F_IT.begin();
std::vector<unsigned int>::iterator V_IT = result->_V_IT.begin();
for (size_t i = 0; i < meshes.size(); ++i) {
FarSubdivisionTables const * tables = meshes[i]->GetSubdivisionTables();
int vertexOffset = vertexOffsets[i];
// remap F_IT, V_IT tables
F_IT = copyWithOffset(F_IT, tables->Get_F_IT(), vertexOffset);
V_IT = copyWithOffset(V_IT, tables->Get_V_IT(), vertexOffset);
}
// merge other tables
std::vector<int>::iterator F_ITa = result->_F_ITa.begin();
std::vector<int>::iterator E_IT = result->_E_IT.begin();
std::vector<float>::iterator E_W = result->_E_W.begin();
std::vector<float>::iterator V_W = result->_V_W.begin();
std::vector<int>::iterator V_ITa = result->_V_ITa.begin();
for (size_t i = 0; i < meshes.size(); ++i) {
FarSubdivisionTables const * tables = meshes[i]->GetSubdivisionTables();
// copy face tables
F_ITa = copyWithOffsetF_ITa(F_ITa, tables->Get_F_ITa(), F_IToffsets[i]);
// copy edge tables
E_IT = copyWithOffsetE_IT(E_IT, tables->Get_E_IT(), vertexOffsets[i]);
E_W = copyWithOffset(E_W, tables->Get_E_W(), 0);
// copy vert tables
if (scheme == FarSubdivisionTables::CATMARK or
scheme == FarSubdivisionTables::LOOP) {
V_ITa = copyWithOffsetV_ITa(V_ITa, tables->Get_V_ITa(), V_IToffsets[i], vertexOffsets[i]);
} else {
V_ITa = copyWithOffset(V_ITa, tables->Get_V_ITa(), vertexOffsets[i]);
}
V_W = copyWithOffset(V_W, tables->Get_V_W(), 0);
}
// merge batch, model by model
int editTableIndexOffset = 0;
for (int i = 0; i < (int)meshes.size(); ++i) {
int numBatches = (int)meshes[i]->GetKernelBatches().size();
for (int j = 0; j < numBatches; ++j) {
FarKernelBatch batch = meshes[i]->GetKernelBatches()[j];
batch._meshIndex = i;
batch._vertexOffset += vertexOffsets[i];
if (batch._kernelType == FarKernelBatch::CATMARK_FACE_VERTEX or
batch._kernelType == FarKernelBatch::BILINEAR_FACE_VERTEX) {
batch._tableOffset += fvOffsets[i];
} else if (batch._kernelType == FarKernelBatch::CATMARK_EDGE_VERTEX or
batch._kernelType == FarKernelBatch::LOOP_EDGE_VERTEX or
batch._kernelType == FarKernelBatch::BILINEAR_EDGE_VERTEX) {
batch._tableOffset += evOffsets[i];
} else if (batch._kernelType == FarKernelBatch::CATMARK_VERT_VERTEX_A1 or
batch._kernelType == FarKernelBatch::CATMARK_VERT_VERTEX_A2 or
batch._kernelType == FarKernelBatch::CATMARK_VERT_VERTEX_B or
batch._kernelType == FarKernelBatch::LOOP_VERT_VERTEX_A1 or
batch._kernelType == FarKernelBatch::LOOP_VERT_VERTEX_A2 or
batch._kernelType == FarKernelBatch::LOOP_VERT_VERTEX_B or
batch._kernelType == FarKernelBatch::BILINEAR_VERT_VERTEX) {
batch._tableOffset += vvOffsets[i];
} else if (batch._kernelType == FarKernelBatch::HIERARCHICAL_EDIT) {
batch._tableIndex += editTableIndexOffset;
}
batches->push_back(batch);
}
editTableIndexOffset += meshes[i]->GetVertexEdit() ?
meshes[i]->GetVertexEdit()->GetNumBatches() : 0;
}
// count verts offsets
result->_vertsOffsets.resize(maxLevel+2);
for (size_t i = 0; i < meshes.size(); ++i) {
FarSubdivisionTables const * tables = meshes[i]->GetSubdivisionTables();
for (size_t j = 0; j < tables->_vertsOffsets.size(); ++j) {
result->_vertsOffsets[j] += tables->_vertsOffsets[j];
}
}
return result;
}
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;

View File

@ -85,6 +85,10 @@ public:
// Note : Subtract type edits are converted into Adds in order to save kernel calls.
// Compute-kernel that applies the edits
template <class CONTEXT>
void computeVertexEdits(int tableIndex, int offset, int tableOffset, int start, int end, CONTEXT *context) const;
/// \brief This class holds an array of edits. each batch has unique index/width/operation
class VertexEditBatch {
public:
@ -117,7 +121,6 @@ public:
private:
template <class X, class Y> friend class FarVertexEditTablesFactory;
template <class X, class Y> friend class FarMultiMeshFactory;
std::vector<unsigned int> _vertIndices; // absolute vertex index array for edits
std::vector<float> _edits; // edit values array
@ -142,12 +145,6 @@ public:
private:
template <class X, class Y> friend class FarVertexEditTablesFactory;
template <class X, class Y> friend class FarMultiMeshFactory;
friend class FarComputeController;
// Compute-kernel that applies the edits
template <class CONTEXT>
void computeVertexEdits(int tableIndex, int offset, int tableOffset, int start, int end, CONTEXT *context) const;
#if defined(__GNUC__)
// XXX(dyu): seems like there is a compiler bug in g++ that requires

View File

@ -44,6 +44,13 @@ namespace OPENSUBDIV_VERSION {
///
template <class T, class U> class FarVertexEditTablesFactory {
public:
typedef std::vector<FarMesh<U> const *> FarMeshVector;
/// \brief Splices vertex edit tables from multiple meshes and returns it.
/// Client code is responsible for deallocation.
static FarVertexEditTables *Splice(FarMeshVector const &meshes);
protected:
template <class X, class Y> friend class FarMeshFactory;
@ -201,6 +208,31 @@ FarVertexEditTablesFactory<T,U>::Create( FarMeshFactory<T,U> const * factory, Fa
return result;
}
// splicing functions
template <class T, class U> FarVertexEditTables *
FarVertexEditTablesFactory<T, U>::Splice(FarMeshVector const &meshes) {
FarVertexEditTables * result = new FarVertexEditTables();
// at this moment, don't merge vertex edit tables (separate batch)
for (size_t i = 0; i < meshes.size(); ++i) {
const FarVertexEditTables *vertexEditTables = meshes[i]->GetVertexEdit();
if (not vertexEditTables) continue;
// copy each edit batch XXX:inefficient copy
result->_batches.insert(result->_batches.end(),
vertexEditTables->_batches.begin(),
vertexEditTables->_batches.end());
}
if (result->_batches.empty()) {
delete result;
return NULL;
}
return result;
}
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;