mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-23 12:10:08 +00:00
WIP check-point for Gregory basis factorization
- adding support for StencilTables creation from a Gregory basis - fix a bug in the prot-stencil allocator (slow memory pool was not being cleared properly)
This commit is contained in:
parent
c2fa2616d2
commit
c237ab00fc
@ -156,7 +156,7 @@ GLMesh::initializeVertexComponentBuffer(float const * vertData, int nverts) {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void
|
||||
GLMesh::Initialize(Options options,
|
||||
GLMesh::Initialize(Options /* options */,
|
||||
int nverts, int nfaces, int * vertsperface, int * faceverts,
|
||||
float const * vertexData) {
|
||||
|
||||
|
@ -115,6 +115,7 @@ int g_displayPatchColor = 1,
|
||||
g_VtrDrawPtexIDs = false,
|
||||
g_VtrDrawEdgeSharpness = false,
|
||||
g_numPatches = 0,
|
||||
g_maxValence = 0,
|
||||
g_currentPatch = 0,
|
||||
g_Adaptive = true;
|
||||
|
||||
@ -546,27 +547,38 @@ static GLMesh gregoryWire;
|
||||
|
||||
static void
|
||||
createGregoryBasis(OpenSubdiv::Far::TopologyRefiner const & refiner,
|
||||
OpenSubdiv::Far::StencilTables const & stencils, int maxvalence,
|
||||
std::vector<Vertex> const & vertexBuffer) {
|
||||
|
||||
int level = refiner.GetMaxLevel(),
|
||||
nfaces = refiner.GetNumFaces(level);
|
||||
|
||||
int vertOffset = 0;
|
||||
for (int i=0; i<level; ++i) {
|
||||
vertOffset += refiner.GetNumVertices(i);
|
||||
std::vector<OpenSubdiv::Far::Index> gpatches(nfaces);
|
||||
for (int face=0; face<nfaces; ++face) {
|
||||
if (not refiner.FaceIsRegular(level, face)) {
|
||||
gpatches.push_back(face);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> vertsperedge, edgeindices;
|
||||
std::vector<Vertex> edgeverts;
|
||||
int npatches = (int)gpatches.size();
|
||||
|
||||
for (int face=0; face<nfaces; ++face) {
|
||||
bool regular = refiner.FaceIsRegular(level, face);
|
||||
if (not regular) {
|
||||
OpenSubdiv::Far::GregoryBasis const * gbasis =
|
||||
OpenSubdiv::Far::GregoryBasisFactory::Create(refiner, face);
|
||||
OpenSubdiv::Far::GregoryBasisFactory factory(
|
||||
refiner, stencils, npatches, maxvalence);
|
||||
|
||||
for (int i=0; i<npatches; ++i) {
|
||||
factory.AddPatchBasis(gpatches[i]);
|
||||
}
|
||||
|
||||
{ // initialize wireframe
|
||||
OpenSubdiv::Far::StencilTables const * gstencils =
|
||||
factory.CreateStencilTables();
|
||||
|
||||
int nedges = npatches * 20;
|
||||
|
||||
std::vector<int> vertsperedge(nedges), edgeindices(nedges*2);
|
||||
std::vector<Vertex> edgeverts(npatches*20);
|
||||
gstencils->UpdateValues(&vertexBuffer[0], &edgeverts[0]);
|
||||
|
||||
for (int patch=0; patch<npatches; ++patch) {
|
||||
|
||||
static int basisedges[40] = { 0, 1, 0, 2, 1, 3, 2, 4,
|
||||
5, 6, 5, 7, 6, 8, 7, 9,
|
||||
@ -574,40 +586,29 @@ createGregoryBasis(OpenSubdiv::Far::TopologyRefiner const & refiner,
|
||||
15, 16, 15, 17, 16, 18, 17, 19,
|
||||
1, 7, 6, 12, 11, 17, 16, 2 };
|
||||
|
||||
int nedges = (int)vertsperedge.size();
|
||||
|
||||
vertsperedge.resize(nedges+20);
|
||||
edgeindices.resize(nedges*2+40);
|
||||
|
||||
int * vpe = &vertsperedge[nedges],
|
||||
* ev = &edgeindices[nedges*2];
|
||||
int offset = patch * 20,
|
||||
* vpe = &vertsperedge[offset],
|
||||
* indices = &edgeindices[patch * 40];
|
||||
for (int i=0; i<20; ++i) {
|
||||
vpe[i] = 2;
|
||||
ev[i*2] = basisedges[i*2] + nedges;
|
||||
ev[i*2+1] = basisedges[i*2+1] + nedges;
|
||||
}
|
||||
indices[i*2] = basisedges[i*2] + offset;
|
||||
indices[i*2+1] =basisedges[i*2+1] + offset;
|
||||
}
|
||||
|
||||
std::vector<Vertex> gverts(20);
|
||||
gbasis->Evaluate(&vertexBuffer[vertOffset], &gverts[0]);
|
||||
|
||||
Vertex const * verts = &edgeverts[offset];
|
||||
static char buf[16];
|
||||
for (int i=0; i<4; ++i) {
|
||||
int vid = i * 5;
|
||||
snprintf(buf, 16, " P%d", i);
|
||||
g_font->Print3D(gverts[vid].GetPos(), buf, 3);
|
||||
g_font->Print3D(verts[vid].GetPos(), buf, 3);
|
||||
snprintf(buf, 16, " Ep%d", i);
|
||||
g_font->Print3D(gverts[vid+1].GetPos(), buf, 3);
|
||||
g_font->Print3D(verts[vid+1].GetPos(), buf, 3);
|
||||
snprintf(buf, 16, " Em%d", i);
|
||||
g_font->Print3D(gverts[vid+2].GetPos(), buf, 3);
|
||||
g_font->Print3D(verts[vid+2].GetPos(), buf, 3);
|
||||
snprintf(buf, 16, " Fp%d", i);
|
||||
g_font->Print3D(gverts[vid+3].GetPos(), buf, 3);
|
||||
g_font->Print3D(verts[vid+3].GetPos(), buf, 3);
|
||||
snprintf(buf, 16, " Fm%d", i);
|
||||
g_font->Print3D(gverts[vid+4].GetPos(), buf, 3);
|
||||
}
|
||||
delete gbasis;
|
||||
|
||||
edgeverts.insert(edgeverts.end(), gverts.begin(), gverts.end());
|
||||
g_font->Print3D(verts[vid+4].GetPos(), buf, 3);
|
||||
}
|
||||
}
|
||||
|
||||
@ -697,6 +698,7 @@ createVtrMesh(Shape * shape, int maxlevel) {
|
||||
patchTables = OpenSubdiv::Far::PatchTablesFactory::Create(*refiner);
|
||||
|
||||
g_numPatches = patchTables->GetNumPatchesTotal();
|
||||
g_maxValence = patchTables->GetMaxValence();
|
||||
} else {
|
||||
refiner->RefineUniform(maxlevel, /*fullTopology*/true);
|
||||
}
|
||||
@ -726,12 +728,13 @@ createVtrMesh(Shape * shape, int maxlevel) {
|
||||
//printf(" %f ms (total)\n", float(s.GetTotalElapsed())*1000.0f);
|
||||
}
|
||||
#else
|
||||
OpenSubdiv::Far::StencilTables const * stencilTables = 0;
|
||||
{
|
||||
OpenSubdiv::Far::StencilTablesFactory::Options options;
|
||||
options.generateOffsets=true;
|
||||
options.generateIntermediateLevels=true;
|
||||
|
||||
OpenSubdiv::Far::StencilTables const * stencilTables =
|
||||
stencilTables =
|
||||
OpenSubdiv::Far::StencilTablesFactory::Create(*refiner, options);
|
||||
|
||||
stencilTables->UpdateValues(verts, verts + ncoarseverts);
|
||||
@ -755,7 +758,7 @@ createVtrMesh(Shape * shape, int maxlevel) {
|
||||
}
|
||||
|
||||
if (g_Adaptive and g_drawGregoryBasis) {
|
||||
createGregoryBasis(*refiner, vertexBuffer);
|
||||
createGregoryBasis(*refiner, *stencilTables, g_maxValence, vertexBuffer);
|
||||
}
|
||||
|
||||
createEdgeNumbers(*refiner, vertexBuffer, g_VtrDrawEdgeIDs!=0, g_VtrDrawEdgeSharpness!=0);
|
||||
@ -780,6 +783,7 @@ createVtrMesh(Shape * shape, int maxlevel) {
|
||||
|
||||
delete refiner;
|
||||
delete patchTables;
|
||||
delete stencilTables;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -32,6 +32,26 @@
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
// Builds a table of local indices pairs for each vertex of the patch.
|
||||
//
|
||||
// o
|
||||
// N0 |
|
||||
// | ....
|
||||
// | .... : Gregory patch
|
||||
// o ------ o ------ o ....
|
||||
// N1 V | .... M3
|
||||
// | .......
|
||||
// | .......
|
||||
// o .......
|
||||
// N2
|
||||
//
|
||||
// [...] [N2 - N3] [...]
|
||||
//
|
||||
// Each value pair is composed of 2 index values in range [0-4[ pointing
|
||||
// to the 2 neighbor vertices of the vertex 'V' belonging to the Gregory patch.
|
||||
// Neighbor ordering is valence CCW and must match the winding of the 1-ring
|
||||
// vertices.
|
||||
//
|
||||
static void
|
||||
getQuadOffsets(Vtr::Level const& level, Vtr::Index fIndex, Vtr::Index offsets[]) {
|
||||
|
||||
@ -61,10 +81,12 @@ getQuadOffsets(Vtr::Level const& level, Vtr::Index fIndex, Vtr::Index offsets[])
|
||||
}
|
||||
}
|
||||
|
||||
#define GetNumMaxElems( maxvalence ) \
|
||||
16 + maxvalence - 3
|
||||
|
||||
// limit valence of 30 because we use a pre-computed closed-form 'ef' table
|
||||
static const int MAX_VALENCE=30,
|
||||
MAX_ELEMS = 16 + MAX_VALENCE - 3;
|
||||
|
||||
MAX_ELEMS = GetNumMaxElems(MAX_VALENCE);
|
||||
|
||||
namespace Far {
|
||||
|
||||
@ -72,7 +94,7 @@ namespace Far {
|
||||
// Basis point
|
||||
//
|
||||
// Implements arithmetic operators to manipulate the influence of the
|
||||
// control vertices supporting the patch basis
|
||||
// 1-ring control vertices supporting the patch basis
|
||||
//
|
||||
class Point {
|
||||
|
||||
@ -152,6 +174,12 @@ public:
|
||||
Point p(*this); return p-=other;
|
||||
}
|
||||
|
||||
void OffsetIndices(Index offset) {
|
||||
for (int i=0; i<_size; ++i) {
|
||||
_indices[i] += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Copy(int ** size, Index ** indices, float ** weights) const;
|
||||
|
||||
private:
|
||||
@ -196,12 +224,17 @@ Point::Copy(int ** size, Index ** indices, float ** weights) const {
|
||||
//
|
||||
// ProtoBasis
|
||||
//
|
||||
// Given a Vtr::Level and a face index, gathers all the influences of the 1-ring
|
||||
// that supports the 20 CVs of a Gregory patch basis.
|
||||
//
|
||||
struct ProtoBasis {
|
||||
|
||||
ProtoBasis(Vtr::Level const & level, Index faceIndex);
|
||||
|
||||
int GetNumElements() const;
|
||||
|
||||
void OffsetIndices(Index offset);
|
||||
|
||||
void Copy(int * sizes, Index * indices, float * weights) const;
|
||||
|
||||
// Control Vertices based on :
|
||||
@ -233,7 +266,6 @@ struct ProtoBasis {
|
||||
|
||||
int
|
||||
ProtoBasis::GetNumElements() const {
|
||||
|
||||
int nelems=0;
|
||||
for (int vid=0; vid<4; ++vid) {
|
||||
nelems += P[vid].GetSize();
|
||||
@ -244,10 +276,18 @@ ProtoBasis::GetNumElements() const {
|
||||
}
|
||||
return nelems;
|
||||
}
|
||||
|
||||
void
|
||||
ProtoBasis::OffsetIndices(Index offset) {
|
||||
for (int vid=0; vid<4; ++vid) {
|
||||
P[vid].OffsetIndices(offset);
|
||||
Ep[vid].OffsetIndices(offset);
|
||||
Em[vid].OffsetIndices(offset);
|
||||
Fp[vid].OffsetIndices(offset);
|
||||
Fm[vid].OffsetIndices(offset);
|
||||
}
|
||||
}
|
||||
void
|
||||
ProtoBasis::Copy(int * sizes, Index * indices, float * weights) const {
|
||||
|
||||
for (int vid=0; vid<4; ++vid) {
|
||||
P[vid].Copy(&sizes, &indices, &weights);
|
||||
Ep[vid].Copy(&sizes, &indices, &weights);
|
||||
@ -256,7 +296,6 @@ ProtoBasis::Copy(int * sizes, Index * indices, float * weights) const {
|
||||
Fm[vid].Copy(&sizes, &indices, &weights);
|
||||
}
|
||||
}
|
||||
|
||||
inline float csf(Index n, Index j) {
|
||||
if (j%2 == 0) {
|
||||
return cosf((2.0f * float(M_PI) * float(float(j-0)/2.0f))/(float(n)+3.0f));
|
||||
@ -264,7 +303,6 @@ inline float csf(Index n, Index j) {
|
||||
return sinf((2.0f * float(M_PI) * float(float(j-1)/2.0f))/(float(n)+3.0f));
|
||||
}
|
||||
}
|
||||
|
||||
ProtoBasis::ProtoBasis(Vtr::Level const & level, Index faceIndex) {
|
||||
|
||||
static float ef[MAX_VALENCE-3] = {
|
||||
@ -502,18 +540,21 @@ ProtoBasis::ProtoBasis(Vtr::Level const & level, Index faceIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
int GregoryBasisFactory::GetMaxValence() {
|
||||
return MAX_VALENCE;
|
||||
}
|
||||
|
||||
//
|
||||
// GregoryBasisFactory
|
||||
// Stateless GregoryBasisFactory
|
||||
//
|
||||
|
||||
GregoryBasis const *
|
||||
GregoryBasisFactory::Create(TopologyRefiner const & refiner, Index faceIndex) {
|
||||
|
||||
// Gregory patches only exist on the hight
|
||||
// Gregory patches are end-caps: they only exist on max-level
|
||||
Vtr::Level const & level = refiner.getLevel(refiner.GetMaxLevel());
|
||||
|
||||
if (level.getMaxValence()>MAX_VALENCE) {
|
||||
if (level.getMaxValence()>GetMaxValence()) {
|
||||
// The proto-basis closed-form table limits valence to 'MAX_VALENCE'
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -536,47 +577,96 @@ GregoryBasisFactory::Create(TopologyRefiner const & refiner, Index faceIndex) {
|
||||
return result;
|
||||
}
|
||||
|
||||
GregoryBasisFactory::GregoryBasisFactory(StencilTables const & stencils,
|
||||
int numpatches, int maxvalence) :
|
||||
_currentStencil(0), _stencils(stencils), _alloc(16 + maxvalence - 3) {
|
||||
|
||||
//
|
||||
// GregoryBasisFactory for StencilTables
|
||||
//
|
||||
GregoryBasisFactory::GregoryBasisFactory(TopologyRefiner const & refiner,
|
||||
StencilTables const & stencils, int numpatches, int maxvalence) :
|
||||
_currentStencil(0), _refiner(refiner),
|
||||
_stencils(stencils), _alloc(GetNumMaxElems(maxvalence)) {
|
||||
_alloc.Resize(numpatches * 20);
|
||||
}
|
||||
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();
|
||||
for (int j=0; j<p.GetSize(); ++j) {
|
||||
dst.AddWithWeight(stencils,
|
||||
p.GetIndices()[j], p.GetWeights()[j]);
|
||||
}
|
||||
}
|
||||
bool
|
||||
GregoryBasisFactory::AddBasis(TopologyRefiner const & refiner, Index faceIndex) {
|
||||
GregoryBasisFactory::AddPatchBasis(Index faceIndex) {
|
||||
|
||||
// Gregory patches only exist on the hight
|
||||
Vtr::Level const & level = refiner.getLevel(refiner.GetMaxLevel());
|
||||
Vtr::Level const & level = _refiner.getLevel(_refiner.GetMaxLevel());
|
||||
|
||||
assert( (not refiner.IsUniform()) and
|
||||
// Sanity checks: the mesh must be adaptively refined and the stencil tables
|
||||
// must have the correct size to factorize all the CVs at
|
||||
// intermediate subdivision levels back to the coarse mesh.
|
||||
assert( (not _refiner.IsUniform()) and
|
||||
(_stencils.GetNumStencils() ==
|
||||
refiner.GetNumVerticesTotal()-refiner.GetNumVertices(0)) );
|
||||
_refiner.GetNumVerticesTotal()-_refiner.GetNumVertices(0)) );
|
||||
|
||||
if (level.getMaxValence()>MAX_VALENCE) {
|
||||
if (level.getMaxValence()>GetMaxValence()) {
|
||||
// The proto-basis closed-form table limits valence to 'MAX_VALENCE'
|
||||
return false;
|
||||
}
|
||||
|
||||
int voffset = 0;
|
||||
for (int i=0; i<refiner.GetMaxLevel(); ++i) {
|
||||
voffset += refiner.GetNumVertices(i);
|
||||
}
|
||||
|
||||
// Gather the CVs that influence the Gregory patch and their relative
|
||||
// weights in a basis
|
||||
ProtoBasis basis(level, faceIndex);
|
||||
|
||||
// The basis vertex indices are currently local to maxlevel: need to offset
|
||||
// to match layout of adaptive StencilTables
|
||||
int voffset = 0;
|
||||
for (int i=1; i<_refiner.GetMaxLevel(); ++i) {
|
||||
voffset += _refiner.GetNumVertices(i);
|
||||
}
|
||||
basis.OffsetIndices(voffset);
|
||||
|
||||
// Factorize the basis CVs with the stencil tables: the basis is now
|
||||
// expressed as a linear combination of vertices from the coarse control
|
||||
// mesh with no data dependencies
|
||||
for (int i=0; i<4; ++i) {
|
||||
|
||||
int idx = _currentStencil + i*5;
|
||||
|
||||
ProtoStencil stencilP = _alloc[idx];
|
||||
stencilP.Clear();
|
||||
for (int j=0; j<basis.P[i].GetSize(); ++j) {
|
||||
|
||||
int offset = _currentStencil + i * 5;
|
||||
factorizeBasisVertex(_stencils, basis.P[i], _alloc[offset]);
|
||||
factorizeBasisVertex(_stencils, basis.Ep[i], _alloc[offset+1]);
|
||||
factorizeBasisVertex(_stencils, basis.Em[i], _alloc[offset+2]);
|
||||
factorizeBasisVertex(_stencils, basis.Fp[i], _alloc[offset+3]);
|
||||
factorizeBasisVertex(_stencils, basis.Fm[i], _alloc[offset+4]);
|
||||
}
|
||||
}
|
||||
|
||||
_currentStencil += 20;
|
||||
return true;
|
||||
}
|
||||
StencilTables const *
|
||||
GregoryBasisFactory::CreateStencilTables( ) {
|
||||
|
||||
// Finalize the stencil tables from the temporary pool allocator
|
||||
StencilTables * result = new StencilTables;
|
||||
|
||||
int nstencils = (int)_alloc.GetNumStencils(),
|
||||
nelems = _alloc.GetNumVerticesTotal();
|
||||
|
||||
result->_numControlVertices = _refiner.GetNumVertices(0);
|
||||
|
||||
result->resize(nstencils, nelems);
|
||||
|
||||
Stencil dst(&result->_sizes.at(0),
|
||||
&result->_indices.at(0), &result->_weights.at(0));
|
||||
|
||||
for (int i=0; i<_alloc.GetNumStencils(); ++i) {
|
||||
*dst._size = _alloc.CopyStencil(i, dst._indices, dst._weights);
|
||||
dst.Next();
|
||||
}
|
||||
|
||||
result->generateOffsets();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
|
@ -40,8 +40,18 @@ class GregoryBasis {
|
||||
|
||||
public:
|
||||
|
||||
template <class T>
|
||||
void Evaluate(T const * controlValues, T values[20]) const {
|
||||
/// \brief Updates point values based on the control values
|
||||
///
|
||||
/// \note The destination buffers are assumed to have allocated at least
|
||||
/// \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param controlValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
/// @param values Destination buffer for the interpolated primvar
|
||||
/// data
|
||||
///
|
||||
template <class T, class U>
|
||||
void Evaluate(T const & controlValues, U values[20]) const {
|
||||
|
||||
Index const * indices = &_indices.at(0);
|
||||
float const * weights = &_weights.at(0);
|
||||
@ -71,19 +81,50 @@ class GregoryBasisFactory {
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
// Single patch GregoryBasis basis factory
|
||||
//
|
||||
|
||||
/// \brief Instantiates a GregoryBasis from a TopologyRefiner that has been
|
||||
/// refined adaptively for a given face.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param faceIndex The index of the face (level is assumed to be MaxLevel)
|
||||
///
|
||||
static GregoryBasis const * Create(TopologyRefiner const & refiner, Index faceIndex);
|
||||
|
||||
/// \brief Returns the maximum valence of a vertex in the mesh that the
|
||||
/// Gregory patches can handle
|
||||
static int GetMaxValence();
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
// Multi-patch Gregory stencils factory
|
||||
//
|
||||
|
||||
// This factory accumulates Gregory patch basis into StencilTables
|
||||
//
|
||||
// Note: the TopologyRefiner and StencilTables references are held for the
|
||||
// lifespan of the factory - neither can be deleted or modified while
|
||||
// this factory is active.
|
||||
//
|
||||
GregoryBasisFactory(TopologyRefiner const & refiner,
|
||||
StencilTables const & stencils, int numpatches, int maxvalence);
|
||||
|
||||
// Creates a basis for the face and adds it to the stencil pool allocator
|
||||
bool AddPatchBasis(Index faceIndex);
|
||||
|
||||
// After all the patches have been collected, create the final table
|
||||
StencilTables const * CreateStencilTables();
|
||||
|
||||
private:
|
||||
|
||||
GregoryBasisFactory(StencilTables const & stencils, int numpatches, int maxvalence);
|
||||
|
||||
bool AddBasis(TopologyRefiner const & refiner, Index faceIndex);
|
||||
|
||||
friend class Point;
|
||||
friend struct ProtoBasis;
|
||||
|
||||
int _currentStencil;
|
||||
|
||||
TopologyRefiner const & _refiner; // XXXX these should be smart pointers !
|
||||
|
||||
StencilTables const & _stencils;
|
||||
StencilAllocator _alloc;
|
||||
};
|
||||
|
@ -40,17 +40,19 @@ namespace Far {
|
||||
// Proto-stencil Pool Allocator classes
|
||||
//
|
||||
// Strategy: allocate up-front a data pool for supporting PROTOSTENCILS of a size
|
||||
// slightly above average. For the (rare) BIG_PROTOSTENCILS that require more support
|
||||
// vertices, switch to (slow) heap allocation.
|
||||
// (maxsize) slightly above average. For the (rare) BIG_PROTOSTENCILS that
|
||||
// require more support vertices, switch to (slow) heap allocation.
|
||||
//
|
||||
template <typename PROTOSTENCIL, class BIG_PROTOSTENCIL>
|
||||
class Allocator {
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
Allocator(int maxSize, bool interpolateVarying=false) :
|
||||
_maxsize(maxSize), _interpolateVarying(interpolateVarying) { }
|
||||
|
||||
// Returns the number of stencils in the allocator
|
||||
int GetNumStencils() const {
|
||||
return (int)_sizes.size();
|
||||
}
|
||||
@ -64,6 +66,8 @@ public:
|
||||
return nverts;
|
||||
}
|
||||
|
||||
// Returns true if the pool allocator executes AddVaryingWithWeight
|
||||
// factorization
|
||||
bool GetInterpolateVarying() const {
|
||||
return _interpolateVarying;
|
||||
}
|
||||
@ -81,10 +85,10 @@ public:
|
||||
|
||||
// Adds the contribution of a supporting vertex that was not yet
|
||||
// in the stencil
|
||||
void PushBackVertex(Index stencil, Index vert, float weight) {
|
||||
void PushBackVertex(Index protoStencil, Index vert, float weight) {
|
||||
assert(weight!=0.0f);
|
||||
unsigned char & size = _sizes[stencil];
|
||||
Index idx = stencil*_maxsize;
|
||||
unsigned char & size = _sizes[protoStencil];
|
||||
Index idx = protoStencil*_maxsize;
|
||||
if (size < (_maxsize-1)) {
|
||||
idx += size;
|
||||
_indices[idx] = vert;
|
||||
@ -93,11 +97,11 @@ public:
|
||||
BIG_PROTOSTENCIL * dst = 0;
|
||||
if (size==(_maxsize-1)) {
|
||||
dst = new BIG_PROTOSTENCIL(size, &_indices[idx], &_weights[idx]);
|
||||
assert(_bigStencils.find(stencil)==_bigStencils.end());
|
||||
_bigStencils[stencil] = dst;
|
||||
assert(_bigStencils.find(protoStencil)==_bigStencils.end());
|
||||
_bigStencils[protoStencil] = dst;
|
||||
} else {
|
||||
assert(_bigStencils.find(stencil)!=_bigStencils.end());
|
||||
dst = _bigStencils[stencil];
|
||||
assert(_bigStencils.find(protoStencil)!=_bigStencils.end());
|
||||
dst = _bigStencils[protoStencil];
|
||||
}
|
||||
dst->_indices.push_back(vert);
|
||||
dst->_weights.push_back(weight);
|
||||
@ -105,14 +109,11 @@ public:
|
||||
++size;
|
||||
}
|
||||
|
||||
unsigned char GetSize(Index stencil) const {
|
||||
assert(stencil<(int)_sizes.size());
|
||||
return _sizes[stencil];
|
||||
}
|
||||
|
||||
Index FindVertex(Index stencil, Index vert) {
|
||||
int size = _sizes[stencil];
|
||||
Index const * indices = GetIndices(stencil);
|
||||
// Returns the local index in 'stencil' of a given vertex index, or
|
||||
// INDEX_INVALID if the stencil does not contain this vertex
|
||||
int FindVertex(Index protoStencil, Index vert) {
|
||||
int size = _sizes[protoStencil];
|
||||
Index const * indices = GetIndices(protoStencil);
|
||||
for (int i=0; i<size; ++i) {
|
||||
if (indices[i]==vert) {
|
||||
return i;
|
||||
@ -121,82 +122,102 @@ public:
|
||||
return Vtr::INDEX_INVALID;
|
||||
}
|
||||
|
||||
bool IsBigStencil(Index stencil) const {
|
||||
assert(stencil<(int)_sizes.size());
|
||||
return _sizes[stencil]>=_maxsize;
|
||||
// Returns true of the stencil does not fit in the pool allocator and
|
||||
// has been moved to the 'big' (slow) allocation pool
|
||||
bool IsBigStencil(Index protoStencil) const {
|
||||
assert(protoStencil<(int)_sizes.size());
|
||||
return _sizes[protoStencil]>=_maxsize;
|
||||
}
|
||||
|
||||
Index * GetIndices(Index stencil) {
|
||||
if (not IsBigStencil(stencil)) {
|
||||
return &_indices[stencil*_maxsize];
|
||||
// Returns the size of a given proto-stencil
|
||||
unsigned char GetSize(Index protoStencil) const {
|
||||
assert(protoStencil<(int)_sizes.size());
|
||||
return _sizes[protoStencil];
|
||||
}
|
||||
|
||||
// Resolve memory pool and return a pointer to the indices of a given
|
||||
// proto-stencil
|
||||
Index * GetIndices(Index protoStencil) {
|
||||
if (not IsBigStencil(protoStencil)) {
|
||||
return &_indices[protoStencil*_maxsize];
|
||||
} else {
|
||||
assert(_bigStencils.find(stencil)!=_bigStencils.end());
|
||||
return &_bigStencils[stencil]->_indices[0];
|
||||
assert(_bigStencils.find(protoStencil)!=_bigStencils.end());
|
||||
return &_bigStencils[protoStencil]->_indices[0];
|
||||
}
|
||||
}
|
||||
|
||||
float * GetWeights(Index stencil) {
|
||||
if (not IsBigStencil(stencil)) {
|
||||
return &_weights[stencil*_maxsize];
|
||||
// Resolve memory pool and return a pointer to the weights of a given
|
||||
// proto-stencil
|
||||
float * GetWeights(Index protoStencil) {
|
||||
if (not IsBigStencil(protoStencil)) {
|
||||
return &_weights[protoStencil*_maxsize];
|
||||
} else {
|
||||
assert(_bigStencils.find(stencil)!=_bigStencils.end());
|
||||
return &_bigStencils[stencil]->_weights[0];
|
||||
assert(_bigStencils.find(protoStencil)!=_bigStencils.end());
|
||||
return &_bigStencils[protoStencil]->_weights[0];
|
||||
}
|
||||
}
|
||||
|
||||
PROTOSTENCIL operator[] (Index i) {
|
||||
// Returns the proto-stencil at a given index
|
||||
PROTOSTENCIL operator[] (Index protoStencil) {
|
||||
// If the allocator is empty, AddWithWeight() expects a coarse control
|
||||
// vertex instead of a stencil and we only need to pass the index
|
||||
return PROTOSTENCIL(i, this->GetNumStencils()>0 ? this : 0);
|
||||
return PROTOSTENCIL(protoStencil, this->GetNumStencils()>0 ? this : 0);
|
||||
}
|
||||
|
||||
PROTOSTENCIL operator[] (Index i) const {
|
||||
// Returns the proto-stencil at a given index
|
||||
PROTOSTENCIL operator[] (Index protoStencil) const {
|
||||
// If the allocator is empty, AddWithWeight() expects a coarse control
|
||||
// vertex instead of a stencil and we only need to pass the index
|
||||
return PROTOSTENCIL(i, this->GetNumStencils()>0 ?
|
||||
return PROTOSTENCIL(protoStencil, this->GetNumStencils()>0 ?
|
||||
const_cast<Allocator<PROTOSTENCIL, BIG_PROTOSTENCIL> *>(this) : 0);
|
||||
}
|
||||
|
||||
void ClearStencil(Index stencil) {
|
||||
memset(GetWeights(stencil), 0, _sizes[stencil]*sizeof(float));
|
||||
}
|
||||
|
||||
unsigned char CopyStencil(Index i, Index * indices, float * weights) {
|
||||
unsigned char size = GetSize(i);
|
||||
memcpy(indices, this->GetIndices(i), size*sizeof(Index));
|
||||
memcpy(weights, this->GetWeights(i), size*sizeof(float));
|
||||
// Copy the proto-stencil out of the pool
|
||||
unsigned char CopyStencil(Index protoStencil,
|
||||
Index * indices, float * weights) {
|
||||
unsigned char size = GetSize(protoStencil);
|
||||
memcpy(indices, this->GetIndices(protoStencil), size*sizeof(Index));
|
||||
memcpy(weights, this->GetWeights(protoStencil), size*sizeof(float));
|
||||
return size;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// delete 'slow' memory pool
|
||||
void clearBigStencils() {
|
||||
typename BigStencilMap::iterator it;
|
||||
for (it=_bigStencils.begin(); it!=_bigStencils.end(); ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
_bigStencils.clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
int _maxsize;
|
||||
int _maxsize; // max size of stencil that fits in the 'fast' pool
|
||||
|
||||
bool _interpolateVarying;
|
||||
bool _interpolateVarying; // true for varying interpolation
|
||||
|
||||
std::vector<unsigned char> _sizes;
|
||||
std::vector<unsigned char> _sizes; // 'fast' memory pool
|
||||
std::vector<int> _indices;
|
||||
std::vector<float> _weights;
|
||||
|
||||
typedef std::map<int, BIG_PROTOSTENCIL *> BigStencilMap;
|
||||
BigStencilMap _bigStencils;
|
||||
BigStencilMap _bigStencils; // 'slow' memory pool
|
||||
};
|
||||
|
||||
//
|
||||
// Specialization of the Allocator for stencils with tangents that require
|
||||
// additional derivative weights.
|
||||
//
|
||||
template <typename PROTOSTENCIL, class BIG_PROTOSTENCIL>
|
||||
class LimitAllocator : public Allocator<PROTOSTENCIL, BIG_PROTOSTENCIL> {
|
||||
|
||||
public:
|
||||
|
||||
LimitAllocator(int maxSize) : Allocator<PROTOSTENCIL, BIG_PROTOSTENCIL>(maxSize) { }
|
||||
// Constructor
|
||||
LimitAllocator(int maxSize) :
|
||||
Allocator<PROTOSTENCIL, BIG_PROTOSTENCIL>(maxSize) { }
|
||||
|
||||
void Resize(int size) {
|
||||
Allocator<PROTOSTENCIL, BIG_PROTOSTENCIL>::Resize(size);
|
||||
@ -205,11 +226,11 @@ public:
|
||||
_tan2Weights.resize(nelems);
|
||||
}
|
||||
|
||||
void PushBackVertex(Index stencil,
|
||||
void PushBackVertex(Index protoStencil,
|
||||
Index vert, float weight, float tan1Weight, float tan2Weight) {
|
||||
assert(weight!=0.0f);
|
||||
unsigned char & size = this->_sizes[stencil];
|
||||
Index idx = stencil*this->_maxsize;
|
||||
unsigned char & size = this->_sizes[protoStencil];
|
||||
Index idx = protoStencil*this->_maxsize;
|
||||
if (size < (this->_maxsize-1)) {
|
||||
idx += size;
|
||||
this->_indices[idx] = vert;
|
||||
@ -219,13 +240,14 @@ public:
|
||||
} else {
|
||||
BIG_PROTOSTENCIL * dst = 0;
|
||||
if (size==(this->_maxsize-1)) {
|
||||
dst = new BIG_PROTOSTENCIL(size, &this->_indices[idx],
|
||||
&this->_weights[idx], &this->_tan1Weights[idx], &this->_tan2Weights[idx]);
|
||||
assert(this->_bigStencils.find(stencil)==this->_bigStencils.end());
|
||||
this->_bigStencils[stencil] = dst;
|
||||
dst = new BIG_PROTOSTENCIL(size,
|
||||
&this->_indices[idx], &this->_weights[idx],
|
||||
&this->_tan1Weights[idx], &this->_tan2Weights[idx]);
|
||||
assert(this->_bigStencils.find(protoStencil)==this->_bigStencils.end());
|
||||
this->_bigStencils[protoStencil] = dst;
|
||||
} else {
|
||||
assert(this->_bigStencils.find(stencil)!=this->_bigStencils.end());
|
||||
dst = this->_bigStencils[stencil];
|
||||
assert(this->_bigStencils.find(protoStencil)!=this->_bigStencils.end());
|
||||
dst = this->_bigStencils[protoStencil];
|
||||
}
|
||||
dst->_indices.push_back(vert);
|
||||
dst->_weights.push_back(weight);
|
||||
@ -235,41 +257,42 @@ public:
|
||||
++size;
|
||||
}
|
||||
|
||||
float * GetTan1Weights(Index stencil) {
|
||||
if (not this->IsBigStencil(stencil)) {
|
||||
return &_tan1Weights[stencil*this->_maxsize];
|
||||
float * GetTan1Weights(Index protoStencil) {
|
||||
if (not this->IsBigStencil(protoStencil)) {
|
||||
return &_tan1Weights[protoStencil*this->_maxsize];
|
||||
} else {
|
||||
assert(this->_bigStencils.find(stencil)!=this->_bigStencils.end());
|
||||
return &this->_bigStencils[stencil]->_tan1Weights[0];
|
||||
assert(this->_bigStencils.find(protoStencil)!=this->_bigStencils.end());
|
||||
return &this->_bigStencils[protoStencil]->_tan1Weights[0];
|
||||
}
|
||||
}
|
||||
|
||||
float * GetTan2Weights(Index stencil) {
|
||||
if (not this->IsBigStencil(stencil)) {
|
||||
return &_tan2Weights[stencil*this->_maxsize];
|
||||
float * GetTan2Weights(Index protoStencil) {
|
||||
if (not this->IsBigStencil(protoStencil)) {
|
||||
return &_tan2Weights[protoStencil*this->_maxsize];
|
||||
} else {
|
||||
assert(this->_bigStencils.find(stencil)!=this->_bigStencils.end());
|
||||
return &this->_bigStencils[stencil]->_tan2Weights[0];
|
||||
assert(this->_bigStencils.find(protoStencil)!=this->_bigStencils.end());
|
||||
return &this->_bigStencils[protoStencil]->_tan2Weights[0];
|
||||
}
|
||||
}
|
||||
|
||||
PROTOSTENCIL operator[] (Index i) {
|
||||
PROTOSTENCIL operator[] (Index protoStencil) {
|
||||
assert(this->GetNumStencils()>0);
|
||||
return PROTOSTENCIL(i, this);
|
||||
return PROTOSTENCIL(protoStencil, this);
|
||||
}
|
||||
|
||||
void ClearStencil(Index stencil) {
|
||||
Allocator<PROTOSTENCIL, BIG_PROTOSTENCIL>::ClearStencil(stencil);
|
||||
memset(GetTan1Weights(stencil), 0, this->_sizes[stencil]*sizeof(float));
|
||||
memset(GetTan2Weights(stencil), 0, this->_sizes[stencil]*sizeof(float));
|
||||
void ClearStencil(Index protoStencil) {
|
||||
Allocator<PROTOSTENCIL, BIG_PROTOSTENCIL>::ClearStencil(protoStencil);
|
||||
memset(GetTan1Weights(protoStencil), 0, this->_sizes[protoStencil]*sizeof(float));
|
||||
memset(GetTan2Weights(protoStencil), 0, this->_sizes[protoStencil]*sizeof(float));
|
||||
}
|
||||
|
||||
unsigned char CopyLimitStencil(Index i, Index * indices,
|
||||
float * weights, float * tan1Weights, float * tan2Weights) {
|
||||
unsigned char CopyLimitStencil(Index protoStencil,
|
||||
Index * indices, float * weights, float * tan1Weights, float * tan2Weights) {
|
||||
unsigned char size =
|
||||
Allocator<PROTOSTENCIL, BIG_PROTOSTENCIL>::CopyStencil(i, indices, weights);
|
||||
memcpy(tan1Weights, this->GetTan1Weights(i), size*sizeof(Index));
|
||||
memcpy(tan2Weights, this->GetTan2Weights(i), size*sizeof(float));
|
||||
Allocator<PROTOSTENCIL, BIG_PROTOSTENCIL>::CopyStencil(
|
||||
protoStencil, indices, weights);
|
||||
memcpy(tan1Weights, this->GetTan1Weights(protoStencil), size*sizeof(Index));
|
||||
memcpy(tan2Weights, this->GetTan2Weights(protoStencil), size*sizeof(float));
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -281,8 +304,8 @@ private:
|
||||
//
|
||||
// 'Big' Proto stencil classes
|
||||
//
|
||||
// When proto-stencils exceed _maxsize, fall back to dynamically
|
||||
// allocated "BigStencils"
|
||||
// When proto-stencils exceed _maxsize, fall back to dynamically allocated
|
||||
// "BigStencils" (with 'Limit' specialization to handle tangents)
|
||||
//
|
||||
struct BigStencil {
|
||||
|
||||
@ -299,9 +322,11 @@ struct BigStencil {
|
||||
};
|
||||
struct BigLimitStencil : public BigStencil {
|
||||
|
||||
BigLimitStencil(unsigned char size, Index const * indices,
|
||||
float const * weights, float const * tan1Weights, float const * tan2Weights) :
|
||||
BigLimitStencil(unsigned char size,
|
||||
Index const * indices, float const * weights,
|
||||
float const * tan1Weights, float const * tan2Weights) :
|
||||
BigStencil(size, indices, weights) {
|
||||
|
||||
_tan1Weights.reserve(size+5); _tan1Weights.resize(size);
|
||||
memcpy(&_tan1Weights.at(0), tan1Weights, size*sizeof(float));
|
||||
_tan2Weights.reserve(size+5); _tan2Weights.resize(size);
|
||||
@ -327,9 +352,11 @@ public:
|
||||
_id(id), _alloc(alloc) { }
|
||||
|
||||
void Clear() {
|
||||
_alloc->ClearStencil(_id);
|
||||
// Clear() can only ever be called on an empty stencil: nothing to do
|
||||
assert(_alloc->GetSize(_id)==0);
|
||||
}
|
||||
|
||||
// Factorize from a proto-stencil allocator
|
||||
void AddWithWeight(ProtoStencil const & src, float weight) {
|
||||
|
||||
if(weight==0.0f) {
|
||||
@ -342,11 +369,54 @@ public:
|
||||
Index const * srcIndices = src._alloc->GetIndices(src._id);
|
||||
float const * srcWeights = src._alloc->GetWeights(src._id);
|
||||
|
||||
addWithWeight(weight, srcSize, srcIndices, srcWeights);
|
||||
} else {
|
||||
// Coarse vertex contribution
|
||||
Index n = _alloc->FindVertex(_id, src._id);
|
||||
if (Vtr::IndexIsValid(n)) {
|
||||
_alloc->GetWeights(_id)[n] += weight;
|
||||
assert(_alloc->GetWeights(_id)[n]>0.0f);
|
||||
} else {
|
||||
_alloc->PushBackVertex(_id, src._id, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Factorize from a finished stencil table
|
||||
void AddWithWeight(StencilTables const & table, Index idx, float weight) {
|
||||
|
||||
assert(idx<table.GetNumStencils());
|
||||
|
||||
if(weight==0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char srcSize = table.GetSizes()[idx];
|
||||
Index offset = table.GetOffsets()[idx];
|
||||
Index const * srcIndices = &table.GetControlIndices()[offset];
|
||||
float const * srcWeights = &table.GetWeights()[offset];
|
||||
|
||||
addWithWeight(weight, srcSize, srcIndices, srcWeights);
|
||||
}
|
||||
|
||||
void AddVaryingWithWeight(ProtoStencil const & src, float weight) {
|
||||
if (_alloc->GetInterpolateVarying()) {
|
||||
AddWithWeight(src, weight);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
friend class ProtoLimitStencil;
|
||||
|
||||
void addWithWeight(float weight, unsigned char srcSize,
|
||||
Index const * srcIndices, float const * srcWeights) {
|
||||
|
||||
for (unsigned char i=0; i<srcSize; ++i) {
|
||||
|
||||
assert(srcWeights[i]!=0.0f);
|
||||
float w = weight * srcWeights[i];
|
||||
|
||||
float w = weight * srcWeights[i];
|
||||
if (w==0.0f) {
|
||||
continue;
|
||||
}
|
||||
@ -360,27 +430,7 @@ public:
|
||||
_alloc->PushBackVertex(_id, vertIndex, w);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Coarse vertex contribution
|
||||
Index n = _alloc->FindVertex(_id, src._id);
|
||||
if (Vtr::IndexIsValid(n)) {
|
||||
_alloc->GetWeights(_id)[n] += weight;
|
||||
assert(_alloc->GetWeights(_id)[n]>0.0f);
|
||||
} else {
|
||||
_alloc->PushBackVertex(_id, src._id, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddVaryingWithWeight(ProtoStencil const & src, float weight) {
|
||||
if (_alloc->GetInterpolateVarying()) {
|
||||
AddWithWeight(src, weight);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
friend class ProtoLimitStencil;
|
||||
|
||||
Index _id;
|
||||
Allocator<ProtoStencil, BigStencil> * _alloc;
|
||||
@ -395,12 +445,14 @@ typedef Allocator<ProtoStencil, BigStencil> StencilAllocator;
|
||||
class ProtoLimitStencil {
|
||||
|
||||
public:
|
||||
|
||||
ProtoLimitStencil(Index id,
|
||||
LimitAllocator<ProtoLimitStencil, BigLimitStencil> * alloc) :
|
||||
_id(id), _alloc(alloc) { }
|
||||
|
||||
void Clear() {
|
||||
_alloc->ClearStencil(_id);
|
||||
// Clear() can only ever be called on an empty stencil: nothing to do
|
||||
assert(_alloc->GetSize(_id)==0);
|
||||
}
|
||||
|
||||
void AddWithWeight(Stencil const & src,
|
||||
|
@ -100,6 +100,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class GregoryBasisFactory;
|
||||
friend class StencilTablesFactory;
|
||||
friend class LimitStencilTablesFactory;
|
||||
|
||||
@ -135,7 +136,7 @@ public:
|
||||
}
|
||||
|
||||
/// \brief Returns a Stencil at index i in the tables
|
||||
Stencil GetStencil(int i) const;
|
||||
Stencil GetStencil(Index i) const;
|
||||
|
||||
/// \brief Returns the number of control vertices of each stencil in the table
|
||||
std::vector<unsigned char> const & GetSizes() const {
|
||||
@ -158,12 +159,12 @@ public:
|
||||
}
|
||||
|
||||
/// \brief Returns the stencil at index i in the tables
|
||||
Stencil operator[] (int index) const;
|
||||
Stencil operator[] (Index index) const;
|
||||
|
||||
/// \brief Updates point values based on the control values
|
||||
///
|
||||
/// \note The destination buffers ('uderivs' & 'vderivs') are assumed to
|
||||
/// have allocated at least \c GetNumStencils() elements.
|
||||
/// \note The destination buffers are assumed to have allocated at least
|
||||
/// \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param controlValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
@ -175,7 +176,7 @@ public:
|
||||
/// @param end Index of last value to update
|
||||
///
|
||||
template <class T>
|
||||
void UpdateValues(T const *controlValues, T *values, int start=-1, int end=-1) const {
|
||||
void UpdateValues(T const *controlValues, T *values, Index start=-1, Index end=-1) const {
|
||||
|
||||
update(controlValues, values, _weights, start, end);
|
||||
}
|
||||
@ -193,7 +194,7 @@ protected:
|
||||
|
||||
// Update values by appling cached stencil weights to new control values
|
||||
template <class T> void update( T const *controlValues, T *values,
|
||||
std::vector<float> const & valueWeights, int start, int end) const;
|
||||
std::vector<float> const & valueWeights, Index start, Index end) const;
|
||||
|
||||
// Populate the offsets table from the stencil sizes in _sizes (factory helper)
|
||||
void generateOffsets();
|
||||
@ -204,6 +205,7 @@ protected:
|
||||
protected:
|
||||
|
||||
friend class StencilTablesFactory;
|
||||
friend class GregoryBasisFactory;
|
||||
|
||||
int _numControlVertices; // number of control vertices
|
||||
|
||||
@ -335,7 +337,7 @@ private:
|
||||
// Update values by appling cached stencil weights to new control values
|
||||
template <class T> void
|
||||
StencilTables::update(T const *controlValues, T *values,
|
||||
std::vector<float> const &valueWeights, int start, int end) const {
|
||||
std::vector<float> const &valueWeights, Index start, Index end) const {
|
||||
|
||||
unsigned char const * sizes = &_sizes.at(0);
|
||||
Index const * indices = &_indices.at(0);
|
||||
@ -387,7 +389,7 @@ StencilTables::resize(int nstencils, int nelems) {
|
||||
|
||||
// Returns a Stencil at index i in the table
|
||||
inline Stencil
|
||||
StencilTables::GetStencil(int i) const {
|
||||
StencilTables::GetStencil(Index i) const {
|
||||
|
||||
assert((not _offsets.empty()) and i<(int)_offsets.size());
|
||||
|
||||
@ -399,7 +401,7 @@ StencilTables::GetStencil(int i) const {
|
||||
}
|
||||
|
||||
inline Stencil
|
||||
StencilTables::operator[] (int index) const {
|
||||
StencilTables::operator[] (Index index) const {
|
||||
return GetStencil(index);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user