Blender V4.3
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 else {
68 int newChildNodeIndex = (int)_quadtree.size();
69 _quadtree.push_back(QuadNode());
70 node->SetChild(quadrant, newChildNodeIndex, false);
71 return &_quadtree[newChildNodeIndex];
72 }
73}
74
75//
76// Constructor and initialization methods for the handles and quadtree:
77//
78PatchMap::PatchMap(PatchTable const &patchTable)
79 : _minPatchFace(-1), _maxPatchFace(-1), _maxDepth(0)
80{
81
82 _patchesAreTriangular = patchTable.GetVaryingPatchDescriptor().GetNumControlVertices() == 3;
83
84 if (patchTable.GetNumPatchesTotal() > 0) {
85 initializeHandles(patchTable);
86 initializeQuadtree(patchTable);
87 }
88}
89
90void PatchMap::initializeHandles(PatchTable const &patchTable)
91{
92
93 //
94 // Populate the vector of patch Handles. Keep track of the min and max
95 // face indices to allocate resources accordingly and limit queries:
96 //
97 _minPatchFace = (int)patchTable.GetPatchParamTable()[0].GetFaceId();
98 _maxPatchFace = _minPatchFace;
99
100 int numArrays = (int)patchTable.GetNumPatchArrays();
101 int numPatches = (int)patchTable.GetNumPatchesTotal();
102
103 _handles.resize(numPatches);
104
105 for (int pArray = 0, handleIndex = 0; pArray < numArrays; ++pArray) {
106
107 ConstPatchParamArray params = patchTable.GetPatchParams(pArray);
108
109 int patchSize = patchTable.GetPatchArrayDescriptor(pArray).GetNumControlVertices();
110
111 for (Index j = 0; j < patchTable.GetNumPatches(pArray); ++j, ++handleIndex) {
112
113 Handle &h = _handles[handleIndex];
114
115 h.arrayIndex = pArray;
116 h.patchIndex = handleIndex;
117 h.vertIndex = j * patchSize;
118
119 int patchFaceId = params[j].GetFaceId();
120 _minPatchFace = std::min(_minPatchFace, patchFaceId);
121 _maxPatchFace = std::max(_maxPatchFace, patchFaceId);
122 }
123 }
124}
125
126void PatchMap::initializeQuadtree(PatchTable const &patchTable)
127{
128
129 //
130 // Reserve quadtree nodes for the worst case and prune later. Set the
131 // initial size to accomodate the root node of each patch face:
132 //
133 int nPatchFaces = (_maxPatchFace - _minPatchFace) + 1;
134
135 int nHandles = int(_handles.size());
136
137 _quadtree.reserve(nPatchFaces + nHandles);
138 _quadtree.resize(nPatchFaces);
139
140 PatchParamTable const &params = patchTable.GetPatchParamTable();
141
142 for (int handle = 0; handle < nHandles; ++handle) {
143
144 PatchParam const &param = params[handle];
145
146 int depth = param.GetDepth();
147 int rootDepth = param.NonQuadRoot();
148
149 _maxDepth = std::max(_maxDepth, depth);
150
151 QuadNode *node = &_quadtree[param.GetFaceId() - _minPatchFace];
152
153 if (depth == rootDepth) {
154 assignRootNode(node, handle);
155 continue;
156 }
157
158 if (!_patchesAreTriangular) {
159 // Use the UV bits of the PatchParam directly for quad patches:
160 int u = param.GetU();
161 int v = param.GetV();
162
163 for (int j = rootDepth + 1; j <= depth; ++j) {
164 int uBit = (u >> (depth - j)) & 1;
165 int vBit = (v >> (depth - j)) & 1;
166
167 int quadrant = (vBit << 1) | uBit;
168
169 node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
170 }
171 }
172 else {
173 // Use an interior UV point of triangles to identify quadrants:
174 double u = 0.25;
175 double v = 0.25;
176 param.UnnormalizeTriangle(u, v);
177
178 double median = 0.5;
179 bool triRotated = false;
180
181 for (int j = rootDepth + 1; j <= depth; ++j, median *= 0.5) {
182 int quadrant = transformUVToTriQuadrant(median, u, v, triRotated);
183
184 node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
185 }
186 }
187 }
188
189 // Swap the Node vector with a copy to reduce worst case memory allocation:
190 QuadTree tmpTree = _quadtree;
191 _quadtree.swap(tmpTree);
192}
193
194} // namespace blender::opensubdiv
ATTR_WARN_UNUSED_RESULT const BMVert * v
PatchMap(OpenSubdiv::Far::PatchTable const &patchTable)
Constructor.
Definition patch_map.cc:78
OperationNode * node
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void SetChild(int quadrant, int index, bool isLeaf)
Definition patch_map.cc:35