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
36 CCL_NAMESPACE_BEGIN
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 */
set_childPatchMapQuadNode46 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 */
set_childPatchMapQuadNode54 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
resolve_quadrant(T & median,T & u,T & v)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
build_patch_map(PackedPatchTable & table,OpenSubdiv::Far::PatchTable * patch_table,int offset)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 ¶m = 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
total_size()191 size_t PackedPatchTable::total_size()
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
pack(Far::PatchTable * patch_table,int offset)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 ¶m_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
copy_adjusting_offsets(uint * dest,int doffset)259 void PackedPatchTable::copy_adjusting_offsets(uint *dest, int doffset)
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
295 CCL_NAMESPACE_END
296