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