merge with trunk at r31523
[blender.git] / source / blender / blenkernel / intern / subsurf_ccg.c
index 4c85656dd914d4187b9ef4ac2c920ab30a1c94ca..7e3b5691177cd574c70072c734a52a40d41784c0 100644 (file)
@@ -48,6 +48,7 @@
 #include "BKE_paint.h"
 #include "BKE_scene.h"
 #include "BKE_subsurf.h"
+#include "BKE_tessmesh.h"
 #include "BKE_utildefines.h"
 
 #include "BLI_blenlib.h"
@@ -55,6 +56,8 @@
 #include "BLI_math.h"
 #include "BLI_memarena.h"
 #include "BLI_pbvh.h"
+#include "PIL_time.h"
+#include "BLI_array.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 
 #include "CCGSubSurf.h"
 
-static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v);
-static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e);
-static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f);
+static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
+                                         int drawInteriorEdges,
+                                         int useSubsurfUv,
+                                         DerivedMesh *dm);
 
 static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm);
 
@@ -156,7 +160,8 @@ static int getEdgeIndex(CCGSubSurf *ss, CCGEdge *e, int x, int edgeSize) {
                return edgeBase + x-1;
        }
 }
-static int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize) {
+
+BM_INLINE int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize) {
        int faceBase = *((int*) ccgSubSurf_getFaceUserData(ss, f));
        int numVerts = ccgSubSurf_getFaceNumVerts(f);
 
@@ -211,10 +216,11 @@ static void get_face_uv_map_vert(UvVertMap *vmap, struct MFace *mf, int fi, CCGV
 }
 
 static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MTFace *tface) {
-       MFace *mface = dm->getFaceArray(dm);
+#if 0
+       MFace *mface = dm->getTessFaceArray(dm);
        MVert *mvert = dm->getVertArray(dm);
        int totvert = dm->getNumVerts(dm);
-       int totface = dm->getNumFaces(dm);
+       int totface = dm->getNumTessFaces(dm);
        int i, j, seam;
        UvMapVert *v;
        UvVertMap *vmap;
@@ -304,6 +310,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
        free_uv_vert_map(vmap);
        ccgSubSurf_processSync(ss);
 
+#endif
        return 1;
 }
 
@@ -376,7 +383,6 @@ static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result,
        MEM_freeN(faceMap);
 }
 
-/* face weighting */
 static void calc_ss_weights(int gridFaces,
                                                        FaceVertWeight **qweight, FaceVertWeight **tweight)
 {
@@ -420,22 +426,496 @@ static void calc_ss_weights(int gridFaces,
        }
 }
 
+/* face weighting */
+typedef struct FaceVertWeightEntry {
+       FaceVertWeight *weight;
+       float *w;
+       int valid;
+} FaceVertWeightEntry;
+
+typedef struct WeightTable {
+       FaceVertWeightEntry *weight_table;
+       int len;
+} WeightTable;
+
+static float *get_ss_weights(WeightTable *wtable, int gridCuts, int faceLen)
+{
+       int x, y, i, j;
+       float *w, w1, w2, w4, fac, fac2, fx, fy;
+
+       if (wtable->len <= faceLen) {
+               void *tmp = MEM_callocN(sizeof(FaceVertWeightEntry)*(faceLen+1), "weight table alloc 2");
+               
+               if (wtable->len) {
+                       memcpy(tmp, wtable->weight_table, sizeof(FaceVertWeightEntry)*wtable->len);
+                       MEM_freeN(wtable->weight_table);
+               }
+               
+               wtable->weight_table = tmp;
+               wtable->len = faceLen+1;
+       }
+
+       if (!wtable->weight_table[faceLen].valid) {
+               wtable->weight_table[faceLen].valid = 1;
+               wtable->weight_table[faceLen].w = w = MEM_callocN(sizeof(float)*faceLen*faceLen*(gridCuts+2)*(gridCuts+2), "weight table alloc");
+               fac = 1.0 / (float)faceLen;
+
+               for (i=0; i<faceLen; i++) {
+                       for (x=0; x<gridCuts+2; x++) {
+                               for (y=0; y<gridCuts+2; y++) {
+                                       fx = 0.5f - (float)x / (float)(gridCuts+1) / 2.0f;
+                                       fy = 0.5f - (float)y / (float)(gridCuts+1) / 2.0f;
+                               
+                                       fac2 = faceLen - 4;
+                                       w1 = (1.0f - fx) * (1.0f - fy) + (-fac2*fx*fy*fac);
+                                       w2 = (1.0f - fx + fac2*fx*-fac) * (fy);
+                                       w4 = (fx) * (1.0 - fy + -fac2*fy*fac);
+                                       
+                                       fac2 = 1.0 - (w1+w2+w4);
+                                       fac2 = fac2 / (float)(faceLen-3);
+                                       for (j=0; j<faceLen; j++)
+                                               w[j] = fac2;
+                                       
+                                       w[i] = w1;
+                                       w[(i-1+faceLen)%faceLen] = w2;
+                                       w[(i+1)%faceLen] = w4;
+
+                                       w += faceLen;
+                               }
+                       }
+               }
+       }
+
+       return wtable->weight_table[faceLen].w;
+}
+
+void free_ss_weights(WeightTable *wtable)
+{
+       int i;
+
+       for (i=0; i<wtable->len; i++) {
+               if (wtable->weight_table[i].valid)
+                       MEM_freeN(wtable->weight_table[i].w);
+       }
+}
+
+static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
+                                 int drawInteriorEdges, int useSubsurfUv,
+                                 DerivedMesh *dm, struct MultiresSubsurf *ms)
+{
+       DerivedMesh *cgdm, *result;
+       double curt = PIL_check_seconds_timer();
+
+       cgdm = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);
+       result = CDDM_copy(cgdm, 1);
+
+       printf("subsurf conversion time: %.6lf\n", PIL_check_seconds_timer() - curt);
+       
+       cgdm->needsFree = 1;
+       cgdm->release(cgdm);
+
+       CDDM_calc_normals(result);
+
+       return result;
+#if 0
+       DerivedMesh *result;
+       int edgeSize = ccgSubSurf_getEdgeSize(ss);
+       int gridSize = ccgSubSurf_getGridSize(ss);
+       int gridFaces = gridSize - 1;
+       int edgeBase, faceBase;
+       int i, j, k, S, x, y, index;
+       int *vertIdx = NULL;
+       BLI_array_declare(vertIdx);
+       CCGVertIterator *vi;
+       CCGEdgeIterator *ei;
+       CCGFaceIterator *fi;
+       CCGFace **faceMap2;
+       CCGEdge **edgeMap2;
+       CCGVert **vertMap2;
+       int totvert, totedge, totface;
+       MVert *mvert;
+       MEdge *med;
+       float *w = NULL;
+       WeightTable wtable;
+       BLI_array_declare(w);
+       MFace *mf;
+       int *origIndex;
+
+       memset(&wtable, 0, sizeof(wtable));
+
+       /* vert map */
+       totvert = ccgSubSurf_getNumVerts(ss);
+       vertMap2 = MEM_mallocN(totvert*sizeof(*vertMap2), "vertmap");
+       vi = ccgSubSurf_getVertIterator(ss);
+       for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
+               CCGVert *v = ccgVertIterator_getCurrent(vi);
+
+               vertMap2[GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v))] = v;
+       }
+       ccgVertIterator_free(vi);
+
+       totedge = ccgSubSurf_getNumEdges(ss);
+       edgeMap2 = MEM_mallocN(totedge*sizeof(*edgeMap2), "edgemap");
+       ei = ccgSubSurf_getEdgeIterator(ss);
+       for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+               CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+
+               edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] = e;
+       }
+
+       totface = ccgSubSurf_getNumFaces(ss);
+       faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap");
+       fi = ccgSubSurf_getFaceIterator(ss);
+       for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+               CCGFace *f = ccgFaceIterator_getCurrent(fi);
+
+               faceMap2[GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f))] = f;
+       }
+       ccgFaceIterator_free(fi);
+
+       if(ms) {
+               result = MultiresDM_new(ms, dm, ccgSubSurf_getNumFinalVerts(ss),
+                                       ccgSubSurf_getNumFinalEdges(ss),
+                                       ccgSubSurf_getNumFinalFaces(ss), 0, 0);
+       }
+       else {
+               if(dm) {
+                       result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss),
+                                                   ccgSubSurf_getNumFinalEdges(ss),
+                                                   ccgSubSurf_getNumFinalFaces(ss), 0, 0);
+               } else {
+                       result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss),
+                                         ccgSubSurf_getNumFinalEdges(ss),
+                                         ccgSubSurf_getNumFinalFaces(ss), 0, 0);
+               }
+       }
+
+       // load verts
+       faceBase = i = 0;
+       mvert = CDDM_get_verts(result);
+       origIndex = result->getVertData(result, 0, CD_ORIGINDEX);
+
+       for(index = 0; index < totface; index++) {
+               CCGFace *f = faceMap2[index];
+               int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
+               FaceVertWeight *weight = 0;//get_ss_weights(&wtable, gridFaces-1, numVerts);
+
+               BLI_array_empty(vertIdx);
+
+               for(S = 0; S < numVerts; S++) {
+                       CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+                       BLI_array_growone(vertIdx);
+
+                       vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+               }
+
+#if 0
+               DM_interp_vert_data(dm, result, vertIdx, weight[0][0], numVerts, i);
+#endif
+               copy_v3_v3(mvert->co, ccgSubSurf_getFaceCenterData(f));
+               *origIndex = ORIGINDEX_NONE;
+               ++mvert;
+               ++origIndex;
+               i++;
+
+               BLI_array_empty(w);
+               for (x=0; x<numVerts; x++) {
+                       BLI_array_growone(w);
+               }
+
+               for(S = 0; S < numVerts; S++) {
+                       int prevS = (S - 1 + numVerts) % numVerts;
+                       int nextS = (S + 1) % numVerts;
+                       int otherS = (numVerts >= 4) ? (S + 2) % numVerts : 3;
+
+                       for(x = 1; x < gridFaces; x++) {
+#if 0
+                               w[prevS]  = weight[x][0][0];
+                               w[S]      = weight[x][0][1];
+                               w[nextS]  = weight[x][0][2];
+                               w[otherS] = weight[x][0][3];
+
+                               DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
+#endif
+                               copy_v3_v3(mvert->co,
+                                        ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
+
+                               *origIndex = ORIGINDEX_NONE;
+                               ++mvert;
+                               ++origIndex;
+                               i++;
+                       }
+               }
+               
+               BLI_array_empty(w);
+               for (x=0; x<numVerts; x++) {
+                       BLI_array_growone(w);
+               }
+
+               for(S = 0; S < numVerts; S++) {
+                       int prevS = (S - 1 + numVerts) % numVerts;
+                       int nextS = (S + 1) % numVerts;
+                       int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+                       
+                       for(y = 1; y < gridFaces; y++) {
+                               for(x = 1; x < gridFaces; x++) {
+#if 0
+                                       w[prevS]  = weight[y * gridFaces + x][0][0];
+                                       w[S]      = weight[y * gridFaces + x][0][1];
+                                       w[nextS]  = weight[y * gridFaces + x][0][2];
+                                       w[otherS] = weight[y * gridFaces + x][0][3];
+                                       DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
+#endif
+
+                                       copy_v3_v3(mvert->co,
+                                                ccgSubSurf_getFaceGridData(ss, f, S, x, y));
+                                       *origIndex = ORIGINDEX_NONE;
+                                       ++mvert;
+                                       ++origIndex;
+                                       i++;
+                               }
+                       }
+               }
+               *((int*)ccgSubSurf_getFaceUserData(ss, f)) = faceBase;
+               faceBase += 1 + numVerts * ((gridSize-2) + (gridSize-2) * (gridSize-2));
+       }
+
+       edgeBase = i;
+       for(index = 0; index < totedge; index++) {
+               CCGEdge *e = edgeMap2[index];
+               int x;
+               int vertIdx[2];
+
+               CCGVert *v;
+               v = ccgSubSurf_getEdgeVert0(e);
+               vertIdx[0] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+               v = ccgSubSurf_getEdgeVert1(e);
+               vertIdx[1] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+               
+               for(x = 1; x < edgeSize - 1; x++) {
+                       float w2[2];
+
+                       w2[1] = (float) x / (edgeSize - 1);
+                       w2[0] = 1 - w2[1];
+                       DM_interp_vert_data(dm, result, vertIdx, w2, 2, i);
+
+                       copy_v3_v3(mvert->co, ccgSubSurf_getEdgeData(ss, e, x));
+                       *origIndex = ORIGINDEX_NONE;
+                       ++mvert;
+                       ++origIndex;
+                       i++;
+               }
+
+               *((int*)ccgSubSurf_getEdgeUserData(ss, e)) = edgeBase;
+               edgeBase += edgeSize-2;
+       }
+
+       for(index = 0; index < totvert; index++) {
+               CCGVert *v = vertMap2[index];
+               int vertIdx;
+
+               vertIdx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+
+               DM_copy_vert_data(dm, result, vertIdx, i, 1);
+               copy_v3_v3(mvert->co, ccgSubSurf_getVertData(ss, v));
+
+               *((int*)ccgSubSurf_getVertUserData(ss, v)) = i;
+               *origIndex = ccgDM_getVertMapIndex(ss, v);
+               ++mvert;
+               ++origIndex;
+               i++;
+       }
+
+       // load edges
+       i = 0;
+       med = CDDM_get_edges(result);
+       origIndex = result->getEdgeData(result, 0, CD_ORIGINDEX);
+
+       for(index = 0; index < totface; index++) {
+               CCGFace *f = faceMap2[index];
+               int numVerts = ccgSubSurf_getFaceNumVerts(f);
+
+               for(k = 0; k < numVerts; k++) {
+                       for(x = 0; x < gridFaces; x++) {
+                               if(drawInteriorEdges) med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+                               med->v1 = getFaceIndex(ss, f, k, x, 0, edgeSize, gridSize);
+                               med->v2 = getFaceIndex(ss, f, k, x+1, 0, edgeSize, gridSize);
+                               *origIndex = ORIGINDEX_NONE;
+                               ++med;
+                               ++origIndex;
+                               i++;
+                       }
+
+                       for(x = 1; x < gridFaces; x++) {
+                               for(y = 0; y < gridFaces; y++) {
+                                       if(drawInteriorEdges)
+                                               med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+                                       med->v1 = getFaceIndex(ss, f, k, x, y, edgeSize, gridSize);
+                                       med->v2 = getFaceIndex(ss, f, k, x, y + 1,
+                                                              edgeSize, gridSize);
+                                       *origIndex = ORIGINDEX_NONE;
+                                       ++med;
+                                       ++origIndex;
+                                       i++;
+
+                                       if(drawInteriorEdges)
+                                               med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+                                       med->v1 = getFaceIndex(ss, f, k, y, x, edgeSize, gridSize);
+                                       med->v2 = getFaceIndex(ss, f, k, y + 1, x,
+                                                              edgeSize, gridSize);
+                                       *origIndex = ORIGINDEX_NONE;
+                                       ++med;
+                                       ++origIndex;
+                                       i++;
+                               }
+                       }
+               }
+       }
+
+       for(index = 0; index < totedge; index++) {
+               CCGEdge *e = edgeMap2[index];
+               unsigned int flags = 0;
+               char bweight = 0;
+               int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e));
+
+               if(!ccgSubSurf_getEdgeNumFaces(e)) flags |= ME_LOOSEEDGE;
+
+
+               if(edgeIdx != -1 && dm) {
+                       MEdge origMed;
+                       dm->getEdge(dm, edgeIdx, &origMed);
+
+                       flags |= origMed.flag;
+                       bweight = origMed.bweight;
+               }
+
+               for(x = 0; x < edgeSize - 1; x++) {
+                       med->v1 = getEdgeIndex(ss, e, x, edgeSize);
+                       med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize);
+                       med->flag = flags;
+                       med->bweight = bweight;
+                       *origIndex = ccgDM_getEdgeMapIndex(ss, e);
+                       ++med;
+                       ++origIndex;
+                       i++;
+               }
+       }
+
+       // load faces
+       i = 0;
+       mf = CDDM_get_tessfaces(result);
+       origIndex = result->getTessFaceData(result, 0, CD_ORIGINDEX);
+
+       for(index = 0; index < totface; index++) {
+               CCGFace *f = faceMap2[index];
+               int numVerts = ccgSubSurf_getFaceNumVerts(f);
+               int mat_nr;
+               int flag;
+               int mapIndex = ccgDM_getFaceMapIndex(ss, f);
+               int faceIdx = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
+
+               if(!ssFromEditmesh) {
+                       MFace origMFace;
+                       dm->getTessFace(dm, faceIdx, &origMFace);
+                       
+                       mat_nr = origMFace.mat_nr;
+                       flag = origMFace.flag;
+               } else {
+                       BMFace *ef = ccgSubSurf_getFaceFaceHandle(ss, f);
+                       mat_nr = ef->mat_nr;
+                       flag = BMFlags_To_MEFlags(ef);
+               }
+
+               for(S = 0; S < numVerts; S++) {
+                       FaceVertWeight *weight = 0;//get_ss_weights(&wtable, gridFaces-1, numVerts);
+                       
+                       for(y = 0; y < gridFaces; y++) {
+                               for(x = 0; x < gridFaces; x++) {
+                                       mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
+                                                             edgeSize, gridSize);
+                                       mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
+                                                             edgeSize, gridSize);
+                                       mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
+                                                             edgeSize, gridSize);
+                                       mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
+                                                             edgeSize, gridSize);
+                                       mf->mat_nr = mat_nr;
+                                       mf->flag = flag;
+#if 0 //BMESH_TODO
+                                       if(dm) {
+                                               int prevS = (S - 1 + numVerts) % numVerts;
+                                               int nextS = (S + 1) % numVerts;
+                                               int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+                                               FaceVertWeight w;
+
+                                               for(j = 0; j < 4; ++j) {
+                                                       w[j][prevS]  = (*weight)[j][0];
+                                                       w[j][S]      = (*weight)[j][1];
+                                                       w[j][nextS]  = (*weight)[j][2];
+                                                       w[j][otherS] = (*weight)[j][3];
+                                               }
+                                               
+                                               DM_interp_tessface_data(dm, result, &faceIdx, NULL,
+                                                                   &w, 1, i);
+                                               weight++;
+                                       }
+#endif
+
+                                       *origIndex = mapIndex;
+                                       ++mf;
+                                       ++origIndex;
+                                       i++;
+                               }
+                       }
+               }
+       }
+
+       MEM_freeN(faceMap2);
+       MEM_freeN(edgeMap2);
+       MEM_freeN(vertMap2);
+
+       free_ss_weights(&wtable);
+
+       BLI_array_free(vertIdx);
+
+       if(useSubsurfUv) {
+               CustomData *fdata = &result->faceData;
+               CustomData *dmfdata = &dm->faceData;
+               int numlayer = CustomData_number_of_layers(fdata, CD_MTFACE);
+               int dmnumlayer = CustomData_number_of_layers(dmfdata, CD_MTFACE);
+               
+               for (i=0; i<numlayer && i<dmnumlayer; i++)
+                       set_subsurf_uv(ss, dm, result, i);
+       }
+
+       CDDM_calc_normals(result);
+       CDDM_tessfaces_to_faces(result);
+       
+       BLI_array_free(w);
+       return result;
+#endif
+}
+
 static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
                                                                         float (*vertexCos)[3], int useFlatSubdiv)
 {
        float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss);
-       CCGVertHDL fVerts[4];
+       CCGVertHDL *fVerts = NULL;
+       BLI_array_declare(fVerts);
        int totvert = dm->getNumVerts(dm);
        int totedge = dm->getNumEdges(dm);
-       int totface = dm->getNumFaces(dm);
+       int totface = dm->getNumTessFaces(dm);
+       int totpoly = dm->getNumFaces(dm);
        int i;
        int *index;
        MVert *mvert = dm->getVertArray(dm);
        MEdge *medge = dm->getEdgeArray(dm);
-       MFace *mface = dm->getFaceArray(dm);
+       MFace *mface = dm->getTessFaceArray(dm);
        MVert *mv;
        MEdge *me;
        MFace *mf;
+       DMFaceIter *fiter;
+       DMLoopIter *liter;
 
        ccgSubSurf_initFullSync(ss);
 
@@ -467,28 +947,31 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
 
                ((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = (index)? *index++: i;
        }
-
-       mf = mface;
-       index = (int *)dm->getFaceDataArray(dm, CD_ORIGINDEX);
-       for (i = 0; i < totface; i++, mf++) {
+       
+       fiter = dm->newFaceIter(dm);
+       for (i=0; !fiter->done; fiter->step(fiter), i++) {
                CCGFace *f;
+               BLI_array_empty(fVerts);
 
-               fVerts[0] = SET_INT_IN_POINTER(mf->v1);
-               fVerts[1] = SET_INT_IN_POINTER(mf->v2);
-               fVerts[2] = SET_INT_IN_POINTER(mf->v3);
-               fVerts[3] = SET_INT_IN_POINTER(mf->v4);
+               index = (int*) fiter->getCDData(fiter, CD_ORIGINDEX, -1);
+               liter = fiter->getLoopsIter(fiter);
 
-               // this is very bad, means mesh is internally consistent.
-               // it is not really possible to continue without modifying
-               // other parts of code significantly to handle missing faces.
-               // since this really shouldn't even be possible we just bail.
-               if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), fVerts[3] ? 4 : 3,
+               for (; !liter->done; liter->step(liter)) {
+                       BLI_array_growone(fVerts);
+                       fVerts[BLI_array_count(fVerts)-1] = SET_INT_IN_POINTER(liter->vindex);
+               }
+
+               /* this is very bad, means mesh is internally inconsistent.
+                * it is not really possible to continue without modifying
+                * other parts of code significantly to handle missing faces.
+                * since this really shouldn't even be possible we just bail.*/
+               if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), fiter->len, 
                                                           fVerts, &f) == eCCGError_InvalidValue) {
                        static int hasGivenError = 0;
 
                        if(!hasGivenError) {
-                               //XXX error("Unrecoverable error in SubSurf calculation,"
-                               //      " mesh is inconsistent.");
+                               printf("Unrecoverable error in SubSurf calculation,"
+                                      " mesh is inconsistent.\n");
 
                                hasGivenError = 1;
                        }
@@ -498,27 +981,30 @@ static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
 
                ((int*)ccgSubSurf_getFaceUserData(ss, f))[1] = (index)? *index++: i;
        }
+       fiter->free(fiter);
 
        ccgSubSurf_processSync(ss);
+
+       BLI_array_free(fVerts);
 }
 
 /***/
 
-static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v) {
+int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v) {
        return ((int*) ccgSubSurf_getVertUserData(ss, v))[1];
 }
 
-static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e) {
+int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e) {
        return ((int*) ccgSubSurf_getEdgeUserData(ss, e))[1];
 }
 
-static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f) {
+int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f) {
        return ((int*) ccgSubSurf_getFaceUserData(ss, f))[1];
 }
 
-static void ccgDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        CCGVertIterator *vi = ccgSubSurf_getVertIterator(ss);
        CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
        CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
@@ -560,32 +1046,32 @@ static void ccgDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
        ccgEdgeIterator_free(ei);
        ccgVertIterator_free(vi);
 }
-static int ccgDM_getNumVerts(DerivedMesh *dm) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+static int cgdm_getNumVerts(DerivedMesh *dm) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 
-       return ccgSubSurf_getNumFinalVerts(ccgdm->ss);
+       return ccgSubSurf_getNumFinalVerts(cgdm->ss);
 }
-static int ccgDM_getNumEdges(DerivedMesh *dm) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+static int cgdm_getNumEdges(DerivedMesh *dm) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 
-       return ccgSubSurf_getNumFinalEdges(ccgdm->ss);
+       return ccgSubSurf_getNumFinalEdges(cgdm->ss);
 }
-static int ccgDM_getNumFaces(DerivedMesh *dm) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+static int cgdm_getNumTessFaces(DerivedMesh *dm) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 
-       return ccgSubSurf_getNumFinalFaces(ccgdm->ss);
+       return ccgSubSurf_getNumFinalFaces(cgdm->ss);
 }
 
 static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
 {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        DMGridData *vd;
        int i;
 
        memset(mv, 0, sizeof(*mv));
 
-       if((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
+       if((vertNum < cgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
                /* this vert comes from face data */
                int lastface = ccgSubSurf_getNumFaces(ss) - 1;
                CCGFace *f;
@@ -598,10 +1084,10 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
                int gridInternalEnd;
 
                i = 0;
-               while(i < lastface && vertNum >= ccgdm->faceMap[i + 1].startVert)
+               while(i < lastface && vertNum >= cgdm->faceMap[i + 1].startVert)
                        ++i;
 
-               f = ccgdm->faceMap[i].face;
+               f = cgdm->faceMap[i].face;
                numVerts = ccgSubSurf_getFaceNumVerts(f);
 
                gridSideVerts = gridSize - 2;
@@ -610,7 +1096,7 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
                gridSideEnd = 1 + numVerts * gridSideVerts;
                gridInternalEnd = gridSideEnd + numVerts * gridInternalVerts;
 
-               offset = vertNum - ccgdm->faceMap[i].startVert;
+               offset = vertNum - cgdm->faceMap[i].startVert;
                if(offset < 1) {
                        vd = ccgSubSurf_getFaceCenterData(f);
                        copy_v3_v3(mv->co, vd->co);
@@ -632,28 +1118,28 @@ static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
                        copy_v3_v3(mv->co, vd->co);
                        normal_float_to_short_v3(mv->no, vd->no);
                }
-       } else if((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
+       } else if((vertNum < cgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
                /* this vert comes from edge data */
                CCGEdge *e;
                int lastedge = ccgSubSurf_getNumEdges(ss) - 1;
                int x;
 
                i = 0;
-               while(i < lastedge && vertNum >= ccgdm->edgeMap[i + 1].startVert)
+               while(i < lastedge && vertNum >= cgdm->edgeMap[i + 1].startVert)
                        ++i;
 
-               e = ccgdm->edgeMap[i].edge;
+               e = cgdm->edgeMap[i].edge;
 
-               x = vertNum - ccgdm->edgeMap[i].startVert + 1;
+               x = vertNum - cgdm->edgeMap[i].startVert + 1;
                vd = ccgSubSurf_getEdgeData(ss, e, x);
                copy_v3_v3(mv->co, vd->co);
                normal_float_to_short_v3(mv->no, vd->no);
        } else {
                /* this vert comes from vert data */
                CCGVert *v;
-               i = vertNum - ccgdm->vertMap[0].startVert;
+               i = vertNum - cgdm->vertMap[0].startVert;
 
-               v = ccgdm->vertMap[i].vert;
+               v = cgdm->vertMap[i].vert;
                vd = ccgSubSurf_getVertData(ss, v);
                copy_v3_v3(mv->co, vd->co);
                normal_float_to_short_v3(mv->no, vd->no);
@@ -678,13 +1164,13 @@ static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float no_r[3])
 
 static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
 {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        int i;
 
        memset(med, 0, sizeof(*med));
 
-       if(edgeNum < ccgdm->edgeMap[0].startEdge) {
+       if(edgeNum < cgdm->edgeMap[0].startEdge) {
                /* this edge comes from face data */
                int lastface = ccgSubSurf_getNumFaces(ss) - 1;
                CCGFace *f;
@@ -696,16 +1182,16 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
                int gridInternalEdges;
 
                i = 0;
-               while(i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge)
+               while(i < lastface && edgeNum >= cgdm->faceMap[i + 1].startEdge)
                        ++i;
 
-               f = ccgdm->faceMap[i].face;
+               f = cgdm->faceMap[i].face;
                numVerts = ccgSubSurf_getFaceNumVerts(f);
 
                gridSideEdges = gridSize - 1;
                gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; 
 
-               offset = edgeNum - ccgdm->faceMap[i].startEdge;
+               offset = edgeNum - cgdm->faceMap[i].startEdge;
                grid = offset / (gridSideEdges + gridInternalEdges);
                offset %= (gridSideEdges + gridInternalEdges);
 
@@ -733,18 +1219,18 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
                short *edgeFlag;
                unsigned int flags = 0;
 
-               i = (edgeNum - ccgdm->edgeMap[0].startEdge) / (edgeSize - 1);
+               i = (edgeNum - cgdm->edgeMap[0].startEdge) / (edgeSize - 1);
 
-               e = ccgdm->edgeMap[i].edge;
+               e = cgdm->edgeMap[i].edge;
 
                if(!ccgSubSurf_getEdgeNumFaces(e)) flags |= ME_LOOSEEDGE;
 
-               x = edgeNum - ccgdm->edgeMap[i].startEdge;
+               x = edgeNum - cgdm->edgeMap[i].startEdge;
 
                med->v1 = getEdgeIndex(ss, e, x, edgeSize);
                med->v2 = getEdgeIndex(ss, e, x+1, edgeSize);
 
-               edgeFlag = (ccgdm->edgeFlags)? &ccgdm->edgeFlags[i]: NULL;
+               edgeFlag = (cgdm->edgeFlags)? &cgdm->edgeFlags[i]: NULL;
                if(edgeFlag)
                        flags |= (*edgeFlag & (ME_SEAM | ME_SHARP))
                                         | ME_EDGEDRAW | ME_EDGERENDER;
@@ -757,8 +1243,8 @@ static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
 
 static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
 {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        int gridSize = ccgSubSurf_getGridSize(ss);
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int gridSideEdges = gridSize - 1;
@@ -770,18 +1256,18 @@ static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
        int grid;
        int x, y;
        int lastface = ccgSubSurf_getNumFaces(ss) - 1;
-       char *faceFlags = ccgdm->faceFlags;
+       char *faceFlags = cgdm->faceFlags;
 
        memset(mf, 0, sizeof(*mf));
+       if (faceNum >= cgdm->dm.numFaceData)
+               return;
 
-       i = 0;
-       while(i < lastface && faceNum >= ccgdm->faceMap[i + 1].startFace)
-               ++i;
+       i = cgdm->reverseFaceMap[faceNum];
 
-       f = ccgdm->faceMap[i].face;
+       f = cgdm->faceMap[i].face;
        numVerts = ccgSubSurf_getFaceNumVerts(f);
 
-       offset = faceNum - ccgdm->faceMap[i].startFace;
+       offset = faceNum - cgdm->faceMap[i].startFace;
        grid = offset / gridFaces;
        offset %= gridFaces;
        y = offset / gridSideEdges;
@@ -801,8 +1287,8 @@ static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
 
 static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
 {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        DMGridData *vd;
        int index;
        int totvert, totedge, totface;
@@ -812,7 +1298,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
 
        totface = ccgSubSurf_getNumFaces(ss);
        for(index = 0; index < totface; index++) {
-               CCGFace *f = ccgdm->faceMap[index].face;
+               CCGFace *f = cgdm->faceMap[index].face;
                int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
 
                vd= ccgSubSurf_getFaceCenterData(f);
@@ -841,7 +1327,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
 
        totedge = ccgSubSurf_getNumEdges(ss);
        for(index = 0; index < totedge; index++) {
-               CCGEdge *e = ccgdm->edgeMap[index].edge;
+               CCGEdge *e = cgdm->edgeMap[index].edge;
                int x;
 
                for(x = 1; x < edgeSize - 1; x++, i++) {
@@ -854,7 +1340,7 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
 
        totvert = ccgSubSurf_getNumVerts(ss);
        for(index = 0; index < totvert; index++) {
-               CCGVert *v = ccgdm->vertMap[index].vert;
+               CCGVert *v = cgdm->vertMap[index].vert;
 
                vd= ccgSubSurf_getVertData(ss, v);
                copy_v3_v3(mvert[i].co, vd->co);
@@ -865,25 +1351,25 @@ static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
 
 static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
 {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        int index;
        int totedge, totface;
        int gridSize = ccgSubSurf_getGridSize(ss);
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int i = 0;
-       short *edgeFlags = ccgdm->edgeFlags;
+       short *edgeFlags = cgdm->edgeFlags;
 
        totface = ccgSubSurf_getNumFaces(ss);
        for(index = 0; index < totface; index++) {
-               CCGFace *f = ccgdm->faceMap[index].face;
+               CCGFace *f = cgdm->faceMap[index].face;
                int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
 
                for(S = 0; S < numVerts; S++) {
                        for(x = 0; x < gridSize - 1; x++) {
                                MEdge *med = &medge[i];
 
-                               if(ccgdm->drawInteriorEdges)
+                               if(cgdm->drawInteriorEdges)
                                        med->flag = ME_EDGEDRAW | ME_EDGERENDER;
                                med->v1 = getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize);
                                med->v2 = getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize);
@@ -895,7 +1381,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
                                        MEdge *med;
 
                                        med = &medge[i];
-                                       if(ccgdm->drawInteriorEdges)
+                                       if(cgdm->drawInteriorEdges)
                                                med->flag = ME_EDGEDRAW | ME_EDGERENDER;
                                        med->v1 = getFaceIndex(ss, f, S, x, y,
                                                                                   edgeSize, gridSize);
@@ -904,7 +1390,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
                                        i++;
 
                                        med = &medge[i];
-                                       if(ccgdm->drawInteriorEdges)
+                                       if(cgdm->drawInteriorEdges)
                                                med->flag = ME_EDGEDRAW | ME_EDGERENDER;
                                        med->v1 = getFaceIndex(ss, f, S, y, x,
                                                                                   edgeSize, gridSize);
@@ -918,7 +1404,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
 
        totedge = ccgSubSurf_getNumEdges(ss);
        for(index = 0; index < totedge; index++) {
-               CCGEdge *e = ccgdm->edgeMap[index].edge;
+               CCGEdge *e = cgdm->edgeMap[index].edge;
                unsigned int flags = 0;
                int x;
                int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e));
@@ -944,20 +1430,177 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
        }
 }
 
+struct cgdm_faceIter;
+
+typedef struct cgdm_loopIter {
+       DMLoopIter head;
+       int curloop;
+       int lindex; //loop index within the mesh, not the face
+       CCGDerivedMesh *cgdm;
+       struct cgdm_faceIter *fiter;
+} cgdm_loopIter;
+
+typedef struct cgdm_faceIter {
+       DMFaceIter head;
+       CCGDerivedMesh *cgdm;
+       MFace *mface, *mf;
+
+       cgdm_loopIter liter;
+       EdgeHash *ehash; /*edge map for populating loopiter->eindex*/
+} cgdm_faceIter;
+
+void cgdm_faceIterStep(void *self)
+{
+       cgdm_faceIter *fiter = self;
+
+       if (!fiter->cgdm || !fiter->cgdm->ss) {
+               fiter->head.done = 1;
+               return;
+       }
+
+       if (fiter->head.index+1 >= ccgSubSurf_getNumFinalFaces(fiter->cgdm->ss)) {
+               fiter->head.done = 1;
+               return;
+       };
+
+       fiter->head.index++;
+       
+       fiter->mf++;
+
+       fiter->head.flags = fiter->mface->flag;
+       fiter->head.mat_nr = fiter->mface->mat_nr;
+       fiter->head.len = 4;
+}
+
+void *cgdm_faceIterCData(void *self, int type, int layer)
+{
+       cgdm_faceIter *fiter = self;
+       
+       if (layer == -1) 
+               return CustomData_get(&fiter->cgdm->dm.polyData, fiter->head.index, type);
+       else
+               return CustomData_get_n(&fiter->cgdm->dm.polyData, type, fiter->head.index, layer);
+}
+
+void cgdm_loopIterStep(void *self)
+{
+       cgdm_loopIter *liter = self;
+       MFace *mf = liter->fiter->mface;
+       int i, v1, v2;
+
+       liter->head.index++;
+       i = liter->head.index;
+
+       if (liter->head.index >= 4) {
+               liter->head.done = 1;
+               return;
+       }
+
+       switch (i) {
+               case 0:
+                       v1 = liter->fiter->mf->v1;
+                       v2 = liter->fiter->mf->v2;
+                       break;
+               case 1:
+                       v1 = liter->fiter->mf->v2;
+                       v2 = liter->fiter->mf->v3;
+                       break;
+               case 2:
+                       v1 = liter->fiter->mf->v3;
+                       v2 = liter->fiter->mf->v4;
+                       break;
+               case 3:
+                       v1 = liter->fiter->mf->v4;
+                       v2 = liter->fiter->mf->v1;
+                       break;
+       }
+
+       liter->head.vindex = v1;
+       liter->head.eindex = GET_INT_FROM_POINTER(BLI_edgehash_lookup(liter->fiter->cgdm->ehash, v1, v2));
+       liter->lindex += 1;
+       
+       ccgDM_getFinalVert((DerivedMesh*)liter->cgdm, v1, &liter->head.v);
+}
+
+void *cgdm_loopIterGetVCData(void *self, int type, int layer)
+{
+       cgdm_loopIter *liter = self;
+
+       if (layer == -1)
+               return CustomData_get(&liter->cgdm->dm.vertData, liter->head.vindex, type);
+       else return CustomData_get_n(&liter->cgdm->dm.vertData, type, liter->head.vindex, layer);
+}
+
+void *cgdm_loopIterGetCData(void *self, int type, int layer)
+{
+       cgdm_loopIter *liter = self;
+
+       if (layer == -1)
+               return CustomData_get(&liter->cgdm->dm.loopData, liter->lindex, type);
+       else return CustomData_get_n(&liter->cgdm->dm.loopData, type, liter->lindex, layer);
+}
+
+DMLoopIter *cgdm_faceIterGetLIter(void *self)
+{
+       cgdm_faceIter *fiter = self;
+       
+       fiter->liter.head.index = -1;
+       fiter->liter.head.done = 0;
+       fiter->liter.head.step(&fiter->liter);
+
+       return (DMLoopIter*) &fiter->liter;
+}
+
+void cgdm_faceIterFree(void *vfiter)
+{
+       cgdm_faceIter *fiter = vfiter;
+
+       MEM_freeN(fiter->mface);
+       MEM_freeN(fiter);
+}
+
+DMFaceIter *cgdm_newFaceIter(DerivedMesh *dm)
+{
+       cgdm_faceIter *fiter = MEM_callocN(sizeof(cgdm_faceIter), "cgdm_faceIter");
+       MEdge medge;
+       int i, totedge = cgdm_getNumEdges(dm);
+
+       fiter->cgdm = dm;
+       fiter->liter.cgdm = dm;
+       fiter->mface = fiter->mf = dm->dupTessFaceArray(dm);
+       fiter->mf--;
+
+       fiter->head.free = cgdm_faceIterFree;
+       fiter->head.step = cgdm_faceIterStep;
+       fiter->head.index = -1;
+       fiter->head.getCDData = cgdm_faceIterCData;
+       fiter->head.getLoopsIter = cgdm_faceIterGetLIter;
+
+       fiter->liter.fiter = fiter;
+       fiter->liter.head.getLoopCDData = cgdm_loopIterGetCData;
+       fiter->liter.head.getVertCDData = cgdm_loopIterGetVCData;
+       fiter->liter.head.step = cgdm_loopIterStep;
+       fiter->liter.lindex = -1;
+
+       fiter->head.step(fiter);
+
+       return fiter;
+}
+
 static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
 {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        int index;
        int totface;
        int gridSize = ccgSubSurf_getGridSize(ss);
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int i = 0;
-       char *faceFlags = ccgdm->faceFlags;
+       char *faceFlags = cgdm->faceFlags;
 
        totface = ccgSubSurf_getNumFaces(ss);
        for(index = 0; index < totface; index++) {
-               CCGFace *f = ccgdm->faceMap[index].face;
+               CCGFace *f = cgdm->faceMap[index].face;
                int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
                int flag = (faceFlags)? faceFlags[index*2]: ME_SMOOTH;
                int mat_nr = (faceFlags)? faceFlags[index*2+1]: 0;
@@ -974,6 +1617,11 @@ static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
                                                                                  edgeSize, gridSize);
                                        mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
                                                                                  edgeSize, gridSize);
+                                       if (faceFlags) {
+                                               mat_nr = faceFlags[index*2+1];
+                                               mf->flag = faceFlags[index*2];
+                                       } else mf->flag = flag;
+
                                        mf->mat_nr = mat_nr;
                                        mf->flag = flag;
 
@@ -984,9 +1632,9 @@ static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
        }
 }
 
-static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int gridSize = ccgSubSurf_getGridSize(ss);
        int i;
@@ -1067,14 +1715,14 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
        MEM_freeN(edgeMap2);
        MEM_freeN(faceMap2);
 }
-static void ccgDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGVertIterator *vi = ccgSubSurf_getVertIterator(ccgdm->ss);
+static void cgdm_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGVertIterator *vi = ccgSubSurf_getVertIterator(cgdm->ss);
 
        for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
                CCGVert *v = ccgVertIterator_getCurrent(vi);
-               DMGridData *vd = ccgSubSurf_getVertData(ccgdm->ss, v);
-               int index = ccgDM_getVertMapIndex(ccgdm->ss, v);
+               DMGridData *vd = ccgSubSurf_getVertData(cgdm->ss, v);
+               int index = ccgDM_getVertMapIndex(cgdm->ss, v);
 
                if (index!=-1)
                        func(userData, index, vd->co, vd->no, NULL);
@@ -1082,9 +1730,9 @@ static void ccgDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData
 
        ccgVertIterator_free(vi);
 }
-static void ccgDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
        int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
 
@@ -1103,8 +1751,8 @@ static void ccgDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData
 }
 
 static void ccgDM_drawVerts(DerivedMesh *dm) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int gridSize = ccgSubSurf_getGridSize(ss);
        CCGVertIterator *vi;
@@ -1213,8 +1861,8 @@ static void ccgDM_drawEdges(DerivedMesh *dm, int drawLooseEdges, int drawAllEdge
        ccgEdgeIterator_free(ei);
 }
 static void ccgDM_drawLooseEdges(DerivedMesh *dm) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
        int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
 
@@ -1235,7 +1883,7 @@ static void ccgDM_drawLooseEdges(DerivedMesh *dm) {
        ccgEdgeIterator_free(ei);
 }
 
-static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
+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];
@@ -1274,7 +1922,6 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
        int step = (fast)? gridSize-1: 1;
 
        ccgdm_pbvh_update(ccgdm);
-
        if(ccgdm->pbvh && ccgdm->multires.mmd && !fast) {
                if(dm->numFaceData) {
                        /* should be per face */
@@ -1289,6 +1936,8 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
                return;
        }
 
+       gridSize = ccgSubSurf_getGridSize(ss);
+
        fi = ccgSubSurf_getFaceIterator(ss);
        for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
                CCGFace *f = ccgFaceIterator_getCurrent(fi);
@@ -1352,21 +2001,21 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
 }
 
        /* Only used by non-editmesh types */
-static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
        GPUVertexAttribs gattribs;
        DMVertexAttribs attribs;
-       MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE);
+       MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE);
        int gridSize = ccgSubSurf_getGridSize(ss);
        int gridFaces = gridSize - 1;
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int transp, orig_transp, new_transp;
-       char *faceFlags = ccgdm->faceFlags;
+       char *faceFlags = cgdm->faceFlags;
        int a, b, i, doDraw, numVerts, matnr, new_matnr, totface;
 
-       ccgdm_pbvh_update(ccgdm);
+       ccgdm_pbvh_update(cgdm);
 
        doDraw = 0;
        numVerts = 0;
@@ -1399,7 +2048,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v
 
        totface = ccgSubSurf_getNumFaces(ss);
        for(a = 0, i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
+               CCGFace *f = cgdm->faceMap[i].face;
                int S, x, y, drawSmooth;
                int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
                int origIndex = ccgDM_getFaceMapIndex(ss, f);
@@ -1510,19 +2159,19 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, v
        ccgFaceIterator_free(fi);
 }
 
-static void ccgDM_drawFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs)) {
+static void cgdm_drawFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs)) {
        dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
 }
 
-static void ccgDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
        int gridSize = ccgSubSurf_getGridSize(ss);
        unsigned char *cp1, *cp2;
        int useTwoSide=1;
 
-       ccgdm_pbvh_update(ccgdm);
+       ccgdm_pbvh_update(cgdm);
 
        cp1= col1;
        if(col2) {
@@ -1581,27 +2230,27 @@ static void ccgDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned ch
        ccgFaceIterator_free(fi);
 }
 
-static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
-       int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
+static void cgdm_drawFacesTex_common(DerivedMesh *dm,
+       int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
        int (*drawParamsMapped)(void *userData, int index),
        void *userData) 
 {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
-       MCol *mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
-       MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
-       char *faceFlags = ccgdm->faceFlags;
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
+       MCol *mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
+       MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
+       char *faceFlags = cgdm->faceFlags;
        int i, totface, flag, gridSize = ccgSubSurf_getGridSize(ss);
        int gridFaces = gridSize - 1;
 
-       ccgdm_pbvh_update(ccgdm);
+       ccgdm_pbvh_update(cgdm);
 
        if(!mcol)
-               mcol = dm->getFaceDataArray(dm, CD_MCOL);
+               mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
 
        totface = ccgSubSurf_getNumFaces(ss);
        for(i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
+               CCGFace *f = cgdm->faceMap[i].face;
                int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
                int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
                int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
@@ -1618,7 +2267,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
                }
 
                if(drawParams)
-                       flag = drawParams(tf, mcol, mat_nr);
+                       flag = drawParams(tf, mcol!=NULL, mat_nr);
                else
                        flag= (drawParamsMapped)? drawParamsMapped(userData, index): 1;
                
@@ -1718,21 +2367,21 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
        }
 }
 
-static void ccgDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+static void cgdm_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
 {
-       ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
+       cgdm_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
 }
 
-static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+static void cgdm_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
 {
-       ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
+       cgdm_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
 }
 
-static void ccgDM_drawUVEdges(DerivedMesh *dm)
+static void cgdm_drawUVEdges(DerivedMesh *dm)
 {
 
-       MFace *mf = dm->getFaceArray(dm);
-       MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+       MFace *mf = dm->getTessFaceArray(dm);
+       MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
        int i;
        
        if (tf) {
@@ -1762,22 +2411,22 @@ static void ccgDM_drawUVEdges(DerivedMesh *dm)
 }
 
 static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        MCol *mcol= NULL;
        int i, gridSize = ccgSubSurf_getGridSize(ss);
-       char *faceFlags = ccgdm->faceFlags;
+       char *faceFlags = cgdm->faceFlags;
        int gridFaces = gridSize - 1, totface;
 
        if(useColors) {
-               mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
+               mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
                if(!mcol)
-                       mcol = dm->getFaceDataArray(dm, CD_MCOL);
+                       mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
        }
 
        totface = ccgSubSurf_getNumFaces(ss);
        for(i = 0; i < totface; i++) {
-               CCGFace *f = ccgdm->faceMap[i].face;
+               CCGFace *f = cgdm->faceMap[i].face;
                int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
                int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
                int origIndex;
@@ -1873,9 +2522,9 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *u
                }
        }
 }
-static void ccgDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
        int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
 
@@ -1903,9 +2552,9 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *u
 
        ccgEdgeIterator_free(ei);
 }
-static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
        int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
 
@@ -1934,9 +2583,9 @@ static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(v
 
        ccgEdgeIterator_free(ei);
 }
-static void ccgDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) {
-       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
-       CCGSubSurf *ss = ccgdm->ss;
+static void cgdm_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) {
+       CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = cgdm->ss;
        CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
 
        for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
@@ -1954,7 +2603,7 @@ static void ccgDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *us
        ccgFaceIterator_free(fi);
 }
 
-static void ccgDM_release(DerivedMesh *dm) {
+static void cgdm_release(DerivedMesh *dm) {
        CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 
        if (DM_release(dm)) {
@@ -1967,6 +2616,10 @@ static void ccgDM_release(DerivedMesh *dm) {
                                ccgdm->multires.update(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->gridAdjacency) MEM_freeN(ccgdm->gridAdjacency);
@@ -1983,12 +2636,66 @@ static void ccgDM_release(DerivedMesh *dm) {
        }
 }
 
+void ccg_loops_to_corners(CustomData *fdata, CustomData *ldata, 
+                         CustomData *pdata, int loopstart, int findex, 
+                         int polyindex, int numTex, int numCol) 
+{
+       MTFace *texface;
+       MTexPoly *texpoly;
+       MCol *mcol;
+       MLoopCol *mloopcol;
+       MLoopUV *mloopuv;
+       int i, j, hasWCol = CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL);
+
+       for(i=0; i < numTex; i++){
+               texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
+               texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i);
+               
+               texface->tpage = texpoly->tpage;
+               texface->flag = texpoly->flag;
+               texface->transp = texpoly->transp;
+               texface->mode = texpoly->mode;
+               texface->tile = texpoly->tile;
+               texface->unwrap = texpoly->unwrap;
+
+               mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
+               for (j=0; j<4; j++, mloopuv++) {
+                       texface->uv[j][0] = mloopuv->uv[0];
+                       texface->uv[j][1] = mloopuv->uv[1];
+               }
+       }
+
+       for(i=0; i < numCol; i++){
+               mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i);
+               mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
+
+               for (j=0; j<4; j++, mloopcol++) {
+                       mcol[j].r = mloopcol->r;
+                       mcol[j].g = mloopcol->g;
+                       mcol[j].b = mloopcol->b;
+                       mcol[j].a = mloopcol->a;
+               }
+       }
+       
+       if (hasWCol) {
+               mloopcol = CustomData_get(ldata, loopstart, CD_WEIGHT_MLOOPCOL);
+               mcol = CustomData_get(fdata, findex, CD_WEIGHT_MCOL);
+
+               for (j=0; j<4; j++, mloopcol++) {
+                       mcol[j].r = mloopcol->r;
+                       mcol[j].g = mloopcol->g;
+                       mcol[j].b = mloopcol->b;
+                       mcol[j].a = mloopcol->a;
+               }
+       }
+}
+
 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;
+               CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
+               CCGSubSurf *ss= cgdm->ss;
                int *origindex;
                int a, index, totnone, totorig;
 
@@ -2003,8 +2710,8 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
                        origindex[a]= ORIGINDEX_NONE;
 
                for(index=0; index<totorig; index++, a++) {
-                       CCGVert *v = ccgdm->vertMap[index].vert;
-                       origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v);
+                       CCGVert *v = cgdm->vertMap[index].vert;
+                       origindex[a] = ccgDM_getVertMapIndex(cgdm->ss, v);
                }
 
                return origindex;
@@ -2017,8 +2724,8 @@ 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;
+               CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
+               CCGSubSurf *ss= cgdm->ss;
                int *origindex;
                int a, i, index, totnone, totorig, totedge;
                int edgeSize= ccgSubSurf_getEdgeSize(ss);
@@ -2035,7 +2742,7 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type)
                        origindex[a]= ORIGINDEX_NONE;
 
                for(index=0; index<totedge; index++) {
-                       CCGEdge *e= ccgdm->edgeMap[index].edge;
+                       CCGEdge *e= cgdm->edgeMap[index].edge;
                        int mapIndex= ccgDM_getEdgeMapIndex(ss, e);
 
                        for(i = 0; i < edgeSize - 1; i++, a++)
@@ -2052,19 +2759,19 @@ static void *ccgDM_get_face_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;
+               CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
+               CCGSubSurf *ss= cgdm->ss;
                int *origindex;
                int a, i, index, totface;
                int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
 
                DM_add_face_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
-               origindex= DM_get_face_data_layer(dm, CD_ORIGINDEX);
+               origindex= DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
 
                totface= ccgSubSurf_getNumFaces(ss);
 
                for(a=0, index=0; index<totface; index++) {
-                       CCGFace *f = ccgdm->faceMap[index].face;
+                       CCGFace *f = cgdm->faceMap[index].face;
                        int numVerts = ccgSubSurf_getFaceNumVerts(f);
                        int mapIndex = ccgDM_getFaceMapIndex(ss, f);
 
@@ -2075,19 +2782,19 @@ static void *ccgDM_get_face_data_layer(DerivedMesh *dm, int type)
                return origindex;
        }
 
-       return DM_get_face_data_layer(dm, type);
+       return DM_get_tessface_data_layer(dm, type);
 }
 
 static int ccgDM_getNumGrids(DerivedMesh *dm)
 {
-       CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
+       CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
        int index, numFaces, numGrids;
 
-       numFaces= ccgSubSurf_getNumFaces(ccgdm->ss);
+       numFaces= ccgSubSurf_getNumFaces(cgdm->ss);
        numGrids= 0;
 
        for(index=0; index<numFaces; index++) {
-               CCGFace *f = ccgdm->faceMap[index].face;
+               CCGFace *f = cgdm->faceMap[index].face;
                numGrids += ccgSubSurf_getFaceNumVerts(f);
        }
 
@@ -2096,11 +2803,11 @@ static int ccgDM_getNumGrids(DerivedMesh *dm)
 
 static int ccgDM_getGridSize(DerivedMesh *dm)
 {
-       CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
-       return ccgSubSurf_getGridSize(ccgdm->ss);
+       CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
+       return ccgSubSurf_getGridSize(cgdm->ss);
 }
 
-static int ccgdm_adjacent_grid(CCGSubSurf *ss, int *gridOffset, CCGFace *f, int S, int offset)
+static int cgdm_adjacent_grid(CCGSubSurf *ss, int *gridOffset, CCGFace *f, int S, int offset)
 {
        CCGFace *adjf;
        CCGEdge *e;
@@ -2133,15 +2840,15 @@ static int ccgdm_adjacent_grid(CCGSubSurf *ss, int *gridOffset, CCGFace *f, int
 
 static void ccgdm_create_grids(DerivedMesh *dm)
 {
-       CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
-       CCGSubSurf *ss= ccgdm->ss;
+       CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
+       CCGSubSurf *ss= cgdm->ss;
        DMGridData **gridData;
        DMGridAdjacency *gridAdjacency, *adj;
        CCGFace **gridFaces;
        int *gridOffset;
        int index, numFaces, numGrids, S, gIndex, gridSize;
 
-       if(ccgdm->gridData)
+       if(cgdm->gridData)
                return;
        
        numGrids = ccgDM_getNumGrids(dm);
@@ -2149,10 +2856,10 @@ static void ccgdm_create_grids(DerivedMesh *dm)
        gridSize = ccgDM_getGridSize(dm);
 
        /* compute offset into grid array for each face */
-       gridOffset = MEM_mallocN(sizeof(int)*numFaces, "ccgdm.gridOffset");
+       gridOffset = MEM_mallocN(sizeof(int)*numFaces, "cgdm.gridOffset");
 
        for(gIndex = 0, index = 0; index < numFaces; index++) {
-               CCGFace *f = ccgdm->faceMap[index].face;
+               CCGFace *f = cgdm->faceMap[index].face;
                int numVerts = ccgSubSurf_getFaceNumVerts(f);
 
                gridOffset[index] = gIndex;
@@ -2160,12 +2867,12 @@ static void ccgdm_create_grids(DerivedMesh *dm)
        }
 
        /* compute grid data */
-       gridData = MEM_mallocN(sizeof(DMGridData*)*numGrids, "ccgdm.gridData");
-       gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency)*numGrids, "ccgdm.gridAdjacency");
-       gridFaces = MEM_mallocN(sizeof(CCGFace*)*numGrids, "ccgdm.gridFaces");
+       gridData = MEM_mallocN(sizeof(DMGridData*)*numGrids, "cgdm.gridData");
+       gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency)*numGrids, "cgdm.gridAdjacency");
+       gridFaces = MEM_mallocN(sizeof(CCGFace*)*numGrids, "cgdm.gridFaces");
 
        for(gIndex = 0, index = 0; index < numFaces; index++) {
-               CCGFace *f = ccgdm->faceMap[index].face;
+               CCGFace *f = cgdm->faceMap[index].face;
                int numVerts = ccgSubSurf_getFaceNumVerts(f);
 
                for(S = 0; S < numVerts; S++, gIndex++) {
@@ -2179,43 +2886,43 @@ static void ccgdm_create_grids(DerivedMesh *dm)
 
                        adj->index[0] = gIndex - S + nextS;
                        adj->rotation[0] = 3;
-                       adj->index[1] = ccgdm_adjacent_grid(ss, gridOffset, f, prevS, 0);
+                       adj->index[1] = cgdm_adjacent_grid(ss, gridOffset, f, prevS, 0);
                        adj->rotation[1] = 1;
-                       adj->index[2] = ccgdm_adjacent_grid(ss, gridOffset, f, S, 1);
+                       adj->index[2] = cgdm_adjacent_grid(ss, gridOffset, f, S, 1);
                        adj->rotation[2] = 3;
                        adj->index[3] = gIndex - S + prevS;
                        adj->rotation[3] = 1;
                }
        }
 
-       ccgdm->gridData = gridData;
-       ccgdm->gridFaces = gridFaces;
-       ccgdm->gridAdjacency = gridAdjacency;
-       ccgdm->gridOffset = gridOffset;
+       cgdm->gridData = gridData;
+       cgdm->gridFaces = gridFaces;
+       cgdm->gridAdjacency = gridAdjacency;
+       cgdm->gridOffset = gridOffset;
 }
 
 static DMGridData **ccgDM_getGridData(DerivedMesh *dm)
 {
-       CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
+       CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
 
        ccgdm_create_grids(dm);
-       return ccgdm->gridData;
+       return cgdm->gridData;
 }
 
 static DMGridAdjacency *ccgDM_getGridAdjacency(DerivedMesh *dm)
 {
-       CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
+       CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
 
        ccgdm_create_grids(dm);
-       return ccgdm->gridAdjacency;
+       return cgdm->gridAdjacency;
 }
 
 static int *ccgDM_getGridOffset(DerivedMesh *dm)
 {
-       CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
+       CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
 
        ccgdm_create_grids(dm);
-       return ccgdm->gridOffset;
+       return cgdm->gridOffset;
 }
 
 static ListBase *ccgDM_getFaceMap(Object *ob, DerivedMesh *dm)
@@ -2313,50 +3020,74 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
                                                                                 int useSubsurfUv,
                                                                                 DerivedMesh *dm)
 {
-       CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm");
+       CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "cgdm");
        CCGVertIterator *vi;
        CCGEdgeIterator *ei;
        CCGFaceIterator *fi;
        int index, totvert, totedge, totface;
        int i;
        int vertNum, edgeNum, faceNum;
+       int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex; /* *edgeOrigIndex - as yet, unused  */
        short *edgeFlags;
        char *faceFlags;
-       int edgeSize;
+       int *loopidx = NULL, *vertidx = NULL;
+       BLI_array_declare(loopidx);
+       BLI_array_declare(vertidx);
+       int loopindex, loopindex2;
+       int edgeSize, has_edge_origindex;
        int gridSize;
-       int gridFaces;
+       int gridFaces, gridCuts;
        int gridSideVerts;
        int gridSideEdges;
+       int numTex, numCol;
        int gridInternalEdges;
-       MEdge *medge = NULL;
+       float *w = NULL, one = 1.0f;
+       WeightTable wtable = {0};
+       MCol *mcol;
+       MEdge *medge = NULL, medge2;
        MFace *mface = NULL;
+       MPoly *mpoly = NULL;
        int *orig_indices;
-       FaceVertWeight *qweight, *tweight;
 
        DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM,
                                         ccgSubSurf_getNumFinalVerts(ss),
                                         ccgSubSurf_getNumFinalEdges(ss),
+                                        ccgSubSurf_getNumFinalFaces(ss),
+                                        ccgSubSurf_getNumFinalFaces(ss)*4, 
                                         ccgSubSurf_getNumFinalFaces(ss));
+       
+       numTex = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPUV);
+       numCol = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPCOL);
+       
+       if (numTex && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MTFACE) != numTex)
+               CustomData_from_bmeshpoly(&ccgdm->dm.faceData, &ccgdm->dm.polyData, &ccgdm->dm.loopData, ccgSubSurf_getNumFinalFaces(ss));
+       else if (numCol && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MCOL) != numCol)
+               CustomData_from_bmeshpoly(&ccgdm->dm.faceData, &ccgdm->dm.polyData, &ccgdm->dm.loopData, ccgSubSurf_getNumFinalFaces(ss));
+
+       ccgdm->dm.getMinMax = cgdm_getMinMax;
+       ccgdm->dm.getNumVerts = cgdm_getNumVerts;
+       ccgdm->dm.getNumEdges = cgdm_getNumEdges;
+       ccgdm->dm.getNumTessFaces = cgdm_getNumTessFaces;
+       ccgdm->dm.getNumFaces = cgdm_getNumTessFaces;
 
-       ccgdm->dm.getMinMax = ccgDM_getMinMax;
-       ccgdm->dm.getNumVerts = ccgDM_getNumVerts;
-       ccgdm->dm.getNumFaces = ccgDM_getNumFaces;
+       ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
+       ccgdm->dm.getPBVH = ccgDM_getPBVH;
 
-       ccgdm->dm.getNumEdges = ccgDM_getNumEdges;
+       ccgdm->dm.newFaceIter = cgdm_newFaceIter;
        ccgdm->dm.getVert = ccgDM_getFinalVert;
        ccgdm->dm.getEdge = ccgDM_getFinalEdge;
-       ccgdm->dm.getFace = ccgDM_getFinalFace;
+       ccgdm->dm.getTessFace = ccgDM_getFinalFace;
        ccgdm->dm.getVertCo = ccgDM_getFinalVertCo;
        ccgdm->dm.getVertNo = ccgDM_getFinalVertNo;
        ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
        ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
-       ccgdm->dm.copyFaceArray = ccgDM_copyFinalFaceArray;
+       ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
        ccgdm->dm.getVertData = DM_get_vert_data;
        ccgdm->dm.getEdgeData = DM_get_edge_data;
-       ccgdm->dm.getFaceData = DM_get_face_data;
+       ccgdm->dm.getTessFaceData = DM_get_face_data;
        ccgdm->dm.getVertDataArray = ccgDM_get_vert_data_layer;
        ccgdm->dm.getEdgeDataArray = ccgDM_get_edge_data_layer;
-       ccgdm->dm.getFaceDataArray = ccgDM_get_face_data_layer;
+       ccgdm->dm.getTessFaceDataArray = ccgDM_get_face_data_layer;
        ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
        ccgdm->dm.getGridSize = ccgDM_getGridSize;
        ccgdm->dm.getGridData = ccgDM_getGridData;
@@ -2365,27 +3096,38 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
        ccgdm->dm.getFaceMap = ccgDM_getFaceMap;
        ccgdm->dm.getPBVH = ccgDM_getPBVH;
 
-       ccgdm->dm.getVertCos = ccgdm_getVertCos;
-       ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert;
-       ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge;
-       ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
+       ccgdm->dm.getTessFace = ccgDM_getFinalFace;
+       ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
+       ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
+       ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
+       ccgdm->dm.getVertData = DM_get_vert_data;
+       ccgdm->dm.getEdgeData = DM_get_edge_data;
+       ccgdm->dm.getTessFaceData = DM_get_face_data;
+       ccgdm->dm.getVertDataArray = DM_get_vert_data_layer;
+       ccgdm->dm.getEdgeDataArray = DM_get_edge_data_layer;
+       ccgdm->dm.getTessFaceDataArray = DM_get_tessface_data_layer;
+
+       ccgdm->dm.getVertCos = cgdm_getVertCos;
+       ccgdm->dm.foreachMappedVert = cgdm_foreachMappedVert;
+       ccgdm->dm.foreachMappedEdge = cgdm_foreachMappedEdge;
+       ccgdm->dm.foreachMappedFaceCenter = cgdm_foreachMappedFaceCenter;
        
        ccgdm->dm.drawVerts = ccgDM_drawVerts;
        ccgdm->dm.drawEdges = ccgDM_drawEdges;
        ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
        ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid;
-       ccgdm->dm.drawFacesColored = ccgDM_drawFacesColored;
-       ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex;
-       ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL;
+       ccgdm->dm.drawFacesColored = cgdm_drawFacesColored;
+       ccgdm->dm.drawFacesTex = cgdm_drawFacesTex;
+       ccgdm->dm.drawFacesGLSL = cgdm_drawFacesGLSL;
        ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces;
-       ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
-       ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL;
-       ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges;
+       ccgdm->dm.drawMappedFacesTex = cgdm_drawMappedFacesTex;
+       ccgdm->dm.drawMappedFacesGLSL = cgdm_drawMappedFacesGLSL;
+       ccgdm->dm.drawUVEdges = cgdm_drawUVEdges;
 
-       ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
-       ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
+       ccgdm->dm.drawMappedEdgesInterp = cgdm_drawMappedEdgesInterp;
+       ccgdm->dm.drawMappedEdges = cgdm_drawMappedEdges;
        
-       ccgdm->dm.release = ccgDM_release;
+       ccgdm->dm.release = cgdm_release;
        
        ccgdm->ss = ss;
        ccgdm->drawInteriorEdges = drawInteriorEdges;
@@ -2420,139 +3162,187 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
        }
        ccgFaceIterator_free(fi);
 
+       ccgdm->reverseFaceMap = MEM_callocN(sizeof(int)*ccgSubSurf_getNumFinalFaces(ss), "reverseFaceMap");
+
        edgeSize = ccgSubSurf_getEdgeSize(ss);
        gridSize = ccgSubSurf_getGridSize(ss);
        gridFaces = gridSize - 1;
        gridSideVerts = gridSize - 2;
+       gridCuts = gridSize - 2;
        /*gridInternalVerts = gridSideVerts * gridSideVerts; - as yet, unused */
        gridSideEdges = gridSize - 1;
        gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; 
 
-       calc_ss_weights(gridFaces, &qweight, &tweight);
-
        vertNum = 0;
        edgeNum = 0;
        faceNum = 0;
 
        /* mvert = dm->getVertArray(dm); - as yet unused */
        medge = dm->getEdgeArray(dm);
-       mface = dm->getFaceArray(dm);
+       mface = dm->getTessFaceArray(dm);
 
+       mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+       /*CDDM hack*/
+       edgeFlags = ccgdm->edgeFlags = MEM_callocN(sizeof(short)*totedge, "faceFlags");
        faceFlags = ccgdm->faceFlags = MEM_callocN(sizeof(char)*2*totface, "faceFlags");
 
-       orig_indices = (int*)ccgdm->dm.getFaceDataArray(&ccgdm->dm, CD_ORIGINDEX);
-       for(index = 0; index < totface; ++index) {
+       vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+       /*edgeOrigIndex = DM_get_edge_data_layer(&cgdm->dm, CD_ORIGINDEX);*/
+       faceOrigIndex = DM_get_tessface_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+
+       polyOrigIndex = DM_get_face_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+
+       if (!CustomData_has_layer(&ccgdm->dm.faceData, CD_MCOL))
+               DM_add_tessface_layer(&ccgdm->dm, CD_MCOL, CD_CALLOC, NULL);
+
+       mcol = DM_get_tessface_data_layer(&ccgdm->dm, CD_MCOL);
+       has_edge_origindex = CustomData_has_layer(&ccgdm->dm.edgeData, CD_ORIGINDEX);
+
+       faceNum = 0;
+       loopindex = loopindex2 = 0; //current loop index
+       for (index = 0; index < totface; index++) {
                CCGFace *f = ccgdm->faceMap[index].face;
                int numVerts = ccgSubSurf_getFaceNumVerts(f);
                int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges);
                int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
-               FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
-               int S, x, y;
-               int vertIdx[4];
+               int g2_wid = gridCuts+2;
+               float *w2;
+               int s, x, y;
+
+               w = get_ss_weights(&wtable, gridCuts, numVerts);
 
                ccgdm->faceMap[index].startVert = vertNum;
                ccgdm->faceMap[index].startEdge = edgeNum;
                ccgdm->faceMap[index].startFace = faceNum;
-
-               if(orig_indices)
-                       orig_indices[faceNum] = origIndex;
+               
+               faceFlags[0] = mpoly[origIndex].flag;
+               faceFlags[1] = mpoly[origIndex].mat_nr;
+               faceFlags += 2;
 
                /* set the face base vert */
                *((int*)ccgSubSurf_getFaceUserData(ss, f)) = vertNum;
 
-               for(S = 0; S < numVerts; S++) {
-                       CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+               BLI_array_empty(loopidx);               
+               for (s=0; s<numVerts; s++) {
+                       BLI_array_growone(loopidx);
+                       loopidx[s] = loopindex++;
+               }
+               
+               BLI_array_empty(vertidx);
+               for(s = 0; s < numVerts; s++) {
+                       CCGVert *v = ccgSubSurf_getFaceVert(ss, f, s);
+                       
+                       BLI_array_growone(vertidx);
+                       vertidx[s] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+               }
+               
 
-                       vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+               /*I think this is for interpolating the center vert?*/
+               w2 = w; // + numVerts*(g2_wid-1)*(g2_wid-1); //numVerts*((g2_wid-1)*g2_wid+g2_wid-1);
+               DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
+                                   numVerts, vertNum);
+               if (vertOrigIndex) {
+                       *vertOrigIndex = ORIGINDEX_NONE;
+                       ++vertOrigIndex;
                }
 
-               DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, weight[0][0],
-                                                       numVerts, vertNum);
                ++vertNum;
 
-               for(S = 0; S < numVerts; S++) {
-                       int prevS = (S - 1 + numVerts) % numVerts;
-                       int nextS = (S + 1) % numVerts;
-                       int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+               /*interpolate per-vert data*/
+               for(s = 0; s < numVerts; s++) {
                        for(x = 1; x < gridFaces; x++) {
-                               float w[4];
-                               w[prevS]  = weight[x][0][0];
-                               w[S]      = weight[x][0][1];
-                               w[nextS]  = weight[x][0][2];
-                               w[otherS] = weight[x][0][3];
-                               DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w,
-                                                                       numVerts, vertNum);
+                               w2 = w + s*numVerts*g2_wid*g2_wid + x*numVerts;
+                               DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
+                                                   numVerts, vertNum);
+
+                               if (vertOrigIndex) {
+                                       *vertOrigIndex = ORIGINDEX_NONE;
+                                       ++vertOrigIndex;
+                               }
+
                                ++vertNum;
                        }
                }
 
-               for(S = 0; S < numVerts; S++) {
-                       int prevS = (S - 1 + numVerts) % numVerts;
-                       int nextS = (S + 1) % numVerts;
-                       int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+               /*interpolate per-vert data*/
+               for(s = 0; s < numVerts; s++) {
                        for(y = 1; y < gridFaces; y++) {
                                for(x = 1; x < gridFaces; x++) {
-                                       float w[4];
-                                       w[prevS]  = weight[y * gridFaces + x][0][0];
-                                       w[S]      = weight[y * gridFaces + x][0][1];
-                                       w[nextS]  = weight[y * gridFaces + x][0][2];
-                                       w[otherS] = weight[y * gridFaces + x][0][3];
-                                       DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w,
-                                                                               numVerts, vertNum);
+                                       w2 = w + s*numVerts*g2_wid*g2_wid + (y*g2_wid+x)*numVerts;
+                                       DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
+                                                           numVerts, vertNum);
+
+                                       if (vertOrigIndex) {
+                                               *vertOrigIndex = ORIGINDEX_NONE;
+                                               ++vertOrigIndex;
+                                       }
+
                                        ++vertNum;
                                }
                        }
                }
 
-               for(S = 0; S < numVerts; S++) {
-                       int prevS = (S - 1 + numVerts) % numVerts;
-                       int nextS = (S + 1) % numVerts;
-                       int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
-
-                       weight = (numVerts == 4) ? qweight : tweight;
-
-                       for(y = 0; y < gridFaces; y++) {
-                               for(x = 0; x < gridFaces; x++) {
-                                       FaceVertWeight w;
-                                       int j;
-
-                                       for(j = 0; j < 4; ++j) {
-                                               w[j][prevS]  = (*weight)[j][0];
-                                               w[j][S]      = (*weight)[j][1];
-                                               w[j][nextS]  = (*weight)[j][2];
-                                               w[j][otherS] = (*weight)[j][3];
+               if (has_edge_origindex) {
+                       for(i = 0; i < numFinalEdges; ++i)
+                               *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i,
+                                                        CD_ORIGINDEX) = ORIGINDEX_NONE;
+               }
+
+               for (s=0; s<numVerts; s++) {
+                       /*interpolate per-face data*/
+                       for (y=0; y<gridFaces; y++) {
+                               for (x=0; x<gridFaces; x++) {
+                                       w2 = w + s*numVerts*g2_wid*g2_wid + (y*g2_wid+x)*numVerts;
+                                       CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
+                                                         loopidx, w2, NULL, numVerts, loopindex2);
+                                       loopindex2++;
+
+                                       w2 = w + s*numVerts*g2_wid*g2_wid + ((y+1)*g2_wid+(x))*numVerts;
+                                       CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
+                                                         loopidx, w2, NULL, numVerts, loopindex2);
+                                       loopindex2++;
+
+                                       w2 = w + s*numVerts*g2_wid*g2_wid + ((y+1)*g2_wid+(x+1))*numVerts;
+                                       CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
+                                                         loopidx, w2, NULL, numVerts, loopindex2);
+                                       loopindex2++;
+                                       
+                                       w2 = w + s*numVerts*g2_wid*g2_wid + ((y)*g2_wid+(x+1))*numVerts;
+                                       CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
+                                                         loopidx, w2, NULL, numVerts, loopindex2);
+                                       loopindex2++;
+
+                                       /*copy over poly data, e.g. mtexpoly*/
+                                       CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1);
+
+                                       /*generate tesselated face data used for drawing*/
+                                       ccg_loops_to_corners(&ccgdm->dm.faceData, &ccgdm->dm.loopData,
+                                               &ccgdm->dm.polyData, loopindex2-4, faceNum, faceNum, numTex, numCol);
+                                       
+                                       /*set original index data*/
+                                       if (faceOrigIndex) {
+                                               *faceOrigIndex = origIndex;
+                                               faceOrigIndex++;
+                                       }
+                                       if (polyOrigIndex) {
+                                               *polyOrigIndex = origIndex;
+                                               polyOrigIndex++;
                                        }
 
-                                       DM_interp_face_data(dm, &ccgdm->dm, &origIndex, NULL,
-                                                                               &w, 1, faceNum);
-                                       weight++;
+                                       ccgdm->reverseFaceMap[faceNum] = index;
 
-                                       ++faceNum;
+                                       faceNum++;
                                }
                        }
                }
 
-               faceFlags[index*2] = mface[origIndex].flag;
-               faceFlags[index*2 + 1] = mface[origIndex].mat_nr;
-
                edgeNum += numFinalEdges;
        }
 
-       if(useSubsurfUv) {
-               CustomData *fdata = &ccgdm->dm.faceData;
-               CustomData *dmfdata = &dm->faceData;
-               int numlayer = CustomData_number_of_layers(fdata, CD_MTFACE);
-               int dmnumlayer = CustomData_number_of_layers(dmfdata, CD_MTFACE);
-
-               for (i=0; i<numlayer && i<dmnumlayer; i++)
-                       set_subsurf_uv(ss, dm, &ccgdm->dm, i);
-       }
-
-       edgeFlags = ccgdm->edgeFlags = MEM_callocN(sizeof(short)*totedge, "edgeFlags");
-
        for(index = 0; index < totedge; ++index) {
                CCGEdge *e = ccgdm->edgeMap[index].edge;
                int numFinalEdges = edgeSize - 1;
+               int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
                int x;
                int vertIdx[2];
                int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e));
@@ -2566,6 +3356,9 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
                ccgdm->edgeMap[index].startVert = vertNum;
                ccgdm->edgeMap[index].startEdge = edgeNum;
 
+               if(edgeIdx >= 0 && edgeFlags)
+                       edgeFlags[edgeIdx] = medge[edgeIdx].flag;
+
                /* set the edge base vert */
                *((int*)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum;
 
@@ -2574,32 +3367,59 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
                        w[1] = (float) x / (edgeSize - 1);
                        w[0] = 1 - w[1];
                        DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, 2, vertNum);
+                       if (vertOrigIndex) {
+                               *vertOrigIndex = ORIGINDEX_NONE;
+                               ++vertOrigIndex;
+                       }
                        ++vertNum;
                }
 
-               edgeFlags[index]= medge[edgeIdx].flag;
+               for(i = 0; i < numFinalEdges; ++i) {
+                       if (has_edge_origindex) {
+                               *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i,
+                                                CD_ORIGINDEX) = mapIndex;
+                       }
+               }
 
                edgeNum += numFinalEdges;
        }
 
        for(index = 0; index < totvert; ++index) {
                CCGVert *v = ccgdm->vertMap[index].vert;
-               int vertIdx;
+               int mapIndex = ccgDM_getVertMapIndex(ccgdm->ss, v);
+               int vidx;
 
-               vertIdx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
+               vidx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
 
                ccgdm->vertMap[index].startVert = vertNum;
 
                /* set the vert base vert */
                *((int*) ccgSubSurf_getVertUserData(ss, v)) = vertNum;
 
-               DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1);
+               DM_copy_vert_data(dm, &ccgdm->dm, vidx, vertNum, 1);
 
+               if (vertOrigIndex) {
+                       *vertOrigIndex = mapIndex;
+                       ++vertOrigIndex;
+               }
                ++vertNum;
        }
 
-       MEM_freeN(qweight);
-       MEM_freeN(tweight);
+       ccgdm->dm.numVertData = vertNum;
+       ccgdm->dm.numEdgeData = edgeNum;
+       ccgdm->dm.numFaceData = faceNum;
+       ccgdm->dm.numLoopData = loopindex2;
+       ccgdm->dm.numPolyData = faceNum;
+
+       BLI_array_free(vertidx);
+       BLI_array_free(loopidx);
+       free_ss_weights(&wtable);
+
+       ccgdm->ehash = BLI_edgehash_new();
+       for (i=0; i<ccgdm->dm.numEdgeData; i++) {
+               ccgDM_getFinalEdge((DerivedMesh*)ccgdm, i, &medge2);
+               BLI_edgehash_insert(ccgdm->ehash, medge2.v1, medge2.v2, SET_INT_IN_POINTER(i));
+       }
 
        return ccgdm;
 }
@@ -2616,7 +3436,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
        int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr;
        int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
        int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
-       CCGDerivedMesh *result;
+       CCGDerivedMesh *result = NULL;
 
        if(editMode) {
                int levels= (smd->modifier.scene)? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels): smd->levels;
@@ -2645,7 +3465,7 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
 
                result->freeSS = 1;
        } else {
-               int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
+               int useIncremental = 1; //(smd->flags & eSubsurfModifierFlag_Incremental);
                int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr;
                int levels= (smd->modifier.scene)? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels): smd->levels;
                CCGSubSurf *ss;
@@ -2689,8 +3509,8 @@ struct DerivedMesh *subsurf_make_derived_from_derived(
                                result->freeSS = 1;
                }
        }
-
-       return (DerivedMesh*)result;
+       
+       return result;
 }
 
 void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3])