2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
// Copyright 2014 DreamWorks Animation LLC.
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "../far/stencilTablesFactory.h"
|
2014-10-02 23:09:17 +00:00
|
|
|
#include "../far/patchTablesFactory.h"
|
2014-09-12 23:59:16 +00:00
|
|
|
#include "../far/patchMap.h"
|
|
|
|
#include "../far/stencilTables.h"
|
2014-09-05 22:07:46 +00:00
|
|
|
#include "../far/topologyRefiner.h"
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstdio>
|
|
|
|
#include <cstring>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
class ProtoStencilAllocator;
|
|
|
|
|
2014-10-09 23:36:23 +00:00
|
|
|
typedef OpenSubdiv::Far::Index Index;
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
//------------------------------------------------------------------------------
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
//
|
2014-09-12 23:59:16 +00:00
|
|
|
// ProtoStencil
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2014-09-12 23:59:16 +00:00
|
|
|
// ProtoStencils are used to interpolate stencils from supporting vertices.
|
|
|
|
// These stencils are backed by a pool allocator (ProtoStencilAllocator) to
|
|
|
|
// allow for fast push-back of additional vertex weights & indices.
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2014-09-12 23:59:16 +00:00
|
|
|
class ProtoStencil {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
// Return stencil unique ID in pool allocator
|
2014-10-09 23:36:23 +00:00
|
|
|
Index GetID() const {
|
2014-09-05 22:07:46 +00:00
|
|
|
return _ID;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set stencil weights to 0.0
|
|
|
|
void Clear();
|
|
|
|
|
|
|
|
// Weighted add for coarse vertices (size=1, weight=1.0f)
|
|
|
|
void AddWithWeight(int, float weight);
|
|
|
|
|
|
|
|
// Weighted add of a Stencil
|
2014-09-12 23:59:16 +00:00
|
|
|
void AddWithWeight(ProtoStencil const & src, float weight);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// Weighted add for coarse vertices (size=1, weight=1.0f)
|
|
|
|
void AddVaryingWithWeight(int, float);
|
|
|
|
|
|
|
|
// Weighted add of a Stencil
|
2014-09-12 23:59:16 +00:00
|
|
|
void AddVaryingWithWeight(ProtoStencil const &, float);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// Returns the current size of the Stencil
|
|
|
|
int GetSize() const;
|
|
|
|
|
|
|
|
// Returns a pointer to the vertex indices of the stencil
|
2014-10-09 23:36:23 +00:00
|
|
|
Index const * GetIndices() const;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// Returns a pointer to the vertex weights of the stencil
|
|
|
|
float const * GetWeights() const;
|
|
|
|
|
|
|
|
// Debug output
|
|
|
|
void Print() const;
|
|
|
|
|
|
|
|
// Comparison operator to sort stencils by size
|
2014-09-12 23:59:16 +00:00
|
|
|
static bool CompareSize(ProtoStencil const & a, ProtoStencil const & b) {
|
2014-09-05 22:07:46 +00:00
|
|
|
return (a.GetSize() < b.GetSize());
|
|
|
|
}
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
protected:
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
friend class ProtoStencilAllocator;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// Returns the location of vertex 'vertex' in the stencil indices or -1
|
2014-10-09 23:36:23 +00:00
|
|
|
Index findVertex(Index vertex);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
protected:
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-10-09 23:36:23 +00:00
|
|
|
Index _ID; // Stencil ID in allocator
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencilAllocator * _alloc; // Pool allocator
|
2014-09-05 22:07:46 +00:00
|
|
|
};
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
typedef std::vector<ProtoStencil> ProtoStencilVec;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
//
|
|
|
|
// ProtoLimitStencil
|
|
|
|
//
|
|
|
|
// ProtoStencil class extended to support interpolation of derivatives.
|
|
|
|
//
|
|
|
|
class ProtoLimitStencil : public ProtoStencil {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
typedef OpenSubdiv::Far::Stencil Stencil;
|
|
|
|
|
|
|
|
// Returns a pointer to the vertex U derivative weights of the stencil
|
|
|
|
float const * GetDuWeights() const;
|
|
|
|
|
|
|
|
// Returns a pointer to the vertex U derivative weights of the stencil
|
|
|
|
float const * GetDvWeights() const;
|
|
|
|
|
|
|
|
// Set stencil weights to 0.0
|
|
|
|
void Clear();
|
|
|
|
|
|
|
|
// Weighted add of a LimitStencil
|
|
|
|
void AddWithWeight(Stencil const & src, float w, float wDu, float wDv);
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::vector<ProtoLimitStencil> ProtoLimitStencilVec;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Stencil pool allocator
|
|
|
|
//
|
|
|
|
// Strategy: allocate up-front a data pool for supporting stencils of a size
|
|
|
|
// slightly above average. For the (rare) stencils that require more support
|
|
|
|
// vertices, switch to (slow) heap allocation.
|
|
|
|
//
|
2014-09-12 23:59:16 +00:00
|
|
|
class ProtoStencilAllocator {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
enum Mode {
|
|
|
|
INTERPOLATE_VERTEX,
|
|
|
|
INTERPOLATE_VARYING,
|
|
|
|
INTERPOLATE_LIMITS,
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef OpenSubdiv::Far::TopologyRefiner TopologyRefiner;
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
// Constructor
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencilAllocator(TopologyRefiner const & refiner, Mode mode);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// Destructor
|
2014-09-12 23:59:16 +00:00
|
|
|
~ProtoStencilAllocator() ;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// Returns an array of all the Stencils in the allocator
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencilVec & GetStencils() {
|
2014-09-05 22:07:46 +00:00
|
|
|
return _stencils;
|
|
|
|
}
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
// Returns an array of all the Stencils in the allocator
|
|
|
|
ProtoLimitStencilVec & GetLimitStencils() {
|
|
|
|
return reinterpret_cast<ProtoLimitStencilVec &>(_stencils);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the stencil interpolation mode
|
|
|
|
Mode GetMode() const {
|
|
|
|
return _mode;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Append a support vertex of index 'index' and weight 'weight' to the
|
|
|
|
// Stencil 'stencil' (use findVertex() to make sure it does not exist
|
|
|
|
// yet)
|
2014-10-09 23:36:23 +00:00
|
|
|
void PushBackVertex(ProtoStencil & stencil, Index index, float weight);
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
// Append a support vertex of index 'index' and weight 'weight' to the
|
|
|
|
// LimitStencil 'stencil' (use findVertex() to make sure it does not exist
|
|
|
|
// yet)
|
2014-10-09 23:36:23 +00:00
|
|
|
void PushBackVertex(ProtoLimitStencil & stencil, Index index,
|
2014-09-12 23:59:16 +00:00
|
|
|
float weight, float duweight, float dvweight);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// Allocate enough memory to hold 'numStencils' Stencils
|
|
|
|
void Resize(int numStencils);
|
|
|
|
|
|
|
|
// Returns the number of stencil vertices that have been pushed back
|
|
|
|
int GetNumVertices() const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
friend class ProtoStencil;
|
|
|
|
friend class ProtoLimitStencil;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// returns the size of the stencil
|
2014-10-09 23:36:23 +00:00
|
|
|
unsigned char * getSize(Index stencilID) {
|
2014-09-12 23:59:16 +00:00
|
|
|
assert(stencilID<(int)_sizes.size());
|
|
|
|
return &_sizes[stencilID];
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// returns the indices of the stencil
|
2014-10-09 23:36:23 +00:00
|
|
|
Index * getIndices(Index stencilID) {
|
2014-09-12 23:59:16 +00:00
|
|
|
if (*getSize(stencilID)<_maxsize) {
|
|
|
|
return &_indices[stencilID*_maxsize];
|
2014-09-05 22:07:46 +00:00
|
|
|
} else {
|
2014-09-12 23:59:16 +00:00
|
|
|
if (GetMode()==INTERPOLATE_LIMITS) {
|
|
|
|
return &_biglimitstencils[stencilID]->indices[0];
|
|
|
|
} else {
|
|
|
|
return &_bigstencils[stencilID]->indices[0];
|
|
|
|
}
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns the weights of the stencil
|
2014-10-09 23:36:23 +00:00
|
|
|
float * getWeights(Index stencilID) {
|
2014-09-12 23:59:16 +00:00
|
|
|
if (*getSize(stencilID)<_maxsize) {
|
|
|
|
return &_weights[stencilID*_maxsize];
|
|
|
|
} else {
|
|
|
|
if (GetMode()==INTERPOLATE_LIMITS) {
|
|
|
|
return &_biglimitstencils[stencilID]->weights[0];
|
|
|
|
} else {
|
|
|
|
return &_bigstencils[stencilID]->weights[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns the U derivative weights of the stencil
|
2014-10-09 23:36:23 +00:00
|
|
|
float * getDuWeights(Index stencilID) {
|
2014-09-12 23:59:16 +00:00
|
|
|
assert(GetMode()==INTERPOLATE_LIMITS);
|
|
|
|
if (*getSize(stencilID)<_maxsize) {
|
|
|
|
return &_duWeights[stencilID*_maxsize];
|
2014-09-05 22:07:46 +00:00
|
|
|
} else {
|
2014-09-12 23:59:16 +00:00
|
|
|
return &_biglimitstencils[stencilID]->duWeights[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns the V derivative weights of the stencil
|
2014-10-09 23:36:23 +00:00
|
|
|
float * getDvWeights(Index stencilID) {
|
2014-09-12 23:59:16 +00:00
|
|
|
assert(GetMode()==INTERPOLATE_LIMITS);
|
|
|
|
if (*getSize(stencilID)<_maxsize) {
|
|
|
|
return &_dvWeights[stencilID*_maxsize];
|
|
|
|
} else {
|
|
|
|
return &_biglimitstencils[stencilID]->dvWeights[0];
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
Mode _mode;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
int _maxsize; // maximum size of a pre-allocated stencil
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencilVec _stencils;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
std::vector<unsigned char> _sizes; // temp stencils data (as SOA)
|
2014-10-09 23:36:23 +00:00
|
|
|
std::vector<Index> _indices;
|
2014-09-05 22:07:46 +00:00
|
|
|
std::vector<float> _weights;
|
2014-09-12 23:59:16 +00:00
|
|
|
std::vector<float> _duWeights;
|
|
|
|
std::vector<float> _dvWeights;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
//
|
|
|
|
// When proto-stencils exceed _maxsize, fall back to heap allocated
|
|
|
|
// "BigStencils"
|
|
|
|
//
|
2014-09-05 22:07:46 +00:00
|
|
|
struct BigStencil {
|
|
|
|
|
2014-10-09 23:36:23 +00:00
|
|
|
BigStencil(int size, Index const * iindices, float const * iweights) {
|
2014-09-05 22:07:46 +00:00
|
|
|
indices.reserve(size+5); indices.resize(size);
|
|
|
|
weights.reserve(size+5); weights.resize(size);
|
|
|
|
memcpy(&indices.at(0), iindices, size*sizeof(int) );
|
|
|
|
memcpy(&weights.at(0), iweights, size*sizeof(int) );
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<int> indices;
|
|
|
|
std::vector<float> weights;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::map<int, BigStencil *> BigStencilMap;
|
|
|
|
|
|
|
|
BigStencilMap _bigstencils;
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Same as "BigStencil", except with limit derivatives
|
|
|
|
//
|
|
|
|
struct BigLimitStencil : public BigStencil {
|
|
|
|
|
2014-10-09 23:36:23 +00:00
|
|
|
BigLimitStencil(int size, Index const * iindices, float const * iweights,
|
2014-09-12 23:59:16 +00:00
|
|
|
float const * iduWeights, float const * idvWeights) :
|
|
|
|
BigStencil(size, iindices, iweights) {
|
|
|
|
|
|
|
|
duWeights.reserve(size+10); duWeights.resize(size);
|
|
|
|
dvWeights.reserve(size+10); dvWeights.resize(size);
|
|
|
|
|
|
|
|
memcpy(&duWeights.at(0), iduWeights, size*sizeof(int) );
|
|
|
|
memcpy(&dvWeights.at(0), idvWeights, size*sizeof(int) );
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<float> duWeights,
|
|
|
|
dvWeights;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::map<int, BigLimitStencil *> BigLimitStencilMap;
|
|
|
|
|
|
|
|
BigLimitStencilMap _biglimitstencils;
|
2014-09-05 22:07:46 +00:00
|
|
|
};
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
// Constructor
|
|
|
|
ProtoStencilAllocator::ProtoStencilAllocator(
|
|
|
|
TopologyRefiner const & refiner, Mode mode) : _mode(mode) {
|
|
|
|
|
|
|
|
using namespace OpenSubdiv;
|
|
|
|
|
|
|
|
// Make an educated guess as to what the max size should be
|
|
|
|
switch (mode) {
|
|
|
|
case INTERPOLATE_VERTEX : {
|
|
|
|
Sdc::Type type = refiner.GetSchemeType();
|
|
|
|
switch (type) {
|
|
|
|
case Sdc::TYPE_BILINEAR : _maxsize = 5; break;
|
|
|
|
case Sdc::TYPE_CATMARK : _maxsize = 17; break;
|
|
|
|
case Sdc::TYPE_LOOP : _maxsize = 10; break;
|
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
case INTERPOLATE_VARYING : _maxsize = 5; break;
|
|
|
|
case INTERPOLATE_LIMITS : _maxsize = 17; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destructor
|
|
|
|
ProtoStencilAllocator::~ProtoStencilAllocator() {
|
|
|
|
|
|
|
|
|
|
|
|
for (BigStencilMap::iterator it=_bigstencils.begin();
|
|
|
|
it!=_bigstencils.end(); ++it) {
|
|
|
|
|
|
|
|
delete it->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (BigLimitStencilMap::iterator it=_biglimitstencils.begin();
|
|
|
|
it!=_biglimitstencils.end(); ++it) {
|
|
|
|
|
|
|
|
delete it->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate enough memory to hold 'numStencils' Stencils
|
|
|
|
void
|
|
|
|
ProtoStencilAllocator::Resize(int numStencils) {
|
|
|
|
|
|
|
|
int currentSize = (int)_stencils.size();
|
|
|
|
|
|
|
|
// Pre-allocate the Stencils
|
|
|
|
_stencils.resize(numStencils);
|
|
|
|
|
2014-10-09 23:36:23 +00:00
|
|
|
for (Index i=currentSize; i<numStencils; ++i) {
|
2014-09-12 23:59:16 +00:00
|
|
|
_stencils[i]._ID = i;
|
|
|
|
_stencils[i]._alloc = this;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nelems = numStencils * _maxsize;
|
|
|
|
_sizes.clear();
|
|
|
|
_sizes.resize(numStencils);
|
|
|
|
_indices.resize(nelems);
|
|
|
|
_weights.resize(nelems);
|
|
|
|
if (_mode==INTERPOLATE_LIMITS) {
|
|
|
|
_duWeights.resize(nelems);
|
|
|
|
_dvWeights.resize(nelems);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (BigStencilMap::iterator it=_bigstencils.begin();
|
|
|
|
it!=_bigstencils.end(); ++it) {
|
|
|
|
|
|
|
|
delete it->second;
|
|
|
|
}
|
|
|
|
_bigstencils.clear();
|
|
|
|
|
|
|
|
for (BigLimitStencilMap::iterator it=_biglimitstencils.begin();
|
|
|
|
it!=_biglimitstencils.end(); ++it) {
|
|
|
|
|
|
|
|
delete it->second;
|
|
|
|
}
|
|
|
|
_biglimitstencils.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append a support vertex of index 'index' and weight 'weight' to the
|
|
|
|
// Stencil 'stencil' (use findVertex() to make sure it does not exist
|
|
|
|
// yet)
|
|
|
|
void
|
|
|
|
ProtoStencilAllocator::PushBackVertex(
|
2014-10-09 23:36:23 +00:00
|
|
|
ProtoStencil & stencil, Index index, float weight) {
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-09-18 00:53:38 +00:00
|
|
|
assert(weight!=0.0f);
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
unsigned char * size = getSize(stencil.GetID());
|
2014-10-09 23:36:23 +00:00
|
|
|
Index * indices = getIndices(stencil.GetID());
|
2014-09-12 23:59:16 +00:00
|
|
|
float * weights = getWeights(stencil.GetID());
|
|
|
|
|
|
|
|
|
|
|
|
if (*size<(_maxsize-1)) {
|
|
|
|
|
|
|
|
// The stencil still fits in pool memory, just copy the data
|
|
|
|
indices[*size]=index;
|
|
|
|
weights[*size]=weight;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// The stencil is now too big: fall back to heap memory
|
|
|
|
BigStencil * dst=0;
|
|
|
|
|
|
|
|
// Is this stencil already a BigStencil or do we need a new one ?
|
|
|
|
if (*size==(_maxsize-1)) {
|
|
|
|
dst = new BigStencil(*size, indices, weights);
|
|
|
|
assert(_bigstencils.find(stencil.GetID())==_bigstencils.end());
|
|
|
|
_bigstencils[stencil.GetID()]=dst;
|
|
|
|
} else {
|
|
|
|
assert(_bigstencils.find(stencil.GetID())!=_bigstencils.end());
|
|
|
|
dst = _bigstencils[stencil.GetID()];
|
|
|
|
}
|
|
|
|
assert(dst);
|
|
|
|
|
|
|
|
// push back the new vertex
|
|
|
|
dst->indices.push_back(index);
|
|
|
|
dst->weights.push_back(weight);
|
|
|
|
}
|
|
|
|
++(*size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Append a support vertex of index 'index' and weight 'weight' to the
|
|
|
|
// LimitStencil 'stencil' (use findVertex() to make sure it does not exist
|
|
|
|
// yet)
|
|
|
|
void
|
2014-10-09 23:36:23 +00:00
|
|
|
ProtoStencilAllocator::PushBackVertex(ProtoLimitStencil & stencil,
|
|
|
|
Index index, float weight, float duweight, float dvweight) {
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
assert(weight!=0.0f);
|
|
|
|
|
|
|
|
unsigned char * size = getSize(stencil.GetID());
|
2014-10-09 23:36:23 +00:00
|
|
|
Index * indices = getIndices(stencil.GetID());
|
2014-09-12 23:59:16 +00:00
|
|
|
float * weights = getWeights(stencil.GetID()),
|
|
|
|
* duweights = getDuWeights(stencil.GetID()),
|
|
|
|
* dvweights = getDvWeights(stencil.GetID());
|
|
|
|
|
|
|
|
if (*size<(_maxsize-1)) {
|
|
|
|
|
|
|
|
// The stencil still fits in pool memory, just copy the data
|
|
|
|
indices[*size]=index;
|
|
|
|
weights[*size]=weight;
|
|
|
|
duweights[*size]=duweight;
|
|
|
|
dvweights[*size]=dvweight;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// The stencil is now too big: fall back to heap memory
|
|
|
|
BigLimitStencil * dst=0;
|
|
|
|
|
|
|
|
// Is this stencil already a BigLimitStencil or do we need a new one ?
|
|
|
|
if (*size==(_maxsize-1)) {
|
|
|
|
dst = new BigLimitStencil(*size, indices, weights, duweights, dvweights);
|
|
|
|
assert(_biglimitstencils.find(stencil.GetID())==_biglimitstencils.end());
|
|
|
|
_biglimitstencils[stencil.GetID()]=dst;
|
|
|
|
} else {
|
|
|
|
assert(_biglimitstencils.find(stencil.GetID())!=_biglimitstencils.end());
|
|
|
|
dst = _biglimitstencils[stencil.GetID()];
|
|
|
|
}
|
|
|
|
assert(dst);
|
|
|
|
|
|
|
|
// push back the new vertex
|
|
|
|
dst->indices.push_back(index);
|
|
|
|
dst->weights.push_back(weight);
|
|
|
|
dst->duWeights.push_back(duweight);
|
|
|
|
dst->dvWeights.push_back(dvweight);
|
|
|
|
}
|
|
|
|
++(*size);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the number of stencil vertices that have been pushed back
|
|
|
|
int
|
|
|
|
ProtoStencilAllocator::GetNumVertices() const {
|
|
|
|
|
|
|
|
int nverts=0;
|
|
|
|
for (int i=0; i<(int)_stencils.size(); ++i) {
|
|
|
|
nverts+=_stencils[i].GetSize();
|
|
|
|
}
|
|
|
|
return nverts;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the current size of the Stencil
|
|
|
|
int
|
|
|
|
ProtoStencil::GetSize() const {
|
|
|
|
return (int)*_alloc->getSize(this->GetID());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a pointer to the vertex indices of the stencil
|
2014-10-09 23:36:23 +00:00
|
|
|
Index const *
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencil::GetIndices() const {
|
|
|
|
return _alloc->getIndices(this->GetID());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a pointer to the vertex weights of the stencil
|
|
|
|
float const *
|
|
|
|
ProtoStencil::GetWeights() const {
|
|
|
|
return _alloc->getWeights(this->GetID());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a pointer to the vertex weights of the stencil
|
|
|
|
float const *
|
|
|
|
ProtoLimitStencil::GetDuWeights() const {
|
|
|
|
return _alloc->getDuWeights(this->GetID());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a pointer to the vertex weights of the stencil
|
|
|
|
float const *
|
|
|
|
ProtoLimitStencil::GetDvWeights() const {
|
|
|
|
return _alloc->getDvWeights(this->GetID());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Debug dump
|
|
|
|
void
|
|
|
|
ProtoStencil::Print() const {
|
|
|
|
|
|
|
|
printf("tempStencil size=%d indices={ ", GetSize());
|
|
|
|
for (int i=0; i<GetSize(); ++i) {
|
|
|
|
printf("%d ", GetIndices()[i]);
|
|
|
|
}
|
|
|
|
printf("} weights={ ");
|
|
|
|
for (int i=0; i<GetSize(); ++i) {
|
|
|
|
printf("%f ", GetWeights()[i]);
|
|
|
|
}
|
|
|
|
printf("}\n");
|
|
|
|
}
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
// Find the location of vertex 'vertex' in the stencil indices.
|
2014-10-09 23:36:23 +00:00
|
|
|
inline Index
|
|
|
|
ProtoStencil::findVertex(Index vertex) {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
// XXXX manuelk serial search -> we can figure out something better ?
|
|
|
|
unsigned char * size = _alloc->getSize(this->GetID());
|
2014-10-09 23:36:23 +00:00
|
|
|
Index * indices = _alloc->getIndices(this->GetID());
|
2014-09-05 22:07:46 +00:00
|
|
|
for (int i=0; i<*size; ++i) {
|
|
|
|
if (indices[i]==vertex)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set stencil weights to 0.0
|
|
|
|
void
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencil::Clear() {
|
|
|
|
float * weights = _alloc->getWeights(this->GetID());
|
|
|
|
for (int i=0; i<*_alloc->getSize(this->GetID()); ++i) {
|
2014-09-05 22:07:46 +00:00
|
|
|
weights[i]=0.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Weighted add of a coarse vertex
|
|
|
|
inline void
|
2014-10-09 23:36:23 +00:00
|
|
|
ProtoStencil::AddWithWeight(Index vertIndex, float weight) {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
if (weight==0.0f) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-09 23:36:23 +00:00
|
|
|
Index n = findVertex(vertIndex);
|
2014-09-05 22:07:46 +00:00
|
|
|
if (n<0) {
|
|
|
|
_alloc->PushBackVertex(*this, vertIndex, weight);
|
|
|
|
} else {
|
2014-09-12 23:59:16 +00:00
|
|
|
float * dstWeights = _alloc->getWeights(this->GetID());
|
2014-09-05 22:07:46 +00:00
|
|
|
dstWeights[n] += weight;
|
|
|
|
assert(dstWeights[n]>0.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Weighted add of a Stencil
|
|
|
|
inline void
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencil::AddWithWeight(ProtoStencil const & src, float weight) {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
if (weight==0.0f) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
unsigned char const * srcSize = src._alloc->getSize(src.GetID());
|
2014-10-09 23:36:23 +00:00
|
|
|
Index const * srcIndices = src._alloc->getIndices(src.GetID());
|
2014-09-12 23:59:16 +00:00
|
|
|
float const * srcWeights = src._alloc->getWeights(src.GetID());
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
for (int i=0; i<*srcSize; ++i) {
|
|
|
|
|
2014-09-18 00:53:38 +00:00
|
|
|
assert(srcWeights[i]!=0.0f);
|
|
|
|
float w = weight * srcWeights[i];
|
|
|
|
|
|
|
|
if (w==0.0f) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-10-09 23:36:23 +00:00
|
|
|
Index vertIndex = srcIndices[i];
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// Attempt to locate the vertex index in the list of supporting vertices
|
|
|
|
// of the destination stencil.
|
2014-10-09 23:36:23 +00:00
|
|
|
Index n = findVertex(vertIndex);
|
2014-09-05 22:07:46 +00:00
|
|
|
if (n<0) {
|
2014-09-18 00:53:38 +00:00
|
|
|
_alloc->PushBackVertex(*this, vertIndex, w);
|
2014-09-05 22:07:46 +00:00
|
|
|
} else {
|
2014-09-12 23:59:16 +00:00
|
|
|
float * dstWeights = _alloc->getWeights(this->GetID());
|
2014-09-18 00:53:38 +00:00
|
|
|
dstWeights[n] += w;
|
|
|
|
assert(dstWeights[n]!=0.0f);
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2014-10-09 23:36:23 +00:00
|
|
|
ProtoStencil::AddVaryingWithWeight(Index vertIndex, float weight) {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
if (_alloc->GetMode()==ProtoStencilAllocator::INTERPOLATE_VARYING) {
|
2014-09-05 22:07:46 +00:00
|
|
|
AddWithWeight(vertIndex, weight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencil::AddVaryingWithWeight(ProtoStencil const & src, float weight) {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
if (_alloc->GetMode()==ProtoStencilAllocator::INTERPOLATE_VARYING) {
|
2014-09-05 22:07:46 +00:00
|
|
|
AddWithWeight(src, weight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
// Clear ProtoLimitStencil
|
2014-09-13 14:38:12 +00:00
|
|
|
void
|
|
|
|
ProtoLimitStencil::Clear() {
|
|
|
|
float * weights = _alloc->getWeights(this->GetID()),
|
|
|
|
* duweights = _alloc->getDuWeights(this->GetID()),
|
|
|
|
* dvweights = _alloc->getDvWeights(this->GetID());
|
|
|
|
for (int i=0; i<*_alloc->getSize(this->GetID()); ++i) {
|
|
|
|
weights[i]=0.0f;
|
|
|
|
duweights[i]=0.0f;
|
|
|
|
dvweights[i]=0.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
// Weighted add on a ProtoLimitStencil
|
2014-09-12 23:59:16 +00:00
|
|
|
inline void
|
|
|
|
ProtoLimitStencil::AddWithWeight(Stencil const & src,
|
|
|
|
float weight, float duWeight, float dvWeight) {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
if (weight==0.0f) {
|
|
|
|
return;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
unsigned char const * srcSize = src.GetSizePtr();
|
2014-10-09 23:36:23 +00:00
|
|
|
Index const * srcIndices = src.GetVertexIndices();
|
2014-09-12 23:59:16 +00:00
|
|
|
float const * srcWeights = src.GetWeights();
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
for (int i=0; i<*srcSize; ++i) {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-10-09 23:36:23 +00:00
|
|
|
Index vertIndex = srcIndices[i];
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-18 00:53:38 +00:00
|
|
|
float srcWeight = srcWeights[i];
|
|
|
|
|
|
|
|
if (srcWeight==0.0f) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-10-09 23:36:23 +00:00
|
|
|
Index n = findVertex(vertIndex);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
if (n<0) {
|
|
|
|
_alloc->PushBackVertex(*this, vertIndex,
|
2014-09-18 00:53:38 +00:00
|
|
|
weight * srcWeight, duWeight*srcWeight, dvWeight*srcWeight);
|
2014-09-12 23:59:16 +00:00
|
|
|
} else {
|
|
|
|
float * dstWeights = _alloc->getWeights(this->GetID()),
|
|
|
|
* dstDuWeights = _alloc->getDuWeights(this->GetID()),
|
|
|
|
* dstDvWeights = _alloc->getDvWeights(this->GetID());
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-18 00:53:38 +00:00
|
|
|
dstWeights[n] += weight * srcWeight;
|
|
|
|
dstDuWeights[n] += duWeight * srcWeight;
|
|
|
|
dstDvWeights[n] += dvWeight * srcWeight;
|
2014-09-12 23:59:16 +00:00
|
|
|
}
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
2014-09-12 23:59:16 +00:00
|
|
|
}
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
} // end namespace unnamed
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
namespace OpenSubdiv {
|
|
|
|
namespace OPENSUBDIV_VERSION {
|
|
|
|
|
|
|
|
namespace Far {
|
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
static void
|
|
|
|
generateOffsets(std::vector<unsigned char> const & sizes,
|
2014-10-09 23:36:23 +00:00
|
|
|
std::vector<Index> & offsets ) {
|
2014-09-19 00:48:34 +00:00
|
|
|
|
2014-10-09 23:36:23 +00:00
|
|
|
Index offset=0;
|
|
|
|
for (int i=0; i<(int)sizes.size(); ++i ) {
|
2014-09-19 00:48:34 +00:00
|
|
|
//assert(sizes[i]!=0);
|
2014-10-09 23:36:23 +00:00
|
|
|
offsets[i]=offset;
|
|
|
|
offset+=sizes[i];
|
2014-09-19 00:48:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
// Copy a stencil into StencilTables
|
|
|
|
template <> void
|
2014-09-12 23:59:16 +00:00
|
|
|
StencilTablesFactory::copyStencil(ProtoStencil const & src, Stencil & dst) {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
unsigned char size = (unsigned char)src.GetSize();
|
2014-10-09 23:36:23 +00:00
|
|
|
Index const * indices = src.GetIndices();
|
2014-09-05 22:07:46 +00:00
|
|
|
float const * weights = src.GetWeights();
|
|
|
|
|
|
|
|
*dst._size = size;
|
|
|
|
for (unsigned char i=0; i<size; ++i) {
|
|
|
|
memcpy(dst._indices, indices, size*sizeof(int));
|
|
|
|
memcpy(dst._weights, weights, size*sizeof(float));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// (Sort &) Copy a vector of stencils into StencilTables
|
|
|
|
template <> void
|
2014-09-12 23:59:16 +00:00
|
|
|
StencilTablesFactory::copyStencils(ProtoStencilVec & src,
|
2014-09-05 22:07:46 +00:00
|
|
|
Stencil & dst, bool sortBySize) {
|
|
|
|
|
|
|
|
if (sortBySize) {
|
2014-09-12 23:59:16 +00:00
|
|
|
std::sort(src.begin(), src.end(), ProtoStencil::CompareSize);
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i=0; i<(int)src.size(); ++i) {
|
|
|
|
copyStencil(src[i], dst);
|
|
|
|
dst.Next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
void
|
|
|
|
StencilTablesFactory::generateControlVertStencils(
|
|
|
|
int numControlVerts, Stencil & dst) {
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
for (int i=0; i<numControlVerts; ++i) {
|
|
|
|
*dst._size = 1;
|
|
|
|
*dst._indices = i;
|
|
|
|
*dst._weights = 1.0f;
|
|
|
|
dst.Next();
|
2014-09-12 23:59:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
// StencilTables factory
|
|
|
|
//
|
|
|
|
StencilTables const *
|
|
|
|
StencilTablesFactory::Create(TopologyRefiner const & refiner,
|
|
|
|
Options options) {
|
|
|
|
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
StencilTables * result = new StencilTables;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
int maxlevel = refiner.GetMaxLevel();
|
2014-09-05 22:07:46 +00:00
|
|
|
if (maxlevel==0) {
|
2014-09-12 23:59:16 +00:00
|
|
|
return result;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
2014-09-24 21:49:51 +00:00
|
|
|
ProtoStencilAllocator::Mode mode=ProtoStencilAllocator::INTERPOLATE_VERTEX;
|
2014-09-12 23:59:16 +00:00
|
|
|
switch (options.interpolationMode) {
|
|
|
|
case INTERPOLATE_VERTEX:
|
|
|
|
mode = ProtoStencilAllocator::INTERPOLATE_VERTEX; break;
|
|
|
|
case INTERPOLATE_VARYING:
|
|
|
|
mode = ProtoStencilAllocator::INTERPOLATE_VARYING; break;
|
2014-09-24 21:49:51 +00:00
|
|
|
default:
|
|
|
|
assert(0);
|
2014-09-12 23:59:16 +00:00
|
|
|
}
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
std::vector<ProtoStencilAllocator> allocators(
|
2014-09-05 22:07:46 +00:00
|
|
|
options.generateAllLevels ? maxlevel : 2,
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencilAllocator(refiner, mode));
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencilAllocator * srcAlloc, * dstAlloc;
|
2014-09-05 22:07:46 +00:00
|
|
|
if (options.generateAllLevels) {
|
|
|
|
srcAlloc = 0;
|
|
|
|
dstAlloc = &allocators[0];
|
|
|
|
} else {
|
|
|
|
srcAlloc = &allocators[0];
|
|
|
|
dstAlloc = &allocators[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Interpolate stencils for each refinement level using
|
|
|
|
// TopologyRefiner::InterpolateLevel<>()
|
|
|
|
|
|
|
|
for (int level=1;level<=maxlevel; ++level) {
|
|
|
|
|
|
|
|
dstAlloc->Resize(refiner.GetNumVertices(level));
|
|
|
|
|
|
|
|
if (level==1) {
|
|
|
|
|
|
|
|
// coarse vertices have a single index and a weight of 1.0f
|
2014-10-09 23:36:23 +00:00
|
|
|
Index * srcStencils = new Index[refiner.GetNumVertices(0)];
|
2014-09-05 22:07:46 +00:00
|
|
|
for (int i=0; i<refiner.GetNumVertices(0); ++i) {
|
|
|
|
srcStencils[i]=i;
|
|
|
|
}
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencil * dstStencils = &(dstAlloc->GetStencils()).at(0);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
if (mode==ProtoStencilAllocator::INTERPOLATE_VERTEX) {
|
2014-09-05 22:07:46 +00:00
|
|
|
refiner.Interpolate(level, srcStencils, dstStencils);
|
|
|
|
} else {
|
|
|
|
refiner.InterpolateVarying(level, srcStencils, dstStencils);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete [] srcStencils;
|
|
|
|
} else {
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencil * srcStencils = &(srcAlloc->GetStencils()).at(0),
|
|
|
|
* dstStencils = &(dstAlloc->GetStencils()).at(0);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
if (mode==ProtoStencilAllocator::INTERPOLATE_VERTEX) {
|
2014-09-05 22:07:46 +00:00
|
|
|
refiner.Interpolate(level, srcStencils, dstStencils);
|
|
|
|
} else {
|
|
|
|
refiner.InterpolateVarying(level, srcStencils, dstStencils);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.generateAllLevels) {
|
|
|
|
if (level<maxlevel) {
|
|
|
|
srcAlloc = &allocators[level-1];
|
|
|
|
dstAlloc = &allocators[level];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::swap(srcAlloc, dstAlloc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort & Copy stencils into tables
|
|
|
|
{
|
|
|
|
result->_numControlVertices = refiner.GetNumVertices(0);
|
|
|
|
|
|
|
|
// Add total number of stencils, weights & indices
|
|
|
|
int nelems = 0, nstencils=0;
|
|
|
|
if (options.generateAllLevels) {
|
|
|
|
|
|
|
|
for (int level=0; level<maxlevel; ++level) {
|
|
|
|
nstencils += (int)allocators[level].GetStencils().size();
|
|
|
|
nelems += allocators[level].GetNumVertices();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nstencils = (int)srcAlloc->GetStencils().size();
|
|
|
|
nelems = srcAlloc->GetNumVertices();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
{ // Allocate
|
2014-09-19 00:48:34 +00:00
|
|
|
if (options.generateControlVerts) {
|
|
|
|
nstencils += result->_numControlVertices;
|
|
|
|
nelems += result->_numControlVertices;
|
|
|
|
}
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
result->_sizes.resize(nstencils);
|
|
|
|
if (options.generateOffsets) {
|
|
|
|
result->_offsets.resize(nstencils);
|
|
|
|
}
|
|
|
|
result->_indices.resize(nelems);
|
|
|
|
result->_weights.resize(nelems);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy stencils
|
|
|
|
Stencil dst(&result->_sizes.at(0),
|
|
|
|
&result->_indices.at(0), &result->_weights.at(0));
|
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
if (options.generateControlVerts) {
|
|
|
|
generateControlVertStencils(result->_numControlVertices, dst);
|
|
|
|
}
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
bool doSort = options.sortBySize!=0;
|
|
|
|
|
|
|
|
if (options.generateAllLevels) {
|
|
|
|
for (int level=0; level<maxlevel; ++level) {
|
|
|
|
copyStencils(allocators[level].GetStencils(), dst, doSort);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
copyStencils(srcAlloc->GetStencils(), dst, doSort);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.generateOffsets) {
|
2014-09-12 23:59:16 +00:00
|
|
|
generateOffsets(result->_sizes, result->_offsets);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Copy a stencil into StencilTables
|
|
|
|
template <> void
|
|
|
|
LimitStencilTablesFactory::copyLimitStencil(
|
|
|
|
ProtoLimitStencil const & src, LimitStencil & dst) {
|
|
|
|
|
|
|
|
unsigned char size = (unsigned char)src.GetSize();
|
2014-10-09 23:36:23 +00:00
|
|
|
Index const * indices = src.GetIndices();
|
2014-09-12 23:59:16 +00:00
|
|
|
float const * weights = src.GetWeights(),
|
|
|
|
* duWeights = src.GetDuWeights(),
|
|
|
|
* dvWeights = src.GetDvWeights();
|
|
|
|
|
|
|
|
*dst._size = size;
|
|
|
|
for (unsigned char i=0; i<size; ++i) {
|
|
|
|
memcpy(dst._indices, indices, size*sizeof(int));
|
|
|
|
memcpy(dst._weights, weights, size*sizeof(float));
|
|
|
|
memcpy(dst._duWeights, duWeights, size*sizeof(float));
|
|
|
|
memcpy(dst._dvWeights, dvWeights, size*sizeof(float));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// (Sort &) Copy a vector of stencils into StencilTables
|
|
|
|
template <> void
|
|
|
|
LimitStencilTablesFactory::copyLimitStencils(
|
|
|
|
ProtoLimitStencilVec & src, LimitStencil & dst) {
|
|
|
|
|
|
|
|
for (int i=0; i<(int)src.size(); ++i) {
|
|
|
|
copyLimitStencil(src[i], dst);
|
|
|
|
dst.Next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
LimitStencilTables const *
|
|
|
|
LimitStencilTablesFactory::Create(TopologyRefiner const & refiner,
|
2014-10-02 23:09:17 +00:00
|
|
|
LocationArrayVec const & locationArrays, StencilTables const * cvStencils,
|
|
|
|
PatchTables const * patchTables) {
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-10-02 23:09:17 +00:00
|
|
|
bool uniform = refiner.IsUniform();
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
// Compute the total number of stencils to generate
|
|
|
|
int numStencils=0, numLimitStencils=0;
|
|
|
|
for (int i=0; i<(int)locationArrays.size(); ++i) {
|
2014-10-02 23:09:17 +00:00
|
|
|
assert(locationArrays[i].numLocations>=0);
|
2014-09-19 00:48:34 +00:00
|
|
|
numStencils += locationArrays[i].numLocations;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (numStencils<=0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-10-02 23:09:17 +00:00
|
|
|
int maxlevel = refiner.GetMaxLevel();
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-10-02 23:09:17 +00:00
|
|
|
StencilTables const * _cvStencils = cvStencils;
|
|
|
|
if (not _cvStencils) {
|
|
|
|
// Generate stencils for the control vertices
|
|
|
|
// note: the control vertices of the mesh are added as single-index
|
|
|
|
// stencils of weight 1.0f
|
|
|
|
StencilTablesFactory::Options options;
|
|
|
|
options.generateAllLevels = uniform ? false :true;
|
|
|
|
options.generateControlVerts = true;
|
|
|
|
options.generateOffsets = true;
|
|
|
|
|
|
|
|
_cvStencils = StencilTablesFactory::Create(refiner, options);
|
|
|
|
} else {
|
|
|
|
// sanity checks
|
2014-10-04 00:54:30 +00:00
|
|
|
if (_cvStencils->GetNumStencils() != (uniform ?
|
2014-10-02 23:09:17 +00:00
|
|
|
refiner.GetNumVertices(maxlevel) :
|
2014-10-04 00:54:30 +00:00
|
|
|
refiner.GetNumVerticesTotal())) {
|
2014-10-02 23:09:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PatchTables const * _patchTables = patchTables;
|
|
|
|
if (not patchTables) {
|
|
|
|
_patchTables = PatchTablesFactory::Create(refiner);
|
|
|
|
} else {
|
|
|
|
// sanity checks
|
|
|
|
if (patchTables->IsFeatureAdaptive()==uniform) {
|
|
|
|
// XXXX smart pointers /grumble
|
|
|
|
if (not cvStencils) {
|
|
|
|
delete _cvStencils;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert( _patchTables and _cvStencils );
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
// Create a patch-map to locate sub-patches faster
|
2014-10-02 23:09:17 +00:00
|
|
|
PatchMap patchmap( *_patchTables );
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
// Create a pool allocator to accumulate ProtoLimitStencils
|
2014-09-12 23:59:16 +00:00
|
|
|
ProtoStencilAllocator alloc(refiner,
|
|
|
|
ProtoStencilAllocator::INTERPOLATE_LIMITS);
|
|
|
|
|
|
|
|
alloc.Resize(numStencils);
|
|
|
|
|
|
|
|
// Generate limit stencils for locations
|
2014-10-02 23:09:17 +00:00
|
|
|
|
|
|
|
// XXXX manuelk we can make uniform much faster with a dedicated
|
|
|
|
// code path that does not use PatchTables
|
2014-09-12 23:59:16 +00:00
|
|
|
for (int i=0, currentStencil=0; i<(int)locationArrays.size(); ++i) {
|
|
|
|
|
|
|
|
LocationArray const & array = locationArrays[i];
|
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
assert(array.ptexIdx>=0);
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
for (int j=0; j<array.numLocations; ++j, ++currentStencil) {
|
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
float s = array.s[j],
|
|
|
|
t = array.t[j];
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
PatchMap::Handle const * handle =
|
2014-09-19 00:48:34 +00:00
|
|
|
patchmap.FindPatch(array.ptexIdx, s, t);
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
if (handle) {
|
|
|
|
|
|
|
|
ProtoLimitStencil & dst =
|
|
|
|
alloc.GetLimitStencils()[currentStencil];
|
|
|
|
|
2014-10-02 23:09:17 +00:00
|
|
|
if (uniform) {
|
|
|
|
_patchTables->Interpolate(*handle, s, t, *_cvStencils, &dst);
|
|
|
|
} else {
|
|
|
|
_patchTables->Limit(*handle, s, t, *_cvStencils, &dst);
|
|
|
|
}
|
2014-09-12 23:59:16 +00:00
|
|
|
++numLimitStencils;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-09-19 00:48:34 +00:00
|
|
|
// Sort & Copy the proto stencils into the limit stencil tables
|
|
|
|
LimitStencilTables * result = new LimitStencilTables;
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
int nelems = alloc.GetNumVertices();
|
|
|
|
if (nelems>0) {
|
|
|
|
|
|
|
|
// Allocate
|
|
|
|
result->_sizes.resize(numLimitStencils);
|
|
|
|
result->_offsets.resize(numLimitStencils);
|
|
|
|
result->_indices.resize(nelems);
|
|
|
|
result->_weights.resize(nelems);
|
|
|
|
result->_duWeights.resize(nelems);
|
|
|
|
result->_dvWeights.resize(nelems);
|
|
|
|
|
|
|
|
// Copy stencils
|
|
|
|
LimitStencil dst(&result->_sizes.at(0),
|
|
|
|
&result->_indices.at(0),
|
|
|
|
&result->_weights.at(0),
|
|
|
|
&result->_duWeights.at(0),
|
|
|
|
&result->_dvWeights.at(0));
|
|
|
|
|
|
|
|
copyLimitStencils(alloc.GetLimitStencils(), dst);
|
|
|
|
|
|
|
|
generateOffsets(result->_sizes, result->_offsets);
|
|
|
|
}
|
|
|
|
result->_numControlVertices = refiner.GetNumVertices(0);
|
|
|
|
|
2014-10-02 23:09:17 +00:00
|
|
|
if (not cvStencils) {
|
|
|
|
delete _cvStencils;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (not patchTables) {
|
|
|
|
delete _patchTables;
|
|
|
|
}
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
KernelBatch
|
|
|
|
StencilTablesFactory::Create(StencilTables const &stencilTables) {
|
|
|
|
|
|
|
|
return KernelBatch( KernelBatch::KERNEL_STENCIL_TABLE,
|
|
|
|
-1, 0, stencilTables.GetNumStencils());
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end namespace Far
|
|
|
|
|
|
|
|
} // end namespace OPENSUBDIV_VERSION
|
|
|
|
} // end namespace OpenSubdiv
|