Cleanup: style, use braces for blenkernel
[blender.git] / source / blender / blenkernel / intern / CCGSubSurf_opensubdiv_converter.c
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
17 /** \file
18  * \ingroup bke
19  */
20
21 #ifdef WITH_OPENSUBDIV
22
23 #  include <stdlib.h>
24
25 #  include "MEM_guardedalloc.h"
26 #  include "BLI_sys_types.h"  // for intptr_t support
27
28 #  include "BLI_utildefines.h" /* for BLI_assert */
29 #  include "BLI_math.h"
30
31 #  include "CCGSubSurf.h"
32 #  include "CCGSubSurf_intern.h"
33
34 #  include "BKE_DerivedMesh.h"
35 #  include "BKE_mesh_mapping.h"
36
37 #  include "opensubdiv_capi.h"
38 #  include "opensubdiv_converter_capi.h"
39
40 /* Use mesh element mapping structures during conversion.
41  * Uses more memory but is much faster than naive algorithm.
42  */
43 #  define USE_MESH_ELEMENT_MAPPING
44
45 /**
46  * Converter from DerivedMesh.
47  */
48
49 typedef struct ConvDMStorage {
50   CCGSubSurf *ss;
51   DerivedMesh *dm;
52
53 #  ifdef USE_MESH_ELEMENT_MAPPING
54   MeshElemMap *vert_edge_map, *vert_poly_map, *edge_poly_map;
55   int *vert_edge_mem, *vert_poly_mem, *edge_poly_mem;
56 #  endif
57
58   MVert *mvert;
59   MEdge *medge;
60   MLoop *mloop;
61   MPoly *mpoly;
62
63   MeshIslandStore island_store;
64   int num_uvs;
65   float *uvs;
66   int *face_uvs;
67 } ConvDMStorage;
68
69 static OpenSubdiv_SchemeType conv_dm_get_type(const OpenSubdiv_Converter *converter)
70 {
71   ConvDMStorage *storage = converter->user_data;
72   if (storage->ss->meshIFC.simpleSubdiv) {
73     return OSD_SCHEME_BILINEAR;
74   }
75   else {
76     return OSD_SCHEME_CATMARK;
77   }
78 }
79
80 static OpenSubdiv_VtxBoundaryInterpolation conv_dm_get_vtx_boundary_interpolation(
81     const OpenSubdiv_Converter *UNUSED(converter))
82 {
83   return OSD_VTX_BOUNDARY_EDGE_ONLY;
84 }
85
86 static OpenSubdiv_FVarLinearInterpolation conv_dm_get_fvar_linear_interpolation(
87     const OpenSubdiv_Converter *converter)
88 {
89   ConvDMStorage *storage = converter->user_data;
90   if (storage->ss->osd_subdiv_uvs) {
91     return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
92   }
93   return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
94 }
95
96 static bool conv_dm_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter))
97 {
98   return true;
99 }
100
101 static int conv_dm_get_num_faces(const OpenSubdiv_Converter *converter)
102 {
103   ConvDMStorage *storage = converter->user_data;
104   DerivedMesh *dm = storage->dm;
105   return dm->getNumPolys(dm);
106 }
107
108 static int conv_dm_get_num_edges(const OpenSubdiv_Converter *converter)
109 {
110   ConvDMStorage *storage = converter->user_data;
111   DerivedMesh *dm = storage->dm;
112   return dm->getNumEdges(dm);
113 }
114
115 static int conv_dm_get_num_verts(const OpenSubdiv_Converter *converter)
116 {
117   ConvDMStorage *storage = converter->user_data;
118   DerivedMesh *dm = storage->dm;
119   return dm->getNumVerts(dm);
120 }
121
122 static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter, int face)
123 {
124   ConvDMStorage *storage = converter->user_data;
125   const MPoly *mpoly = &storage->mpoly[face];
126   return mpoly->totloop;
127 }
128
129 static void conv_dm_get_face_verts(const OpenSubdiv_Converter *converter,
130                                    int face,
131                                    int *face_verts)
132 {
133   ConvDMStorage *storage = converter->user_data;
134   const MPoly *mpoly = &storage->mpoly[face];
135   int loop;
136   for (loop = 0; loop < mpoly->totloop; loop++) {
137     face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v;
138   }
139 }
140
141 static void conv_dm_get_face_edges(const OpenSubdiv_Converter *converter,
142                                    int face,
143                                    int *face_edges)
144 {
145   ConvDMStorage *storage = converter->user_data;
146   const MPoly *mpoly = &storage->mpoly[face];
147   int loop;
148   for (loop = 0; loop < mpoly->totloop; loop++) {
149     face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e;
150   }
151 }
152
153 static void conv_dm_get_edge_verts(const OpenSubdiv_Converter *converter,
154                                    int edge,
155                                    int *edge_verts)
156 {
157   ConvDMStorage *storage = converter->user_data;
158   const MEdge *medge = &storage->medge[edge];
159   edge_verts[0] = medge->v1;
160   edge_verts[1] = medge->v2;
161 }
162
163 static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge)
164 {
165   ConvDMStorage *storage = converter->user_data;
166 #  ifndef USE_MESH_ELEMENT_MAPPING
167   DerivedMesh *dm = storage->dm;
168   int num = 0, poly;
169   for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
170     const MPoly *mpoly = &user_data->mpoly[poly];
171     int loop;
172     for (loop = 0; loop < mpoly->totloop; loop++) {
173       const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
174       if (mloop->e == edge) {
175         ++num;
176         break;
177       }
178     }
179   }
180   return num;
181 #  else
182   return storage->edge_poly_map[edge].count;
183 #  endif
184 }
185
186 static void conv_dm_get_edge_faces(const OpenSubdiv_Converter *converter,
187                                    int edge,
188                                    int *edge_faces)
189 {
190   ConvDMStorage *storage = converter->user_data;
191 #  ifndef USE_MESH_ELEMENT_MAPPING
192   DerivedMesh *dm = storage->dm;
193   int num = 0, poly;
194   for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
195     const MPoly *mpoly = &user_data->mpoly[poly];
196     int loop;
197     for (loop = 0; loop < mpoly->totloop; loop++) {
198       const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
199       if (mloop->e == edge) {
200         edge_faces[num++] = poly;
201         break;
202       }
203     }
204   }
205 #  else
206   memcpy(edge_faces,
207          storage->edge_poly_map[edge].indices,
208          sizeof(int) * storage->edge_poly_map[edge].count);
209 #  endif
210 }
211
212 static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge)
213 {
214   ConvDMStorage *storage = converter->user_data;
215   CCGSubSurf *ss = storage->ss;
216   const MEdge *medge = storage->medge;
217   return (float)medge[edge].crease / 255.0f * ss->subdivLevels;
218 }
219
220 static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert)
221 {
222   ConvDMStorage *storage = converter->user_data;
223 #  ifndef USE_MESH_ELEMENT_MAPPING
224   DerivedMesh *dm = storage->dm;
225   int num = 0, edge;
226   for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
227     const MEdge *medge = &user_data->medge[edge];
228     if (medge->v1 == vert || medge->v2 == vert) {
229       ++num;
230     }
231   }
232   return num;
233 #  else
234   return storage->vert_edge_map[vert].count;
235 #  endif
236 }
237
238 static void conv_dm_get_vert_edges(const OpenSubdiv_Converter *converter,
239                                    int vert,
240                                    int *vert_edges)
241 {
242   ConvDMStorage *storage = converter->user_data;
243 #  ifndef USE_MESH_ELEMENT_MAPPING
244   DerivedMesh *dm = storage->dm;
245   int num = 0, edge;
246   for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
247     const MEdge *medge = &user_data->medge[edge];
248     if (medge->v1 == vert || medge->v2 == vert) {
249       vert_edges[num++] = edge;
250     }
251   }
252 #  else
253   memcpy(vert_edges,
254          storage->vert_edge_map[vert].indices,
255          sizeof(int) * storage->vert_edge_map[vert].count);
256 #  endif
257 }
258
259 static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert)
260 {
261   ConvDMStorage *storage = converter->user_data;
262 #  ifndef USE_MESH_ELEMENT_MAPPING
263   DerivedMesh *dm = storage->dm;
264   int num = 0, poly;
265   for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
266     const MPoly *mpoly = &user_data->mpoly[poly];
267     int loop;
268     for (loop = 0; loop < mpoly->totloop; loop++) {
269       const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
270       if (mloop->v == vert) {
271         ++num;
272         break;
273       }
274     }
275   }
276   return num;
277 #  else
278   return storage->vert_poly_map[vert].count;
279 #  endif
280 }
281
282 static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
283                                    int vert,
284                                    int *vert_faces)
285 {
286   ConvDMStorage *storage = converter->user_data;
287 #  ifndef USE_MESH_ELEMENT_MAPPING
288   DerivedMesh *dm = storage->dm;
289   int num = 0, poly;
290   for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
291     const MPoly *mpoly = &storage->mpoly[poly];
292     int loop;
293     for (loop = 0; loop < mpoly->totloop; loop++) {
294       const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
295       if (mloop->v == vert) {
296         vert_faces[num++] = poly;
297         break;
298       }
299     }
300   }
301 #  else
302   memcpy(vert_faces,
303          storage->vert_poly_map[vert].indices,
304          sizeof(int) * storage->vert_poly_map[vert].count);
305 #  endif
306 }
307
308 static bool conv_dm_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter),
309                                              int UNUSED(manifold_vertex_index))
310 {
311   return false;
312 }
313
314 static float conv_dm_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter),
315                                           int UNUSED(manifold_vertex_index))
316 {
317   return 0.0f;
318 }
319
320 static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter)
321 {
322   ConvDMStorage *storage = converter->user_data;
323   DerivedMesh *dm = storage->dm;
324   int num_uv_layers = CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
325   return num_uv_layers;
326 }
327
328 static void conv_dm_precalc_uv_layer(const OpenSubdiv_Converter *converter, int layer)
329 {
330   ConvDMStorage *storage = converter->user_data;
331   DerivedMesh *dm = storage->dm;
332
333   const MLoopUV *mloopuv = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, layer);
334   const int num_loops = dm->getNumLoops(dm);
335
336   /* Initialize memory required for the operations. */
337   if (storage->uvs == NULL) {
338     storage->uvs = MEM_mallocN(sizeof(float) * 2 * num_loops, "osd uvs");
339   }
340   if (storage->face_uvs == NULL) {
341     storage->face_uvs = MEM_mallocN(sizeof(int) * num_loops, "osd face uvs");
342   }
343
344   /* Calculate islands connectivity of the UVs. */
345   BKE_mesh_calc_islands_loop_poly_uvmap(storage->mvert,
346                                         dm->getNumVerts(dm),
347                                         storage->medge,
348                                         dm->getNumEdges(dm),
349                                         storage->mpoly,
350                                         dm->getNumPolys(dm),
351                                         storage->mloop,
352                                         dm->getNumLoops(dm),
353                                         mloopuv,
354                                         &storage->island_store);
355
356   /* Here we "weld" duplicated vertices from island to the same UV value.
357    * The idea here is that we need to pass individual islands to OpenSubdiv.
358    */
359   storage->num_uvs = 0;
360   for (int island = 0; island < storage->island_store.islands_num; ++island) {
361     MeshElemMap *island_poly_map = storage->island_store.islands[island];
362     for (int poly = 0; poly < island_poly_map->count; ++poly) {
363       int poly_index = island_poly_map->indices[poly];
364       /* Within the same UV island we should share UV points across
365        * loops. Otherwise each poly will be subdivided individually
366        * which we don't really want.
367        */
368       const MPoly *mpoly = &storage->mpoly[poly_index];
369       for (int loop = 0; loop < mpoly->totloop; ++loop) {
370         const MLoopUV *luv = &mloopuv[mpoly->loopstart + loop];
371         bool found = false;
372         /* TODO(sergey): Quite bad loop, which gives us O(N^2)
373          * complexity here. But how can we do it smarter, hopefully
374          * without requiring lots of additional memory.
375          */
376         for (int i = 0; i < storage->num_uvs; ++i) {
377           if (equals_v2v2(luv->uv, &storage->uvs[2 * i])) {
378             storage->face_uvs[mpoly->loopstart + loop] = i;
379             found = true;
380             break;
381           }
382         }
383         if (!found) {
384           copy_v2_v2(&storage->uvs[2 * storage->num_uvs], luv->uv);
385           storage->face_uvs[mpoly->loopstart + loop] = storage->num_uvs;
386           ++storage->num_uvs;
387         }
388       }
389     }
390   }
391 }
392
393 static void conv_dm_finish_uv_layer(const OpenSubdiv_Converter *converter)
394 {
395   ConvDMStorage *storage = converter->user_data;
396   BKE_mesh_loop_islands_free(&storage->island_store);
397 }
398
399 static int conv_dm_get_num_uvs(const OpenSubdiv_Converter *converter)
400 {
401   ConvDMStorage *storage = converter->user_data;
402   return storage->num_uvs;
403 }
404
405 static int conv_dm_get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
406                                             int face,
407                                             int corner)
408 {
409   ConvDMStorage *storage = converter->user_data;
410   const MPoly *mpoly = &storage->mpoly[face];
411   return storage->face_uvs[mpoly->loopstart + corner];
412 }
413
414 static void conv_dm_free_user_data(const OpenSubdiv_Converter *converter)
415 {
416   ConvDMStorage *user_data = converter->user_data;
417   if (user_data->uvs != NULL) {
418     MEM_freeN(user_data->uvs);
419   }
420   if (user_data->face_uvs != NULL) {
421     MEM_freeN(user_data->face_uvs);
422   }
423
424 #  ifdef USE_MESH_ELEMENT_MAPPING
425   MEM_freeN(user_data->vert_edge_map);
426   MEM_freeN(user_data->vert_edge_mem);
427   MEM_freeN(user_data->vert_poly_map);
428   MEM_freeN(user_data->vert_poly_mem);
429   MEM_freeN(user_data->edge_poly_map);
430   MEM_freeN(user_data->edge_poly_mem);
431 #  endif
432   MEM_freeN(user_data);
433 }
434
435 void ccgSubSurf_converter_setup_from_derivedmesh(CCGSubSurf *ss,
436                                                  DerivedMesh *dm,
437                                                  OpenSubdiv_Converter *converter)
438 {
439   ConvDMStorage *user_data;
440
441   converter->getSchemeType = conv_dm_get_type;
442
443   converter->getVtxBoundaryInterpolation = conv_dm_get_vtx_boundary_interpolation;
444   converter->getFVarLinearInterpolation = conv_dm_get_fvar_linear_interpolation;
445   converter->specifiesFullTopology = conv_dm_specifies_full_topology;
446
447   converter->getNumFaces = conv_dm_get_num_faces;
448   converter->getNumEdges = conv_dm_get_num_edges;
449   converter->getNumVertices = conv_dm_get_num_verts;
450
451   converter->getNumFaceVertices = conv_dm_get_num_face_verts;
452   converter->getFaceVertices = conv_dm_get_face_verts;
453   converter->getFaceEdges = conv_dm_get_face_edges;
454
455   converter->getEdgeVertices = conv_dm_get_edge_verts;
456   converter->getNumEdgeFaces = conv_dm_get_num_edge_faces;
457   converter->getEdgeFaces = conv_dm_get_edge_faces;
458   converter->getEdgeSharpness = conv_dm_get_edge_sharpness;
459
460   converter->getNumVertexEdges = conv_dm_get_num_vert_edges;
461   converter->getVertexEdges = conv_dm_get_vert_edges;
462   converter->getNumVertexFaces = conv_dm_get_num_vert_faces;
463   converter->getVertexFaces = conv_dm_get_vert_faces;
464   converter->isInfiniteSharpVertex = conv_dm_is_infinite_sharp_vertex;
465   converter->getVertexSharpness = conv_dm_get_vertex_sharpness;
466
467   converter->getNumUVLayers = conv_dm_get_num_uv_layers;
468   converter->precalcUVLayer = conv_dm_precalc_uv_layer;
469   converter->finishUVLayer = conv_dm_finish_uv_layer;
470   converter->getNumUVCoordinates = conv_dm_get_num_uvs;
471   converter->getFaceCornerUVIndex = conv_dm_get_face_corner_uv_index;
472
473   user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
474   user_data->ss = ss;
475   user_data->dm = dm;
476
477   user_data->mvert = dm->getVertArray(dm);
478   user_data->medge = dm->getEdgeArray(dm);
479   user_data->mloop = dm->getLoopArray(dm);
480   user_data->mpoly = dm->getPolyArray(dm);
481
482   memset(&user_data->island_store, 0, sizeof(user_data->island_store));
483
484   user_data->uvs = NULL;
485   user_data->face_uvs = NULL;
486
487   converter->freeUserData = conv_dm_free_user_data;
488   converter->user_data = user_data;
489
490 #  ifdef USE_MESH_ELEMENT_MAPPING
491   {
492     const MEdge *medge = dm->getEdgeArray(dm);
493     const MLoop *mloop = dm->getLoopArray(dm);
494     const MPoly *mpoly = dm->getPolyArray(dm);
495     const int num_vert = dm->getNumVerts(dm), num_edge = dm->getNumEdges(dm),
496               num_loop = dm->getNumLoops(dm), num_poly = dm->getNumPolys(dm);
497     BKE_mesh_vert_edge_map_create(
498         &user_data->vert_edge_map, &user_data->vert_edge_mem, medge, num_vert, num_edge);
499
500     BKE_mesh_vert_poly_map_create(&user_data->vert_poly_map,
501                                   &user_data->vert_poly_mem,
502                                   mpoly,
503                                   mloop,
504                                   num_vert,
505                                   num_poly,
506                                   num_loop);
507
508     BKE_mesh_edge_poly_map_create(&user_data->edge_poly_map,
509                                   &user_data->edge_poly_mem,
510                                   medge,
511                                   num_edge,
512                                   mpoly,
513                                   num_poly,
514                                   mloop,
515                                   num_loop);
516   }
517 #  endif /* USE_MESH_ELEMENT_MAPPING */
518 }
519
520 /**
521  * Converter from CCGSubSurf
522  */
523
524 static OpenSubdiv_SchemeType conv_ccg_get_bilinear_type(const OpenSubdiv_Converter *converter)
525 {
526   CCGSubSurf *ss = converter->user_data;
527   if (ss->meshIFC.simpleSubdiv) {
528     return OSD_SCHEME_BILINEAR;
529   }
530   else {
531     return OSD_SCHEME_CATMARK;
532   }
533 }
534
535 static OpenSubdiv_VtxBoundaryInterpolation conv_ccg_get_vtx_boundary_interpolation(
536     const OpenSubdiv_Converter *UNUSED(converter))
537 {
538   return OSD_VTX_BOUNDARY_EDGE_ONLY;
539 }
540
541 static OpenSubdiv_FVarLinearInterpolation conv_ccg_get_fvar_linear_interpolation(
542     const OpenSubdiv_Converter *converter)
543 {
544   CCGSubSurf *ss = converter->user_data;
545   if (ss->osd_subdiv_uvs) {
546     return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY;
547   }
548   return OSD_FVAR_LINEAR_INTERPOLATION_ALL;
549 }
550
551 static bool conv_ccg_specifies_full_topology(const OpenSubdiv_Converter *UNUSED(converter))
552 {
553   return true;
554 }
555
556 static int conv_ccg_get_num_faces(const OpenSubdiv_Converter *converter)
557 {
558   CCGSubSurf *ss = converter->user_data;
559   return ss->fMap->numEntries;
560 }
561
562 static int conv_ccg_get_num_edges(const OpenSubdiv_Converter *converter)
563 {
564   CCGSubSurf *ss = converter->user_data;
565   return ss->eMap->numEntries;
566 }
567
568 static int conv_ccg_get_num_verts(const OpenSubdiv_Converter *converter)
569 {
570   CCGSubSurf *ss = converter->user_data;
571   return ss->vMap->numEntries;
572 }
573
574 static int conv_ccg_get_num_face_verts(const OpenSubdiv_Converter *converter, int face)
575 {
576   CCGSubSurf *ss = converter->user_data;
577   CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
578   return ccgSubSurf_getFaceNumVerts(ccg_face);
579 }
580
581 static void conv_ccg_get_face_verts(const OpenSubdiv_Converter *converter,
582                                     int face,
583                                     int *face_verts)
584 {
585   CCGSubSurf *ss = converter->user_data;
586   CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
587   int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face);
588   int loop;
589   for (loop = 0; loop < num_face_verts; loop++) {
590     CCGVert *ccg_vert = ccgSubSurf_getFaceVert(ccg_face, loop);
591     face_verts[loop] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert));
592   }
593 }
594
595 static void conv_ccg_get_face_edges(const OpenSubdiv_Converter *converter,
596                                     int face,
597                                     int *face_edges)
598 {
599   CCGSubSurf *ss = converter->user_data;
600   CCGFace *ccg_face = ccgSubSurf_getFace(ss, POINTER_FROM_INT(face));
601   int num_face_verts = ccgSubSurf_getFaceNumVerts(ccg_face);
602   int loop;
603   for (loop = 0; loop < num_face_verts; loop++) {
604     CCGEdge *ccg_edge = ccgSubSurf_getFaceEdge(ccg_face, loop);
605     face_edges[loop] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
606   }
607 }
608
609 static void conv_ccg_get_edge_verts(const OpenSubdiv_Converter *converter,
610                                     int edge,
611                                     int *edge_verts)
612 {
613   CCGSubSurf *ss = converter->user_data;
614   CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
615   CCGVert *ccg_vert0 = ccgSubSurf_getEdgeVert0(ccg_edge);
616   CCGVert *ccg_vert1 = ccgSubSurf_getEdgeVert1(ccg_edge);
617   edge_verts[0] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert0));
618   edge_verts[1] = POINTER_AS_INT(ccgSubSurf_getVertVertHandle(ccg_vert1));
619 }
620
621 static int conv_ccg_get_num_edge_faces(const OpenSubdiv_Converter *converter, int edge)
622 {
623   CCGSubSurf *ss = converter->user_data;
624   CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
625   return ccgSubSurf_getEdgeNumFaces(ccg_edge);
626 }
627
628 static void conv_ccg_get_edge_faces(const OpenSubdiv_Converter *converter,
629                                     int edge,
630                                     int *edge_faces)
631 {
632   CCGSubSurf *ss = converter->user_data;
633   CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
634   int num_edge_faces = ccgSubSurf_getEdgeNumFaces(ccg_edge);
635   int face;
636   for (face = 0; face < num_edge_faces; face++) {
637     CCGFace *ccg_face = ccgSubSurf_getEdgeFace(ccg_edge, face);
638     edge_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
639   }
640 }
641
642 static float conv_ccg_get_edge_sharpness(const OpenSubdiv_Converter *converter, int edge)
643 {
644   CCGSubSurf *ss = converter->user_data;
645   CCGEdge *ccg_edge = ccgSubSurf_getEdge(ss, POINTER_FROM_INT(edge));
646   /* TODO(sergey): Multiply by subdivision level once CPU evaluator
647    * is switched to uniform subdivision type.
648    */
649   return ccg_edge->crease;
650 }
651
652 static int conv_ccg_get_num_vert_edges(const OpenSubdiv_Converter *converter, int vert)
653 {
654   CCGSubSurf *ss = converter->user_data;
655   CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
656   return ccgSubSurf_getVertNumEdges(ccg_vert);
657 }
658
659 static void conv_ccg_get_vert_edges(const OpenSubdiv_Converter *converter,
660                                     int vert,
661                                     int *vert_edges)
662 {
663   CCGSubSurf *ss = converter->user_data;
664   CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
665   int num_vert_edges = ccgSubSurf_getVertNumEdges(ccg_vert);
666   int edge;
667   for (edge = 0; edge < num_vert_edges; edge++) {
668     CCGEdge *ccg_edge = ccgSubSurf_getVertEdge(ccg_vert, edge);
669     vert_edges[edge] = POINTER_AS_INT(ccgSubSurf_getEdgeEdgeHandle(ccg_edge));
670   }
671 }
672
673 static int conv_ccg_get_num_vert_faces(const OpenSubdiv_Converter *converter, int vert)
674 {
675   CCGSubSurf *ss = converter->user_data;
676   CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
677   return ccgSubSurf_getVertNumFaces(ccg_vert);
678 }
679
680 static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter,
681                                     int vert,
682                                     int *vert_faces)
683 {
684   CCGSubSurf *ss = converter->user_data;
685   CCGVert *ccg_vert = ccgSubSurf_getVert(ss, POINTER_FROM_INT(vert));
686   int num_vert_faces = ccgSubSurf_getVertNumFaces(ccg_vert);
687   int face;
688   for (face = 0; face < num_vert_faces; face++) {
689     CCGFace *ccg_face = ccgSubSurf_getVertFace(ccg_vert, face);
690     vert_faces[face] = POINTER_AS_INT(ccgSubSurf_getFaceFaceHandle(ccg_face));
691   }
692 }
693
694 static bool conv_ccg_is_infinite_sharp_vertex(const OpenSubdiv_Converter *UNUSED(converter),
695                                               int UNUSED(manifold_vertex_index))
696 {
697   return false;
698 }
699
700 static float conv_ccg_get_vertex_sharpness(const OpenSubdiv_Converter *UNUSED(converter),
701                                            int UNUSED(manifold_vertex_index))
702 {
703   return 0.0f;
704 }
705
706 static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter))
707 {
708   return 0;
709 }
710
711 static void conv_ccg_precalc_uv_layer(const OpenSubdiv_Converter *UNUSED(converter),
712                                       int UNUSED(layer))
713 {
714 }
715
716 static void conv_ccg_finish_uv_layer(const OpenSubdiv_Converter *UNUSED(converter))
717 {
718 }
719
720 static int conv_ccg_get_num_uvs(const OpenSubdiv_Converter *UNUSED(converter))
721 {
722   return 0;
723 }
724
725 static int conv_ccg_get_face_corner_uv_index(const OpenSubdiv_Converter *UNUSED(converter),
726                                              int UNUSED(face),
727                                              int UNUSED(corner_))
728 {
729   return 0;
730 }
731
732 void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss, OpenSubdiv_Converter *converter)
733 {
734   converter->getSchemeType = conv_ccg_get_bilinear_type;
735
736   converter->getVtxBoundaryInterpolation = conv_ccg_get_vtx_boundary_interpolation;
737   converter->getFVarLinearInterpolation = conv_ccg_get_fvar_linear_interpolation;
738   converter->specifiesFullTopology = conv_ccg_specifies_full_topology;
739
740   converter->getNumFaces = conv_ccg_get_num_faces;
741   converter->getNumEdges = conv_ccg_get_num_edges;
742   converter->getNumVertices = conv_ccg_get_num_verts;
743
744   converter->getNumFaceVertices = conv_ccg_get_num_face_verts;
745   converter->getFaceVertices = conv_ccg_get_face_verts;
746   converter->getFaceEdges = conv_ccg_get_face_edges;
747
748   converter->getEdgeVertices = conv_ccg_get_edge_verts;
749   converter->getNumEdgeFaces = conv_ccg_get_num_edge_faces;
750   converter->getEdgeFaces = conv_ccg_get_edge_faces;
751   converter->getEdgeSharpness = conv_ccg_get_edge_sharpness;
752
753   converter->getNumVertexEdges = conv_ccg_get_num_vert_edges;
754   converter->getVertexEdges = conv_ccg_get_vert_edges;
755   converter->getNumVertexFaces = conv_ccg_get_num_vert_faces;
756   converter->getVertexFaces = conv_ccg_get_vert_faces;
757   converter->isInfiniteSharpVertex = conv_ccg_is_infinite_sharp_vertex;
758   converter->getVertexSharpness = conv_ccg_get_vertex_sharpness;
759
760   converter->getNumUVLayers = conv_ccg_get_num_uv_layers;
761   converter->precalcUVLayer = conv_ccg_precalc_uv_layer;
762   converter->finishUVLayer = conv_ccg_finish_uv_layer;
763   converter->getNumUVCoordinates = conv_ccg_get_num_uvs;
764   converter->getFaceCornerUVIndex = conv_ccg_get_face_corner_uv_index;
765
766   converter->freeUserData = NULL;
767   converter->user_data = ss;
768 }
769
770 void ccgSubSurf_converter_free(struct OpenSubdiv_Converter *converter)
771 {
772   if (converter->freeUserData) {
773     converter->freeUserData(converter);
774   }
775 }
776
777 #endif /* WITH_OPENSUBDIV */