Merge branch 'master' into blender2.8
[blender.git] / source / blender / blenkernel / intern / subsurf_ccg.c
index 221c600f502a4a21eea65fb94bdf2bf92dd46b9c..6db306854f4ebf2d1f538b5625d075543d8d5988 100644 (file)
@@ -69,6 +69,7 @@
 #include "BKE_mesh_mapping.h"
 #include "BKE_modifier.h"
 #include "BKE_multires.h"
+#include "BKE_object.h"
 #include "BKE_paint.h"
 #include "BKE_scene.h"
 #include "BKE_subsurf.h"
 #  include "BLI_array.h"
 #endif
 
-#include "GPU_draw.h"
-#include "GPU_glew.h"
-#include "GPU_buffers.h"
-#include "GPU_shader.h"
-#include "GPU_basic_shader.h"
-
 #include "CCGSubSurf.h"
 
 #ifdef WITH_OPENSUBDIV
@@ -1766,47 +1761,7 @@ static void ccgDM_foreachMappedLoop(
        }
 }
 
-static void ccgDM_drawVerts(DerivedMesh *dm)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       int edgeSize = ccgSubSurf_getEdgeSize(ss);
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       CCGVertIterator vi;
-       CCGEdgeIterator ei;
-       CCGFaceIterator fi;
-
-       glBegin(GL_POINTS);
-       for (ccgSubSurf_initVertIterator(ss, &vi); !ccgVertIterator_isStopped(&vi); ccgVertIterator_next(&vi)) {
-               CCGVert *v = ccgVertIterator_getCurrent(&vi);
-               glVertex3fv(ccgSubSurf_getVertData(ss, v));
-       }
-
-       for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
-               CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
-               int x;
-
-               for (x = 1; x < edgeSize - 1; x++)
-                       glVertex3fv(ccgSubSurf_getEdgeData(ss, e, x));
-       }
-
-       for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
-               CCGFace *f = ccgFaceIterator_getCurrent(&fi);
-               int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
-               glVertex3fv(ccgSubSurf_getFaceCenterData(f));
-               for (S = 0; S < numVerts; S++)
-                       for (x = 1; x < gridSize - 1; x++)
-                               glVertex3fv(ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
-               for (S = 0; S < numVerts; S++)
-                       for (y = 1; y < gridSize - 1; y++)
-                               for (x = 1; x < gridSize - 1; x++)
-                                       glVertex3fv(ccgSubSurf_getFaceGridData(ss, f, S, x, y));
-       }
-       glEnd();
-}
-
-static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm)
+static void UNUSED_FUNCTION(ccgdm_pbvh_update)(CCGDerivedMesh *ccgdm)
 {
        if (ccgdm->pbvh && ccgDM_use_grid_pbvh(ccgdm)) {
                CCGFace **faces;
@@ -1821,2402 +1776,229 @@ static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm)
        }
 }
 
-static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEdges)
+static void ccgDM_foreachMappedFaceCenter(
+        DerivedMesh *dm,
+        void (*func)(void *userData, int index, const float co[3], const float no[3]),
+        void *userData,
+        DMForeachFlag flag)
 {
-       GPUDrawObject *gdo;
        CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
+       CCGSubSurf *ss = ccgdm->ss;
+       CCGKey key;
+       CCGFaceIterator fi;
 
-#ifdef WITH_OPENSUBDIV
-       if (ccgdm->useGpuBackend) {
-               /* TODO(sergey): We currently only support all edges drawing. */
-               if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
-                       ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
+       CCG_key_top_level(&key, ss);
+
+       for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
+               CCGFace *f = ccgFaceIterator_getCurrent(&fi);
+               const int index = ccgDM_getFaceMapIndex(ss, f);
+
+               if (index != -1) {
+                       /* Face center data normal isn't updated atm. */
+                       CCGElem *vd = ccgSubSurf_getFaceGridData(ss, f, 0, 0, 0);
+                       const float *no = (flag & DM_FOREACH_USE_NORMAL) ? CCG_elem_no(&key, vd) : NULL;
+                       func(userData, index, CCG_elem_co(&key, vd), no);
                }
-               return;
        }
-#endif
-
-       ccgdm_pbvh_update(ccgdm);
+}
 
-/* old debug feature for edges, unsupported for now */
-#if 0
-       int useAging = 0;
+static void ccgDM_release(DerivedMesh *dm)
+{
+       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
 
-       if (!(G.f & G_BACKBUFSEL)) {
-               CCGSubSurf *ss = ccgdm->ss;
-               ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
+       if (DM_release(dm)) {
+               /* Before freeing, need to update the displacement map */
+               if (ccgdm->multires.modified_flags) {
+                       /* Check that mmd still exists */
+                       if (!ccgdm->multires.local_mmd &&
+                           BLI_findindex(&ccgdm->multires.ob->modifiers, ccgdm->multires.mmd) < 0)
+                       {
+                               ccgdm->multires.mmd = NULL;
+                       }
 
-               /* it needs some way to upload this to VBO now */
-               if (useAging) {
-                       int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
-                       glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
+                       if (ccgdm->multires.mmd) {
+                               if (ccgdm->multires.modified_flags & MULTIRES_COORDS_MODIFIED)
+                                       multires_modifier_update_mdisps(dm, NULL);
+                               if (ccgdm->multires.modified_flags & MULTIRES_HIDDEN_MODIFIED)
+                                       multires_modifier_update_hidden(dm);
+                       }
                }
-       }
-#endif
 
-       GPU_edge_setup(dm);
-       gdo = dm->drawObject;
-       if (gdo->edges && gdo->points) {
-               if (drawAllEdges && drawLooseEdges) {
-                       GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, (gdo->totedge - gdo->totinterior) * 2);
-               }
-               else if (drawAllEdges) {
-                       GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->loose_edge_offset * 2);
+               if (ccgdm->ehash)
+                       BLI_edgehash_free(ccgdm->ehash, NULL);
+
+               if (ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap);
+               if (ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces);
+               if (ccgdm->gridData) MEM_freeN(ccgdm->gridData);
+               if (ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset);
+               if (ccgdm->gridFlagMats) MEM_freeN(ccgdm->gridFlagMats);
+               if (ccgdm->gridHidden) {
+                       /* Using dm->getNumGrids(dm) accesses freed memory */
+                       uint numGrids = ccgdm->numGrid;
+                       for (uint i = 0; i < numGrids; i++) {
+                               if (ccgdm->gridHidden[i]) {
+                                       MEM_freeN(ccgdm->gridHidden[i]);
+                               }
+                       }
+                       MEM_freeN(ccgdm->gridHidden);
                }
-               else {
-                       GPU_buffer_draw_elements(gdo->edges, GL_LINES, 0, gdo->tot_edge_drawn * 2);
-                       GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->loose_edge_offset * 2, gdo->tot_loose_edge_drawn * 2);
+               if (ccgdm->freeSS) ccgSubSurf_free(ccgdm->ss);
+               if (ccgdm->pmap) MEM_freeN(ccgdm->pmap);
+               if (ccgdm->pmap_mem) MEM_freeN(ccgdm->pmap_mem);
+               MEM_freeN(ccgdm->edgeFlags);
+               MEM_freeN(ccgdm->faceFlags);
+               if (ccgdm->useGpuBackend == false) {
+                       MEM_freeN(ccgdm->vertMap);
+                       MEM_freeN(ccgdm->edgeMap);
+                       MEM_freeN(ccgdm->faceMap);
                }
-       }
 
-       if (gdo->edges && ccgdm->drawInteriorEdges) {
-               GPU_buffer_draw_elements(gdo->edges, GL_LINES, gdo->interior_offset * 2, gdo->totinterior * 2);
+               BLI_mutex_end(&ccgdm->loops_cache_lock);
+               BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock);
+
+               MEM_freeN(ccgdm);
        }
-       GPU_buffers_unbind();
 }
 
-static void ccgDM_drawLooseEdges(DerivedMesh *dm)
+static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
 {
-       int start;
-       int count;
+       if (type == CD_ORIGINDEX) {
+               /* create origindex on demand to save memory */
+               CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+               CCGSubSurf *ss = ccgdm->ss;
+               int *origindex;
+               int a, index, totnone, totorig;
 
-#ifdef WITH_OPENSUBDIV
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       if (ccgdm->useGpuBackend) {
-               /* TODO(sergey): Needs implementation. */
-               return;
-       }
-#endif
+               /* Avoid re-creation if the layer exists already */
+               BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_READ);
+               origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+               BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
+               if (origindex) {
+                       return origindex;
+               }
+
+               BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE);
+               DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+               origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+
+               totorig = ccgSubSurf_getNumVerts(ss);
+               totnone = dm->numVertData - totorig;
 
-       GPU_edge_setup(dm);
+               /* original vertices are at the end */
+               for (a = 0; a < totnone; a++)
+                       origindex[a] = ORIGINDEX_NONE;
 
-       start = (dm->drawObject->loose_edge_offset * 2);
-       count = (dm->drawObject->interior_offset - dm->drawObject->loose_edge_offset) * 2;
+               for (index = 0; index < totorig; index++, a++) {
+                       CCGVert *v = ccgdm->vertMap[index].vert;
+                       origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v);
+               }
+               BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
 
-       if (count) {
-               GPU_buffer_draw_elements(dm->drawObject->edges, GL_LINES, start, count);
+               return origindex;
        }
 
-       GPU_buffers_unbind();
+       return DM_get_vert_data_layer(dm, type);
 }
 
-static void ccgDM_NormalFast(float *a, float *b, float *c, float *d, float no[3])
+static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type)
 {
-       float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
-       float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
+       if (type == CD_ORIGINDEX) {
+               /* create origindex on demand to save memory */
+               CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
+               CCGSubSurf *ss = ccgdm->ss;
+               int *origindex;
+               int a, i, index, totnone, totorig, totedge;
+               int edgeSize = ccgSubSurf_getEdgeSize(ss);
+
+               /* Avoid re-creation if the layer exists already */
+               origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+               if (origindex) {
+                       return origindex;
+               }
 
-       no[0] = b_dY * a_cZ - b_dZ * a_cY;
-       no[1] = b_dZ * a_cX - b_dX * a_cZ;
-       no[2] = b_dX * a_cY - b_dY * a_cX;
+               DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+               origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
 
-       normalize_v3(no);
-}
+               totedge = ccgSubSurf_getNumEdges(ss);
+               totorig = totedge * (edgeSize - 1);
+               totnone = dm->numEdgeData - totorig;
 
+               /* original edges are at the end */
+               for (a = 0; a < totnone; a++)
+                       origindex[a] = ORIGINDEX_NONE;
 
-static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
-{
-       float a_cX = c[0] - a[0], a_cY = c[1] - a[1], a_cZ = c[2] - a[2];
-       float b_dX = d[0] - b[0], b_dY = d[1] - b[1], b_dZ = d[2] - b[2];
-       float no[3];
+               for (index = 0; index < totedge; index++) {
+                       CCGEdge *e = ccgdm->edgeMap[index].edge;
+                       int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
+
+                       for (i = 0; i < edgeSize - 1; i++, a++)
+                               origindex[a] = mapIndex;
+               }
 
-       no[0] = b_dY * a_cZ - b_dZ * a_cY;
-       no[1] = b_dZ * a_cX - b_dX * a_cZ;
-       no[2] = b_dX * a_cY - b_dY * a_cX;
+               return origindex;
+       }
 
-       /* don't normalize, GL_NORMALIZE is enabled */
-       glNormal3fv(no);
+       return DM_get_edge_data_layer(dm, type);
 }
 
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_normal(
-        DerivedMesh *dm, short *varray)
+static void *ccgDM_get_tessface_data_layer(DerivedMesh *dm, int type)
 {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       int gridFaces = gridSize - 1;
-       DMFlagMat *faceFlags = ccgdm->faceFlags;
-       int i, totface = ccgSubSurf_getNumFaces(ss);
-       int shademodel;
-       int start = 0;
+       if (type == CD_ORIGINDEX) {
+               /* create origindex on demand to save memory */
+               int *origindex;
 
-       /* we are in sculpt mode, disable loop normals (since they won't get updated) */
-       if (ccgdm->pbvh)
-               lnors = NULL;
+               /* Avoid re-creation if the layer exists already */
+               origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
+               if (origindex) {
+                       return origindex;
+               }
 
-       CCG_key_top_level(&key, ss);
+               DM_add_tessface_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
+               origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
 
-       for (i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
-               int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-               int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-               const float (*ln)[3] = NULL;
+               /* silly loop counting up */
+               range_vn_i(origindex, dm->getNumTessFaces(dm), 0);
 
-               if (faceFlags) {
-                       shademodel = (lnors || (faceFlags[index].flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT;
-               }
-               else {
-                       shademodel = GL_SMOOTH;
-               }
+               return origindex;
+       }
 
-               if (lnors) {
-                       ln = lnors;
-                       lnors += gridFaces * gridFaces * numVerts * 4;
-               }
+       if (type == CD_TESSLOOPNORMAL) {
+               /* Create tessloopnormal on demand to save memory. */
+               /* Note that since tessellated face corners are the same a loops in CCGDM, and since all faces have four
+                * loops/corners, we can simplify the code here by converting tessloopnormals from 'short (*)[4][3]'
+                * to 'short (*)[3]'.
+                */
+               short (*tlnors)[3];
 
-               for (S = 0; S < numVerts; S++) {
-                       CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+               /* Avoid re-creation if the layer exists already */
+               tlnors = DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL);
+               if (!tlnors) {
+                       float (*lnors)[3];
+                       short (*tlnors_it)[3];
+                       const int numLoops = ccgDM_getNumLoops(dm);
+                       int i;
 
-                       if (ln) {
-                               /* Can't use quad strips here... */
-                               for (y = 0; y < gridFaces; y ++) {
-                                       for (x = 0; x < gridFaces; x ++) {
-                                               normal_float_to_short_v3(&varray[start + 0],  ln[0]);
-                                               normal_float_to_short_v3(&varray[start + 4],  ln[3]);
-                                               normal_float_to_short_v3(&varray[start + 8],  ln[2]);
-                                               normal_float_to_short_v3(&varray[start + 12], ln[1]);
-
-                                               start += 16;
-                                               ln += 4;
-                                       }
-                               }
-                       }
-                       else if (shademodel == GL_SMOOTH) {
-                               for (y = 0; y < gridFaces; y ++) {
-                                       for (x = 0; x < gridFaces; x ++) {
-                                               float *a = CCG_grid_elem_no(&key, faceGridData, x, y );
-                                               float *b = CCG_grid_elem_no(&key, faceGridData, x + 1, y);
-                                               float *c = CCG_grid_elem_no(&key, faceGridData, x + 1, y + 1);
-                                               float *d = CCG_grid_elem_no(&key, faceGridData, x, y + 1);
-
-                                               normal_float_to_short_v3(&varray[start], a);
-                                               normal_float_to_short_v3(&varray[start + 4], b);
-                                               normal_float_to_short_v3(&varray[start + 8], c);
-                                               normal_float_to_short_v3(&varray[start + 12], d);
-
-                                               start += 16;
-                                       }
-                               }
+                       lnors = dm->getLoopDataArray(dm, CD_NORMAL);
+                       if (!lnors) {
+                               return NULL;
                        }
-                       else {
-                               for (y = 0; y < gridFaces; y ++) {
-                                       for (x = 0; x < gridFaces; x ++) {
-                                               float f_no[3];
-                                               short f_no_s[3];
-
-                                               float *a = CCG_grid_elem_co(&key, faceGridData, x, y );
-                                               float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y );
-                                               float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
-                                               float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
-                                               ccgDM_NormalFast(a, b, c, d, f_no);
-                                               normal_float_to_short_v3(f_no_s, f_no);
 
-                                               copy_v3_v3_short(&varray[start], f_no_s);
-                                               copy_v3_v3_short(&varray[start + 4], f_no_s);
-                                               copy_v3_v3_short(&varray[start + 8], f_no_s);
-                                               copy_v3_v3_short(&varray[start + 12], f_no_s);
+                       DM_add_tessface_layer(dm, CD_TESSLOOPNORMAL, CD_CALLOC, NULL);
+                       tlnors = tlnors_it = (short (*)[3])DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL);
 
-                                               start += 16;
-                                       }
-                               }
+                       /* With ccgdm, we have a simple one to one mapping between loops and tessellated face corners. */
+                       for (i = 0; i < numLoops; ++i, ++tlnors_it, ++lnors) {
+                               normal_float_to_short_v3(*tlnors_it, *lnors);
                        }
                }
-       }
-}
 
-typedef struct FaceCount {
-       unsigned int i_visible;
-       unsigned int i_hidden;
-       unsigned int i_tri_visible;
-       unsigned int i_tri_hidden;
-} FaceCount;
+               return tlnors;
+       }
 
+       return DM_get_tessface_data_layer(dm, type);
+}
 
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_triangles(
-        DerivedMesh *dm, unsigned int *varray,
-        const int *mat_orig_to_new)
-{
-       GPUBufferMaterial *gpumat, *gpumaterials = dm->drawObject->materials;
-       const int gpu_totmat = dm->drawObject->totmaterial;
-       const short dm_totmat = dm->totmat;
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       int gridFaces = gridSize - 1;
-       DMFlagMat *faceFlags = ccgdm->faceFlags;
-       int i, totface = ccgSubSurf_getNumFaces(ss);
-       short mat_nr = -1;
-       int start;
-       int totloops = 0;
-       FaceCount *fc = MEM_mallocN(sizeof(*fc) * gpu_totmat, "gpumaterial.facecount");
-
-       CCG_key_top_level(&key, ss);
-
-       for (i = 0; i < gpu_totmat; i++) {
-               fc[i].i_visible = 0;
-               fc[i].i_tri_visible = 0;
-               fc[i].i_hidden = gpumaterials[i].totpolys - 1;
-               fc[i].i_tri_hidden = gpumaterials[i].totelements - 1;
-       }
-
-       for (i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
-               int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-               int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-               bool is_hidden;
-               int mati;
-
-               if (faceFlags) {
-                       mat_nr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat);
-                       is_hidden = (faceFlags[index].flag & ME_HIDE) != 0;
-               }
-               else {
-                       mat_nr = 0;
-                       is_hidden = false;
-               }
-               mati = mat_orig_to_new[mat_nr];
-               gpumat = dm->drawObject->materials + mati;
-
-               if (is_hidden) {
-                       for (S = 0; S < numVerts; S++) {
-                               for (y = 0; y < gridFaces; y++) {
-                                       for (x = 0; x < gridFaces; x++) {
-                                               start = gpumat->start + fc[mati].i_tri_hidden;
-
-                                               varray[start--] = totloops;
-                                               varray[start--] = totloops + 2;
-                                               varray[start--] = totloops + 3;
-
-                                               varray[start--] = totloops;
-                                               varray[start--] = totloops + 1;
-                                               varray[start--] = totloops + 2;
-
-                                               fc[mati].i_tri_hidden -= 6;
-
-                                               totloops += 4;
-                                       }
-                               }
-                       }
-                       gpumat->polys[fc[mati].i_hidden--] = i;
-               }
-               else {
-                       for (S = 0; S < numVerts; S++) {
-                               for (y = 0; y < gridFaces; y++) {
-                                       for (x = 0; x < gridFaces; x++) {
-                                               start = gpumat->start + fc[mati].i_tri_visible;
-
-                                               varray[start++] = totloops + 3;
-                                               varray[start++] = totloops + 2;
-                                               varray[start++] = totloops;
-
-                                               varray[start++] = totloops + 2;
-                                               varray[start++] = totloops + 1;
-                                               varray[start++] = totloops;
-
-                                               fc[mati].i_tri_visible += 6;
-
-                                               totloops += 4;
-                                       }
-                               }
-                       }
-                       gpumat->polys[fc[mati].i_visible++] = i;
-               }
-       }
-
-       /* set the visible polygons */
-       for (i = 0; i < gpu_totmat; i++) {
-               gpumaterials[i].totvisiblepolys = fc[i].i_visible;
-       }
-
-       MEM_freeN(fc);
-}
-
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_vertex(
-        DerivedMesh *dm, void *varray_p)
-{
-       float *varray = varray_p;
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       int gridFaces = gridSize - 1;
-       int i, totface = ccgSubSurf_getNumFaces(ss);
-       int totedge = ccgSubSurf_getNumEdges(ss);
-       int start = 0;
-       int edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-       CCG_key_top_level(&key, ss);
-
-       for (i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
-               int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
-               for (S = 0; S < numVerts; S++) {
-                       CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
-                       for (y = 0; y < gridFaces; y++) {
-                               for (x = 0; x < gridFaces; x++) {
-                                       float *a = CCG_grid_elem_co(&key, faceGridData, x, y);
-                                       float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
-                                       float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
-                                       float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
-                                       copy_v3_v3(&varray[start], a);
-                                       copy_v3_v3(&varray[start + 3], b);
-                                       copy_v3_v3(&varray[start + 6], c);
-                                       copy_v3_v3(&varray[start + 9], d);
-
-                                       start += 12;
-                               }
-                       }
-               }
-       }
-
-       /* upload loose points */
-       for (i = 0; i < totedge; i++) {
-               CCGEdge *e = ccgdm->edgeMap[i].edge;
-               CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
-
-               if (!ccgSubSurf_getEdgeNumFaces(e)) {
-                       int j = 0;
-                       for (j = 0; j < edgeSize; j++) {
-                               copy_v3_v3(&varray[start], CCG_elem_offset_co(&key, edgeData, j));
-                               start += 3;
-                       }
-               }
-       }
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_buffer_copy_color(
-        DerivedMesh *dm, unsigned char *varray,
-        const void *user_data)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       const unsigned char *mloopcol = user_data;
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       int gridFaces = gridSize - 1;
-       int i, totface = ccgSubSurf_getNumFaces(ss);
-       int start = 0;
-       int iface = 0;
-
-       CCG_key_top_level(&key, ss);
-
-
-       for (i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
-               int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
-               for (S = 0; S < numVerts; S++) {
-                       for (y = 0; y < gridFaces; y++) {
-                               for (x = 0; x < gridFaces; x++) {
-                                       copy_v4_v4_uchar(&varray[start + 0], &mloopcol[iface * 16 + 0]);
-                                       copy_v4_v4_uchar(&varray[start + 4], &mloopcol[iface * 16 + 12]);
-                                       copy_v4_v4_uchar(&varray[start + 8], &mloopcol[iface * 16 + 8]);
-                                       copy_v4_v4_uchar(&varray[start + 12], &mloopcol[iface * 16 + 4]);
-
-                                       start += 16;
-                                       iface++;
-                               }
-                       }
-               }
-       }
-}
-
-static void ccgDM_buffer_copy_uv(
-        DerivedMesh *dm, void *varray_p)
-{
-       float *varray = varray_p;
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       MLoopUV *mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV);
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       int gridFaces = gridSize - 1;
-       int i, totface = ccgSubSurf_getNumFaces(ss);
-       int start = 0;
-
-       CCG_key_top_level(&key, ss);
-
-       for (i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
-               int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
-               for (S = 0; S < numVerts; S++) {
-                       for (y = 0; y < gridFaces; y++) {
-                               for (x = 0; x < gridFaces; x++) {
-                                       copy_v2_v2(&varray[start + 0], mloopuv[0].uv);
-                                       copy_v2_v2(&varray[start + 2], mloopuv[3].uv);
-                                       copy_v2_v2(&varray[start + 4], mloopuv[2].uv);
-                                       copy_v2_v2(&varray[start + 6], mloopuv[1].uv);
-
-                                       mloopuv += 4;
-                                       start += 8;
-                               }
-                       }
-               }
-       }
-}
-
-static void ccgDM_buffer_copy_uv_texpaint(
-        DerivedMesh *dm, float *varray)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       int gridFaces = gridSize - 1;
-       int i, totface = ccgSubSurf_getNumFaces(ss);
-       int start = 0;
-       DMFlagMat *faceFlags = ccgdm->faceFlags;
-       int dm_totmat = dm->totmat;
-       MLoopUV **mloopuv_base;
-       MLoopUV  *stencil_base;
-       int stencil;
-
-       CCG_key_top_level(&key, ss);
-
-       /* should have been checked for before, reassert */
-       BLI_assert(DM_get_loop_data_layer(dm, CD_MLOOPUV));
-       mloopuv_base = MEM_mallocN(dm_totmat * sizeof(*mloopuv_base), "texslots");
-
-       for (i = 0; i < dm_totmat; i++) {
-               mloopuv_base[i] = DM_paint_uvlayer_active_get(dm, i);
-       }
-
-       stencil = CustomData_get_stencil_layer(&dm->loopData, CD_MLOOPUV);
-       stencil_base = CustomData_get_layer_n(&dm->loopData, CD_MLOOPUV, stencil);
-
-       start = 0;
-
-       for (i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
-               int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-               int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-               int matnr;
-
-               if (faceFlags) {
-                       matnr = faceFlags[index].mat_nr;
-               }
-               else {
-                       matnr = 0;
-               }
-
-               for (S = 0; S < numVerts; S++) {
-                       for (y = 0; y < gridFaces; y++) {
-                               for (x = 0; x < gridFaces; x++) {
-                                       /* divide by 4, gives us current loop-index */
-                                       unsigned int i_ml = start / 4;
-                                       copy_v2_v2(&varray[start + 0],  mloopuv_base[matnr][i_ml + 0].uv);
-                                       copy_v2_v2(&varray[start + 2],         stencil_base[i_ml + 0].uv);
-                                       copy_v2_v2(&varray[start + 4],  mloopuv_base[matnr][i_ml + 3].uv);
-                                       copy_v2_v2(&varray[start + 6],         stencil_base[i_ml + 3].uv);
-                                       copy_v2_v2(&varray[start + 8],  mloopuv_base[matnr][i_ml + 2].uv);
-                                       copy_v2_v2(&varray[start + 10],        stencil_base[i_ml + 2].uv);
-                                       copy_v2_v2(&varray[start + 12], mloopuv_base[matnr][i_ml + 1].uv);
-                                       copy_v2_v2(&varray[start + 14],        stencil_base[i_ml + 1].uv);
-                                       start += 16;
-                               }
-                       }
-               }
-       }
-
-       MEM_freeN(mloopuv_base);
-}
-
-static void ccgDM_buffer_copy_uvedge(
-        DerivedMesh *dm, float *varray)
-{
-       int i, totpoly;
-       int start;
-       const MLoopUV *mloopuv;
-#ifndef USE_LOOP_LAYOUT_FAST
-       const MPoly *mpoly = dm->getPolyArray(dm);
-#endif
-
-       if ((mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV)) == NULL) {
-               return;
-       }
-
-       totpoly = dm->getNumPolys(dm);
-       start = 0;
-
-#ifndef USE_LOOP_LAYOUT_FAST
-       for (i = 0; i < totpoly; i++, mpoly++) {
-               for (j = 0; j < mpoly->totloop; j++) {
-                       copy_v2_v2(&varray[start], mloopuv[mpoly->loopstart + j].uv);
-                       copy_v2_v2(&varray[start + 2], mloopuv[mpoly->loopstart + (j + 1) % mpoly->totloop].uv);
-                       start += 4;
-               }
-       }
-#else
-       for (i = 0; i < totpoly; i++) {
-               copy_v2_v2(&varray[start +  0], mloopuv[(i * 4) + 0].uv);
-               copy_v2_v2(&varray[start +  2], mloopuv[(i * 4) + 1].uv);
-
-               copy_v2_v2(&varray[start +  4], mloopuv[(i * 4) + 1].uv);
-               copy_v2_v2(&varray[start +  6], mloopuv[(i * 4) + 2].uv);
-
-               copy_v2_v2(&varray[start +  8], mloopuv[(i * 4) + 2].uv);
-               copy_v2_v2(&varray[start + 10], mloopuv[(i * 4) + 3].uv);
-
-               copy_v2_v2(&varray[start + 12], mloopuv[(i * 4) + 3].uv);
-               copy_v2_v2(&varray[start + 14], mloopuv[(i * 4) + 0].uv);
-
-               start += 16;
-       }
-#endif
-}
-
-static void ccgDM_buffer_copy_edge(
-        DerivedMesh *dm, unsigned int *varray)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       /* getEdgeSuze returns num of verts, edges is one less */
-       int i, j, edgeSize = ccgSubSurf_getEdgeSize(ss) - 1;
-       int totedge = ccgSubSurf_getNumEdges(ss);
-       int grid_face_side = ccgSubSurf_getGridSize(ss) - 1;
-       int totface = ccgSubSurf_getNumFaces(ss);
-       unsigned int index_start;
-       unsigned int tot_interior = 0;
-       unsigned int grid_tot_face = grid_face_side * grid_face_side;
-
-       unsigned int iloose, inorm, iloosehidden, inormhidden;
-       unsigned int tot_loose_hidden = 0, tot_loose = 0;
-       unsigned int tot_hidden = 0, tot = 0;
-       unsigned int iloosevert;
-       /* int tot_interior = 0; */
-
-       /* first, handle hidden/loose existing edges, then interior edges */
-       for (j = 0; j < totedge; j++) {
-               CCGEdge *e = ccgdm->edgeMap[j].edge;
-
-               if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) {
-                       if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose_hidden++;
-                       else tot_hidden++;
-               }
-               else {
-                       if (!ccgSubSurf_getEdgeNumFaces(e)) tot_loose++;
-                       else tot++;
-               }
-       }
-
-       inorm = 0;
-       inormhidden = tot * edgeSize;
-       iloose = (tot + tot_hidden) * edgeSize;
-       iloosehidden = (tot + tot_hidden + tot_loose) * edgeSize;
-       iloosevert = dm->drawObject->tot_loop_verts;
-
-       /* part one, handle all normal edges */
-       for (j = 0; j < totedge; j++) {
-               CCGFace *f;
-               int fhandle = 0;
-               int totvert = 0;
-               unsigned int S = 0;
-               CCGEdge *e = ccgdm->edgeMap[j].edge;
-               bool isloose = !ccgSubSurf_getEdgeNumFaces(e);
-
-               if (!isloose) {
-                       CCGVert *v1, *v2;
-                       CCGVert *ev1 = ccgSubSurf_getEdgeVert0(e);
-                       CCGVert *ev2 = ccgSubSurf_getEdgeVert1(e);
-
-                       f = ccgSubSurf_getEdgeFace(e, 0);
-                       fhandle = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-                       totvert = ccgSubSurf_getFaceNumVerts(f);
-
-                       /* find the index of vertices in the face */
-                       for (i = 0; i < totvert; i++) {
-                               v1 = ccgSubSurf_getFaceVert(f, i);
-                               v2 = ccgSubSurf_getFaceVert(f, (i + 1) % totvert);
-
-                               if ((ev1 == v1 && ev2 == v2) || (ev1 == v2 && ev2 == v1)) {
-                                       S = i;
-                                       break;
-                               }
-                       }
-               }
-
-               if (ccgdm->edgeFlags && !(ccgdm->edgeFlags[j] & ME_EDGEDRAW)) {
-                       if (isloose) {
-                               for (i = 0; i < edgeSize; i++) {
-                                       varray[iloosehidden * 2] = iloosevert;
-                                       varray[iloosehidden * 2 + 1] = iloosevert + 1;
-                                       iloosehidden++;
-                                       iloosevert++;
-                               }
-                               /* we are through with this loose edge and moving to the next, so increase by one */
-                               iloosevert++;
-                       }
-                       else {
-                               index_start = ccgdm->faceMap[fhandle].startFace;
-
-                               for (i = 0; i < grid_face_side; i++) {
-                                       varray[inormhidden * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1;
-                                       varray[inormhidden * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2;
-                                       varray[inormhidden * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2;
-                                       varray[inormhidden * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3;
-                                       inormhidden += 2;
-                               }
-                       }
-               }
-               else {
-                       if (isloose) {
-                               for (i = 0; i < edgeSize; i++) {
-                                       varray[iloose * 2] = iloosevert;
-                                       varray[iloose * 2 + 1] = iloosevert + 1;
-                                       iloose++;
-                                       iloosevert++;
-                               }
-                               /* we are through with this loose edge and moving to the next, so increase by one */
-                               iloosevert++;
-                       }
-                       else {
-                               index_start = ccgdm->faceMap[fhandle].startFace;
-
-                               for (i = 0; i < grid_face_side; i++) {
-                                       varray[inorm * 2] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 1;
-                                       varray[inorm * 2 + 1] = (index_start + S * grid_tot_face + i * grid_face_side + grid_face_side - 1) * 4 + 2;
-                                       varray[inorm * 2 + 2] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 2;
-                                       varray[inorm * 2 + 3] = (index_start + ((S + 1) % totvert) * grid_tot_face + grid_face_side * (grid_face_side - 1) + i) * 4 + 3;
-                                       inorm += 2;
-                               }
-                       }
-               }
-       }
-
-       /* part two, handle interior edges */
-       inorm = totedge * grid_face_side * 2;
-
-       index_start = 0;
-       for (i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
-               unsigned int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-
-               for (S = 0; S < numVerts; S++) {
-                       for (x = 1; x < grid_face_side; x++) {
-                               for (y = 0; y < grid_face_side; y++) {
-                                       unsigned int tmp = (index_start + x * grid_face_side + y) * 4;
-                                       varray[inorm * 2] = tmp;
-                                       varray[inorm * 2 + 1] = tmp + 1;
-                                       inorm++;
-                               }
-                       }
-                       for (x = 0; x < grid_face_side; x++) {
-                               for (y = 0; y < grid_face_side; y++) {
-                                       unsigned int tmp = (index_start + x * grid_face_side + y) * 4;
-                                       varray[inorm * 2] = tmp + 3;
-                                       varray[inorm * 2 + 1] = tmp;
-                                       inorm++;
-                               }
-                       }
-
-                       tot_interior += grid_face_side * (2 * grid_face_side - 1);
-                       index_start += grid_tot_face;
-               }
-       }
-
-       dm->drawObject->tot_loose_edge_drawn = tot_loose * edgeSize;
-       dm->drawObject->loose_edge_offset = (tot + tot_hidden) * edgeSize;
-       dm->drawObject->tot_edge_drawn = tot * edgeSize;
-
-       dm->drawObject->interior_offset = totedge * edgeSize;
-       dm->drawObject->totinterior = tot_interior;
-}
-
-static void ccgDM_copy_gpu_data(
-        DerivedMesh *dm, int type, void *varray_p,
-        const int *mat_orig_to_new, const void *user_data)
-{
-       /* 'varray_p' cast is redundant but include for self-documentation */
-       switch (type) {
-               case GPU_BUFFER_VERTEX:
-                       ccgDM_buffer_copy_vertex(dm, (float *)varray_p);
-                       break;
-               case GPU_BUFFER_NORMAL:
-                       ccgDM_buffer_copy_normal(dm, (short *)varray_p);
-                       break;
-               case GPU_BUFFER_UV:
-                       ccgDM_buffer_copy_uv(dm, (float *)varray_p);
-                       break;
-               case GPU_BUFFER_UV_TEXPAINT:
-                       ccgDM_buffer_copy_uv_texpaint(dm, (float *)varray_p);
-                       break;
-               case GPU_BUFFER_COLOR:
-                       ccgDM_buffer_copy_color(dm, (unsigned char *)varray_p, user_data);
-                       break;
-               case GPU_BUFFER_UVEDGE:
-                       ccgDM_buffer_copy_uvedge(dm, (float *)varray_p);
-                       break;
-               case GPU_BUFFER_EDGE:
-                       ccgDM_buffer_copy_edge(dm, (unsigned int *)varray_p);
-                       break;
-               case GPU_BUFFER_TRIANGLES:
-                       ccgDM_buffer_copy_triangles(dm, (unsigned int *)varray_p, mat_orig_to_new);
-                       break;
-               default:
-                       break;
-       }
-}
-
-static GPUDrawObject *ccgDM_GPUObjectNew(DerivedMesh *dm)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       GPUDrawObject *gdo;
-       DMFlagMat *faceFlags = ccgdm->faceFlags;
-       int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
-       const short dm_totmat = (faceFlags) ? dm->totmat : 1;
-       GPUBufferMaterial *matinfo;
-       int i;
-       unsigned int tot_internal_edges = 0;
-       int edgeVerts = ccgSubSurf_getEdgeSize(ss);
-       int edgeSize = edgeVerts - 1;
-
-       int totedge = ccgSubSurf_getNumEdges(ss);
-       int totface = ccgSubSurf_getNumFaces(ss);
-
-       /* object contains at least one material (default included) so zero means uninitialized dm */
-       BLI_assert(dm_totmat != 0);
-
-       matinfo = MEM_callocN(sizeof(*matinfo) * dm_totmat, "GPU_drawobject_new.mat_orig_to_new");
-
-       if (faceFlags) {
-               for (i = 0; i < totface; i++) {
-                       CCGFace *f = ccgdm->faceMap[i].face;
-                       int numVerts = ccgSubSurf_getFaceNumVerts(f);
-                       int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-                       const short new_matnr = ME_MAT_NR_TEST(faceFlags[index].mat_nr, dm_totmat);
-                       matinfo[new_matnr].totelements += numVerts * gridFaces * gridFaces * 6;
-                       matinfo[new_matnr].totloops += numVerts * gridFaces * gridFaces * 4;
-                       matinfo[new_matnr].totpolys++;
-                       tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1);
-               }
-       }
-       else {
-               for (i = 0; i < totface; i++) {
-                       CCGFace *f = ccgdm->faceMap[i].face;
-                       int numVerts = ccgSubSurf_getFaceNumVerts(f);
-                       matinfo[0].totelements += numVerts * gridFaces * gridFaces * 6;
-                       matinfo[0].totloops += numVerts * gridFaces * gridFaces * 4;
-                       matinfo[0].totpolys++;
-                       tot_internal_edges += numVerts * gridFaces * (2 * gridFaces - 1);
-               }
-       }
-
-       /* create the GPUDrawObject */
-       gdo = MEM_callocN(sizeof(GPUDrawObject), "GPUDrawObject");
-       gdo->totvert = 0; /* used to count indices, doesn't really matter for ccgsubsurf */
-       gdo->totedge = (totedge * edgeSize + tot_internal_edges);
-
-       GPU_buffer_material_finalize(gdo, matinfo, dm_totmat);
-
-       /* store total number of points used for triangles */
-       gdo->tot_triangle_point = ccgSubSurf_getNumFinalFaces(ss) * 6;
-       gdo->tot_loop_verts = ccgSubSurf_getNumFinalFaces(ss) * 4;
-
-       /* finally, count loose points */
-       for (i = 0; i < totedge; i++) {
-               CCGEdge *e = ccgdm->edgeMap[i].edge;
-
-               if (!ccgSubSurf_getEdgeNumFaces(e))
-                       gdo->tot_loose_point += edgeVerts;
-       }
-
-       return gdo;
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)[4], bool fast, DMSetMaterial setMaterial)
-{
-       int a;
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-
-       ccgdm_pbvh_update(ccgdm);
-
-       if (ccgdm->pbvh && ccgdm->multires.mmd) {
-               if (BKE_pbvh_has_faces(ccgdm->pbvh)) {
-                       BKE_pbvh_draw(ccgdm->pbvh, partial_redraw_planes, NULL,
-                                     setMaterial, false, fast);
-               }
-
-               return;
-       }
-
-#ifdef WITH_OPENSUBDIV
-       if (ccgdm->useGpuBackend) {
-               CCGSubSurf *ss = ccgdm->ss;
-               const DMFlagMat *faceFlags = ccgdm->faceFlags;
-               const int level = ccgSubSurf_getSubdivisionLevels(ss);
-               const int face_side = 1 << level;
-               const int grid_side = 1 << (level - 1);
-               const int face_patches = face_side * face_side;
-               const int grid_patches = grid_side * grid_side;
-               const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
-               int i, current_patch = 0;
-               int mat_nr = -1;
-               bool draw_smooth = false;
-               int start_draw_patch = -1, num_draw_patches = 0;
-               if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL, -1) == false)) {
-                       return;
-               }
-               if (setMaterial == NULL) {
-                       ccgSubSurf_drawGLMesh(ss,
-                                             true,
-                                             -1,
-                                             -1);
-                       return;
-               }
-               for (i = 0; i < num_base_faces; ++i) {
-                       const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
-                       const int num_patches = (num_face_verts == 4) ? face_patches
-                                                                     : num_face_verts * grid_patches;
-                       int new_matnr;
-                       bool new_draw_smooth;
-                       if (faceFlags) {
-                               new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
-                               new_matnr = (faceFlags[i].mat_nr + 1);
-                       }
-                       else {
-                               new_draw_smooth = true;
-                               new_matnr = 1;
-                       }
-                       if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
-                               if (num_draw_patches != 0) {
-                                       bool do_draw = setMaterial(mat_nr, NULL);
-                                       if (do_draw) {
-                                               glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
-                                               ccgSubSurf_drawGLMesh(ss,
-                                                                     true,
-                                                                     start_draw_patch,
-                                                                     num_draw_patches);
-                                       }
-                               }
-                               start_draw_patch = current_patch;
-                               num_draw_patches = num_patches;
-                               mat_nr = new_matnr;
-                               draw_smooth = new_draw_smooth;
-                       }
-                       else {
-                               num_draw_patches += num_patches;
-                       }
-                       current_patch += num_patches;
-               }
-               if (num_draw_patches != 0) {
-                       bool do_draw = setMaterial(mat_nr, NULL);
-                       if (do_draw) {
-                               glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
-                               ccgSubSurf_drawGLMesh(ss,
-                                                     true,
-                                                     start_draw_patch,
-                                                     num_draw_patches);
-                       }
-               }
-               glShadeModel(GL_SMOOTH);
-               return;
-       }
-#endif
-
-       GPU_vertex_setup(dm);
-       GPU_normal_setup(dm);
-       GPU_triangle_setup(dm);
-       for (a = 0; a < dm->drawObject->totmaterial; a++) {
-               if (!setMaterial || setMaterial(dm->drawObject->materials[a].mat_nr + 1, NULL)) {
-                       GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, dm->drawObject->materials[a].start,
-                                                dm->drawObject->materials[a].totelements);
-               }
-       }
-       GPU_buffers_unbind();
-}
-
-typedef struct {
-       DMVertexAttribs attribs;
-       int numdata;
-
-       GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/
-} GPUMaterialConv;
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
-                                      DMSetMaterial setMaterial,
-                                      DMSetDrawOptions setDrawOptions,
-                                      void *userData)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       GPUVertexAttribs gattribs;
-       int a, b;
-       const DMFlagMat *faceFlags = ccgdm->faceFlags;
-       unsigned char *varray;
-       size_t max_element_size = 0;
-       int tot_loops = 0;
-       int totpoly = ccgSubSurf_getNumFaces(ss);
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       int gridFaces = gridSize - 1;
-       int edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
-       if (ccgdm->useGpuBackend) {
-               const int level = ccgSubSurf_getSubdivisionLevels(ss);
-               const int face_side = 1 << level;
-               const int grid_side = 1 << (level - 1);
-               const int face_patches = face_side * face_side;
-               const int grid_patches = grid_side * grid_side;
-               const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
-               int i, current_patch = 0;
-               int mat_nr = -1;
-               bool draw_smooth = false;
-               int start_draw_patch = -1, num_draw_patches = 0;
-               GPU_draw_update_fvar_offset(dm);
-               if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false, -1) == false)) {
-                       return;
-               }
-               for (i = 0; i < num_base_faces; ++i) {
-                       const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
-                       const int num_patches = (num_face_verts == 4) ? face_patches
-                                                                     : num_face_verts * grid_patches;
-                       int new_matnr;
-                       bool new_draw_smooth;
-
-                       if (faceFlags) {
-                               new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
-                               new_matnr = (faceFlags[i].mat_nr + 1);
-                       }
-                       else {
-                               new_draw_smooth = true;
-                               new_matnr = 1;
-                       }
-                       if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
-                               if (num_draw_patches != 0) {
-                                       bool do_draw = setMaterial(mat_nr, &gattribs);
-                                       if (do_draw) {
-                                               glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
-                                               ccgSubSurf_drawGLMesh(ss,
-                                                                     true,
-                                                                     start_draw_patch,
-                                                                     num_draw_patches);
-                                       }
-                               }
-                               start_draw_patch = current_patch;
-                               num_draw_patches = num_patches;
-                               mat_nr = new_matnr;
-                               draw_smooth = new_draw_smooth;
-                       }
-                       else {
-                               num_draw_patches += num_patches;
-                       }
-                       current_patch += num_patches;
-               }
-               if (num_draw_patches != 0) {
-                       bool do_draw = setMaterial(mat_nr, &gattribs);
-                       if (do_draw) {
-                               glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
-                               ccgSubSurf_drawGLMesh(ss,
-                                                     true,
-                                                     start_draw_patch,
-                                                     num_draw_patches);
-                       }
-               }
-               glShadeModel(GL_SMOOTH);
-               return;
-       }
-#endif
-
-       CCG_key_top_level(&key, ss);
-       ccgdm_pbvh_update(ccgdm);
-
-       if (setDrawOptions != NULL) {
-               const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-               DMVertexAttribs attribs = {{{NULL}}};
-               int i;
-               int matnr = -1;
-               int do_draw = 0;
-
-#define PASSATTRIB(dx, dy, vert) {                                           \
-    if (attribs.totorco)                                                     \
-        index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize);  \
-    else                                                                     \
-        index = 0;                                                           \
-    DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert);       \
-    DM_draw_attrib_vertex_uniforms(&attribs);                                \
-} (void)0
-
-               totpoly = ccgSubSurf_getNumFaces(ss);
-               for (a = 0, i = 0; i < totpoly; i++) {
-                       CCGFace *f = ccgdm->faceMap[i].face;
-                       const float (*ln)[3] = NULL;
-                       int S, x, y, drawSmooth;
-                       int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-                       int origIndex = ccgDM_getFaceMapIndex(ss, f);
-
-                       int numVerts = ccgSubSurf_getFaceNumVerts(f);
-                       int new_matnr;
-
-                       if (faceFlags) {
-                               drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH));
-                               new_matnr = faceFlags[index].mat_nr + 1;
-                       }
-                       else {
-                               drawSmooth = 1;
-                               new_matnr = 1;
-                       }
-
-                       if (lnors) {
-                               ln = lnors;
-                               lnors += (gridFaces * gridFaces * numVerts) * 4;
-                       }
-
-                       if (new_matnr != matnr) {
-                               do_draw = setMaterial(matnr = new_matnr, &gattribs);
-                               if (do_draw)
-                                       DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
-                       }
-
-                       if (!do_draw || (setDrawOptions && (origIndex != ORIGINDEX_NONE) &&
-                                       (setDrawOptions(userData, origIndex) == DM_DRAW_OPTION_SKIP)))
-                       {
-                               a += gridFaces * gridFaces * numVerts;
-                               continue;
-                       }
-
-                       glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT);
-                       for (S = 0; S < numVerts; S++) {
-                               CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
-                               CCGElem *vda, *vdb;
-
-                               if (ln) {
-                                       glBegin(GL_QUADS);
-                                       for (y = 0; y < gridFaces; y++) {
-                                               for (x = 0; x < gridFaces; x++) {
-                                                       float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
-                                                       float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
-                                                       float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
-                                                       float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
-                                                       PASSATTRIB(0, 1, 1);
-                                                       glNormal3fv(ln[1]);
-                                                       glVertex3fv(dco);
-                                                       PASSATTRIB(1, 1, 2);
-                                                       glNormal3fv(ln[2]);
-                                                       glVertex3fv(cco);
-                                                       PASSATTRIB(1, 0, 3);
-                                                       glNormal3fv(ln[3]);
-                                                       glVertex3fv(bco);
-                                                       PASSATTRIB(0, 0, 0);
-                                                       glNormal3fv(ln[0]);
-                                                       glVertex3fv(aco);
-
-                                                       ln += 4;
-                                                       a++;
-                                               }
-                                       }
-                                       glEnd();
-                               }
-                               else if (drawSmooth) {
-                                       for (y = 0; y < gridFaces; y++) {
-                                               glBegin(GL_QUAD_STRIP);
-                                               for (x = 0; x < gridFaces; x++) {
-                                                       vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
-                                                       vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
-                                                       PASSATTRIB(0, 0, 0);
-                                                       glNormal3fv(CCG_elem_no(&key, vda));
-                                                       glVertex3fv(CCG_elem_co(&key, vda));
-
-                                                       PASSATTRIB(0, 1, 1);
-                                                       glNormal3fv(CCG_elem_no(&key, vdb));
-                                                       glVertex3fv(CCG_elem_co(&key, vdb));
-
-                                                       if (x != gridFaces - 1)
-                                                               a++;
-                                               }
-
-                                               vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
-                                               vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
-                                               PASSATTRIB(0, 0, 3);
-                                               glNormal3fv(CCG_elem_no(&key, vda));
-                                               glVertex3fv(CCG_elem_co(&key, vda));
-
-                                               PASSATTRIB(0, 1, 2);
-                                               glNormal3fv(CCG_elem_no(&key, vdb));
-                                               glVertex3fv(CCG_elem_co(&key, vdb));
-
-                                               glEnd();
-
-                                               a++;
-                                       }
-                               }
-                               else {
-                                       glBegin(GL_QUADS);
-                                       for (y = 0; y < gridFaces; y++) {
-                                               for (x = 0; x < gridFaces; x++) {
-                                                       float *aco = CCG_grid_elem_co(&key, faceGridData, x, y);
-                                                       float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y);
-                                                       float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
-                                                       float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
-                                                       ccgDM_glNormalFast(aco, bco, cco, dco);
-
-                                                       PASSATTRIB(0, 1, 1);
-                                                       glVertex3fv(dco);
-                                                       PASSATTRIB(1, 1, 2);
-                                                       glVertex3fv(cco);
-                                                       PASSATTRIB(1, 0, 3);
-                                                       glVertex3fv(bco);
-                                                       PASSATTRIB(0, 0, 0);
-                                                       glVertex3fv(aco);
-
-                                                       a++;
-                                               }
-                                       }
-                                       glEnd();
-                               }
-                       }
-               }
-
-               glShadeModel(GL_SMOOTH);
-#undef PASSATTRIB
-       }
-       else {
-               GPUMaterialConv *matconv;
-               size_t offset;
-               int *mat_orig_to_new;
-               int tot_active_mat;
-               GPUBuffer *buffer = NULL;
-
-               GPU_vertex_setup(dm);
-               GPU_normal_setup(dm);
-               GPU_triangle_setup(dm);
-
-               tot_active_mat = dm->drawObject->totmaterial;
-
-               matconv = MEM_callocN(sizeof(*matconv) * tot_active_mat,
-                                     "cdDM_drawMappedFacesGLSL.matconv");
-               mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat,
-                                             "cdDM_drawMappedFacesGLSL.mat_orig_to_new");
-
-               /* part one, check what attributes are needed per material */
-               for (a = 0; a < tot_active_mat; a++) {
-                       int new_matnr;
-                       int do_draw;
-
-                       new_matnr = dm->drawObject->materials[a].mat_nr;
-
-                       /* map from original material index to new
-                        * GPUBufferMaterial index */
-                       mat_orig_to_new[new_matnr] = a;
-                       do_draw = setMaterial(new_matnr + 1, &gattribs);
-
-                       if (do_draw) {
-                               int numdata = 0;
-                               DM_vertex_attributes_from_gpu(dm, &gattribs, &matconv[a].attribs);
-
-                               if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
-                                       matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
-                                       matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
-                                       matconv[a].datatypes[numdata].size = 3;
-                                       matconv[a].datatypes[numdata].type = GL_FLOAT;
-                                       numdata++;
-                               }
-                               for (b = 0; b < matconv[a].attribs.tottface; b++) {
-                                       if (matconv[a].attribs.tface[b].array) {
-                                               matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
-                                               matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
-                                               matconv[a].datatypes[numdata].size = 2;
-                                               matconv[a].datatypes[numdata].type = GL_FLOAT;
-                                               numdata++;
-                                       }
-                               }
-                               for (b = 0; b < matconv[a].attribs.totmcol; b++) {
-                                       if (matconv[a].attribs.mcol[b].array) {
-                                               matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
-                                               matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
-                                               matconv[a].datatypes[numdata].size = 4;
-                                               matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
-                                               numdata++;
-                                       }
-                               }
-                               for (b = 0; b < matconv[a].attribs.tottang; b++) {
-                                       if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
-                                               matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
-                                               matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
-                                               matconv[a].datatypes[numdata].size = 4;
-                                               matconv[a].datatypes[numdata].type = GL_FLOAT;
-                                               numdata++;
-                                       }
-                               }
-                               if (numdata != 0) {
-                                       matconv[a].numdata = numdata;
-                                       max_element_size = max_ii(GPU_attrib_element_size(matconv[a].datatypes, numdata), max_element_size);
-                               }
-                       }
-               }
-
-               /* part two, generate and fill the arrays with the data */
-               if (max_element_size > 0) {
-                       buffer = GPU_buffer_alloc(max_element_size * dm->drawObject->tot_loop_verts);
-
-                       varray = GPU_buffer_lock_stream(buffer, GPU_BINDING_ARRAY);
-                       if (varray == NULL) {
-                               GPU_buffers_unbind();
-                               GPU_buffer_free(buffer);
-                               MEM_freeN(mat_orig_to_new);
-                               MEM_freeN(matconv);
-                               fprintf(stderr, "Out of memory, can't draw object\n");
-                               return;
-                       }
-
-                       for (a = 0; a < totpoly; a++) {
-                               CCGFace *f = ccgdm->faceMap[a].face;
-                               int orig_index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-                               int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-                               int i;
-
-                               if (faceFlags) {
-                                       i = mat_orig_to_new[faceFlags[orig_index].mat_nr];
-                               }
-                               else {
-                                       i = mat_orig_to_new[0];
-                               }
-
-                               if (matconv[i].numdata != 0) {
-                                       for (S = 0; S < numVerts; S++) {
-                                               for (y = 0; y < gridFaces; y++) {
-                                                       for (x = 0; x < gridFaces; x++) {
-
-                                                               offset = tot_loops * max_element_size;
-
-                                                               if (matconv[i].attribs.totorco && matconv[i].attribs.orco.array) {
-                                                                       int index;
-
-                                                                       index = getFaceIndex(ss, f, S, x, y, edgeSize, gridSize);
-                                                                       copy_v3_v3((float *)&varray[offset],
-                                                                                  (float *)matconv[i].attribs.orco.array[index]);
-                                                                       index = getFaceIndex(ss, f, S, x + 1, y, edgeSize, gridSize);
-                                                                       copy_v3_v3((float *)&varray[offset + max_element_size],
-                                                                               (float *)matconv[i].attribs.orco.array[index]);
-                                                                       index = getFaceIndex(ss, f, S, x + 1, y + 1, edgeSize, gridSize);
-                                                                       copy_v3_v3((float *)&varray[offset + 2 * max_element_size],
-                                                                               (float *)matconv[i].attribs.orco.array[index]);
-                                                                       index = getFaceIndex(ss, f, S, x, y + 1, edgeSize, gridSize);
-                                                                       copy_v3_v3((float *)&varray[offset + 3 * max_element_size],
-                                                                               (float *)matconv[i].attribs.orco.array[index]);
-
-                                                                       offset += sizeof(float) * 3;
-                                                               }
-                                                               for (b = 0; b < matconv[i].attribs.tottface; b++) {
-                                                                       if (matconv[i].attribs.tface[b].array) {
-                                                                               const MLoopUV *mloopuv = matconv[i].attribs.tface[b].array + tot_loops;
-
-                                                                               copy_v2_v2((float *)&varray[offset], mloopuv[0].uv);
-                                                                               copy_v2_v2((float *)&varray[offset + max_element_size], mloopuv[3].uv);
-                                                                               copy_v2_v2((float *)&varray[offset + 2 * max_element_size], mloopuv[2].uv);
-                                                                               copy_v2_v2((float *)&varray[offset + 3 * max_element_size], mloopuv[1].uv);
-
-                                                                               offset += sizeof(float) * 2;
-                                                                       }
-                                                               }
-                                                               for (b = 0; b < matconv[i].attribs.totmcol; b++) {
-                                                                       if (matconv[i].attribs.mcol[b].array) {
-                                                                               const MLoopCol *mloopcol = matconv[i].attribs.mcol[b].array + tot_loops;
-
-                                                                               copy_v4_v4_uchar(&varray[offset], &mloopcol[0].r);
-                                                                               copy_v4_v4_uchar(&varray[offset + max_element_size], &mloopcol[3].r);
-                                                                               copy_v4_v4_uchar(&varray[offset + 2 * max_element_size], &mloopcol[2].r);
-                                                                               copy_v4_v4_uchar(&varray[offset + 3 * max_element_size], &mloopcol[1].r);
-
-                                                                               offset += sizeof(unsigned char) * 4;
-                                                                       }
-                                                               }
-                                                               for (b = 0; b < matconv[i].attribs.tottang; b++) {
-                                                                       if (matconv[i].attribs.tottang && matconv[i].attribs.tang[b].array) {
-                                                                               const float (*looptang)[4] = (const float (*)[4])matconv[i].attribs.tang[b].array + tot_loops;
-
-                                                                               copy_v4_v4((float *)&varray[offset], looptang[0]);
-                                                                               copy_v4_v4((float *)&varray[offset + max_element_size], looptang[3]);
-                                                                               copy_v4_v4((float *)&varray[offset + 2 * max_element_size], looptang[2]);
-                                                                               copy_v4_v4((float *)&varray[offset + 3 * max_element_size], looptang[1]);
-
-                                                                               offset += sizeof(float) * 4;
-                                                                       }
-                                                               }
-
-                                                               tot_loops += 4;
-                                                       }
-                                               }
-                                       }
-                               }
-                               else {
-                                       tot_loops += 4 * numVerts * gridFaces * gridFaces;
-                               }
-                       }
-                       GPU_buffer_unlock(buffer, GPU_BINDING_ARRAY);
-               }
-
-               for (a = 0; a < tot_active_mat; a++) {
-                       int new_matnr;
-                       int do_draw;
-
-                       new_matnr = dm->drawObject->materials[a].mat_nr;
-
-                       do_draw = setMaterial(new_matnr + 1, &gattribs);
-
-                       if (do_draw) {
-                               if (matconv[a].numdata) {
-                                       GPU_interleaved_attrib_setup(buffer, matconv[a].datatypes, matconv[a].numdata, max_element_size);
-                               }
-                               GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES,
-                                                        dm->drawObject->materials[a].start, dm->drawObject->materials[a].totelements);
-                               if (matconv[a].numdata) {
-                                       GPU_interleaved_attrib_unbind();
-                               }
-                       }
-               }
-
-               GPU_buffers_unbind();
-               if (buffer)
-                       GPU_buffer_free(buffer);
-
-               MEM_freeN(mat_orig_to_new);
-               MEM_freeN(matconv);
-       }
-}
-
-static void ccgDM_drawFacesGLSL(DerivedMesh *dm, DMSetMaterial setMaterial)
-{
-       dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
-}
-
-/* Only used by non-editmesh types */
-static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
-                                     void (*setMaterial)(void *userData, int matnr, void *attribs),
-                                     bool (*setFace)(void *userData, int index), void *userData)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       GPUVertexAttribs gattribs;
-       DMVertexAttribs attribs = {{{NULL}}};
-       int gridSize = ccgSubSurf_getGridSize(ss);
-       int gridFaces = gridSize - 1;
-       int edgeSize = ccgSubSurf_getEdgeSize(ss);
-       DMFlagMat *faceFlags = ccgdm->faceFlags;
-       const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-       int a, i, numVerts, matnr, totface;
-
-#ifdef WITH_OPENSUBDIV
-       if (ccgdm->useGpuBackend) {
-               const int level = ccgSubSurf_getSubdivisionLevels(ss);
-               const int face_side = 1 << level;
-               const int grid_side = 1 << (level - 1);
-               const int face_patches = face_side * face_side;
-               const int grid_patches = grid_side * grid_side;
-               const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
-               int current_patch = 0;
-               int mat_nr = -1;
-               bool draw_smooth = false;
-               int start_draw_patch = -1, num_draw_patches = 0;
-               GPU_draw_update_fvar_offset(dm);
-               if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
-                       return;
-               }
-               for (i = 0; i < num_base_faces; ++i) {
-                       const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
-                       const int num_patches = (num_face_verts == 4) ? face_patches
-                                                                     : num_face_verts * grid_patches;
-                       int new_matnr;
-                       bool new_draw_smooth;
-
-                       if (faceFlags) {
-                               new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
-                               new_matnr = (faceFlags[i].mat_nr + 1);
-                       }
-                       else {
-                               new_draw_smooth = true;
-                               new_matnr = 1;
-                       }
-                       if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
-                               if (num_draw_patches != 0) {
-                                       setMaterial(userData, mat_nr, &gattribs);
-                                       glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
-                                       ccgSubSurf_drawGLMesh(ss,
-                                                             true,
-                                                             start_draw_patch,
-                                                             num_draw_patches);
-                               }
-                               start_draw_patch = current_patch;
-                               num_draw_patches = num_patches;
-                               mat_nr = new_matnr;
-                               draw_smooth = new_draw_smooth;
-                       }
-                       else {
-                               num_draw_patches += num_patches;
-                       }
-                       current_patch += num_patches;
-               }
-               if (num_draw_patches != 0) {
-                       setMaterial(userData, mat_nr, &gattribs);
-                       glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
-                       ccgSubSurf_drawGLMesh(ss,
-                                             true,
-                                             start_draw_patch,
-                                             num_draw_patches);
-               }
-               glShadeModel(GL_SMOOTH);
-               return;
-       }
-#endif
-
-       CCG_key_top_level(&key, ss);
-       ccgdm_pbvh_update(ccgdm);
-
-       matnr = -1;
-
-#define PASSATTRIB(dx, dy, vert) {                                           \
-    if (attribs.totorco)                                                     \
-        index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize);  \
-    else                                                                     \
-        index = 0;                                                           \
-    DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert);       \
-    DM_draw_attrib_vertex_uniforms(&attribs);                                \
-} (void)0
-
-       totface = ccgSubSurf_getNumFaces(ss);
-       for (a = 0, i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
-               const float (*ln)[3] = NULL;
-               int S, x, y, drawSmooth;
-               int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-               int origIndex = ccgDM_getFaceMapIndex(ss, f);
-               int new_matnr;
-
-               numVerts = ccgSubSurf_getFaceNumVerts(f);
-
-               /* get flags */
-               if (faceFlags) {
-                       drawSmooth = (lnors || (faceFlags[index].flag & ME_SMOOTH));
-                       new_matnr = faceFlags[index].mat_nr + 1;
-               }
-               else {
-                       drawSmooth = 1;
-                       new_matnr = 1;
-               }
-
-               if (lnors) {
-                       ln = lnors;
-                       lnors += (gridFaces * gridFaces * numVerts) * 4;
-               }
-
-               /* material */
-               if (new_matnr != matnr) {
-                       setMaterial(userData, matnr = new_matnr, &gattribs);
-                       DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
-               }
-
-               /* face hiding */
-               if ((setFace && (origIndex != ORIGINDEX_NONE) && !setFace(userData, origIndex))) {
-                       a += gridFaces * gridFaces * numVerts;
-                       continue;
-               }
-
-               /* draw face*/
-               glShadeModel(drawSmooth ? GL_SMOOTH : GL_FLAT);
-               for (S = 0; S < numVerts; S++) {
-                       CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
-                       CCGElem *vda, *vdb;
-
-                       if (ln) {
-                               glBegin(GL_QUADS);
-                               for (y = 0; y < gridFaces; y++) {
-                                       for (x = 0; x < gridFaces; x++) {
-                                               float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
-                                               float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
-                                               float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
-                                               float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
-                                               PASSATTRIB(0, 1, 1);
-                                               glNormal3fv(ln[1]);
-                                               glVertex3fv(dco);
-                                               PASSATTRIB(1, 1, 2);
-                                               glNormal3fv(ln[2]);
-                                               glVertex3fv(cco);
-                                               PASSATTRIB(1, 0, 3);
-                                               glNormal3fv(ln[3]);
-                                               glVertex3fv(bco);
-                                               PASSATTRIB(0, 0, 0);
-                                               glNormal3fv(ln[0]);
-                                               glVertex3fv(aco);
-
-                                               ln += 4;
-                                               a++;
-                                       }
-                               }
-                               glEnd();
-                       }
-                       else if (drawSmooth) {
-                               for (y = 0; y < gridFaces; y++) {
-                                       glBegin(GL_QUAD_STRIP);
-                                       for (x = 0; x < gridFaces; x++) {
-                                               vda = CCG_grid_elem(&key, faceGridData, x, y);
-                                               vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
-                                               PASSATTRIB(0, 0, 0);
-                                               glNormal3fv(CCG_elem_no(&key, vda));
-                                               glVertex3fv(CCG_elem_co(&key, vda));
-
-                                               PASSATTRIB(0, 1, 1);
-                                               glNormal3fv(CCG_elem_no(&key, vdb));
-                                               glVertex3fv(CCG_elem_co(&key, vdb));
-
-                                               if (x != gridFaces - 1)
-                                                       a++;
-                                       }
-
-                                       vda = CCG_grid_elem(&key, faceGridData, x, y + 0);
-                                       vdb = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
-                                       PASSATTRIB(0, 0, 3);
-                                       glNormal3fv(CCG_elem_no(&key, vda));
-                                       glVertex3fv(CCG_elem_co(&key, vda));
-
-                                       PASSATTRIB(0, 1, 2);
-                                       glNormal3fv(CCG_elem_no(&key, vdb));
-                                       glVertex3fv(CCG_elem_co(&key, vdb));
-
-                                       glEnd();
-
-                                       a++;
-                               }
-                       }
-                       else {
-                               glBegin(GL_QUADS);
-                               for (y = 0; y < gridFaces; y++) {
-                                       for (x = 0; x < gridFaces; x++) {
-                                               float *aco = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
-                                               float *bco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
-                                               float *cco = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
-                                               float *dco = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
-                                               ccgDM_glNormalFast(aco, bco, cco, dco);
-
-                                               PASSATTRIB(0, 1, 1);
-                                               glVertex3fv(dco);
-                                               PASSATTRIB(1, 1, 2);
-                                               glVertex3fv(cco);
-                                               PASSATTRIB(1, 0, 3);
-                                               glVertex3fv(bco);
-                                               PASSATTRIB(0, 0, 0);
-                                               glVertex3fv(aco);
-
-                                               a++;
-                                       }
-                               }
-                               glEnd();
-                       }
-               }
-       }
-
-       glShadeModel(GL_SMOOTH);
-#undef PASSATTRIB
-}
-
-static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
-                                      DMSetDrawOptionsTex drawParams,
-                                      DMSetDrawOptionsMappedTex drawParamsMapped,
-                                      DMCompareDrawOptions compareDrawOptions,
-                                      void *userData, DMDrawFlag flag)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       int colType;
-       const MLoopCol *mloopcol = NULL;
-       MTexPoly *mtexpoly = DM_get_poly_data_layer(dm, CD_MTEXPOLY);
-       DMFlagMat *faceFlags = ccgdm->faceFlags;
-       DMDrawOption draw_option;
-       int i, totpoly;
-       bool flush;
-       const bool use_tface = (flag & DM_DRAW_USE_ACTIVE_UV) != 0;
-       const bool use_colors = (flag & DM_DRAW_USE_COLORS) != 0;
-       unsigned int next_actualFace;
-       unsigned int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
-       int mat_index;
-       int tot_element, start_element, tot_drawn;
-
-       if (use_colors) {
-               colType = CD_TEXTURE_MLOOPCOL;
-               mloopcol = dm->getLoopDataArray(dm, colType);
-               if (!mloopcol) {
-                       colType = CD_PREVIEW_MLOOPCOL;
-                       mloopcol = dm->getLoopDataArray(dm, colType);
-               }
-               if (!mloopcol) {
-                       colType = CD_MLOOPCOL;
-                       mloopcol = dm->getLoopDataArray(dm, colType);
-               }
-       }
-
-#ifdef WITH_OPENSUBDIV
-       if (ccgdm->useGpuBackend) {
-               const int active_uv_layer = CustomData_get_active_layer_index(&dm->loopData, CD_MLOOPUV);
-               if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, active_uv_layer) == false)) {
-                       return;
-               }
-               if (drawParams == NULL) {
-                       ccgSubSurf_drawGLMesh(ss, true, -1, -1);
-                       return;
-               }
-               const int level = ccgSubSurf_getSubdivisionLevels(ss);
-               const int face_side = 1 << level;
-               const int grid_side = 1 << (level - 1);
-               const int face_patches = face_side * face_side;
-               const int grid_patches = grid_side * grid_side;
-               const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
-               int current_patch = 0;
-               int mat_nr = -1;
-               int start_draw_patch = 0, num_draw_patches = 0;
-               bool draw_smooth = false;
-               for (i = 0; i < num_base_faces; ++i) {
-                       const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
-                       const int num_patches = (num_face_verts == 4) ? face_patches
-                                                                     : num_face_verts * grid_patches;
-                       if (faceFlags) {
-                               mat_nr = faceFlags[i].mat_nr;
-                               draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
-                       }
-                       else {
-                               mat_nr = 0;
-                               draw_smooth = false;
-                       }
-
-                       if (drawParams != NULL) {
-                               MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL;
-                               draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
-                       }
-                       else {
-                               draw_option = (drawParamsMapped)
-                                                 ? drawParamsMapped(userData, i, mat_nr)
-                                                 : DM_DRAW_OPTION_NORMAL;
-                       }
-
-                       flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1);
-
-                       const int next_face = min_ii(i + 1, num_base_faces - 1);
-                       if (!flush && compareDrawOptions) {
-                               flush |= compareDrawOptions(userData, i, next_face) == 0;
-                       }
-                       if (!flush && faceFlags) {
-                               bool new_draw_smooth = (faceFlags[next_face].flag & ME_SMOOTH);
-                               flush |= (new_draw_smooth != draw_smooth);
-                       }
-
-                       current_patch += num_patches;
-
-                       if (flush) {
-                               if (draw_option != DM_DRAW_OPTION_SKIP) {
-                                       num_draw_patches += num_patches;
-                               }
-                               if (num_draw_patches != 0) {
-                                       glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
-                                       ccgSubSurf_drawGLMesh(ss,
-                                                             true,
-                                                             start_draw_patch,
-                                                             num_draw_patches);
-                               }
-                               start_draw_patch = current_patch;
-                               num_draw_patches = 0;
-                       }
-                       else {
-                               num_draw_patches += num_patches;
-                       }
-               }
-               glShadeModel(GL_SMOOTH);
-               return;
-       }
-#endif
-
-       CCG_key_top_level(&key, ss);
-       ccgdm_pbvh_update(ccgdm);
-
-       GPU_vertex_setup(dm);
-       GPU_normal_setup(dm);
-       GPU_triangle_setup(dm);
-       if (flag & DM_DRAW_USE_TEXPAINT_UV)
-               GPU_texpaint_uv_setup(dm);
-       else
-               GPU_uv_setup(dm);
-       if (mloopcol) {
-               GPU_color_setup(dm, colType);
-       }
-
-       next_actualFace = 0;
-
-       /* lastFlag = 0; */ /* UNUSED */
-       for (mat_index = 0; mat_index < dm->drawObject->totmaterial; mat_index++) {
-               GPUBufferMaterial *bufmat = dm->drawObject->materials + mat_index;
-               next_actualFace = bufmat->polys[0];
-               totpoly = bufmat->totpolys;
-
-               tot_element = 0;
-               tot_drawn = 0;
-               start_element = 0;
-
-               for (i = 0; i < totpoly; i++) {
-                       int polyindex = bufmat->polys[i];
-                       CCGFace *f = ccgdm->faceMap[polyindex].face;
-                       int numVerts = ccgSubSurf_getFaceNumVerts(f);
-                       int index = ccgDM_getFaceMapIndex(ss, f);
-                       int orig_index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-                       int mat_nr;
-                       int facequads = numVerts * gridFaces * gridFaces;
-                       int actualFace = ccgdm->faceMap[polyindex].startFace;
-
-                       if (i != totpoly - 1) {
-                               polyindex = bufmat->polys[i + 1];
-                               next_actualFace = ccgdm->faceMap[polyindex].startFace;
-                       }
-
-                       if (faceFlags) {
-                               mat_nr = faceFlags[orig_index].mat_nr;
-                       }
-                       else {
-                               mat_nr = 0;
-                       }
-
-                       if (drawParams) {
-                               MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[actualFace] : NULL;
-                               draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
-                       }
-                       else if (index != ORIGINDEX_NONE)
-                               draw_option = (drawParamsMapped) ? drawParamsMapped(userData, index, mat_nr) : DM_DRAW_OPTION_NORMAL;
-                       else
-                               draw_option = DM_DRAW_OPTION_NORMAL;
-
-                       /* flush buffer if current triangle isn't drawable or it's last triangle */
-                       flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == totpoly - 1);
-
-                       if (!flush && compareDrawOptions) {
-                               /* also compare draw options and flush buffer if they're different
-                                * need for face selection highlight in edit mode */
-                               flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0;
-                       }
-
-                       tot_element += facequads * 6;
-
-                       if (flush) {
-                               if (draw_option != DM_DRAW_OPTION_SKIP)
-                                       tot_drawn += facequads * 6;
-
-                               if (tot_drawn) {
-                                       if (mloopcol && draw_option != DM_DRAW_OPTION_NO_MCOL)
-                                               GPU_color_switch(1);
-                                       else
-                                               GPU_color_switch(0);
-
-                                       GPU_buffer_draw_elements(dm->drawObject->triangles, GL_TRIANGLES, bufmat->start + start_element, tot_drawn);
-                                       tot_drawn = 0;
-                               }
-
-                               start_element = tot_element;
-                       }
-                       else {
-                               tot_drawn += facequads * 6;
-                       }
-               }
-       }
-
-
-       GPU_buffers_unbind();
-}
-
-static void ccgDM_drawFacesTex(DerivedMesh *dm,
-                               DMSetDrawOptionsTex setDrawOptions,
-                               DMCompareDrawOptions compareDrawOptions,
-                               void *userData, DMDrawFlag flag)
-{
-       ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
-}
-
-static void ccgDM_drawMappedFacesTex(DerivedMesh *dm,
-                                     DMSetDrawOptionsMappedTex setDrawOptions,
-                                     DMCompareDrawOptions compareDrawOptions,
-                                     void *userData, DMDrawFlag flag)
-{
-       ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
-}
-
-/* same as cdDM_drawUVEdges */
-static void ccgDM_drawUVEdges(DerivedMesh *dm)
-{
-       MPoly *mpoly = dm->getPolyArray(dm);
-       int totpoly = dm->getNumPolys(dm);
-       int prevstart = 0;
-       bool prevdraw = true;
-       int curpos = 0;
-       int i;
-
-       GPU_uvedge_setup(dm);
-       for (i = 0; i < totpoly; i++, mpoly++) {
-               const bool draw = (mpoly->flag & ME_HIDE) == 0;
-
-               if (prevdraw != draw) {
-                       if (prevdraw && (curpos != prevstart)) {
-                               glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
-                       }
-                       prevstart = curpos;
-               }
-
-               curpos += 2 * mpoly->totloop;
-               prevdraw = draw;
-       }
-       if (prevdraw && (curpos != prevstart)) {
-               glDrawArrays(GL_LINES, prevstart, curpos - prevstart);
-       }
-       GPU_buffers_unbind();
-}
-
-static void ccgDM_drawMappedFaces(DerivedMesh *dm,
-                                  DMSetDrawOptions setDrawOptions,
-                                  DMSetMaterial setMaterial,
-                                  DMCompareDrawOptions compareDrawOptions,
-                                  void *userData, DMDrawFlag flag)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       MLoopCol *mloopcol = NULL;
-       const float (*lnors)[3] = dm->getLoopDataArray(dm, CD_NORMAL);
-       int i, gridSize = ccgSubSurf_getGridSize(ss);
-       DMFlagMat *faceFlags = ccgdm->faceFlags;
-       int useColors = flag & DM_DRAW_USE_COLORS;
-       int gridFaces = gridSize - 1, totface;
-       int prev_mat_nr = -1;
-
-       if (ccgdm->pbvh) {
-               if (G.debug_value == 14)
-                       BKE_pbvh_draw_BB(ccgdm->pbvh);
-       }
-
-#ifdef WITH_OPENSUBDIV
-       if (ccgdm->useGpuBackend) {
-               int new_matnr;
-               bool draw_smooth, do_draw = true;
-               if (setDrawOptions == NULL) {
-                       /* TODO(sergey): This is for cases when vertex colors or weights
-                        * are visualising. Currently we don't have CD layers for this data
-                        * and here we only make it so there's no garbage displayed.
-                        *
-                        * In the future we'll either need to have CD for this data or pass
-                        * this data as face-varying or vertex-varying data in OSD mesh.
-                        */
-                       glColor3f(0.8f, 0.8f, 0.8f);
-               }
-               if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
-                       return;
-               }
-               if (faceFlags) {
-                       draw_smooth = (faceFlags[0].flag & ME_SMOOTH);
-                       new_matnr = (faceFlags[0].mat_nr + 1);
-               }
-               else {
-                       draw_smooth = true;
-                       new_matnr = 1;
-               }
-               if (setMaterial) {
-                       setMaterial(new_matnr, NULL);
-               }
-               if (setDrawOptions) {
-                       if (setDrawOptions(userData, 0) == DM_DRAW_OPTION_SKIP) {
-                               do_draw = false;
-                       }
-               }
-               if (do_draw) {
-                       glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
-                       ccgSubSurf_drawGLMesh(ss, true, -1, -1);
-                       glShadeModel(GL_SMOOTH);
-               }
-               return;
-       }
-#endif
-
-       CCG_key_top_level(&key, ss);
-
-       /* currently unused -- each original face is handled separately */
-       (void)compareDrawOptions;
-
-       if (useColors) {
-               mloopcol = dm->getLoopDataArray(dm, CD_PREVIEW_MLOOPCOL);
-               if (!mloopcol)
-                       mloopcol = dm->getLoopDataArray(dm, CD_MLOOPCOL);
-       }
-
-       totface = ccgSubSurf_getNumFaces(ss);
-       for (i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
-               int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
-               int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
-               int origIndex;
-               unsigned char *cp = NULL;
-               const float (*ln)[3] = NULL;
-
-               origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(f));
-
-               if (flag & DM_DRAW_ALWAYS_SMOOTH) drawSmooth = 1;
-               else if (faceFlags) drawSmooth = (lnors || (faceFlags[origIndex].flag & ME_SMOOTH));
-               else drawSmooth = 1;
-
-               if (mloopcol) {
-                       cp = (unsigned char *)mloopcol;
-                       mloopcol += gridFaces * gridFaces * numVerts * 4;
-               }
-
-               if (lnors) {
-                       ln = lnors;
-                       lnors += (gridFaces * gridFaces * numVerts) * 4;
-               }
-
-               {
-                       DMDrawOption draw_option = DM_DRAW_OPTION_NORMAL;
-
-                       if (setMaterial) {
-                               int mat_nr = faceFlags ? faceFlags[origIndex].mat_nr + 1 : 1;
-
-                               if (mat_nr != prev_mat_nr) {
-                                       setMaterial(mat_nr, NULL);  /* XXX, no faceFlags no material */
-                                       prev_mat_nr = mat_nr;
-                               }
-                       }
-
-                       if (setDrawOptions && (index != ORIGINDEX_NONE))
-                               draw_option = setDrawOptions(userData, index);
-
-                       if (draw_option != DM_DRAW_OPTION_SKIP) {
-                               if (draw_option == DM_DRAW_OPTION_STIPPLE) {
-                                       GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
-                                       GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_QUARTTONE);
-                               }
-
-                               for (S = 0; S < numVerts; S++) {
-                                       CCGElem *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
-                                       if (ln) {
-                                               glBegin(GL_QUADS);
-                                               for (y = 0; y < gridFaces; y++) {
-                                                       for (x = 0; x < gridFaces; x++) {
-                                                               float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
-                                                               float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
-                                                               float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
-                                                               float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
-                                                               if (cp) glColor4ubv(&cp[4]);
-                                                               glNormal3fv(ln[1]);
-                                                               glVertex3fv(d);
-                                                               if (cp) glColor4ubv(&cp[8]);
-                                                               glNormal3fv(ln[2]);
-                                                               glVertex3fv(c);
-                                                               if (cp) glColor4ubv(&cp[12]);
-                                                               glNormal3fv(ln[3]);
-                                                               glVertex3fv(b);
-                                                               if (cp) glColor4ubv(&cp[0]);
-                                                               glNormal3fv(ln[0]);
-                                                               glVertex3fv(a);
-
-                                                               if (cp) cp += 16;
-                                                               ln += 4;
-                                                       }
-                                               }
-                                               glEnd();
-                                       }
-                                       else if (drawSmooth) {
-                                               for (y = 0; y < gridFaces; y++) {
-                                                       CCGElem *a, *b;
-                                                       glBegin(GL_QUAD_STRIP);
-                                                       for (x = 0; x < gridFaces; x++) {
-                                                               a = CCG_grid_elem(&key, faceGridData, x, y + 0);
-                                                               b = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
-                                                               if (cp) glColor4ubv(&cp[0]);
-                                                               glNormal3fv(CCG_elem_no(&key, a));
-                                                               glVertex3fv(CCG_elem_co(&key, a));
-                                                               if (cp) glColor4ubv(&cp[4]);
-                                                               glNormal3fv(CCG_elem_no(&key, b));
-                                                               glVertex3fv(CCG_elem_co(&key, b));
-
-                                                               if (x != gridFaces - 1) {
-                                                                       if (cp) cp += 16;
-                                                               }
-                                                       }
-
-                                                       a = CCG_grid_elem(&key, faceGridData, x, y + 0);
-                                                       b = CCG_grid_elem(&key, faceGridData, x, y + 1);
-
-                                                       if (cp) glColor4ubv(&cp[12]);
-                                                       glNormal3fv(CCG_elem_no(&key, a));
-                                                       glVertex3fv(CCG_elem_co(&key, a));
-                                                       if (cp) glColor4ubv(&cp[8]);
-                                                       glNormal3fv(CCG_elem_no(&key, b));
-                                                       glVertex3fv(CCG_elem_co(&key, b));
-
-                                                       if (cp) cp += 16;
-
-                                                       glEnd();
-                                               }
-                                       }
-                                       else {
-                                               glBegin(GL_QUADS);
-                                               for (y = 0; y < gridFaces; y++) {
-                                                       for (x = 0; x < gridFaces; x++) {
-                                                               float *a = CCG_grid_elem_co(&key, faceGridData, x, y + 0);
-                                                               float *b = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 0);
-                                                               float *c = CCG_grid_elem_co(&key, faceGridData, x + 1, y + 1);
-                                                               float *d = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
-
-                                                               ccgDM_glNormalFast(a, b, c, d);
-
-                                                               if (cp) glColor4ubv(&cp[4]);
-                                                               glVertex3fv(d);
-                                                               if (cp) glColor4ubv(&cp[8]);
-                                                               glVertex3fv(c);
-                                                               if (cp) glColor4ubv(&cp[12]);
-                                                               glVertex3fv(b);
-                                                               if (cp) glColor4ubv(&cp[0]);
-                                                               glVertex3fv(a);
-
-                                                               if (cp) cp += 16;
-                                                       }
-                                               }
-                                               glEnd();
-                                       }
-                               }
-                               if (draw_option == DM_DRAW_OPTION_STIPPLE)
-                                       GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
-                       }
-               }
-       }
-}
-
-static void ccgDM_drawMappedEdges(DerivedMesh *dm,
-                                  DMSetDrawOptions setDrawOptions,
-                                  void *userData)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGEdgeIterator ei;
-       CCGKey key;
-       int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
-       if (ccgdm->useGpuBackend) {
-               /* TODO(sergey): Only draw edges from base mesh. */
-               if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
-                       if (!setDrawOptions || (setDrawOptions(userData, 0) != DM_DRAW_OPTION_SKIP)) {
-                               ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
-                       }
-               }
-               return;
-       }
-#endif
-
-       CCG_key_top_level(&key, ss);
-       ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
-       for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
-               CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
-               CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
-               int index = ccgDM_getEdgeMapIndex(ss, e);
-
-               glBegin(GL_LINE_STRIP);
-               if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) {
-                       if (useAging && !(G.f & G_BACKBUFSEL)) {
-                               int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
-                               glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
-                       }
-
-                       for (i = 0; i < edgeSize - 1; i++) {
-                               glVertex3fv(CCG_elem_offset_co(&key, edgeData, i));
-                               glVertex3fv(CCG_elem_offset_co(&key, edgeData, i + 1));
-                       }
-               }
-               glEnd();
-       }
-}
-
-static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm,
-                                        DMSetDrawOptions setDrawOptions,
-                                        DMSetDrawInterpOptions setDrawInterpOptions,
-                                        void *userData)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       CCGEdgeIterator ei;
-       int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-#ifdef WITH_OPENSUBDIV
-       if (ccgdm->useGpuBackend) {
-               BLI_assert(!"Not currently supported");
-               return;
-       }
-#endif
-
-       CCG_key_top_level(&key, ss);
-       ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
-
-       for (ccgSubSurf_initEdgeIterator(ss, &ei); !ccgEdgeIterator_isStopped(&ei); ccgEdgeIterator_next(&ei)) {
-               CCGEdge *e = ccgEdgeIterator_getCurrent(&ei);
-               CCGElem *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
-               int index = ccgDM_getEdgeMapIndex(ss, e);
-
-               glBegin(GL_LINE_STRIP);
-               if (index != -1 && (!setDrawOptions || (setDrawOptions(userData, index) != DM_DRAW_OPTION_SKIP))) {
-                       for (i = 0; i < edgeSize; i++) {
-                               setDrawInterpOptions(userData, index, (float) i / (edgeSize - 1));
-
-                               if (useAging && !(G.f & G_BACKBUFSEL)) {
-                                       int ageCol = 255 - ccgSubSurf_getEdgeAge(ss, e) * 4;
-                                       glColor3ub(0, ageCol > 0 ? ageCol : 0, 0);
-                               }
-
-                               glVertex3fv(CCG_elem_offset_co(&key, edgeData, i));
-                       }
-               }
-               glEnd();
-       }
-}
-
-static void ccgDM_foreachMappedFaceCenter(
-        DerivedMesh *dm,
-        void (*func)(void *userData, int index, const float co[3], const float no[3]),
-        void *userData,
-        DMForeachFlag flag)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       CCGKey key;
-       CCGFaceIterator fi;
-
-       CCG_key_top_level(&key, ss);
-
-       for (ccgSubSurf_initFaceIterator(ss, &fi); !ccgFaceIterator_isStopped(&fi); ccgFaceIterator_next(&fi)) {
-               CCGFace *f = ccgFaceIterator_getCurrent(&fi);
-               const int index = ccgDM_getFaceMapIndex(ss, f);
-
-               if (index != -1) {
-                       /* Face center data normal isn't updated atm. */
-                       CCGElem *vd = ccgSubSurf_getFaceGridData(ss, f, 0, 0, 0);
-                       const float *no = (flag & DM_FOREACH_USE_NORMAL) ? CCG_elem_no(&key, vd) : NULL;
-                       func(userData, index, CCG_elem_co(&key, vd), no);
-               }
-       }
-}
-
-static void ccgDM_release(DerivedMesh *dm)
-{
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
-
-       if (DM_release(dm)) {
-               /* Before freeing, need to update the displacement map */
-               if (ccgdm->multires.modified_flags) {
-                       /* Check that mmd still exists */
-                       if (!ccgdm->multires.local_mmd &&
-                           BLI_findindex(&ccgdm->multires.ob->modifiers, ccgdm->multires.mmd) < 0)
-                       {
-                               ccgdm->multires.mmd = NULL;
-                       }
-
-                       if (ccgdm->multires.mmd) {
-                               if (ccgdm->multires.modified_flags & MULTIRES_COORDS_MODIFIED)
-                                       multires_modifier_update_mdisps(dm);
-                               if (ccgdm->multires.modified_flags & MULTIRES_HIDDEN_MODIFIED)
-                                       multires_modifier_update_hidden(dm);
-                       }
-               }
-
-               if (ccgdm->ehash)
-                       BLI_edgehash_free(ccgdm->ehash, NULL);
-
-               if (ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap);
-               if (ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces);
-               if (ccgdm->gridData) MEM_freeN(ccgdm->gridData);
-               if (ccgdm->gridOffset) MEM_freeN(ccgdm->gridOffset);
-               if (ccgdm->gridFlagMats) MEM_freeN(ccgdm->gridFlagMats);
-               if (ccgdm->gridHidden) {
-                       /* Using dm->getNumGrids(dm) accesses freed memory */
-                       uint numGrids = ccgdm->numGrid;
-                       for (uint i = 0; i < numGrids; i++) {
-                               if (ccgdm->gridHidden[i]) {
-                                       MEM_freeN(ccgdm->gridHidden[i]);
-                               }
-                       }
-                       MEM_freeN(ccgdm->gridHidden);
-               }
-               if (ccgdm->freeSS) ccgSubSurf_free(ccgdm->ss);
-               if (ccgdm->pmap) MEM_freeN(ccgdm->pmap);
-               if (ccgdm->pmap_mem) MEM_freeN(ccgdm->pmap_mem);
-               MEM_freeN(ccgdm->edgeFlags);
-               MEM_freeN(ccgdm->faceFlags);
-               if (ccgdm->useGpuBackend == false) {
-                       MEM_freeN(ccgdm->vertMap);
-                       MEM_freeN(ccgdm->edgeMap);
-                       MEM_freeN(ccgdm->faceMap);
-               }
-
-               BLI_mutex_end(&ccgdm->loops_cache_lock);
-               BLI_rw_mutex_end(&ccgdm->origindex_cache_rwlock);
-
-               MEM_freeN(ccgdm);
-       }
-}
-
-static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
-{
-       if (type == CD_ORIGINDEX) {
-               /* create origindex on demand to save memory */
-               CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
-               CCGSubSurf *ss = ccgdm->ss;
-               int *origindex;
-               int a, index, totnone, totorig;
-
-               /* Avoid re-creation if the layer exists already */
-               BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_READ);
-               origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
-               BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
-               if (origindex) {
-                       return origindex;
-               }
-
-               BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE);
-               DM_add_vert_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
-               origindex = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
-
-               totorig = ccgSubSurf_getNumVerts(ss);
-               totnone = dm->numVertData - totorig;
-
-               /* original vertices are at the end */
-               for (a = 0; a < totnone; a++)
-                       origindex[a] = ORIGINDEX_NONE;
-
-               for (index = 0; index < totorig; index++, a++) {
-                       CCGVert *v = ccgdm->vertMap[index].vert;
-                       origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v);
-               }
-               BLI_rw_mutex_unlock(&ccgdm->origindex_cache_rwlock);
-
-               return origindex;
-       }
-
-       return DM_get_vert_data_layer(dm, type);
-}
-
-static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type)
-{
-       if (type == CD_ORIGINDEX) {
-               /* create origindex on demand to save memory */
-               CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm;
-               CCGSubSurf *ss = ccgdm->ss;
-               int *origindex;
-               int a, i, index, totnone, totorig, totedge;
-               int edgeSize = ccgSubSurf_getEdgeSize(ss);
-
-               /* Avoid re-creation if the layer exists already */
-               origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
-               if (origindex) {
-                       return origindex;
-               }
-
-               DM_add_edge_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
-               origindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
-
-               totedge = ccgSubSurf_getNumEdges(ss);
-               totorig = totedge * (edgeSize - 1);
-               totnone = dm->numEdgeData - totorig;
-
-               /* original edges are at the end */
-               for (a = 0; a < totnone; a++)
-                       origindex[a] = ORIGINDEX_NONE;
-
-               for (index = 0; index < totedge; index++) {
-                       CCGEdge *e = ccgdm->edgeMap[index].edge;
-                       int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
-
-                       for (i = 0; i < edgeSize - 1; i++, a++)
-                               origindex[a] = mapIndex;
-               }
-
-               return origindex;
-       }
-
-       return DM_get_edge_data_layer(dm, type);
-}
-
-static void *ccgDM_get_tessface_data_layer(DerivedMesh *dm, int type)
-{
-       if (type == CD_ORIGINDEX) {
-               /* create origindex on demand to save memory */
-               int *origindex;
-
-               /* Avoid re-creation if the layer exists already */
-               origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
-               if (origindex) {
-                       return origindex;
-               }
-
-               DM_add_tessface_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
-               origindex = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
-
-               /* silly loop counting up */
-               range_vn_i(origindex, dm->getNumTessFaces(dm), 0);
-
-               return origindex;
-       }
-
-       if (type == CD_TESSLOOPNORMAL) {
-               /* Create tessloopnormal on demand to save memory. */
-               /* Note that since tessellated face corners are the same a loops in CCGDM, and since all faces have four
-                * loops/corners, we can simplify the code here by converting tessloopnormals from 'short (*)[4][3]'
-                * to 'short (*)[3]'.
-                */
-               short (*tlnors)[3];
-
-               /* Avoid re-creation if the layer exists already */
-               tlnors = DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL);
-               if (!tlnors) {
-                       float (*lnors)[3];
-                       short (*tlnors_it)[3];
-                       const int numLoops = ccgDM_getNumLoops(dm);
-                       int i;
-
-                       lnors = dm->getLoopDataArray(dm, CD_NORMAL);
-                       if (!lnors) {
-                               return NULL;
-                       }
-
-                       DM_add_tessface_layer(dm, CD_TESSLOOPNORMAL, CD_CALLOC, NULL);
-                       tlnors = tlnors_it = (short (*)[3])DM_get_tessface_data_layer(dm, CD_TESSLOOPNORMAL);
-
-                       /* With ccgdm, we have a simple one to one mapping between loops and tessellated face corners. */
-                       for (i = 0; i < numLoops; ++i, ++tlnors_it, ++lnors) {
-                               normal_float_to_short_v3(*tlnors_it, *lnors);
-                       }
-               }
-
-               return tlnors;
-       }
-
-       return DM_get_tessface_data_layer(dm, type);
-}
-
-static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type)
+static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type)
 {
        if (type == CD_ORIGINDEX) {
                /* create origindex on demand to save memory */
@@ -4534,7 +2316,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
                                     numGrids, &key, (void **) ccgdm->gridFaces, ccgdm->gridFlagMats, ccgdm->gridHidden);
        }
        else if (ob->type == OB_MESH) {
-               Mesh *me = ob->data;
+               Mesh *me = BKE_object_get_original_mesh(ob);
                const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
                MLoopTri *looptri;
 
@@ -4558,7 +2340,7 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
                        totvert = deformdm->getNumVerts(deformdm);
                        vertCos = MEM_malloc_arrayN(totvert, sizeof(float[3]), "ccgDM_getPBVH vertCos");
                        deformdm->getVertCos(deformdm, vertCos);
-                       BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos);
+                       BKE_pbvh_apply_vertCos(ccgdm->pbvh, vertCos, totvert);
                        MEM_freeN(vertCos);
                }
        }
@@ -4671,23 +2453,6 @@ static void set_default_ccgdm_callbacks(CCGDerivedMesh *ccgdm)
        ccgdm->dm.foreachMappedLoop = ccgDM_foreachMappedLoop;
        ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
 
-       ccgdm->dm.drawVerts = ccgDM_drawVerts;
-       ccgdm->dm.drawEdges = ccgDM_drawEdges;
-       ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
-       ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid;
-       ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex;
-       ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL;
-       ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces;
-       ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
-       ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL;
-       ccgdm->dm.drawMappedFacesMat = ccgDM_drawMappedFacesMat;
-       ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges;
-
-       ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
-       ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
-       ccgdm->dm.gpuObjectNew = ccgDM_GPUObjectNew;
-       ccgdm->dm.copy_gpu_data = ccgDM_copy_gpu_data;
-
        ccgdm->dm.release = ccgDM_release;
 }
 
@@ -5139,8 +2904,7 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags)
         */
        return
                (flags & SUBSURF_USE_GPU_BACKEND) != 0 &&
-               (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE) &&
-               (openSubdiv_supportGPUDisplay());
+               (U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE);
 #else
        (void)flags;
        return false;
@@ -5150,12 +2914,13 @@ static bool subsurf_use_gpu_backend(SubsurfFlags flags)
 struct DerivedMesh *subsurf_make_derived_from_derived(
         struct DerivedMesh *dm,
         struct SubsurfModifierData *smd,
+        struct Scene *scene,
         float (*vertCos)[3],
         SubsurfFlags flags)
 {
        int useSimple = (smd->subdivType == ME_SIMPLE_SUBSURF) ? CCG_SIMPLE_SUBDIV : 0;
        CCGFlags useAging = (smd->flags & eSubsurfModifierFlag_DebugIncr) ? CCG_USE_AGING : 0;
-       int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
+       int useSubsurfUv = (smd->uv_smooth != SUBSURF_UV_SMOOTH_NONE);
        int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
        CCGDerivedMesh *result;
        bool use_gpu_backend = subsurf_use_gpu_backend(flags);
@@ -5163,7 +2928,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
        /* note: editmode calculation can only run once per
         * modifier stack evaluation (uses freed cache) [#36299] */
        if (flags & SUBSURF_FOR_EDIT_MODE) {
-               int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
+               int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels;
 
                /* TODO(sergey): Same as emCache below. */
                if ((flags & SUBSURF_IN_EDIT_MODE) && smd->mCache) {
@@ -5184,7 +2949,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
        else if (flags & SUBSURF_USE_RENDER_PARAMS) {
                /* Do not use cache in render mode. */
                CCGSubSurf *ss;
-               int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->renderLevels, true) : smd->renderLevels;
+               int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->renderLevels, true) : smd->renderLevels;
 
                if (levels == 0)
                        return dm;
@@ -5200,7 +2965,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
        }
        else {
                int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
-               int levels = (smd->modifier.scene) ? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels, false) : smd->levels;
+               int levels = (scene != NULL) ? get_render_subsurf_level(&scene->r, smd->levels, false) : smd->levels;
                CCGSubSurf *ss;
 
                /* It is quite possible there is a much better place to do this. It