Cleanup: fix compiler warnings.
[blender.git] / intern / opensubdiv / opensubdiv_converter.cc
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2015 Blender Foundation.
17  * All rights reserved.
18  */
19
20 #include <cstdio>
21 #include <vector>
22
23 #ifdef _MSC_VER
24 #  include "iso646.h"
25 #endif
26
27 #include <opensubdiv/far/topologyRefinerFactory.h>
28
29 #include "MEM_guardedalloc.h"
30
31 #include "opensubdiv_converter_capi.h"
32 #include "opensubdiv_intern.h"
33 #include "opensubdiv_topology_refiner.h"
34
35
36 #include <stack>
37
38 #ifdef OPENSUBDIV_ORIENT_TOPOLOGY
39 namespace {
40
41 inline void reverse_face_verts(int *face_verts, int num_verts)
42 {
43         int last_vert = face_verts[num_verts - 1];
44         for (int i = num_verts - 1; i > 0;  --i) {
45                 face_verts[i] = face_verts[i - 1];
46         }
47         face_verts[0] = last_vert;
48 }
49
50 struct TopologyRefinerData {
51         const OpenSubdiv_Converter& conv;
52         std::vector<float> *uvs;
53 };
54
55 }  /* namespace */
56 #endif /* OPENSUBDIV_ORIENT_TOPOLOGY */
57
58 namespace OpenSubdiv {
59 namespace OPENSUBDIV_VERSION {
60 namespace Far {
61
62 namespace {
63
64 template <typename T>
65 inline int findInArray(T array, int value)
66 {
67         return (int)(std::find(array.begin(), array.end(), value) - array.begin());
68 }
69
70 #ifdef OPENSUBDIV_ORIENT_TOPOLOGY
71 inline int get_loop_winding(int vert0_of_face, int vert1_of_face)
72 {
73         int delta_face = vert1_of_face - vert0_of_face;
74         if (abs(delta_face) != 1) {
75                 if (delta_face > 0) {
76                         delta_face = -1;
77                 }
78                 else {
79                         delta_face = 1;
80                 }
81         }
82         return delta_face;
83 }
84
85 inline void reverse_face_loops(IndexArray face_verts, IndexArray face_edges)
86 {
87         for (int i = 0; i < face_verts.size() / 2; ++i) {
88                 int j = face_verts.size() - i - 1;
89                 if (i != j) {
90                         std::swap(face_verts[i], face_verts[j]);
91                         std::swap(face_edges[i], face_edges[j]);
92                 }
93         }
94         reverse_face_verts(&face_verts[0], face_verts.size());
95 }
96
97 inline void check_oriented_vert_connectivity(const int num_vert_edges,
98                                              const int num_vert_faces,
99                                              const int *vert_edges,
100                                              const int *vert_faces,
101                                              const int *dst_vert_edges,
102                                              const int *dst_vert_faces)
103 {
104 #  ifndef NDEBUG
105         for (int i = 0; i < num_vert_faces; ++i) {
106                 bool found = false;
107                 for (int j = 0; j < num_vert_faces; ++j) {
108                         if (vert_faces[i] == dst_vert_faces[j]) {
109                                 found = true;
110                                 break;
111                         }
112                 }
113                 if (!found) {
114                         assert(!"vert-faces connectivity ruined");
115                 }
116         }
117         for (int i = 0; i < num_vert_edges; ++i) {
118                 bool found = false;
119                 for (int j = 0; j < num_vert_edges; ++j) {
120                         if (vert_edges[i] == dst_vert_edges[j]) {
121                                 found = true;
122                                 break;
123                         }
124                 }
125                 if (!found) {
126                         assert(!"vert-edges connectivity ruined");
127                 }
128         }
129 #  else
130         (void)num_vert_edges;
131         (void)num_vert_faces;
132         (void)vert_edges;
133         (void)vert_faces;
134         (void)dst_vert_edges;
135         (void)dst_vert_faces;
136 #  endif
137 }
138 #endif
139
140 }  /* namespace */
141
142 template <>
143 inline bool TopologyRefinerFactory<TopologyRefinerData>::resizeComponentTopology(
144         TopologyRefiner& refiner,
145         const TopologyRefinerData& cb_data)
146 {
147         const OpenSubdiv_Converter& conv = cb_data.conv;
148         /* Faces and face-verts */
149         const int num_faces = conv.get_num_faces(&conv);
150         setNumBaseFaces(refiner, num_faces);
151         for (int face = 0; face < num_faces; ++face) {
152                 const int num_verts = conv.get_num_face_verts(&conv, face);
153                 setNumBaseFaceVertices(refiner, face, num_verts);
154         }
155         /* Edges and edge-faces. */
156         const int num_edges = conv.get_num_edges(&conv);
157         setNumBaseEdges(refiner, num_edges);
158         for (int edge = 0; edge < num_edges; ++edge) {
159                 const int num_edge_faces = conv.get_num_edge_faces(&conv, edge);
160                 setNumBaseEdgeFaces(refiner, edge, num_edge_faces);
161         }
162         /* Vertices and vert-faces and vert-edges/ */
163         const int num_verts = conv.get_num_verts(&conv);
164         setNumBaseVertices(refiner, num_verts);
165         for (int vert = 0; vert < num_verts; ++vert) {
166                 const int num_vert_edges = conv.get_num_vert_edges(&conv, vert),
167                           num_vert_faces = conv.get_num_vert_faces(&conv, vert);
168                 setNumBaseVertexEdges(refiner, vert, num_vert_edges);
169                 setNumBaseVertexFaces(refiner, vert, num_vert_faces);
170         }
171         return true;
172 }
173
174 template <>
175 inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTopology(
176           TopologyRefiner& refiner,
177           const TopologyRefinerData &cb_data)
178 {
179         const OpenSubdiv_Converter& conv = cb_data.conv;
180         using Far::IndexArray;
181         /* Face relations. */
182         const int num_faces = conv.get_num_faces(&conv);
183         for (int face = 0; face < num_faces; ++face) {
184                 IndexArray dst_face_verts = getBaseFaceVertices(refiner, face);
185                 conv.get_face_verts(&conv, face, &dst_face_verts[0]);
186                 IndexArray dst_face_edges = getBaseFaceEdges(refiner, face);
187                 conv.get_face_edges(&conv, face, &dst_face_edges[0]);
188         }
189         /* Edge relations. */
190         const int num_edges = conv.get_num_edges(&conv);
191         for (int edge = 0; edge < num_edges; ++edge) {
192                 /* Edge-vertices */
193                 IndexArray dst_edge_verts = getBaseEdgeVertices(refiner, edge);
194                 conv.get_edge_verts(&conv, edge, &dst_edge_verts[0]);
195                 /* Edge-faces */
196                 IndexArray dst_edge_faces = getBaseEdgeFaces(refiner, edge);
197                 conv.get_edge_faces(&conv, edge, &dst_edge_faces[0]);
198         }
199 #ifdef OPENSUBDIV_ORIENT_TOPOLOGY
200         /* Make face normals consistent. */
201         bool *face_used = new bool[num_faces];
202         memset(face_used, 0, sizeof(bool) * num_faces);
203         std::stack<int> traverse_stack;
204         int face_start = 0, num_traversed_faces = 0;
205         /* Traverse all islands. */
206         while (num_traversed_faces != num_faces) {
207                 /* Find first face of any untraversed islands. */
208                 while (face_used[face_start]) {
209                         ++face_start;
210                 }
211                 /* Add first face to the stack. */
212                 traverse_stack.push(face_start);
213                 face_used[face_start] = true;
214                 /* Go over whole connected component. */
215                 while (!traverse_stack.empty()) {
216                         int face = traverse_stack.top();
217                         traverse_stack.pop();
218                         IndexArray face_edges = getBaseFaceEdges(refiner, face);
219                         ConstIndexArray face_verts = getBaseFaceVertices(refiner, face);
220                         for (int edge_index = 0; edge_index < face_edges.size(); ++edge_index) {
221                                 const int edge = face_edges[edge_index];
222                                 ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge);
223                                 if (edge_faces.size() != 2) {
224                                         /* Can't make consistent normals for non-manifolds. */
225                                         continue;
226                                 }
227                                 ConstIndexArray edge_verts = getBaseEdgeVertices(refiner, edge);
228                                 /* Get winding of the reference face. */
229                                 int vert0_of_face = findInArray(face_verts, edge_verts[0]),
230                                     vert1_of_face = findInArray(face_verts, edge_verts[1]);
231                                 int delta_face = get_loop_winding(vert0_of_face, vert1_of_face);
232                                 for (int edge_face = 0; edge_face < edge_faces.size(); ++edge_face) {
233                                         int other_face = edge_faces[edge_face];
234                                         /* Never re-traverse faces, only move forward. */
235                                         if (face_used[other_face]) {
236                                                 continue;
237                                         }
238                                         IndexArray other_face_verts = getBaseFaceVertices(refiner,
239                                                                                           other_face);
240                                         int vert0_of_other_face = findInArray(other_face_verts,
241                                                                               edge_verts[0]),
242                                             vert1_of_other_face = findInArray(other_face_verts,
243                                                                               edge_verts[1]);
244                                         int delta_other_face = get_loop_winding(vert0_of_other_face,
245                                                                                 vert1_of_other_face);
246                                         if (delta_face * delta_other_face > 0) {
247                                                 IndexArray other_face_verts = getBaseFaceVertices(refiner,
248                                                                                                   other_face),
249                                                            other_face_edges = getBaseFaceEdges(refiner,
250                                                                                                other_face);
251                                                 reverse_face_loops(other_face_verts,
252                                                                    other_face_edges);
253                                         }
254                                         traverse_stack.push(other_face);
255                                         face_used[other_face] = true;
256                                 }
257                         }
258                         ++num_traversed_faces;
259                 }
260         }
261 #endif  /* OPENSUBDIV_ORIENT_TOPOLOGY */
262         /* Vertex relations */
263         const int num_verts = conv.get_num_verts(&conv);
264         for (int vert = 0; vert < num_verts; ++vert) {
265
266                 /* Vert-Faces */
267                 IndexArray dst_vert_faces = getBaseVertexFaces(refiner, vert);
268                 int num_vert_faces = conv.get_num_vert_faces(&conv, vert);
269                 int *vert_faces = new int[num_vert_faces];
270                 conv.get_vert_faces(&conv, vert, vert_faces);
271                 /* Vert-Edges */
272                 IndexArray dst_vert_edges = getBaseVertexEdges(refiner, vert);
273                 int num_vert_edges = conv.get_num_vert_edges(&conv, vert);
274                 int *vert_edges = new int[num_vert_edges];
275                 conv.get_vert_edges(&conv, vert, vert_edges);
276 #ifdef OPENSUBDIV_ORIENT_TOPOLOGY
277                 /* ** Order vertex edges and faces in a CCW order. ** */
278                 memset(face_used, 0, sizeof(bool) * num_faces);
279                 /* Number of edges and faces added to the ordered array. */
280                 int edge_count_ordered = 0, face_count_ordered = 0;
281                 /* Add loose edges straight into the edges array. */
282                 bool has_fan_connections = false;
283                 for (int i = 0; i < num_vert_edges; ++i) {
284                         IndexArray edge_faces = getBaseEdgeFaces(refiner, vert_edges[i]);
285                         if (edge_faces.size() == 0) {
286                                 dst_vert_edges[edge_count_ordered++] = vert_edges[i];
287                         }
288                         else if (edge_faces.size() > 2) {
289                                 has_fan_connections = true;
290                         }
291                 }
292                 if (has_fan_connections) {
293                         /* OpenSubdiv currently doesn't give us clues how to handle
294                          * fan face connections. and since handling such connections
295                          * complicates the loop below we simply don't do special
296                          * orientation for them.
297                          */
298                         memcpy(&dst_vert_edges[0], vert_edges, sizeof(int) * num_vert_edges);
299                         memcpy(&dst_vert_faces[0], vert_faces, sizeof(int) * num_vert_faces);
300                         delete [] vert_edges;
301                         delete [] vert_faces;
302                         continue;
303                 }
304                 /* Perform at max numbder of vert-edges iteration and try to avoid
305                  * deadlock here for malformed mesh.
306                  */
307                 for (int global_iter = 0; global_iter < num_vert_edges; ++global_iter) {
308                         /* Numbr of edges and faces which are still to be ordered. */
309                         int num_vert_edges_remained = num_vert_edges - edge_count_ordered,
310                             num_vert_faces_remained = num_vert_faces - face_count_ordered;
311                         if (num_vert_edges_remained == 0 && num_vert_faces_remained == 0) {
312                                 /* All done, nothing to do anymore. */
313                                 break;
314                         }
315                         /* Face, edge and face-vertex inndex to start traversal from. */
316                         int face_start = -1, edge_start = -1, face_vert_start = -1;
317                         if (num_vert_edges_remained == num_vert_faces_remained) {
318                                 /* Vertex is eitehr complete manifold or is connected to seevral
319                                  * manifold islands (hourglass-like configuration), can pick up
320                                  * random edge unused and start from it.
321                                  */
322                                 /* TODO(sergey): Start from previous edge from which traversal
323                                  * began at previous iteration.
324                                  */
325                                 for (int i = 0; i < num_vert_edges; ++i) {
326                                         face_start = vert_faces[i];
327                                         if (!face_used[face_start]) {
328                                                 ConstIndexArray
329                                                     face_verts = getBaseFaceVertices(refiner, face_start),
330                                                     face_edges = getBaseFaceEdges(refiner, face_start);
331                                                 face_vert_start = findInArray(face_verts, vert);
332                                                 edge_start = face_edges[face_vert_start];
333                                                 break;
334                                         }
335                                 }
336                         }
337                         else {
338                                 /* Special handle of non-manifold vertex. */
339                                 for (int i = 0; i < num_vert_edges; ++i) {
340                                         edge_start = vert_edges[i];
341                                         IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start);
342                                         if (edge_faces.size() == 1) {
343                                                 face_start = edge_faces[0];
344                                                 if (!face_used[face_start]) {
345                                                         ConstIndexArray
346                                                             face_verts = getBaseFaceVertices(refiner, face_start),
347                                                             face_edges = getBaseFaceEdges(refiner, face_start);
348                                                         face_vert_start = findInArray(face_verts, vert);
349                                                         if (edge_start == face_edges[face_vert_start]) {
350                                                                 break;
351                                                         }
352                                                 }
353                                         }
354                                         /* Reset indices for sanity check below. */
355                                         face_start = edge_start = face_vert_start =  -1;
356                                 }
357                         }
358                         /* Sanity check. */
359                         assert(face_start != -1 &&
360                                edge_start != -1 &&
361                                face_vert_start != -1);
362                         /* Traverse faces starting from the current one. */
363                         int edge_first = edge_start;
364                         dst_vert_faces[face_count_ordered++] = face_start;
365                         dst_vert_edges[edge_count_ordered++] = edge_start;
366                         face_used[face_start] = true;
367                         while (edge_count_ordered < num_vert_edges) {
368                                 IndexArray face_verts = getBaseFaceVertices(refiner, face_start);
369                                 IndexArray face_edges = getBaseFaceEdges(refiner, face_start);
370                                 int face_edge_start = face_vert_start;
371                                 int face_edge_next = (face_edge_start > 0) ? (face_edge_start - 1) : (face_verts.size() - 1);
372                                 Index edge_next = face_edges[face_edge_next];
373                                 if (edge_next == edge_first) {
374                                         /* Multiple manifolds found, stop for now and handle rest
375                                          * in the next iteration.
376                                          */
377                                         break;
378                                 }
379                                 dst_vert_edges[edge_count_ordered++] = edge_next;
380                                 if (face_count_ordered < num_vert_faces) {
381                                         IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_next);
382                                         assert(edge_faces.size() != 0);
383                                         if (edge_faces.size() == 1) {
384                                                 assert(edge_faces[0] == face_start);
385                                                 break;
386                                         }
387                                         else if (edge_faces.size() != 2) {
388                                                 break;
389                                         }
390                                         assert(edge_faces.size() == 2);
391                                         face_start = edge_faces[(edge_faces[0] == face_start) ? 1 : 0];
392                                         face_vert_start = findInArray(getBaseFaceEdges(refiner, face_start), edge_next);
393                                         dst_vert_faces[face_count_ordered++] = face_start;
394                                         face_used[face_start] = true;
395                                 }
396                                 edge_start = edge_next;
397                         }
398                 }
399                 /* Verify ordering doesn't ruin connectivity information. */
400                 assert(face_count_ordered == num_vert_faces);
401                 assert(edge_count_ordered == num_vert_edges);
402                 check_oriented_vert_connectivity(num_vert_edges,
403                                                  num_vert_faces,
404                                                  vert_edges,
405                                                  vert_faces,
406                                                  &dst_vert_edges[0],
407                                                  &dst_vert_faces[0]);
408                 /* For the release builds we're failing mesh construction so instead
409                  * of nasty bugs the unsupported mesh will simply disappear from the
410                  * viewport.
411                  */
412                 if (face_count_ordered != num_vert_faces ||
413                     edge_count_ordered != num_vert_edges)
414                 {
415                         delete [] vert_edges;
416                         delete [] vert_faces;
417                         return false;
418                 }
419 #else  /* OPENSUBDIV_ORIENT_TOPOLOGY */
420                 memcpy(&dst_vert_edges[0], vert_edges, sizeof(int) * num_vert_edges);
421                 memcpy(&dst_vert_faces[0], vert_faces, sizeof(int) * num_vert_faces);
422 #endif  /* OPENSUBDIV_ORIENT_TOPOLOGY */
423                 delete [] vert_edges;
424                 delete [] vert_faces;
425         }
426 #ifdef OPENSUBDIV_ORIENT_TOPOLOGY
427         delete [] face_used;
428 #endif
429         populateBaseLocalIndices(refiner);
430         return true;
431 };
432
433 template <>
434 inline bool TopologyRefinerFactory<TopologyRefinerData>::assignComponentTags(
435         TopologyRefiner& refiner,
436         const TopologyRefinerData& cb_data)
437 {
438         const OpenSubdiv_Converter& conv = cb_data.conv;
439         typedef OpenSubdiv::Sdc::Crease Crease;
440
441         int num_edges = conv.get_num_edges(&conv);
442         for (int edge = 0; edge < num_edges; ++edge) {
443                 float sharpness;
444                 ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge);
445                 if (edge_faces.size() == 2) {
446                         sharpness = conv.get_edge_sharpness(&conv, edge);
447                 }
448                 else {
449                         /* Non-manifold edges must be sharp. */
450                         sharpness = Crease::SHARPNESS_INFINITE;
451                 }
452                 setBaseEdgeSharpness(refiner, edge, sharpness);
453         }
454
455         /* OpenSubdiv expects non-manifold vertices to be sharp but at the
456          * time it handles correct cases when vertex is a corner of plane.
457          * Currently mark verts which are adjacent to a loose edge as sharp,
458          * but this decision needs some more investigation.
459          */
460         int num_vert = conv.get_num_verts(&conv);
461         for (int vert = 0; vert < num_vert; ++vert) {
462                 ConstIndexArray vert_edges = getBaseVertexEdges(refiner, vert);
463                 for (int edge_index = 0; edge_index < vert_edges.size(); ++edge_index) {
464                         int edge = vert_edges[edge_index];
465                         ConstIndexArray edge_faces = getBaseEdgeFaces(refiner, edge);
466                         if (edge_faces.size() == 0) {
467                                 setBaseVertexSharpness(refiner, vert, Crease::SHARPNESS_INFINITE);
468                                 break;
469                         }
470                 }
471                 if (vert_edges.size() == 2) {
472                         int edge0 = vert_edges[0],
473                             edge1 = vert_edges[1];
474                         float sharpness0 = conv.get_edge_sharpness(&conv, edge0),
475                               sharpness1 = conv.get_edge_sharpness(&conv, edge1);
476                         float sharpness = std::min(sharpness0,  sharpness1);
477                         setBaseVertexSharpness(refiner, vert, sharpness);
478                 }
479         }
480
481         return true;
482 }
483
484 template <>
485 inline void TopologyRefinerFactory<TopologyRefinerData>::reportInvalidTopology(
486         TopologyError /*errCode*/,
487         const char *msg,
488         const TopologyRefinerData& /*mesh*/)
489 {
490         printf("OpenSubdiv Error: %s\n", msg);
491 }
492
493 template <>
494 inline bool TopologyRefinerFactory<TopologyRefinerData>::assignFaceVaryingTopology(
495         TopologyRefiner& refiner,
496         const TopologyRefinerData& cb_data)
497 {
498         const OpenSubdiv_Converter& conv = cb_data.conv;
499         const int num_layers = conv.get_num_uv_layers(&conv);
500         if (num_layers <= 0) {
501                 /* No UV maps, we can skip any face-varying data. */
502                 return true;
503         }
504         const int num_faces = getNumBaseFaces(refiner);
505         size_t uvs_offset = 0;
506         for (int layer = 0; layer < num_layers; ++layer) {
507                 conv.precalc_uv_layer(&conv, layer);
508                 const int num_uvs = conv.get_num_uvs(&conv);
509                 /* Fill in UV coordinates. */
510                 cb_data.uvs->resize(cb_data.uvs->size() + num_uvs * 2);
511                 conv.get_uvs(&conv, &cb_data.uvs->at(uvs_offset));
512                 uvs_offset += num_uvs * 2;
513                 /* Fill in per-corner index of the UV. */
514                 const int channel = createBaseFVarChannel(refiner, num_uvs);
515                 for (int face = 0; face < num_faces; ++face) {
516                         Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner,
517                                                                              face,
518                                                                              channel);
519                         for (int corner = 0; corner < dst_face_uvs.size(); ++corner) {
520                                 const int uv_index = conv.get_face_corner_uv_index(&conv,
521                                                                                    face,
522                                                                                    corner);
523                                 dst_face_uvs[corner] = uv_index;
524                         }
525                 }
526                 conv.finish_uv_layer(&conv);
527         }
528         return true;
529 }
530
531 }  /* namespace Far */
532 }  /* namespace OPENSUBDIV_VERSION */
533 }  /* namespace OpenSubdiv */
534
535 namespace {
536
537 OpenSubdiv::Sdc::SchemeType get_capi_scheme_type(OpenSubdiv_SchemeType type)
538 {
539         switch (type) {
540                 case OSD_SCHEME_BILINEAR:
541                         return OpenSubdiv::Sdc::SCHEME_BILINEAR;
542                 case OSD_SCHEME_CATMARK:
543                         return OpenSubdiv::Sdc::SCHEME_CATMARK;
544                 case OSD_SCHEME_LOOP:
545                         return OpenSubdiv::Sdc::SCHEME_LOOP;
546         }
547         assert(!"Unknown scheme type passed via C-API");
548         return OpenSubdiv::Sdc::SCHEME_CATMARK;
549 }
550
551 OpenSubdiv::Sdc::Options::FVarLinearInterpolation
552 get_capi_fvar_linear_interpolation(
553         OpenSubdiv_FVarLinearInterpolation linear_interpolation)
554 {
555         typedef OpenSubdiv::Sdc::Options Options;
556         switch (linear_interpolation) {
557                 case OSD_FVAR_LINEAR_INTERPOLATION_NONE:
558                         return Options::FVAR_LINEAR_NONE;
559                 case OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY:
560                         return Options::FVAR_LINEAR_CORNERS_ONLY;
561                 case OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES:
562                         return Options::FVAR_LINEAR_BOUNDARIES;
563                 case OSD_FVAR_LINEAR_INTERPOLATION_ALL:
564                         return Options::FVAR_LINEAR_ALL;
565         }
566         assert(!"Unknown fvar linear interpolation passed via C-API");
567         return Options::FVAR_LINEAR_NONE;
568 }
569
570 }  /* namespace */
571
572 struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
573         OpenSubdiv_Converter *converter)
574 {
575         typedef OpenSubdiv::Sdc::Options Options;
576
577         using OpenSubdiv::Far::TopologyRefinerFactory;
578         const OpenSubdiv::Sdc::SchemeType scheme_type =
579                 get_capi_scheme_type(converter->get_scheme_type(converter));
580         const Options::FVarLinearInterpolation linear_interpolation =
581                 get_capi_fvar_linear_interpolation(
582                         converter->get_fvar_linear_interpolation(converter));
583         Options options;
584         options.SetVtxBoundaryInterpolation(Options::VTX_BOUNDARY_EDGE_ONLY);
585         options.SetCreasingMethod(Options::CREASE_UNIFORM);
586         options.SetFVarLinearInterpolation(linear_interpolation);
587
588         TopologyRefinerFactory<TopologyRefinerData>::Options
589                 topology_options(scheme_type, options);
590 #ifdef OPENSUBDIV_VALIDATE_TOPOLOGY
591         topology_options.validateFullTopology = true;
592 #endif
593         OpenSubdiv_TopologyRefinerDescr *result = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefinerDescr);
594         TopologyRefinerData cb_data = {*converter, &result->uvs};
595         /* We don't use guarded allocation here so we can re-use the refiner
596          * for GL mesh creation directly.
597          */
598         result->osd_refiner =
599                 TopologyRefinerFactory<TopologyRefinerData>::Create(
600                         cb_data,
601                         topology_options);
602
603         return result;
604 }
605
606 void openSubdiv_deleteTopologyRefinerDescr(
607         OpenSubdiv_TopologyRefinerDescr *topology_refiner)
608 {
609         delete topology_refiner->osd_refiner;
610         OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefinerDescr);
611 }
612
613 int openSubdiv_topologyRefinerGetSubdivLevel(
614         const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
615 {
616         using OpenSubdiv::Far::TopologyRefiner;
617         const TopologyRefiner *refiner = topology_refiner->osd_refiner;
618         return refiner->GetMaxLevel();
619 }
620
621 int openSubdiv_topologyRefinerGetNumVerts(
622         const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
623 {
624         using OpenSubdiv::Far::TopologyLevel;
625         using OpenSubdiv::Far::TopologyRefiner;
626         const TopologyRefiner *refiner = topology_refiner->osd_refiner;
627         const TopologyLevel &base_level = refiner->GetLevel(0);
628         return base_level.GetNumVertices();
629 }
630
631 int openSubdiv_topologyRefinerGetNumEdges(
632         const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
633 {
634         using OpenSubdiv::Far::TopologyLevel;
635         using OpenSubdiv::Far::TopologyRefiner;
636         const TopologyRefiner *refiner = topology_refiner->osd_refiner;
637         const TopologyLevel &base_level = refiner->GetLevel(0);
638         return base_level.GetNumEdges();
639 }
640
641 int openSubdiv_topologyRefinerGetNumFaces(
642         const OpenSubdiv_TopologyRefinerDescr *topology_refiner)
643 {
644         using OpenSubdiv::Far::TopologyLevel;
645         using OpenSubdiv::Far::TopologyRefiner;
646         const TopologyRefiner *refiner = topology_refiner->osd_refiner;
647         const TopologyLevel &base_level = refiner->GetLevel(0);
648         return base_level.GetNumFaces();
649 }
650
651 int openSubdiv_topologyRefinerGetNumFaceVerts(
652         const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
653         int face)
654 {
655         using OpenSubdiv::Far::TopologyLevel;
656         using OpenSubdiv::Far::TopologyRefiner;
657         const TopologyRefiner *refiner = topology_refiner->osd_refiner;
658         const TopologyLevel &base_level = refiner->GetLevel(0);
659         return base_level.GetFaceVertices(face).size();
660 }
661
662 int openSubdiv_topologyRefnerCompareConverter(
663         const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
664         OpenSubdiv_Converter *converter)
665 {
666         typedef OpenSubdiv::Sdc::Options Options;
667         using OpenSubdiv::Far::ConstIndexArray;
668         using OpenSubdiv::Far::TopologyRefiner;
669         using OpenSubdiv::Far::TopologyLevel;
670         const TopologyRefiner *refiner = topology_refiner->osd_refiner;
671         const TopologyLevel &base_level = refiner->GetLevel(0);
672         const int num_verts = base_level.GetNumVertices();
673         const int num_edges = base_level.GetNumEdges();
674         const int num_faces = base_level.GetNumFaces();
675         /* Quick preliminary check. */
676         OpenSubdiv::Sdc::SchemeType scheme_type =
677                 get_capi_scheme_type(converter->get_scheme_type(converter));
678         if (scheme_type != refiner->GetSchemeType()) {
679                 return false;
680         }
681         const Options options = refiner->GetSchemeOptions();
682         const Options::FVarLinearInterpolation interp =
683                 options.GetFVarLinearInterpolation();
684         const Options::FVarLinearInterpolation new_interp =
685                 get_capi_fvar_linear_interpolation(
686                         converter->get_fvar_linear_interpolation(converter));
687         if (new_interp != interp) {
688                 return false;
689         }
690         if (converter->get_num_verts(converter) != num_verts ||
691             converter->get_num_edges(converter) != num_edges ||
692             converter->get_num_faces(converter) != num_faces)
693         {
694                 return false;
695         }
696         /* Compare all edges. */
697         for (int edge = 0; edge < num_edges; ++edge) {
698                 ConstIndexArray edge_verts = base_level.GetEdgeVertices(edge);
699                 int conv_edge_verts[2];
700                 converter->get_edge_verts(converter, edge, conv_edge_verts);
701                 if (conv_edge_verts[0] != edge_verts[0] ||
702                     conv_edge_verts[1] != edge_verts[1])
703                 {
704                         return false;
705                 }
706         }
707         /* Compare all faces. */
708         std::vector<int> conv_face_verts;
709         for (int face = 0; face < num_faces; ++face) {
710                 ConstIndexArray face_verts = base_level.GetFaceVertices(face);
711                 if (face_verts.size() != converter->get_num_face_verts(converter,
712                                                                        face))
713                 {
714                         return false;
715                 }
716                 conv_face_verts.resize(face_verts.size());
717                 converter->get_face_verts(converter, face, &conv_face_verts[0]);
718                 bool direct_match = true;
719                 for (int i = 0; i < face_verts.size(); ++i) {
720                         if (conv_face_verts[i] != face_verts[i]) {
721                                 direct_match = false;
722                                 break;
723                         }
724                 }
725                 if (!direct_match) {
726                         /* If face didn't match in direct direction we also test if it
727                          * matches in reversed direction. This is because conversion might
728                          * reverse loops to make normals consistent.
729                          */
730 #ifdef OPENSUBDIV_ORIENT_TOPOLOGY
731                         reverse_face_verts(&conv_face_verts[0], conv_face_verts.size());
732                         for (int i = 0; i < face_verts.size(); ++i) {
733                                 if (conv_face_verts[i] != face_verts[i]) {
734                                         return false;
735                                 }
736                         }
737 #else
738                         return false;
739 #endif
740                 }
741         }
742         /* Compare sharpness. */
743         for (int edge = 0; edge < num_edges; ++edge) {
744                 ConstIndexArray edge_faces = base_level.GetEdgeFaces(edge);
745                 float sharpness = base_level.GetEdgeSharpness(edge);
746                 float conv_sharpness;
747                 if (edge_faces.size() == 2) {
748                         conv_sharpness = converter->get_edge_sharpness(converter, edge);
749                 }
750                 else {
751                         conv_sharpness = OpenSubdiv::Sdc::Crease::SHARPNESS_INFINITE;
752                 }
753                 if (sharpness != conv_sharpness) {
754                         return false;
755                 }
756         }
757         return true;
758 }