subd_patch_table.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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. #include "subd/subd_patch_table.h"
  27. #include "kernel/kernel_types.h"
  28. #include "util/util_math.h"
  29. #ifdef WITH_OPENSUBDIV
  30. # include <opensubdiv/far/patchTable.h>
  31. #endif
  32. CCL_NAMESPACE_BEGIN
  33. #ifdef WITH_OPENSUBDIV
  34. using namespace OpenSubdiv;
  35. /* functions for building patch maps */
  36. struct PatchMapQuadNode {
  37. /* sets all the children to point to the patch of index */
  38. void set_child(int index)
  39. {
  40. for (int i = 0; i < 4; i++) {
  41. children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF;
  42. }
  43. }
  44. /* sets the child in quadrant to point to the node or patch of the given index */
  45. void set_child(unsigned char quadrant, int index, bool is_leaf = true)
  46. {
  47. assert(quadrant < 4);
  48. children[quadrant] = index | PATCH_MAP_NODE_IS_SET | (is_leaf ? PATCH_MAP_NODE_IS_LEAF : 0);
  49. }
  50. uint children[4];
  51. };
  52. template<class T> static int resolve_quadrant(T &median, T &u, T &v)
  53. {
  54. int quadrant = -1;
  55. if (u < median) {
  56. if (v < median) {
  57. quadrant = 0;
  58. }
  59. else {
  60. quadrant = 1;
  61. v -= median;
  62. }
  63. }
  64. else {
  65. if (v < median) {
  66. quadrant = 3;
  67. }
  68. else {
  69. quadrant = 2;
  70. v -= median;
  71. }
  72. u -= median;
  73. }
  74. return quadrant;
  75. }
  76. static void build_patch_map(PackedPatchTable &table,
  77. OpenSubdiv::Far::PatchTable *patch_table,
  78. int offset)
  79. {
  80. int num_faces = 0;
  81. for (int array = 0; array < table.num_arrays; array++) {
  82. Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
  83. for (int j = 0; j < patch_table->GetNumPatches(array); j++) {
  84. num_faces = max(num_faces, (int)params[j].GetFaceId());
  85. }
  86. }
  87. num_faces++;
  88. vector<PatchMapQuadNode> quadtree;
  89. quadtree.reserve(num_faces + table.num_patches);
  90. quadtree.resize(num_faces);
  91. /* adjust offsets to make indices relative to the table */
  92. int handle_index = -(table.num_patches * PATCH_HANDLE_SIZE);
  93. offset += table.total_size();
  94. /* populate the quadtree from the FarPatchArrays sub-patches */
  95. for (int array = 0; array < table.num_arrays; array++) {
  96. Far::ConstPatchParamArray params = patch_table->GetPatchParams(array);
  97. for (int i = 0; i < patch_table->GetNumPatches(array);
  98. i++, handle_index += PATCH_HANDLE_SIZE) {
  99. const Far::PatchParam &param = params[i];
  100. unsigned short depth = param.GetDepth();
  101. PatchMapQuadNode *node = &quadtree[params[i].GetFaceId()];
  102. if (depth == (param.NonQuadRoot() ? 1 : 0)) {
  103. /* special case : regular BSpline face w/ no sub-patches */
  104. node->set_child(handle_index + offset);
  105. continue;
  106. }
  107. int u = param.GetU();
  108. int v = param.GetV();
  109. int pdepth = param.NonQuadRoot() ? depth - 2 : depth - 1;
  110. int half = 1 << pdepth;
  111. for (int j = 0; j < depth; j++) {
  112. int delta = half >> 1;
  113. int quadrant = resolve_quadrant(half, u, v);
  114. assert(quadrant >= 0);
  115. half = delta;
  116. if (j == pdepth) {
  117. /* we have reached the depth of the sub-patch : add a leaf */
  118. assert(!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET));
  119. node->set_child(quadrant, handle_index + offset, true);
  120. break;
  121. }
  122. else {
  123. /* travel down the child node of the corresponding quadrant */
  124. if (!(node->children[quadrant] & PATCH_MAP_NODE_IS_SET)) {
  125. /* create a new branch in the quadrant */
  126. quadtree.push_back(PatchMapQuadNode());
  127. int idx = (int)quadtree.size() - 1;
  128. node->set_child(quadrant, idx * 4 + offset, false);
  129. node = &quadtree[idx];
  130. }
  131. else {
  132. /* travel down an existing branch */
  133. uint idx = node->children[quadrant] & PATCH_MAP_NODE_INDEX_MASK;
  134. node = &(quadtree[(idx - offset) / 4]);
  135. }
  136. }
  137. }
  138. }
  139. }
  140. /* copy into table */
  141. assert(table.table.size() == table.total_size());
  142. uint map_offset = table.total_size();
  143. table.num_nodes = quadtree.size() * 4;
  144. table.table.resize(table.total_size());
  145. uint *data = &table.table[map_offset];
  146. for (int i = 0; i < quadtree.size(); i++) {
  147. for (int j = 0; j < 4; j++) {
  148. assert(quadtree[i].children[j] & PATCH_MAP_NODE_IS_SET);
  149. *(data++) = quadtree[i].children[j];
  150. }
  151. }
  152. }
  153. #endif
  154. /* packed patch table functions */
  155. size_t PackedPatchTable::total_size()
  156. {
  157. return num_arrays * PATCH_ARRAY_SIZE + num_indices +
  158. num_patches * (PATCH_PARAM_SIZE + PATCH_HANDLE_SIZE) + num_nodes * PATCH_NODE_SIZE;
  159. }
  160. void PackedPatchTable::pack(Far::PatchTable *patch_table, int offset)
  161. {
  162. num_arrays = 0;
  163. num_patches = 0;
  164. num_indices = 0;
  165. num_nodes = 0;
  166. #ifdef WITH_OPENSUBDIV
  167. num_arrays = patch_table->GetNumPatchArrays();
  168. for (int i = 0; i < num_arrays; i++) {
  169. int patches = patch_table->GetNumPatches(i);
  170. int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
  171. num_patches += patches;
  172. num_indices += patches * num_control;
  173. }
  174. table.resize(total_size());
  175. uint *data = table.data();
  176. uint *array = data;
  177. uint *index = array + num_arrays * PATCH_ARRAY_SIZE;
  178. uint *param = index + num_indices;
  179. uint *handle = param + num_patches * PATCH_PARAM_SIZE;
  180. uint current_param = 0;
  181. for (int i = 0; i < num_arrays; i++) {
  182. *(array++) = patch_table->GetPatchArrayDescriptor(i).GetType();
  183. *(array++) = patch_table->GetNumPatches(i);
  184. *(array++) = (index - data) + offset;
  185. *(array++) = (param - data) + offset;
  186. Far::ConstIndexArray indices = patch_table->GetPatchArrayVertices(i);
  187. for (int j = 0; j < indices.size(); j++) {
  188. *(index++) = indices[j];
  189. }
  190. const Far::PatchParamTable &param_table = patch_table->GetPatchParamTable();
  191. int num_control = patch_table->GetPatchArrayDescriptor(i).GetNumControlVertices();
  192. int patches = patch_table->GetNumPatches(i);
  193. for (int j = 0; j < patches; j++, current_param++) {
  194. *(param++) = param_table[current_param].field0;
  195. *(param++) = param_table[current_param].field1;
  196. *(handle++) = (array - data) - PATCH_ARRAY_SIZE + offset;
  197. *(handle++) = (param - data) - PATCH_PARAM_SIZE + offset;
  198. *(handle++) = j * num_control;
  199. }
  200. }
  201. build_patch_map(*this, patch_table, offset);
  202. #else
  203. (void)patch_table;
  204. (void)offset;
  205. #endif
  206. }
  207. void PackedPatchTable::copy_adjusting_offsets(uint *dest, int doffset)
  208. {
  209. uint *src = table.data();
  210. /* arrays */
  211. for (int i = 0; i < num_arrays; i++) {
  212. *(dest++) = *(src++);
  213. *(dest++) = *(src++);
  214. *(dest++) = *(src++) + doffset;
  215. *(dest++) = *(src++) + doffset;
  216. }
  217. /* indices */
  218. for (int i = 0; i < num_indices; i++) {
  219. *(dest++) = *(src++);
  220. }
  221. /* params */
  222. for (int i = 0; i < num_patches; i++) {
  223. *(dest++) = *(src++);
  224. *(dest++) = *(src++);
  225. }
  226. /* handles */
  227. for (int i = 0; i < num_patches; i++) {
  228. *(dest++) = *(src++) + doffset;
  229. *(dest++) = *(src++) + doffset;
  230. *(dest++) = *(src++);
  231. }
  232. /* nodes */
  233. for (int i = 0; i < num_nodes; i++) {
  234. *(dest++) = *(src++) + doffset;
  235. }
  236. }
  237. CCL_NAMESPACE_END