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