mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-12-15 05:10:12 +00:00
170 lines
5.4 KiB
C++
170 lines
5.4 KiB
C++
//
|
|
// 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/patchMap.h"
|
|
|
|
#include <algorithm>
|
|
|
|
namespace OpenSubdiv {
|
|
namespace OPENSUBDIV_VERSION {
|
|
|
|
namespace Far {
|
|
|
|
// Constructor
|
|
PatchMap::PatchMap( PatchTable const & patchTable ) {
|
|
initialize( patchTable );
|
|
}
|
|
|
|
// sets all the children to point to the patch of index patchIdx
|
|
void
|
|
PatchMap::QuadNode::SetChild(int patchIdx) {
|
|
for (int i=0; i<4; ++i) {
|
|
children[i].isSet=true;
|
|
children[i].isLeaf=true;
|
|
children[i].idx=patchIdx;
|
|
}
|
|
}
|
|
|
|
// sets the child in "quadrant" to point to the node or patch of the given index
|
|
void
|
|
PatchMap::QuadNode::SetChild(unsigned char quadrant, int idx, bool isLeaf) {
|
|
assert(quadrant<4);
|
|
children[quadrant].isSet = true;
|
|
children[quadrant].isLeaf = isLeaf;
|
|
children[quadrant].idx = idx;
|
|
}
|
|
|
|
// adds a child to a parent node and pushes it back on the tree
|
|
PatchMap::QuadNode *
|
|
PatchMap::addChild( QuadTree & quadtree, QuadNode * parent, int quadrant ) {
|
|
quadtree.push_back(QuadNode());
|
|
int idx = (int)quadtree.size()-1;
|
|
parent->SetChild(quadrant, idx, false);
|
|
return &(quadtree[idx]);
|
|
}
|
|
|
|
void
|
|
PatchMap::initialize( PatchTable const & patchTable ) {
|
|
|
|
int nfaces = 0,
|
|
narrays = (int)patchTable.GetNumPatchArrays(),
|
|
npatches = (int)patchTable.GetNumPatchesTotal();
|
|
|
|
if (! narrays || ! npatches)
|
|
return;
|
|
|
|
// populate subpatch handles vector
|
|
_handles.resize(npatches);
|
|
|
|
for (int parray=0, current=0; parray<narrays; ++parray) {
|
|
|
|
ConstPatchParamArray params = patchTable.GetPatchParams(parray);
|
|
|
|
int ringsize = patchTable.GetPatchArrayDescriptor(parray).GetNumControlVertices();
|
|
|
|
for (Index j=0; j < patchTable.GetNumPatches(parray); ++j) {
|
|
|
|
Handle & h = _handles[current];
|
|
|
|
h.arrayIndex = parray;
|
|
h.patchIndex = current;
|
|
h.vertIndex = j * ringsize;
|
|
|
|
nfaces = std::max(nfaces, (int)params[j].GetFaceId());
|
|
|
|
++current;
|
|
}
|
|
}
|
|
++nfaces;
|
|
// temporary vector to hold the quadtree while under construction
|
|
std::vector<QuadNode> quadtree;
|
|
|
|
// reserve memory for the octree nodes (size is a worse-case approximation)
|
|
quadtree.reserve( nfaces + npatches );
|
|
|
|
// each coarse face has a root node associated to it that we need to initialize
|
|
quadtree.resize(nfaces);
|
|
|
|
// populate the quadtree from the FarPatchArrays sub-patches
|
|
for (Index parray=0, handleIndex=0; parray<narrays; ++parray) {
|
|
|
|
ConstPatchParamArray params = patchTable.GetPatchParams(parray);
|
|
|
|
for (int i=0; i < patchTable.GetNumPatches(parray); ++i, ++handleIndex) {
|
|
|
|
PatchParam const & param = params[i];
|
|
|
|
unsigned short depth = param.GetDepth();
|
|
|
|
QuadNode * node = &quadtree[ params[i].GetFaceId() ];
|
|
|
|
if (depth==(param.NonQuadRoot() ? 1 : 0)) {
|
|
// special case : regular BSpline face w/ no sub-patches
|
|
node->SetChild( handleIndex );
|
|
continue;
|
|
}
|
|
|
|
int u = param.GetU(),
|
|
v = param.GetV(),
|
|
pdepth = param.NonQuadRoot() ? depth-2 : depth-1,
|
|
half = 1 << pdepth;
|
|
|
|
for (unsigned char j=0; j<depth; ++j) {
|
|
|
|
int delta = half >> 1;
|
|
|
|
int quadrant = resolveQuadrant(half, u, v);
|
|
assert(quadrant>=0);
|
|
|
|
half = delta;
|
|
|
|
if (j==pdepth) {
|
|
// we have reached the depth of the sub-patch : add a leaf
|
|
assert( ! node->children[quadrant].isSet );
|
|
node->SetChild(quadrant, handleIndex, true);
|
|
break;
|
|
} else {
|
|
// travel down the child node of the corresponding quadrant
|
|
if (! node->children[quadrant].isSet) {
|
|
// create a new branch in the quadrant
|
|
node = addChild(quadtree, node, quadrant);
|
|
} else {
|
|
// travel down an existing branch
|
|
node = &(quadtree[ node->children[quadrant].idx ]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// copy the resulting quadtree to eliminate un-unused vector capacity
|
|
_quadtree = quadtree;
|
|
}
|
|
|
|
|
|
} // end namespace Far
|
|
|
|
} // end namespace OPENSUBDIV_VERSION
|
|
} // end namespace OpenSubdiv
|