Blender  V2.93
subd_patch_table.cpp
Go to the documentation of this file.
1 /*
2  * Based on code from OpenSubdiv released under this license:
3  *
4  * Copyright 2014 DreamWorks Animation LLC.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "Apache License")
7  * with the following modification; you may not use this file except in
8  * compliance with the Apache License and the following modification to it:
9  * Section 6. Trademarks. is deleted and replaced with:
10  *
11  * 6. Trademarks. This License does not grant permission to use the trade
12  * names, trademarks, service marks, or product names of the Licensor
13  * and its affiliates, except as required to comply with Section 4(c) of
14  * the License and to reproduce the content of the NOTICE file.
15  *
16  * You may obtain a copy of the Apache License at
17  *
18  * http://www.apache.org/licenses/LICENSE-2.0
19  *
20  * Unless required by applicable law or agreed to in writing, software
21  * distributed under the Apache License with the above modification is
22  * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23  * KIND, either express or implied. See the Apache License for the specific
24  * language governing permissions and limitations under the Apache License.
25  */
26 
27 #include "subd/subd_patch_table.h"
28 #include "kernel/kernel_types.h"
29 
30 #include "util/util_math.h"
31 
32 #ifdef WITH_OPENSUBDIV
33 # include <opensubdiv/far/patchTable.h>
34 #endif
35 
37 
38 #ifdef WITH_OPENSUBDIV
39 
40 using namespace OpenSubdiv;
41 
42 /* functions for building patch maps */
43 
44 struct PatchMapQuadNode {
45  /* sets all the children to point to the patch of index */
46  void set_child(int index)
47  {
48  for (int i = 0; i < 4; i++) {
49  children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF;
50  }
51  }
52 
53  /* sets the child in quadrant to point to the node or patch of the given index */
54  void set_child(unsigned char quadrant, int index, bool is_leaf = true)
55  {
56  assert(quadrant < 4);
57  children[quadrant] = index | PATCH_MAP_NODE_IS_SET | (is_leaf ? PATCH_MAP_NODE_IS_LEAF : 0);
58  }
59 
60  uint children[4];
61 };
62 
63 template<class T> static int resolve_quadrant(T &median, T &u, T &v)
64 {
65  int quadrant = -1;
66 
67  if (u < median) {
68  if (v < median) {
69  quadrant = 0;
70  }
71  else {
72  quadrant = 1;
73  v -= median;
74  }
75  }
76  else {
77  if (v < median) {
78  quadrant = 3;
79  }
80  else {
81  quadrant = 2;
82  v -= median;
83  }
84  u -= median;
85  }
86 
87  return quadrant;
88 }
89 
90 static void build_patch_map(PackedPatchTable &table,
91  OpenSubdiv::Far::PatchTable *patch_table,
92  int offset)
93 {
94  int num_faces = 0;
95 
96  for (int array = 0; array < table.num_arrays; array++) {
97  Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
98 
99  for (int j = 0; j < patch_table->GetNumPatches(array); j++) {
100  num_faces = max(num_faces, (int)params[j].GetFaceId());
101  }
102  }
103  num_faces++;
104 
105  vector<PatchMapQuadNode> quadtree;
106  quadtree.reserve(num_faces + table.num_patches);
107  quadtree.resize(num_faces);
108 
109  /* adjust offsets to make indices relative to the table */
110  int handle_index = -(table.num_patches * PATCH_HANDLE_SIZE);
111  offset += table.total_size();
112 
113  /* populate the quadtree from the FarPatchArrays sub-patches */
114  for (int array = 0; array < table.num_arrays; array++) {
115  Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
116 
117  for (int i = 0; i < patch_table->GetNumPatches(array);
118  i++, handle_index += PATCH_HANDLE_SIZE) {
119  const Far::PatchParam &param = params[i];
120  unsigned short depth = param.GetDepth();
121 
122  PatchMapQuadNode *node = &quadtree[params[i].GetFaceId()];
123 
124  if (depth == (param.NonQuadRoot() ? 1 : 0)) {
125  /* special case : regular BSpline face w/ no sub-patches */
126  node->set_child(handle_index + offset);
127  continue;
128  }
129 
130  int u = param.GetU();
131  int v = param.GetV();
132  int pdepth = param.NonQuadRoot() ? depth - 2 : depth - 1;
133  int half = 1 << pdepth;
134 
135  for (int j = 0; j < depth; j++) {
136  int delta = half >> 1;
137 
138  int quadrant = resolve_quadrant(half, u, v);
139  assert(quadrant >= 0);
140 
141  half = delta;
142 
143  if (j == pdepth) {
144  /* we have reached the depth of the sub-patch : add a leaf */
145  assert(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET));
146  node->set_child(quadrant, handle_index + offset, true);
147  break;
148  }
149  else {
150  /* travel down the child node of the corresponding quadrant */
151  if (!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET)) {
152  /* create a new branch in the quadrant */
153  quadtree.push_back(PatchMapQuadNode());
154 
155  int idx = (int)quadtree.size() - 1;
156  node->set_child(quadrant, idx * 4 + offset, false);
157 
158  node = &quadtree[idx];
159  }
160  else {
161  /* travel down an existing branch */
162  uint idx = node->children[quadrant] & PATCH_MAP_NODE_INDEX_MASK;
163  node = &(quadtree[(idx - offset) / 4]);
164  }
165  }
166  }
167  }
168  }
169 
170  /* copy into table */
171  assert(table.table.size() == table.total_size());
172  uint map_offset = table.total_size();
173 
174  table.num_nodes = quadtree.size() * 4;
175  table.table.resize(table.total_size());
176 
177  uint *data = &table.table[map_offset];
178 
179  for (int i = 0; i < quadtree.size(); i++) {
180  for (int j = 0; j < 4; j++) {
181  assert(quadtree[i].children[j] & PATCH_MAP_NODE_IS_SET);
182  *(data++) = quadtree[i].children[j];
183  }
184  }
185 }
186 
187 #endif
188 
189 /* packed patch table functions */
190 
192 {
193  return num_arrays * PATCH_ARRAY_SIZE + num_indices +
194  num_patches * (PATCH_PARAM_SIZE + PATCH_HANDLE_SIZE) + num_nodes * PATCH_NODE_SIZE;
195 }
196 
197 void PackedPatchTable::pack(Far::PatchTable *patch_table, int offset)
198 {
199  num_arrays = 0;
200  num_patches = 0;
201  num_indices = 0;
202  num_nodes = 0;
203 
204 #ifdef WITH_OPENSUBDIV
205  num_arrays = patch_table->GetNumPatchArrays();
206 
207  for (int i = 0; i < num_arrays; i++) {
208  int patches = patch_table->GetNumPatches(i);
209  int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
210 
211  num_patches += patches;
212  num_indices += patches * num_control;
213  }
214 
215  table.resize(total_size());
216  uint *data = table.data();
217 
218  uint *array = data;
219  uint *index = array + num_arrays * PATCH_ARRAY_SIZE;
220  uint *param = index + num_indices;
221  uint *handle = param + num_patches * PATCH_PARAM_SIZE;
222 
223  uint current_param = 0;
224 
225  for (int i = 0; i < num_arrays; i++) {
226  *(array++) = patch_table->GetPatchArrayDescriptor(i).GetType();
227  *(array++) = patch_table->GetNumPatches(i);
228  *(array++) = (index - data) + offset;
229  *(array++) = (param - data) + offset;
230 
231  Far::ConstIndexArray indices = patch_table->GetPatchArrayVertices(i);
232 
233  for (int j = 0; j < indices.size(); j++) {
234  *(index++) = indices[j];
235  }
236 
237  const Far::PatchParamTable &param_table = patch_table->GetPatchParamTable();
238 
239  int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
240  int patches = patch_table->GetNumPatches(i);
241 
242  for (int j = 0; j < patches; j++, current_param++) {
243  *(param++) = param_table[current_param].field0;
244  *(param++) = param_table[current_param].field1;
245 
246  *(handle++) = (array - data) - PATCH_ARRAY_SIZE + offset;
247  *(handle++) = (param - data) - PATCH_PARAM_SIZE + offset;
248  *(handle++) = j * num_control;
249  }
250  }
251 
252  build_patch_map(*this, patch_table, offset);
253 #else
254  (void)patch_table;
255  (void)offset;
256 #endif
257 }
258 
260 {
261  uint *src = table.data();
262 
263  /* arrays */
264  for (int i = 0; i < num_arrays; i++) {
265  *(dest++) = *(src++);
266  *(dest++) = *(src++);
267  *(dest++) = *(src++) + doffset;
268  *(dest++) = *(src++) + doffset;
269  }
270 
271  /* indices */
272  for (int i = 0; i < num_indices; i++) {
273  *(dest++) = *(src++);
274  }
275 
276  /* params */
277  for (int i = 0; i < num_patches; i++) {
278  *(dest++) = *(src++);
279  *(dest++) = *(src++);
280  }
281 
282  /* handles */
283  for (int i = 0; i < num_patches; i++) {
284  *(dest++) = *(src++) + doffset;
285  *(dest++) = *(src++) + doffset;
286  *(dest++) = *(src++);
287  }
288 
289  /* nodes */
290  for (int i = 0; i < num_nodes; i++) {
291  *(dest++) = *(src++) + doffset;
292  }
293 }
294 
unsigned int uint
Definition: BLI_sys_types.h:83
ATTR_WARN_UNUSED_RESULT const BMVert * v
size_t size() const
Definition: util_array.h:203
T * resize(size_t newsize)
Definition: util_array.h:150
Definition: util_half.h:41
OperationNode * node
static ushort indices[]
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define CCL_NAMESPACE_END
#define PATCH_MAP_NODE_IS_SET
#define PATCH_MAP_NODE_IS_LEAF
#define PATCH_MAP_NODE_INDEX_MASK
#define T
void pack(Far::PatchTable *patch_table, int offset=0)
void copy_adjusting_offsets(uint *dest, int doffset)
array< uint > table
#define PATCH_NODE_SIZE
#define PATCH_HANDLE_SIZE
#define PATCH_ARRAY_SIZE
#define PATCH_PARAM_SIZE
float max