This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/intern/opensubdiv/internal/evaluator/patch_map.cc
Ray molenkamp bbd0c4118b Fix: Build issue with MSVC
std::min was used without including the algorithm
header. Seems to be implicitly included by
something in newer MSVC versions and GCC, however
vs16.4 needed a little help here.
2022-01-04 07:15:51 -07:00

214 lines
6.4 KiB
C++

// Original code 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.
//
// Modifications copyright 2021 Blender Foundation. All rights reserved.
#include "internal/evaluator/patch_map.h"
#include <algorithm>
using OpenSubdiv::Far::ConstPatchParamArray;
using OpenSubdiv::Far::Index;
using OpenSubdiv::Far::PatchParam;
using OpenSubdiv::Far::PatchParamTable;
using OpenSubdiv::Far::PatchTable;
namespace blender {
namespace opensubdiv {
//
// Inline quadtree assembly methods used by the constructor:
//
// sets all the children to point to the patch of given index
inline void PatchMap::QuadNode::SetChildren(int index)
{
for (int i = 0; i < 4; ++i) {
children[i].isSet = true;
children[i].isLeaf = true;
children[i].index = index;
}
}
// sets the child in "quadrant" to point to the node or patch of the given index
inline void PatchMap::QuadNode::SetChild(int quadrant, int index, bool isLeaf)
{
assert(!children[quadrant].isSet);
children[quadrant].isSet = true;
children[quadrant].isLeaf = isLeaf;
children[quadrant].index = index;
}
inline void PatchMap::assignRootNode(QuadNode *node, int index)
{
// Assign the given index to all children of the node (all leaves)
node->SetChildren(index);
}
inline PatchMap::QuadNode *PatchMap::assignLeafOrChildNode(QuadNode *node,
bool isLeaf,
int quadrant,
int index)
{
// Assign the node given if it is a leaf node, otherwise traverse
// the node -- creating/assigning a new child node if needed
if (isLeaf) {
node->SetChild(quadrant, index, true);
return node;
}
if (node->children[quadrant].isSet) {
return &_quadtree[node->children[quadrant].index];
}
else {
int newChildNodeIndex = (int)_quadtree.size();
_quadtree.push_back(QuadNode());
node->SetChild(quadrant, newChildNodeIndex, false);
return &_quadtree[newChildNodeIndex];
}
}
//
// Constructor and initialization methods for the handles and quadtree:
//
PatchMap::PatchMap(PatchTable const &patchTable)
: _minPatchFace(-1), _maxPatchFace(-1), _maxDepth(0)
{
_patchesAreTriangular = patchTable.GetVaryingPatchDescriptor().GetNumControlVertices() == 3;
if (patchTable.GetNumPatchesTotal() > 0) {
initializeHandles(patchTable);
initializeQuadtree(patchTable);
}
}
void PatchMap::initializeHandles(PatchTable const &patchTable)
{
//
// Populate the vector of patch Handles. Keep track of the min and max
// face indices to allocate resources accordingly and limit queries:
//
_minPatchFace = (int)patchTable.GetPatchParamTable()[0].GetFaceId();
_maxPatchFace = _minPatchFace;
int numArrays = (int)patchTable.GetNumPatchArrays();
int numPatches = (int)patchTable.GetNumPatchesTotal();
_handles.resize(numPatches);
for (int pArray = 0, handleIndex = 0; pArray < numArrays; ++pArray) {
ConstPatchParamArray params = patchTable.GetPatchParams(pArray);
int patchSize = patchTable.GetPatchArrayDescriptor(pArray).GetNumControlVertices();
for (Index j = 0; j < patchTable.GetNumPatches(pArray); ++j, ++handleIndex) {
Handle &h = _handles[handleIndex];
h.arrayIndex = pArray;
h.patchIndex = handleIndex;
h.vertIndex = j * patchSize;
int patchFaceId = params[j].GetFaceId();
_minPatchFace = std::min(_minPatchFace, patchFaceId);
_maxPatchFace = std::max(_maxPatchFace, patchFaceId);
}
}
}
void PatchMap::initializeQuadtree(PatchTable const &patchTable)
{
//
// Reserve quadtree nodes for the worst case and prune later. Set the
// initial size to accomodate the root node of each patch face:
//
int nPatchFaces = (_maxPatchFace - _minPatchFace) + 1;
int nHandles = (int)_handles.size();
_quadtree.reserve(nPatchFaces + nHandles);
_quadtree.resize(nPatchFaces);
PatchParamTable const &params = patchTable.GetPatchParamTable();
for (int handle = 0; handle < nHandles; ++handle) {
PatchParam const &param = params[handle];
int depth = param.GetDepth();
int rootDepth = param.NonQuadRoot();
_maxDepth = std::max(_maxDepth, depth);
QuadNode *node = &_quadtree[param.GetFaceId() - _minPatchFace];
if (depth == rootDepth) {
assignRootNode(node, handle);
continue;
}
if (!_patchesAreTriangular) {
// Use the UV bits of the PatchParam directly for quad patches:
int u = param.GetU();
int v = param.GetV();
for (int j = rootDepth + 1; j <= depth; ++j) {
int uBit = (u >> (depth - j)) & 1;
int vBit = (v >> (depth - j)) & 1;
int quadrant = (vBit << 1) | uBit;
node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
}
}
else {
// Use an interior UV point of triangles to identify quadrants:
double u = 0.25;
double v = 0.25;
param.UnnormalizeTriangle(u, v);
double median = 0.5;
bool triRotated = false;
for (int j = rootDepth + 1; j <= depth; ++j, median *= 0.5) {
int quadrant = transformUVToTriQuadrant(median, u, v, triRotated);
node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
}
}
}
// Swap the Node vector with a copy to reduce worst case memory allocation:
QuadTree tmpTree = _quadtree;
_quadtree.swap(tmpTree);
}
} // namespace opensubdiv
} // namespace blender