WIP on end-cap topology generation

- adding functionality to Far::PatchTablesFactory to generate topology indices
  for Gregory basis end-caps (identify and index vertices along basis shared
  edges)
- code is currently #ifdef'ed out until further work can be done to bring the
  feature along all the way through to Osd::Draw
This commit is contained in:
manuelk 2014-11-18 10:48:37 -08:00
parent 0513ef1461
commit 6a2b966f6e
3 changed files with 130 additions and 24 deletions

View File

@ -214,13 +214,6 @@ Point::Copy(int ** size, Index ** indices, float ** weights) const {
++(*size);
}
// Because MSVC does not support VLAs, we have to run alloca() in a macro and
// call in-place constructors - it's only been standardized for 15 years after
// all...
#define AllocaPointsArrays(variable, npoints) \
Point * variable = (Point *)alloca(npoints*sizeof(Point)); \
{ for (int i=0; i<npoints; ++i) { new (&variable[i]) Point; } }
//
// ProtoBasis
//
@ -324,6 +317,13 @@ ProtoBasis::ProtoBasis(Vtr::Level const & level, Index faceIndex) {
Index * manifoldRing = (int *)alloca((maxvalence+2)*2 * sizeof(int));
// Because MSVC does not support VLAs, we have to run alloca() in a macro and
// call in-place constructors - it's only been standardized for 15 years after
// all...
#define AllocaPointsArrays(variable, npoints) \
Point * variable = (Point *)alloca(npoints*sizeof(Point)); \
{ for (int i=0; i<npoints; ++i) { new (&variable[i]) Point; } }
AllocaPointsArrays(f, maxvalence);
AllocaPointsArrays(r, maxvalence*4);
Point e0[4], e1[4], org[4];
@ -617,9 +617,8 @@ GregoryBasisFactory::GregoryBasisFactory(TopologyRefiner const & refiner,
}
}
}
inline void
static inline void
factorizeBasisVertex(StencilTables const & stencils, Point const & p, ProtoStencil dst) {
// Use the Allocator to factorize the Gregory patch influence CVs with the
// supporting CVs from the stencil tables.
dst.Clear();

View File

@ -638,11 +638,13 @@ private:
// XXXX manuelk end-cap stencils will obsolete the other tables
StencilTables const * _endcapStencilTables;
#ifdef ENDCAP_TOPOPOLGY
PTable _endcapTopology;
#endif
VertexValenceTable _vertexValenceTable; // Vertex valence table (for Gregory patches)
QuadOffsetTable _quadOffsetTable; // Quad offsets table (for Gregory patches)
StencilTables const * _endcapStencilTables;
//
// Face-varying data
//

View File

@ -28,6 +28,7 @@
#include "../vtr/level.h"
#include "../vtr/refinement.h"
#include <algorithm>
#include <cassert>
#include <cstring>
@ -412,20 +413,20 @@ PatchTablesFactory::allocateTables(PatchTables * tables, int /* nlevels */, bool
PatchTables::PatchArrayVector const & parrays = tables->GetPatchArrayVector();
int nverts = 0, npatches = 0;
int ncvs = 0, npatches = 0;
for (int i=0; i<(int)parrays.size(); ++i) {
int nps = parrays[i].GetNumPatches(),
ncvs = GetNumControlVertices(parrays[i].GetDescriptor());
ringsize = GetNumControlVertices(parrays[i].GetDescriptor());
npatches += nps;
nverts += ncvs * nps;
ncvs += ringsize * nps;
}
if (nverts==0 or npatches==0)
if (ncvs==0 or npatches==0)
return;
tables->_patches.resize( nverts );
tables->_patches.resize( ncvs );
tables->_paramTable.resize( npatches );
@ -562,13 +563,98 @@ PatchTablesFactory::computePatchParam(TopologyRefiner const & refiner,
return ++coord;
}
// XXXX manuelk work in progress for end-cap topology gathering
#ifdef ENDCAP_TOPOPOLGY
//
// Populate the topology table used by Gregory-basis patches
//
// Note: 'faceIndex' values are expected to be sorted in ascending order !!!
static int
gatherGregoryBasisTopology(Vtr::Level const& level, Index faceIndex, int numVertices,
PatchFaceTag const * levelPatchTags,
bool skip[0], std::vector<Index> & basisIndices, PatchTables::PTable & topology) {
assert(not topology.empty());
Index * dest = &topology[basisIndices.size()*20];
assert(Vtr::INDEX_INVALID==0xFFFFFFFF);
memset(dest, 0xFF, 20*sizeof(Index));
IndexArray fedges = level.getFaceEdges(faceIndex);
assert(fedges.size()==4);
for (int i=0; i<4; ++i) {
Index edge = fedges[i],
adjface = 0;
{ // Gather adjacent faces
IndexArray adjfaces = level.getEdgeFaces(edge);
for (int i=0; i<adjfaces.size(); ++i) {
if (adjfaces[i]==faceIndex) {
// XXXX manuelk if 'edge' is non-manifold, arbitrarily pick the
// next face in the list of adjacent faces
adjface = (adjfaces[(i+1)%adjfaces.size()]);
break;
}
}
}
// We are looking for adjacent faces that:
// - exist (no boundary)
// - have alraedy been processed (known CV indices)
// - are also Gregory basis patches
if (adjface!=Vtr::INDEX_INVALID and (adjface < faceIndex) and
(not levelPatchTags[adjface]._isRegular)) {
IndexArray aedges = level.getFaceEdges(adjface);
int aedge = aedges.FindIndexIn4Tuple(edge);
assert(aedge!=Vtr::INDEX_INVALID);
// Find index of basis in the list of basis already generated
struct compare {
static int op(void const * a, void const * b) {
return *(Index *)a - *(Index *)b;
}
};
Index * ptr = (Index *)std::bsearch( &adjface, &basisIndices[0],
basisIndices.size(), sizeof(Index), compare::op);
int srcBasisIdx = ptr - &basisIndices[0];
assert(ptr and srcBasisIdx>=0 and srcBasisIdx<(int)basisIndices.size());
// Copy the indices of CVs from the face on the other side of the
// shared edge
static int const gregoryEdgeVerts[4][4] = { { 0, 1, 7, 5},
{ 5, 6, 12, 10},
{10, 11, 17, 15},
{15, 16, 2, 0} };
Index * src = &topology[srcBasisIdx*20];
for (int j=0; j<4; ++j) {
dest[i*4+j] = src[gregoryEdgeVerts[aedge][j]];
}
skip[i] = true;
} else {
skip[i] = false;
}
}
for (int i=0; i<20; ++i) {
if (dest[i]==Vtr::INDEX_INVALID) {
dest[i] = numVertices++;
}
}
basisIndices.push_back(faceIndex);
return numVertices;
}
#endif
//
// Populate the quad-offsets table used by Gregory patches
//
void
PatchTablesFactory::getQuadOffsets(Vtr::Level const& level, Vtr::Index fIndex, Index offsets[]) {
PatchTablesFactory::getQuadOffsets(
Vtr::Level const& level, Index faceIndex, Index offsets[]) {
Vtr::IndexArray fVerts = level.getFaceVertices(fIndex);
Vtr::IndexArray fVerts = level.getFaceVertices(faceIndex);
for (int i = 0; i < 4; ++i) {
@ -578,7 +664,7 @@ PatchTablesFactory::getQuadOffsets(Vtr::Level const& level, Vtr::Index fIndex, I
int thisFaceInVFaces = -1;
for (int j = 0; j < vFaces.size(); ++j) {
if (fIndex == vFaces[j]) {
if (faceIndex == vFaces[j]) {
thisFaceInVFaces = j;
break;
}
@ -595,6 +681,7 @@ PatchTablesFactory::getQuadOffsets(Vtr::Level const& level, Vtr::Index fIndex, I
}
}
//
// Indexing sharpnesses
//
@ -1136,15 +1223,27 @@ PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
// To avoid gathering vertex neighborhoods for all vertices, identify vertices involved in
// gregory patches as the faces are traversed, to be gathered later:
//
GregoryBasisFactory * gregoryStencilsFactory = 0;
bool hasGregoryPatches = (patchInventory.G > 0) or (patchInventory.GB > 0) or (patchInventory.GP > 0);
GregoryBasisFactory * gregoryStencilsFactory = 0;
#ifdef ENDCAP_TOPOPOLGY
int numGregoryBasisVertices=0;
std::vector<Index> gregoryBasisIndices;
#endif
if (hasGregoryPatches) {
StencilTables const * adaptiveStencils = options.adaptiveStencilTables;
if (adaptiveStencils and patchInventory.GP>0) {
int maxvalence = refiner.getLevel(0).getMaxValence();
int maxvalence = refiner.getLevel(0).getMaxValence(),
npatches = patchInventory.GP;
gregoryStencilsFactory =
new GregoryBasisFactory(refiner, *adaptiveStencils, patchInventory.GP, maxvalence);
new GregoryBasisFactory(refiner, *adaptiveStencils, npatches, maxvalence);
#ifdef ENDCAP_TOPOPOLGY
gregoryBasisIndices.reserve(npatches);
tables->_endcapTopology.resize(npatches*20);
#endif
}
gregoryVertexFlags.resize(refiner.GetNumVerticesTotal(), false);
}
@ -1270,6 +1369,12 @@ PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
gregoryVertexFlags[iptrs.GP[j]] = true;
}
iptrs.GP += 4;
#ifdef ENDCAP_TOPOPOLGY
bool edgeSkip[4];
numGregoryBasisVertices = gatherGregoryBasisTopology(*level, faceIndex, numGregoryBasisVertices,
levelPatchTags, edgeSkip, gregoryBasisIndices, tables->_endcapTopology);
#endif
gregoryStencilsFactory->AddPatchBasis(faceIndex);
pptrs.GP = computePatchParam(refiner, i, faceIndex, 0, pptrs.GP);
@ -1343,7 +1448,7 @@ PatchTablesFactory::populateAdaptivePatches( TopologyRefiner const & refiner,
// the vast majority of vertices that are not associated with gregory patches -- by having previously
// marked those that are associated above and skipping all others.
//
if (hasGregoryPatches) {
if ((patchInventory.G > 0) or (patchInventory.GB > 0)) {
const int SizePerVertex = 2*tables->_maxValence + 1;
PatchTables::VertexValenceTable & vTable = tables->_vertexValenceTable;