Code cleanup to use array.data() rather than &array[0]
[blender.git] / intern / cycles / subd / subd_patch_table.cpp
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
28 #include "subd_patch_table.h"
29 #include "kernel_types.h"
30
31 #include "util_math.h"
32
33 #ifdef WITH_OPENSUBDIV
34 #include <opensubdiv/far/patchTable.h>
35 #endif
36
37 CCL_NAMESPACE_BEGIN
38
39 #ifdef WITH_OPENSUBDIV
40
41 using namespace OpenSubdiv;
42
43 /* functions for building patch maps */
44
45 struct PatchMapQuadNode {
46         /* sets all the children to point to the patch of index */
47         void set_child(int index)
48         {
49                 for (int i = 0; i < 4; i++) {
50                         children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF;
51                 }
52         }
53
54         /* sets the child in quadrant to point to the node or patch of the given index */
55         void set_child(unsigned char quadrant, int index, bool is_leaf=true)
56         {
57                 assert(quadrant < 4);
58                 children[quadrant] = index | PATCH_MAP_NODE_IS_SET | (is_leaf ? PATCH_MAP_NODE_IS_LEAF : 0);
59         }
60
61         uint children[4];
62 };
63
64 template<class T>
65 static int resolve_quadrant(T& median, T& u, T& v)
66 {
67         int quadrant = -1;
68
69         if(u < median) {
70                 if(v < median) {
71                         quadrant = 0;
72                 }
73                 else {
74                         quadrant = 1;
75                         v -= median;
76                 }
77         }
78         else {
79                 if(v < median) {
80                         quadrant = 3;
81                 }
82                 else {
83                         quadrant = 2;
84                         v -= median;
85                 }
86                 u -= median;
87         }
88
89         return quadrant;
90 }
91
92 static void build_patch_map(PackedPatchTable& table, OpenSubdiv::Far::PatchTable* patch_table, 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); i++, handle_index += PATCH_HANDLE_SIZE) {
118                         const Far::PatchParam& param = params[i];
119                         unsigned short depth = param.GetDepth();
120
121                         PatchMapQuadNode* node = &quadtree[params[i].GetFaceId()];
122
123                         if(depth == (param.NonQuadRoot() ? 1 : 0)) {
124                                 /* special case : regular BSpline face w/ no sub-patches */
125                                 node->set_child(handle_index + offset);
126                                 continue;
127                         }
128
129                         int u = param.GetU();
130                         int v = param.GetV();
131                         int pdepth = param.NonQuadRoot() ? depth-2 : depth-1;
132                         int half = 1 << pdepth;
133
134                         for(int j = 0; j < depth; j++) {
135                                 int delta = half >> 1;
136
137                                 int quadrant = resolve_quadrant(half, u, v);
138                                 assert(quadrant >= 0);
139
140                                 half = delta;
141
142                                 if(j == pdepth) {
143                                         /* we have reached the depth of the sub-patch : add a leaf */
144                                         assert(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET));
145                                         node->set_child(quadrant, handle_index + offset, true);
146                                         break;
147                                 }
148                                 else {
149                                         /* travel down the child node of the corresponding quadrant */
150                                         if(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET)) {
151                                                 /* create a new branch in the quadrant */
152                                                 quadtree.push_back(PatchMapQuadNode());
153
154                                                 int idx = (int)quadtree.size() - 1;
155                                                 node->set_child(quadrant, idx*4 + offset, false);
156
157                                                 node = &quadtree[idx];
158                                         }
159                                         else {
160                                                 /* travel down an existing branch */
161                                                 uint idx = node->children[quadrant] & PATCH_MAP_NODE_INDEX_MASK;
162                                                 node = &(quadtree[(idx - offset)/4]);
163                                         }
164                                 }
165                         }
166                 }
167         }
168
169         /* copy into table */
170         assert(table.table.size() == table.total_size());
171         uint map_offset = table.total_size();
172
173         table.num_nodes = quadtree.size() * 4;
174         table.table.resize(table.total_size());
175
176         uint* data = &table.table[map_offset];
177
178         for(int i = 0; i < quadtree.size(); i++) {
179                 for(int j = 0; j < 4; j++) {
180                         assert(quadtree[i].children[j] & PATCH_MAP_NODE_IS_SET);
181                         *(data++) = quadtree[i].children[j];
182                 }
183         }
184 }
185
186 #endif
187
188 /* packed patch table functions */
189
190 size_t PackedPatchTable::total_size()
191 {
192         return num_arrays * PATCH_ARRAY_SIZE +
193                    num_indices +
194                    num_patches * (PATCH_PARAM_SIZE + PATCH_HANDLE_SIZE) +
195                    num_nodes * PATCH_NODE_SIZE;
196 }
197
198 void PackedPatchTable::pack(Far::PatchTable* patch_table, int offset)
199 {
200         num_arrays = 0;
201         num_patches = 0;
202         num_indices = 0;
203         num_nodes = 0;
204
205 #ifdef WITH_OPENSUBDIV
206         num_arrays = patch_table->GetNumPatchArrays();
207
208         for(int i = 0; i < num_arrays; i++) {
209                 int patches = patch_table->GetNumPatches(i);
210                 int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
211
212                 num_patches += patches;
213                 num_indices += patches * num_control;
214         }
215
216         table.resize(total_size());
217         uint* data = table.data();
218
219         uint* array = data;
220         uint* index = array + num_arrays * PATCH_ARRAY_SIZE;
221         uint* param = index + num_indices;
222         uint* handle = param + num_patches * PATCH_PARAM_SIZE;
223
224         uint current_param = 0;
225
226         for(int i = 0; i < num_arrays; i++) {
227                 *(array++) = patch_table->GetPatchArrayDescriptor(i).GetType();
228                 *(array++) = patch_table->GetNumPatches(i);
229                 *(array++) = (index - data) + offset;
230                 *(array++) = (param - data) + offset;
231
232                 Far::ConstIndexArray indices = patch_table->GetPatchArrayVertices(i);
233
234                 for(int j = 0; j < indices.size(); j++) {
235                         *(index++) = indices[j];
236                 }
237
238                 const Far::PatchParamTable& param_table = patch_table->GetPatchParamTable();
239
240                 int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
241                 int patches = patch_table->GetNumPatches(i);
242
243                 for(int j = 0; j < patches; j++, current_param++) {
244                         *(param++) = param_table[current_param].field0;
245                         *(param++) = param_table[current_param].field1;
246
247                         *(handle++) = (array - data) - PATCH_ARRAY_SIZE + offset;
248                         *(handle++) = (param - data) - PATCH_PARAM_SIZE + offset;
249                         *(handle++) = j * num_control;
250                 }
251         }
252
253         build_patch_map(*this, patch_table, offset);
254 #else
255         (void)patch_table;
256         (void)offset;
257 #endif
258 }
259
260 void PackedPatchTable::copy_adjusting_offsets(uint* dest, int doffset)
261 {
262         uint* src = table.data();
263
264         /* arrays */
265         for(int i = 0; i < num_arrays; i++) {
266                 *(dest++) = *(src++);
267                 *(dest++) = *(src++);
268                 *(dest++) = *(src++) + doffset;
269                 *(dest++) = *(src++) + doffset;
270         }
271
272         /* indices */
273         for(int i = 0; i < num_indices; i++) {
274                 *(dest++) = *(src++);
275         }
276
277         /* params */
278         for(int i = 0; i < num_patches; i++) {
279                 *(dest++) = *(src++);
280                 *(dest++) = *(src++);
281         }
282
283         /* handles */
284         for(int i = 0; i < num_patches; i++) {
285                 *(dest++) = *(src++) + doffset;
286                 *(dest++) = *(src++) + doffset;
287                 *(dest++) = *(src++);
288         }
289
290         /* nodes */
291         for(int i = 0; i < num_nodes; i++) {
292                 *(dest++) = *(src++) + doffset;
293         }
294 }
295
296 CCL_NAMESPACE_END
297