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