Blender V5.0
patch_map.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 Pixar
2 * SPDX-FileCopyrightText: 2021 Blender Foundation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Original code by Pixar with modifications by the Blender foundation. */
7
9#include <algorithm>
10
11using OpenSubdiv::Far::ConstPatchParamArray;
12using OpenSubdiv::Far::Index;
13using OpenSubdiv::Far::PatchParam;
14using OpenSubdiv::Far::PatchParamTable;
15using OpenSubdiv::Far::PatchTable;
16
17namespace blender::opensubdiv {
18
19//
20// Inline quadtree assembly methods used by the constructor:
21//
22
23// sets all the children to point to the patch of given index
24inline void PatchMap::QuadNode::SetChildren(int index)
25{
26
27 for (int i = 0; i < 4; ++i) {
28 children[i].isSet = true;
29 children[i].isLeaf = true;
30 children[i].index = index;
31 }
32}
33
34// sets the child in "quadrant" to point to the node or patch of the given index
35inline void PatchMap::QuadNode::SetChild(int quadrant, int index, bool isLeaf)
36{
37
38 assert(!children[quadrant].isSet);
39 children[quadrant].isSet = true;
40 children[quadrant].isLeaf = isLeaf;
41 children[quadrant].index = index;
42}
43
44inline void PatchMap::assignRootNode(QuadNode *node, int index)
45{
46
47 // Assign the given index to all children of the node (all leaves)
48 node->SetChildren(index);
49}
50
51inline PatchMap::QuadNode *PatchMap::assignLeafOrChildNode(QuadNode *node,
52 bool isLeaf,
53 int quadrant,
54 int index)
55{
56
57 // Assign the node given if it is a leaf node, otherwise traverse
58 // the node -- creating/assigning a new child node if needed
59
60 if (isLeaf) {
61 node->SetChild(quadrant, index, true);
62 return node;
63 }
64 if (node->children[quadrant].isSet) {
65 return &_quadtree[node->children[quadrant].index];
66 }
67
68 int newChildNodeIndex = (int)_quadtree.size();
69 _quadtree.emplace_back();
70 node->SetChild(quadrant, newChildNodeIndex, false);
71 return &_quadtree[newChildNodeIndex];
72}
73
74//
75// Constructor and initialization methods for the handles and quadtree:
76//
77PatchMap::PatchMap(PatchTable const &patchTable)
78 : _minPatchFace(-1), _maxPatchFace(-1), _maxDepth(0)
79{
80
81 _patchesAreTriangular = patchTable.GetVaryingPatchDescriptor().GetNumControlVertices() == 3;
82
83 if (patchTable.GetNumPatchesTotal() > 0) {
84 initializeHandles(patchTable);
85 initializeQuadtree(patchTable);
86 }
87}
88
89void PatchMap::initializeHandles(PatchTable const &patchTable)
90{
91
92 //
93 // Populate the vector of patch Handles. Keep track of the min and max
94 // face indices to allocate resources accordingly and limit queries:
95 //
96 _minPatchFace = (int)patchTable.GetPatchParamTable()[0].GetFaceId();
97 _maxPatchFace = _minPatchFace;
98
99 int numArrays = patchTable.GetNumPatchArrays();
100 int numPatches = patchTable.GetNumPatchesTotal();
101
102 _handles.resize(numPatches);
103
104 for (int pArray = 0, handleIndex = 0; pArray < numArrays; ++pArray) {
105
106 ConstPatchParamArray params = patchTable.GetPatchParams(pArray);
107
108 int patchSize = patchTable.GetPatchArrayDescriptor(pArray).GetNumControlVertices();
109
110 for (Index j = 0; j < patchTable.GetNumPatches(pArray); ++j, ++handleIndex) {
111
112 Handle &h = _handles[handleIndex];
113
114 h.arrayIndex = pArray;
115 h.patchIndex = handleIndex;
116 h.vertIndex = j * patchSize;
117
118 int patchFaceId = params[j].GetFaceId();
119 _minPatchFace = std::min(_minPatchFace, patchFaceId);
120 _maxPatchFace = std::max(_maxPatchFace, patchFaceId);
121 }
122 }
123}
124
125void PatchMap::initializeQuadtree(PatchTable const &patchTable)
126{
127
128 //
129 // Reserve quadtree nodes for the worst case and prune later. Set the
130 // initial size to accomodate the root node of each patch face:
131 //
132 int nPatchFaces = (_maxPatchFace - _minPatchFace) + 1;
133
134 int nHandles = int(_handles.size());
135
136 _quadtree.reserve(nPatchFaces + nHandles);
137 _quadtree.resize(nPatchFaces);
138
139 PatchParamTable const &params = patchTable.GetPatchParamTable();
140
141 for (int handle = 0; handle < nHandles; ++handle) {
142
143 PatchParam const &param = params[handle];
144
145 int depth = param.GetDepth();
146 int rootDepth = param.NonQuadRoot();
147
148 _maxDepth = std::max(_maxDepth, depth);
149
150 QuadNode *node = &_quadtree[param.GetFaceId() - _minPatchFace];
151
152 if (depth == rootDepth) {
153 assignRootNode(node, handle);
154 continue;
155 }
156
157 if (!_patchesAreTriangular) {
158 // Use the UV bits of the PatchParam directly for quad patches:
159 int u = param.GetU();
160 int v = param.GetV();
161
162 for (int j = rootDepth + 1; j <= depth; ++j) {
163 int uBit = (u >> (depth - j)) & 1;
164 int vBit = (v >> (depth - j)) & 1;
165
166 int quadrant = (vBit << 1) | uBit;
167
168 node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
169 }
170 }
171 else {
172 // Use an interior UV point of triangles to identify quadrants:
173 double u = 0.25;
174 double v = 0.25;
175 param.UnnormalizeTriangle(u, v);
176
177 double median = 0.5;
178 bool triRotated = false;
179
180 for (int j = rootDepth + 1; j <= depth; ++j, median *= 0.5) {
181 int quadrant = transformUVToTriQuadrant(median, u, v, triRotated);
182
183 node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
184 }
185 }
186 }
187
188 // Swap the Node vector with a copy to reduce worst case memory allocation:
189 QuadTree tmpTree = _quadtree;
190 _quadtree.swap(tmpTree);
191}
192
193} // namespace blender::opensubdiv
ATTR_WARN_UNUSED_RESULT const BMVert * v
OpenSubdiv::Far::PatchTable::PatchHandle Handle
Definition patch_map.h:49
PatchMap(OpenSubdiv::Far::PatchTable const &patchTable)
Constructor.
Definition patch_map.cc:77
#define assert(assertion)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void SetChild(int quadrant, int index, bool isLeaf)
Definition patch_map.cc:35
i
Definition text_draw.cc:230