Blender V4.3
patch_map.h
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
8#ifndef OPENSUBDIV_PATCH_MAP_H_
9#define OPENSUBDIV_PATCH_MAP_H_
10
11#include <opensubdiv/far/patchTable.h>
12
13namespace blender::opensubdiv {
14
25class PatchMap {
26 public:
27 // Quadtree node with 4 children, tree is just a vector of nodes
28 struct QuadNode {
30 {
31 std::memset(this, 0, sizeof(QuadNode));
32 }
33
34 struct Child {
35 unsigned int isSet : 1; // true if the child has been set
36 unsigned int isLeaf : 1; // true if the child is a QuadNode
37 unsigned int index : 30; // child index (either QuadNode or Handle)
38 };
39
40 // sets all the children to point to the patch of given index
41 void SetChildren(int index);
42
43 // sets the child in "quadrant" to point to the node or patch of the given index
44 void SetChild(int quadrant, int index, bool isLeaf);
45
47 };
48
49 typedef OpenSubdiv::Far::PatchTable::PatchHandle Handle;
50
55 PatchMap(OpenSubdiv::Far::PatchTable const &patchTable);
56
71 Handle const *FindPatch(int patchFaceId, double u, double v) const;
72
73 int getMinPatchFace() const
74 {
75 return _minPatchFace;
76 }
77
78 int getMaxPatchFace() const
79 {
80 return _maxPatchFace;
81 }
82
83 int getMaxDepth() const
84 {
85 return _maxDepth;
86 }
87
89 {
90 return _patchesAreTriangular;
91 }
92
93 const std::vector<Handle> &getHandles()
94 {
95 return _handles;
96 }
97
98 const std::vector<QuadNode> &nodes()
99 {
100 return _quadtree;
101 }
102
103 private:
104 void initializeHandles(OpenSubdiv::Far::PatchTable const &patchTable);
105 void initializeQuadtree(OpenSubdiv::Far::PatchTable const &patchTable);
106
107 typedef std::vector<QuadNode> QuadTree;
108
109 // Internal methods supporting quadtree construction and queries
110 void assignRootNode(QuadNode *node, int index);
111 QuadNode *assignLeafOrChildNode(QuadNode *node, bool isLeaf, int quadrant, int index);
112
113 template<class T> static int transformUVToQuadQuadrant(T const &median, T &u, T &v);
114 template<class T>
115 static int transformUVToTriQuadrant(T const &median, T &u, T &v, bool &rotated);
116
117 private:
118 bool _patchesAreTriangular; // tri and quad assembly and search requirements differ
119
120 int _minPatchFace; // minimum patch face index supported by the map
121 int _maxPatchFace; // maximum patch face index supported by the map
122 int _maxDepth; // maximum depth of a patch in the tree
123
124 std::vector<Handle> _handles; // all the patches in the PatchTable
125 std::vector<QuadNode> _quadtree; // quadtree nodes
126};
127
128//
129// Given a median value for both U and V, these methods transform a (u,v) pair
130// into the quadrant that contains them and returns the quadrant index.
131//
132// Quadrant indexing for tri and quad patches -- consistent with PatchParam's
133// usage of UV bits:
134//
135// (0,1) o-----o-----o (1,1) (0,1) o (1,0) o-----o-----o (0,0)
136// | | | |\ \ 1 |\ 0 |
137// | 2 | 3 | | \ \ | \ |
138// | | | | 2 \ \| 3 \|
139// o-----o-----o o-----o o-----o
140// | | | |\ 3 |\ \ 2 |
141// | 0 | 1 | | \ | \ \ |
142// | | | | 0 \| 1 \ \|
143// (0,0) o-----o-----o (1,0) (0,0) o-----o-----o (1,0) o (0,1)
144//
145// The triangular case also takes and returns/affects the rotation of the
146// quadrant being searched and identified (quadrant 3 imparts a rotation).
147//
148template<class T> inline int PatchMap::transformUVToQuadQuadrant(T const &median, T &u, T &v)
149{
150
151 int uHalf = (u >= median);
152 if (uHalf) {
153 u -= median;
154 }
155
156 int vHalf = (v >= median);
157 if (vHalf) {
158 v -= median;
159 }
160
161 return (vHalf << 1) | uHalf;
162}
163
164template<class T>
165int inline PatchMap::transformUVToTriQuadrant(T const &median, T &u, T &v, bool &rotated)
166{
167
168 if (!rotated) {
169 if (u >= median) {
170 u -= median;
171 return 1;
172 }
173 if (v >= median) {
174 v -= median;
175 return 2;
176 }
177 if ((u + v) >= median) {
178 rotated = true;
179 return 3;
180 }
181 return 0;
182 }
183 else {
184 if (u < median) {
185 v -= median;
186 return 1;
187 }
188 if (v < median) {
189 u -= median;
190 return 2;
191 }
192 u -= median;
193 v -= median;
194 if ((u + v) < median) {
195 rotated = false;
196 return 3;
197 }
198 return 0;
199 }
200}
201
203inline PatchMap::Handle const *PatchMap::FindPatch(int faceid, double u, double v) const
204{
205
206 //
207 // Reject patch faces not supported by this map, or those corresponding
208 // to holes or otherwise unassigned (the root node for a patch will
209 // have all or no quadrants set):
210 //
211 if ((faceid < _minPatchFace) || (faceid > _maxPatchFace)) {
212 return 0;
213 }
214
215 QuadNode const *node = &_quadtree[faceid - _minPatchFace];
216
217 if (!node->children[0].isSet) {
218 return 0;
219 }
220
221 //
222 // Search the tree for the sub-patch containing the given (u,v)
223 //
224 assert((u >= 0.0) && (u <= 1.0) && (v >= 0.0) && (v <= 1.0));
225
226 double median = 0.5;
227 bool triRotated = false;
228
229 for (int depth = 0; depth <= _maxDepth; ++depth, median *= 0.5) {
230
231 int quadrant = _patchesAreTriangular ? transformUVToTriQuadrant(median, u, v, triRotated) :
232 transformUVToQuadQuadrant(median, u, v);
233
234 // holes should have been rejected at the root node of the face
235 assert(node->children[quadrant].isSet);
236
237 if (node->children[quadrant].isLeaf) {
238 return &_handles[node->children[quadrant].index];
239 }
240 else {
241 node = &_quadtree[node->children[quadrant].index];
242 }
243 }
244 assert(0);
245 return 0;
246}
247
248} // namespace blender::opensubdiv
249
250#endif // OPENSUBDIV_PATCH_MAP_H_
ATTR_WARN_UNUSED_RESULT const BMVert * v
An quadtree-based map connecting coarse faces to their sub-patches.
Definition patch_map.h:25
const std::vector< QuadNode > & nodes()
Definition patch_map.h:98
bool getPatchesAreTriangular() const
Definition patch_map.h:88
const std::vector< Handle > & getHandles()
Definition patch_map.h:93
PatchMap(OpenSubdiv::Far::PatchTable const &patchTable)
Constructor.
Definition patch_map.cc:78
Handle const * FindPatch(int patchFaceId, double u, double v) const
Returns a handle to the sub-patch of the face at the given (u,v). Note that the patch face ID corresp...
Definition patch_map.h:203
OpenSubdiv::Far::PatchTable::PatchHandle Handle
Definition patch_map.h:49
void SetChild(int quadrant, int index, bool isLeaf)
Definition patch_map.cc:35