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 &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 
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 &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 
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