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