OpenSubdiv/opensubdiv/far/patchMap.h
manuelk 3ae50d1c50 Amending Apache license language & file headers.
New text:

     Copyright 2013 Pixar

     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.
2013-09-26 12:04:57 -07:00

334 lines
11 KiB
C++

//
// Copyright 2013 Pixar
//
// 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.
//
#ifndef FAR_PATCH_MAP_H
#define FAR_PATCH_MAP_H
#include "../version.h"
#include "../far/patchTables.h"
#include <cassert>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
/// \brief An quadtree-based map connecting coarse faces to their sub-patches
///
/// FarPatchTables::PatchArrays contain lists of patches that represent the limit
/// surface of a mesh, sorted by their topological type. These arrays break the
/// connection between coarse faces and their sub-patches.
///
/// The PatchMap provides a quad-tree based lookup structure that, given a singular
/// parametric location, can efficiently return a handle to the sub-patch that
/// contains this location.
///
class FarPatchMap {
public:
/// \brief Handle that can be used as unique patch identifier within FarPatchTables
struct Handle {
unsigned int patchArrayIdx, // OsdPatchArray containing the patch
patchIdx, // Absolute index of the patch
vertexOffset; // Offset to the first CV of the patch
};
/// \brief Constructor
///
/// @param patchTables A valid set of FarPatchTables
///
FarPatchMap( FarPatchTables const & patchTables );
/// \brief Returns a handle to the sub-patch of the face at the given (u,v).
/// Note : the faceid corresponds to quadrangulated face indices (ie. quads
/// count as 1 index, non-quads add as many indices as they have vertices)
///
/// @param faceid The index of the face
///
/// @param u Local u parameter
///
/// @param v Local v parameter
///
/// @return A patch handle or NULL if the face does not exist or the
/// limit surface is tagged as a hole at the given location
///
Handle const * FindPatch( int faceid, float u, float v ) const;
private:
void initialize( FarPatchTables const & patchTables );
// Quadtree node with 4 children
struct QuadNode {
struct Child {
unsigned int isSet:1, // true if the child has been set
isLeaf:1, // true if the child is a QuadNode
idx:30; // child index (either QuadNode or Handle)
};
// sets all the children to point to the patch of index patchIdx
void SetChild(int patchIdx);
// sets the child in "quadrant" to point to the node or patch of the given index
void SetChild(unsigned char quadrant, int child, bool isLeaf=true);
Child children[4];
};
typedef std::vector<QuadNode> QuadTree;
// adds a child to a parent node and pushes it back on the tree
static QuadNode * addChild( QuadTree & quadtree, QuadNode * parent, int quadrant );
// given a median, transforms the (u,v) to the quadrant they point to, and
// return the quadrant index.
//
// Quadrants indexing:
//
// (0,0) o-----o-----o
// | | |
// | 0 | 3 |
// | | |
// o-----o-----o
// | | |
// | 1 | 2 |
// | | |
// o-----o-----o (1,1)
//
template <class T> static int resolveQuadrant(T & median, T & u, T & v);
std::vector<Handle> _handles; // all the patches in the FarPatchTable
std::vector<QuadNode> _quadtree; // quadtree nodes
};
// Constructor
inline
FarPatchMap::FarPatchMap( FarPatchTables const & patchTables ) {
initialize( patchTables );
}
// sets all the children to point to the patch of index patchIdx
inline void
FarPatchMap::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
inline void
FarPatchMap::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
inline FarPatchMap::QuadNode *
FarPatchMap::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]);
}
// given a median, transforms the (u,v) to the quadrant they point to, and
// return the quadrant index.
template <class T> int
FarPatchMap::resolveQuadrant(T & median, T & u, T & v) {
int quadrant = -1;
if (u<median) {
if (v<median) {
quadrant = 0;
} else {
quadrant = 1;
v-=median;
}
} else {
if (v<median) {
quadrant = 3;
} else {
quadrant = 2;
v-=median;
}
u-=median;
}
return quadrant;
}
/// Returns a handle to the sub-patch of the face at the given (u,v).
inline FarPatchMap::Handle const *
FarPatchMap::FindPatch( int faceid, float u, float v ) const {
if (faceid>(int)_quadtree.size())
return NULL;
assert( (u>=0.0f) and (u<=1.0f) and (v>=0.0f) and (v<=1.0f) );
QuadNode const * node = &_quadtree[faceid];
float half = 0.5f;
// 0xFF : we should never have depths greater than k_InfinitelySharp
for (int depth=0; depth<0xFF; ++depth) {
float delta = half * 0.5f;
int quadrant = resolveQuadrant( half, u, v );
assert(quadrant>=0);
// is the quadrant a hole ?
if (not node->children[quadrant].isSet)
return 0;
if (node->children[quadrant].isLeaf) {
return &_handles[node->children[quadrant].idx];
} else {
node = &_quadtree[node->children[quadrant].idx];
}
half = delta;
}
assert(0);
return 0;
}
// Constructor
inline void
FarPatchMap::initialize( FarPatchTables const & patchTables ) {
int nfaces = 0, npatches = (int)patchTables.GetNumPatches();
if (not npatches)
return;
FarPatchTables::PatchArrayVector const & patchArrays =
patchTables.GetPatchArrayVector();
FarPatchTables::PatchParamTable const & paramTable =
patchTables.GetPatchParamTable();
// populate subpatch handles vector
_handles.resize(npatches);
for (int arrayIdx=0, current=0; arrayIdx<(int)patchArrays.size(); ++arrayIdx) {
FarPatchTables::PatchArray const & parray = patchArrays[arrayIdx];
int ringsize = parray.GetDescriptor().GetNumControlVertices();
for (unsigned int j=0; j < parray.GetNumPatches(); ++j) {
FarPatchParam const & param = paramTable[parray.GetPatchIndex()+j];
Handle & h = _handles[current];
h.patchArrayIdx = arrayIdx;
h.patchIdx = (unsigned int)current;
h.vertexOffset = j * ringsize;
nfaces = std::max(nfaces, (int)param.faceIndex);
++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 (int i=0, handleIdx=0; i<(int)patchArrays.size(); ++i) {
FarPatchTables::PatchArray const & parray = patchArrays[i];
for (unsigned int j=0; j < parray.GetNumPatches(); ++j, ++handleIdx) {
FarPatchParam const & param = paramTable[parray.GetPatchIndex()+j];
FarPatchParam::BitField bits = param.bitField;
unsigned char depth = bits.GetDepth();
QuadNode * node = &quadtree[ param.faceIndex ];
if (depth==(bits.NonQuadRoot() ? 1 : 0)) {
// special case : regular BSpline face w/ no sub-patches
node->SetChild( handleIdx );
continue;
}
short u = bits.GetU(),
v = bits.GetV(),
pdepth = bits.NonQuadRoot() ? depth-2 : depth-1,
half = 1 << pdepth;
for (unsigned char k=0; k<depth; ++k) {
short delta = half >> 1;
int quadrant = resolveQuadrant(half, u, v);
assert(quadrant>=0);
half = delta;
if (k==pdepth) {
// we have reached the depth of the sub-patch : add a leaf
assert( not node->children[quadrant].isSet );
node->SetChild(quadrant, handleIdx, true);
break;
} else {
// travel down the child node of the corresponding quadrant
if (not 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 OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* FAR_PATCH_PARAM */