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