Blender V5.0
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 using Handle = OpenSubdiv::Far::PatchTable::PatchHandle;
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 using QuadTree = std::vector<QuadNode>;
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 bool _patchesAreTriangular; // tri and quad assembly and search requirements differ
118
119 int _minPatchFace; // minimum patch face index supported by the map
120 int _maxPatchFace; // maximum patch face index supported by the map
121 int _maxDepth; // maximum depth of a patch in the tree
122
123 std::vector<Handle> _handles; // all the patches in the PatchTable
124 std::vector<QuadNode> _quadtree; // quadtree nodes
125};
126
127//
128// Given a median value for both U and V, these methods transform a (u,v) pair
129// into the quadrant that contains them and returns the quadrant index.
130//
131// Quadrant indexing for tri and quad patches -- consistent with PatchParam's
132// usage of UV bits:
133//
134// (0,1) o-----o-----o (1,1) (0,1) o (1,0) o-----o-----o (0,0)
135// | | | |\ \ 1 |\ 0 |
136// | 2 | 3 | | \ \ | \ |
137// | | | | 2 \ \| 3 \|
138// o-----o-----o o-----o o-----o
139// | | | |\ 3 |\ \ 2 |
140// | 0 | 1 | | \ | \ \ |
141// | | | | 0 \| 1 \ \|
142// (0,0) o-----o-----o (1,0) (0,0) o-----o-----o (1,0) o (0,1)
143//
144// The triangular case also takes and returns/affects the rotation of the
145// quadrant being searched and identified (quadrant 3 imparts a rotation).
146//
147template<class T> inline int PatchMap::transformUVToQuadQuadrant(T const &median, T &u, T &v)
148{
149
150 int uHalf = (u >= median);
151 if (uHalf) {
152 u -= median;
153 }
154
155 int vHalf = (v >= median);
156 if (vHalf) {
157 v -= median;
158 }
159
160 return (vHalf << 1) | uHalf;
161}
162
163template<class T>
164int inline PatchMap::transformUVToTriQuadrant(T const &median, T &u, T &v, bool &rotated)
165{
166
167 if (!rotated) {
168 if (u >= median) {
169 u -= median;
170 return 1;
171 }
172 if (v >= median) {
173 v -= median;
174 return 2;
175 }
176 if ((u + v) >= median) {
177 rotated = true;
178 return 3;
179 }
180 return 0;
181 }
182
183 if (u < median) {
184 v -= median;
185 return 1;
186 }
187 if (v < median) {
188 u -= median;
189 return 2;
190 }
191 u -= median;
192 v -= median;
193 if ((u + v) < median) {
194 rotated = false;
195 return 3;
196 }
197 return 0;
198}
199
201inline PatchMap::Handle const *PatchMap::FindPatch(int faceid, double u, double v) const
202{
203
204 //
205 // Reject patch faces not supported by this map, or those corresponding
206 // to holes or otherwise unassigned (the root node for a patch will
207 // have all or no quadrants set):
208 //
209 if ((faceid < _minPatchFace) || (faceid > _maxPatchFace)) {
210 return nullptr;
211 }
212
213 QuadNode const *node = &_quadtree[faceid - _minPatchFace];
214
215 if (!node->children[0].isSet) {
216 return nullptr;
217 }
218
219 //
220 // Search the tree for the sub-patch containing the given (u,v)
221 //
222 assert((u >= 0.0) && (u <= 1.0) && (v >= 0.0) && (v <= 1.0));
223
224 double median = 0.5;
225 bool triRotated = false;
226
227 for (int depth = 0; depth <= _maxDepth; ++depth, median *= 0.5) {
228
229 int quadrant = _patchesAreTriangular ? transformUVToTriQuadrant(median, u, v, triRotated) :
230 transformUVToQuadQuadrant(median, u, v);
231
232 // holes should have been rejected at the root node of the face
233 assert(node->children[quadrant].isSet);
234
235 if (node->children[quadrant].isLeaf) {
236 return &_handles[node->children[quadrant].index];
237 }
238 node = &_quadtree[node->children[quadrant].index];
239 }
240 assert(0);
241 return nullptr;
242}
243
244} // namespace blender::opensubdiv
245
246#endif // OPENSUBDIV_PATCH_MAP_H_
ATTR_WARN_UNUSED_RESULT const BMVert * v
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
OpenSubdiv::Far::PatchTable::PatchHandle Handle
Definition patch_map.h:49
PatchMap(OpenSubdiv::Far::PatchTable const &patchTable)
Constructor.
Definition patch_map.cc:77
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:201
#define assert(assertion)
#define T
void SetChild(int quadrant, int index, bool isLeaf)
Definition patch_map.cc:35