2014-09-05 22:07:46 +00:00
|
|
|
//
|
2014-10-21 23:36:26 +00:00
|
|
|
// Copyright 2013 Pixar
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
// 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"
|
2015-04-18 00:36:55 +00:00
|
|
|
#include "../far/endCapGregoryBasisPatchFactory.h"
|
2015-04-23 23:58:45 +00:00
|
|
|
#include "../far/patchTables.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"
|
2014-10-29 17:53:17 +00:00
|
|
|
#include "../far/protoStencil.h"
|
2014-09-05 22:07:46 +00:00
|
|
|
#include "../far/topologyRefiner.h"
|
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
#include <algorithm>
|
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
namespace OpenSubdiv {
|
|
|
|
namespace OPENSUBDIV_VERSION {
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
namespace Far {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
//------------------------------------------------------------------------------
|
2014-09-18 00:53:38 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
void
|
|
|
|
StencilTablesFactory::generateControlVertStencils(
|
|
|
|
int numControlVerts, Stencil & dst) {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
// Control vertices contribute a single index with a weight of 1.0
|
|
|
|
for (int i=0; i<numControlVerts; ++i) {
|
|
|
|
*dst._size = 1;
|
|
|
|
*dst._indices = i;
|
|
|
|
*dst._weights = 1.0f;
|
|
|
|
dst.Next();
|
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
|
|
|
|
2015-04-18 00:36:55 +00:00
|
|
|
// always initialize numControlVertices (useful for torus case)
|
|
|
|
result->_numControlVertices = refiner.GetNumVertices(0);
|
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
int maxlevel = std::min(int(options.maxLevel), refiner.GetMaxLevel());
|
2014-11-25 19:48:49 +00:00
|
|
|
if (maxlevel==0 and (not options.generateControlVerts)) {
|
2014-09-12 23:59:16 +00:00
|
|
|
return result;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
2014-11-25 19:48:49 +00:00
|
|
|
// 'maxsize' reflects the size of the default supporting basis factorized
|
2014-10-21 23:36:26 +00:00
|
|
|
// in the stencils, with a little bit of head-room. Each subdivision scheme
|
|
|
|
// has a set valence for 'regular' vertices, which drives the size of the
|
|
|
|
// supporting basis of control-vertices. The goal is to reduce the number
|
|
|
|
// of incidences where the pool allocator has to switch to dynamically
|
|
|
|
// allocated heap memory when encountering extraordinary vertices that
|
|
|
|
// require a larger supporting basis.
|
|
|
|
//
|
|
|
|
// The maxsize settings we use follow the assumption that the vast
|
|
|
|
// majority of the vertices in a mesh are regular, and that the valence
|
|
|
|
// of the extraordinary vertices is only higher by 1 edge.
|
|
|
|
int maxsize = 0;
|
|
|
|
bool interpolateVarying = false;
|
2014-09-12 23:59:16 +00:00
|
|
|
switch (options.interpolationMode) {
|
2014-10-21 23:36:26 +00:00
|
|
|
case INTERPOLATE_VERTEX: {
|
2015-01-07 01:40:11 +00:00
|
|
|
Sdc::SchemeType type = refiner.GetSchemeType();
|
2014-10-21 23:36:26 +00:00
|
|
|
switch (type) {
|
2015-01-07 01:40:11 +00:00
|
|
|
case Sdc::SCHEME_BILINEAR : maxsize = 5; break;
|
|
|
|
case Sdc::SCHEME_CATMARK : maxsize = 17; break;
|
|
|
|
case Sdc::SCHEME_LOOP : maxsize = 10; break;
|
2014-10-21 23:36:26 +00:00
|
|
|
default:
|
|
|
|
assert(0);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
case INTERPOLATE_VARYING: maxsize = 5; interpolateVarying=true; 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-10-21 23:36:26 +00:00
|
|
|
std::vector<StencilAllocator> allocators(
|
|
|
|
options.generateIntermediateLevels ? maxlevel+1 : 2,
|
|
|
|
StencilAllocator(maxsize, interpolateVarying));
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
StencilAllocator * srcAlloc = &allocators[0],
|
|
|
|
* dstAlloc = &allocators[1];
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-11-25 19:48:49 +00:00
|
|
|
//
|
2014-09-05 22:07:46 +00:00
|
|
|
// Interpolate stencils for each refinement level using
|
|
|
|
// TopologyRefiner::InterpolateLevel<>()
|
2014-10-21 23:36:26 +00:00
|
|
|
//
|
2014-09-05 22:07:46 +00:00
|
|
|
for (int level=1;level<=maxlevel; ++level) {
|
|
|
|
|
|
|
|
dstAlloc->Resize(refiner.GetNumVertices(level));
|
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
if (options.interpolationMode==INTERPOLATE_VERTEX) {
|
|
|
|
refiner.Interpolate(level, *srcAlloc, *dstAlloc);
|
2014-09-05 22:07:46 +00:00
|
|
|
} else {
|
2014-10-21 23:36:26 +00:00
|
|
|
refiner.InterpolateVarying(level, *srcAlloc, *dstAlloc);
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
if (options.generateIntermediateLevels) {
|
2014-09-05 22:07:46 +00:00
|
|
|
if (level<maxlevel) {
|
2014-10-21 23:36:26 +00:00
|
|
|
if (options.factorizeIntermediateLevels) {
|
|
|
|
srcAlloc = &allocators[level];
|
|
|
|
} else {
|
|
|
|
// if the stencils are dependent on the previous level of
|
|
|
|
// subdivision, pass an empty allocator to treat all parent
|
|
|
|
// vertices as control vertices
|
|
|
|
assert(allocators[0].GetNumStencils()==0);
|
|
|
|
}
|
|
|
|
dstAlloc = &allocators[level+1];
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::swap(srcAlloc, dstAlloc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
// Copy stencils from the pool allocator into the tables
|
2014-09-05 22:07:46 +00:00
|
|
|
{
|
|
|
|
// Add total number of stencils, weights & indices
|
|
|
|
int nelems = 0, nstencils=0;
|
2014-10-21 23:36:26 +00:00
|
|
|
if (options.generateIntermediateLevels) {
|
|
|
|
for (int level=0; level<=maxlevel; ++level) {
|
|
|
|
nstencils += allocators[level].GetNumStencils();
|
|
|
|
nelems += allocators[level].GetNumVerticesTotal();
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-10-21 23:36:26 +00:00
|
|
|
nstencils = (int)srcAlloc->GetNumStencils();
|
|
|
|
nelems = srcAlloc->GetNumVerticesTotal();
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
// Allocate
|
|
|
|
result->_numControlVertices = refiner.GetNumVertices(0);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
if (options.generateControlVerts) {
|
|
|
|
nstencils += result->_numControlVertices;
|
|
|
|
nelems += result->_numControlVertices;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
2014-10-29 17:53:17 +00:00
|
|
|
result->resize(nstencils, nelems);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// 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-10-21 23:36:26 +00:00
|
|
|
if (options.generateIntermediateLevels) {
|
|
|
|
for (int level=1; level<=maxlevel; ++level) {
|
|
|
|
for (int i=0; i<allocators[level].GetNumStencils(); ++i) {
|
|
|
|
*dst._size = allocators[level].CopyStencil(i, dst._indices, dst._weights);
|
|
|
|
dst.Next();
|
|
|
|
}
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-10-21 23:36:26 +00:00
|
|
|
for (int i=0; i<srcAlloc->GetNumStencils(); ++i) {
|
|
|
|
*dst._size = srcAlloc->CopyStencil(i, dst._indices, dst._weights);
|
|
|
|
dst.Next();
|
|
|
|
}
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (options.generateOffsets) {
|
2014-10-29 17:53:17 +00:00
|
|
|
result->generateOffsets();
|
2014-09-12 23:59:16 +00:00
|
|
|
}
|
|
|
|
}
|
2014-10-21 23:36:26 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2014-11-13 22:03:21 +00:00
|
|
|
StencilTables const *
|
|
|
|
StencilTablesFactory::Create(int numTables, StencilTables const ** tables) {
|
|
|
|
|
2015-04-08 01:34:05 +00:00
|
|
|
// XXXtakahito:
|
|
|
|
// This function returns NULL for empty inputs or erroneous condition.
|
|
|
|
// It's convenient for skipping varying stencils etc, however,
|
|
|
|
// other Create() API returns an empty stencil instead of NULL.
|
|
|
|
// They need to be consistent.
|
2014-11-13 22:03:21 +00:00
|
|
|
|
|
|
|
if ( (numTables<=0) or (not tables)) {
|
2015-04-08 01:34:05 +00:00
|
|
|
return NULL;
|
2014-11-13 22:03:21 +00:00
|
|
|
}
|
|
|
|
|
2015-04-08 01:34:05 +00:00
|
|
|
int ncvs = -1,
|
2014-11-13 22:03:21 +00:00
|
|
|
nstencils = 0,
|
|
|
|
nelems = 0;
|
|
|
|
|
|
|
|
for (int i=0; i<numTables; ++i) {
|
|
|
|
|
2015-04-08 01:34:05 +00:00
|
|
|
StencilTables const * st = tables[i];
|
|
|
|
// allow the tables could have a null entry.
|
|
|
|
if (!st) continue;
|
2014-11-13 22:03:21 +00:00
|
|
|
|
2015-04-08 01:34:05 +00:00
|
|
|
if (ncvs >= 0 and st->GetNumControlVertices() != ncvs) {
|
|
|
|
return NULL;
|
2014-11-13 22:03:21 +00:00
|
|
|
}
|
2015-04-08 01:34:05 +00:00
|
|
|
ncvs = st->GetNumControlVertices();
|
|
|
|
nstencils += st->GetNumStencils();
|
|
|
|
nelems += (int)st->GetControlIndices().size();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ncvs == -1) {
|
|
|
|
return NULL;
|
2014-11-13 22:03:21 +00:00
|
|
|
}
|
|
|
|
|
2015-04-08 01:34:05 +00:00
|
|
|
StencilTables * result = new StencilTables;
|
2014-11-13 22:03:21 +00:00
|
|
|
result->resize(nstencils, nelems);
|
|
|
|
|
2015-05-19 17:16:56 +00:00
|
|
|
int * sizes = &result->_sizes[0];
|
2014-11-13 22:03:21 +00:00
|
|
|
Index * indices = &result->_indices[0];
|
|
|
|
float * weights = &result->_weights[0];
|
|
|
|
for (int i=0; i<numTables; ++i) {
|
2015-04-08 01:34:05 +00:00
|
|
|
StencilTables const * st = tables[i];
|
|
|
|
if (!st) continue;
|
|
|
|
|
|
|
|
int st_nstencils = st->GetNumStencils(),
|
|
|
|
st_nelems = (int)st->_indices.size();
|
2015-05-19 17:16:56 +00:00
|
|
|
memcpy(sizes, &st->_sizes[0], st_nstencils*sizeof(int));
|
2015-04-08 01:34:05 +00:00
|
|
|
memcpy(indices, &st->_indices[0], st_nelems*sizeof(Index));
|
|
|
|
memcpy(weights, &st->_weights[0], st_nelems*sizeof(float));
|
2015-01-06 02:56:24 +00:00
|
|
|
|
|
|
|
sizes += st_nstencils;
|
|
|
|
indices += st_nelems;
|
|
|
|
weights += st_nelems;
|
2014-11-13 22:03:21 +00:00
|
|
|
}
|
|
|
|
|
2014-11-14 20:41:53 +00:00
|
|
|
result->_numControlVertices = ncvs;
|
|
|
|
|
2014-11-13 22:03:21 +00:00
|
|
|
// have to re-generate offsets from scratch
|
|
|
|
result->generateOffsets();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
2015-04-23 23:58:45 +00:00
|
|
|
StencilTables const *
|
|
|
|
StencilTablesFactory::AppendEndCapStencilTables(
|
|
|
|
TopologyRefiner const &refiner,
|
|
|
|
StencilTables const *baseStencilTables,
|
|
|
|
StencilTables const *endCapStencilTables,
|
|
|
|
bool factorize) {
|
|
|
|
|
|
|
|
// factorize and append.
|
|
|
|
if (baseStencilTables == NULL or
|
|
|
|
endCapStencilTables == NULL) return NULL;
|
|
|
|
|
|
|
|
// endcap stencils have indices that are relative to the level
|
|
|
|
// (maxlevel) of subdivision. These indices need to be offset to match
|
|
|
|
// the indices from the multi-level adaptive stencil tables.
|
|
|
|
// In addition: stencil tables can be built with singular stencils
|
|
|
|
// (single weight of 1.0f) as place-holders for coarse mesh vertices,
|
|
|
|
// which also needs to be accounted for.
|
|
|
|
|
|
|
|
int stencilsIndexOffset = 0;
|
|
|
|
int controlVertsIndexOffset = 0;
|
|
|
|
int nBaseStencils = baseStencilTables->GetNumStencils();
|
|
|
|
int nBaseStencilsElements = (int)baseStencilTables->_indices.size();
|
|
|
|
{
|
|
|
|
int maxlevel = refiner.GetMaxLevel();
|
|
|
|
int nverts = refiner.GetNumVerticesTotal();
|
|
|
|
if (nBaseStencils == nverts) {
|
|
|
|
|
|
|
|
// the table contain stencils for the control vertices
|
|
|
|
//
|
|
|
|
// <----------------- nverts ------------------>
|
|
|
|
//
|
|
|
|
// +---------------+----------------------------+-----------------+
|
|
|
|
// | control verts | refined verts : (max lv) | endcap points |
|
|
|
|
// +---------------+----------------------------+-----------------+
|
|
|
|
// | base stencil tables | endcap stencils |
|
|
|
|
// +--------------------------------------------+-----------------+
|
|
|
|
// : ^ /
|
|
|
|
// : \_________/
|
|
|
|
// <-------------------------------->
|
|
|
|
// stencilsIndexOffset
|
|
|
|
//
|
|
|
|
//
|
|
|
|
stencilsIndexOffset = nverts - refiner.GetNumVertices(maxlevel);
|
|
|
|
controlVertsIndexOffset = stencilsIndexOffset;
|
|
|
|
|
|
|
|
} else if (nBaseStencils == (nverts -refiner.GetNumVertices(0))) {
|
|
|
|
|
|
|
|
// the table does not contain stencils for the control vertices
|
|
|
|
//
|
|
|
|
// <----------------- nverts ------------------>
|
|
|
|
// <------ nBaseStencils ------->
|
|
|
|
// +---------------+----------------------------+-----------------+
|
|
|
|
// | control verts | refined verts : (max lv) | endcap points |
|
|
|
|
// +---------------+----------------------------+-----------------+
|
|
|
|
// | base stencil tables | endcap stencils |
|
|
|
|
// +----------------------------+-----------------+
|
|
|
|
// : ^ /
|
|
|
|
// : \_________/
|
|
|
|
// <---------------->
|
|
|
|
// stencilsIndexOffset
|
|
|
|
// <-------------------------------->
|
|
|
|
// controlVertsIndexOffset
|
|
|
|
//
|
|
|
|
stencilsIndexOffset = nBaseStencils - refiner.GetNumVertices(maxlevel);
|
|
|
|
controlVertsIndexOffset = nverts - refiner.GetNumVertices(maxlevel);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// these are not the stencils you are looking for.
|
|
|
|
assert(0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// copy all endcap stencils to proto stencils, and factorize if needed.
|
|
|
|
int nEndCapStencils = endCapStencilTables->GetNumStencils();
|
|
|
|
int nEndCapStencilsElements = 0;
|
|
|
|
|
|
|
|
// we exclude zero weight stencils. the resulting number of
|
|
|
|
// stencils of endcap may be different from input.
|
|
|
|
StencilAllocator allocator(16);
|
|
|
|
allocator.Resize(nEndCapStencils);
|
|
|
|
for (int i = 0 ; i < nEndCapStencils; ++i) {
|
|
|
|
Stencil src = endCapStencilTables->GetStencil(i);
|
|
|
|
allocator[i].Clear();
|
|
|
|
for (int j = 0; j < src.GetSize(); ++j) {
|
|
|
|
Index index = src.GetVertexIndices()[j];
|
|
|
|
float weight = src.GetWeights()[j];
|
|
|
|
if (weight == 0.0) continue;
|
|
|
|
|
|
|
|
if (factorize) {
|
|
|
|
allocator[i].AddWithWeight(*baseStencilTables,
|
|
|
|
index + stencilsIndexOffset,
|
|
|
|
weight);
|
|
|
|
} else {
|
|
|
|
allocator.PushBackVertex(i,
|
|
|
|
index + controlVertsIndexOffset,
|
|
|
|
weight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nEndCapStencilsElements += allocator.GetSize(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
// create new stencil tables
|
|
|
|
StencilTables * result = new StencilTables;
|
|
|
|
result->_numControlVertices = refiner.GetNumVertices(0);
|
|
|
|
result->resize(nBaseStencils + nEndCapStencils,
|
|
|
|
nBaseStencilsElements + nEndCapStencilsElements);
|
|
|
|
|
2015-05-19 17:16:56 +00:00
|
|
|
int* sizes = &result->_sizes[0];
|
2015-04-23 23:58:45 +00:00
|
|
|
Index * indices = &result->_indices[0];
|
|
|
|
float * weights = &result->_weights[0];
|
|
|
|
|
|
|
|
// put base stencils first
|
|
|
|
memcpy(sizes, &baseStencilTables->_sizes[0],
|
2015-05-19 17:16:56 +00:00
|
|
|
nBaseStencils*sizeof(int));
|
2015-04-23 23:58:45 +00:00
|
|
|
memcpy(indices, &baseStencilTables->_indices[0],
|
|
|
|
nBaseStencilsElements*sizeof(Index));
|
|
|
|
memcpy(weights, &baseStencilTables->_weights[0],
|
|
|
|
nBaseStencilsElements*sizeof(float));
|
|
|
|
|
|
|
|
sizes += nBaseStencils;
|
|
|
|
indices += nBaseStencilsElements;
|
|
|
|
weights += nBaseStencilsElements;
|
|
|
|
|
|
|
|
// endcap stencils second
|
|
|
|
for (int i = 0 ; i < nEndCapStencils; ++i) {
|
|
|
|
int size = allocator.GetSize(i);
|
|
|
|
for (int j = 0; j < size; ++j) {
|
|
|
|
*indices++ = allocator.GetIndices(i)[j];
|
|
|
|
*weights++ = allocator.GetWeights(i)[j];
|
|
|
|
}
|
|
|
|
*sizes++ = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// have to re-generate offsets from scratch
|
|
|
|
result->generateOffsets();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
2014-09-12 23:59:16 +00:00
|
|
|
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-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-21 23:36:26 +00:00
|
|
|
bool uniform = refiner.IsUniform();
|
|
|
|
|
|
|
|
int maxlevel = refiner.GetMaxLevel(), maxsize=17;
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
StencilTables const * cvstencils = cvStencils;
|
|
|
|
if (not cvstencils) {
|
2014-11-11 19:27:25 +00:00
|
|
|
// Generate stencils for the control vertices - this is necessary to
|
|
|
|
// properly factorize patches with control vertices at level 0 (natural
|
|
|
|
// regular patches, such as in a torus)
|
2014-10-02 23:09:17 +00:00
|
|
|
// note: the control vertices of the mesh are added as single-index
|
|
|
|
// stencils of weight 1.0f
|
|
|
|
StencilTablesFactory::Options options;
|
2014-10-21 23:36:26 +00:00
|
|
|
options.generateIntermediateLevels = uniform ? false :true;
|
2014-10-02 23:09:17 +00:00
|
|
|
options.generateControlVerts = true;
|
|
|
|
options.generateOffsets = true;
|
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
// XXXX (manuelk) We could potentially save some mem-copies by not
|
|
|
|
// instanciating the stencil tables and work directly off the pool
|
|
|
|
// allocators.
|
|
|
|
cvstencils = StencilTablesFactory::Create(refiner, options);
|
2014-10-02 23:09:17 +00:00
|
|
|
} else {
|
2014-10-21 23:36:26 +00:00
|
|
|
// Sanity checks
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2014-10-21 23:36:26 +00:00
|
|
|
|
|
|
|
// If a stencil table was given, use it, otherwise, create a new one
|
|
|
|
PatchTables const * patchtables = patchTables;
|
2015-04-23 23:58:45 +00:00
|
|
|
|
2014-10-02 23:09:17 +00:00
|
|
|
if (not patchTables) {
|
2014-10-21 23:36:26 +00:00
|
|
|
// XXXX (manuelk) If no patch-tables was passed, we should be able to
|
|
|
|
// infer the patches fairly easily from the refiner. Once more tags
|
|
|
|
// have been added to the refiner, maybe we can remove the need for the
|
|
|
|
// patch tables.
|
2014-11-11 19:27:25 +00:00
|
|
|
|
2015-04-23 23:58:45 +00:00
|
|
|
PatchTablesFactory::Options options;
|
|
|
|
options.SetEndCapType(
|
|
|
|
Far::PatchTablesFactory::Options::ENDCAP_GREGORY_BASIS);
|
2015-04-18 00:36:55 +00:00
|
|
|
|
2015-04-23 23:58:45 +00:00
|
|
|
patchtables = PatchTablesFactory::Create(refiner, options);
|
2014-11-11 19:27:25 +00:00
|
|
|
|
2015-04-18 00:36:55 +00:00
|
|
|
if (not cvStencils) {
|
2015-04-23 23:58:45 +00:00
|
|
|
// if cvstencils is just created above, append endcap stencils
|
|
|
|
if (StencilTables const *endCapStencilTables =
|
|
|
|
patchtables->GetEndCapVertexStencilTables()) {
|
|
|
|
StencilTables const *tables =
|
|
|
|
StencilTablesFactory::AppendEndCapStencilTables(
|
|
|
|
refiner, cvstencils, endCapStencilTables);
|
2015-04-18 00:36:55 +00:00
|
|
|
delete cvstencils;
|
2015-04-23 23:58:45 +00:00
|
|
|
cvstencils = tables;
|
2015-04-18 00:36:55 +00:00
|
|
|
}
|
|
|
|
}
|
2014-10-02 23:09:17 +00:00
|
|
|
} else {
|
2014-10-21 23:36:26 +00:00
|
|
|
// Sanity checks
|
2014-10-02 23:09:17 +00:00
|
|
|
if (patchTables->IsFeatureAdaptive()==uniform) {
|
|
|
|
if (not cvStencils) {
|
2014-10-21 23:36:26 +00:00
|
|
|
assert(cvstencils and cvstencils!=cvStencils);
|
|
|
|
delete cvstencils;
|
2014-10-02 23:09:17 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2014-10-21 23:36:26 +00:00
|
|
|
|
|
|
|
assert(patchtables and cvstencils);
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
// Create a patch-map to locate sub-patches faster
|
2014-10-21 23:36:26 +00:00
|
|
|
PatchMap patchmap( *patchtables );
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
//
|
|
|
|
// Generate limit stencils for locations
|
|
|
|
//
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
// Create a pool allocator to accumulate ProtoLimitStencils
|
|
|
|
LimitStencilAllocator alloc(maxsize);
|
2014-09-12 23:59:16 +00:00
|
|
|
alloc.Resize(numStencils);
|
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
// XXXX (manuelk) we can make uniform (bilinear) stencils faster with a
|
|
|
|
// dedicated code path that does not use PatchTables or the PatchMap
|
2015-05-20 22:44:29 +00:00
|
|
|
float wP[20], wDs[20], wDt[20];
|
|
|
|
|
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
|
|
|
|
2015-05-20 22:44:29 +00:00
|
|
|
PatchMap::Handle const * handle = patchmap.FindPatch(array.ptexIdx, s, t);
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
if (handle) {
|
2015-05-20 22:44:29 +00:00
|
|
|
|
2015-05-21 16:03:06 +00:00
|
|
|
ConstIndexArray cvs = patchtables->GetPatchVertices(*handle);
|
2015-05-20 22:44:29 +00:00
|
|
|
|
2015-05-21 16:03:06 +00:00
|
|
|
patchtables->EvaluateBasis(*handle, s, t, wP, wDs, wDt);
|
2015-05-20 22:44:29 +00:00
|
|
|
|
|
|
|
StencilTables const & src = *cvstencils;
|
2014-10-21 23:36:26 +00:00
|
|
|
ProtoLimitStencil dst = alloc[currentStencil];
|
2015-05-20 22:44:29 +00:00
|
|
|
|
|
|
|
dst.Clear();
|
|
|
|
for (int k = 0; k < cvs.size(); ++k) {
|
|
|
|
dst.AddWithWeight(src[cvs[k]], wP[k], wDs[k], wDt[k]);
|
2014-10-02 23:09:17 +00:00
|
|
|
}
|
2015-05-20 22:44:29 +00:00
|
|
|
|
2014-09-12 23:59:16 +00:00
|
|
|
++numLimitStencils;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-10-29 17:53:17 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
if (not cvStencils) {
|
|
|
|
delete cvstencils;
|
|
|
|
}
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2015-04-23 23:58:45 +00:00
|
|
|
if (not patchTables) {
|
|
|
|
delete patchtables;
|
|
|
|
}
|
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
//
|
|
|
|
// Copy the proto-stencils into the limit stencil tables
|
|
|
|
//
|
2014-09-19 00:48:34 +00:00
|
|
|
LimitStencilTables * result = new LimitStencilTables;
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
int nelems = alloc.GetNumVerticesTotal();
|
2014-09-12 23:59:16 +00:00
|
|
|
if (nelems>0) {
|
|
|
|
|
|
|
|
// Allocate
|
2014-10-29 17:53:17 +00:00
|
|
|
result->resize(numLimitStencils, nelems);
|
2014-09-12 23:59:16 +00:00
|
|
|
|
|
|
|
// Copy stencils
|
2014-10-21 23:36:26 +00:00
|
|
|
LimitStencil dst(&result->_sizes.at(0), &result->_indices.at(0),
|
|
|
|
&result->_weights.at(0), &result->_duWeights.at(0),
|
|
|
|
&result->_dvWeights.at(0));
|
|
|
|
|
|
|
|
for (int i=0; i<alloc.GetNumStencils(); ++i) {
|
|
|
|
*dst._size = alloc.CopyLimitStencil(i, dst._indices, dst._weights,
|
|
|
|
dst._duWeights, dst._dvWeights);
|
|
|
|
dst.Next();
|
|
|
|
}
|
2014-09-12 23:59:16 +00:00
|
|
|
|
2014-10-21 23:36:26 +00:00
|
|
|
// XXXX manuelk should offset creation be optional ?
|
2014-10-29 17:53:17 +00:00
|
|
|
result->generateOffsets();
|
2014-09-12 23:59:16 +00:00
|
|
|
}
|
|
|
|
result->_numControlVertices = refiner.GetNumVertices(0);
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end namespace Far
|
|
|
|
|
|
|
|
} // end namespace OPENSUBDIV_VERSION
|
|
|
|
} // end namespace OpenSubdiv
|