svn merge -r38200:38300 https://svn.blender.org/svnroot/bf-blender/trunk/blender...
authorCampbell Barton <ideasman42@gmail.com>
Tue, 26 Jul 2011 03:00:55 +0000 (03:00 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 26 Jul 2011 03:00:55 +0000 (03:00 +0000)
27 files changed:
1  2 
release/scripts/startup/bl_ui/space_view3d.py
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/blenlib/intern/pbvh.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/object/object_relations.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/transform_conversions.c
source/blender/gpu/intern/gpu_buffers.c
source/blender/modifiers/intern/MOD_cast.c
source/blender/modifiers/intern/MOD_displace.c
source/blender/modifiers/intern/MOD_hook.c
source/blender/modifiers/intern/MOD_meshdeform.c
source/blender/modifiers/intern/MOD_simpledeform.c
source/blender/modifiers/intern/MOD_smooth.c
source/blender/modifiers/intern/MOD_solidify.c
source/blender/modifiers/intern/MOD_util.c
source/blender/modifiers/intern/MOD_util.h
source/blender/modifiers/intern/MOD_warp.c
source/blender/modifiers/intern/MOD_wave.c
source/blender/render/intern/source/convertblender.c
source/blender/windowmanager/intern/wm_init_exit.c
source/creator/creator.c

Simple merge
index 33f0e76af836897ebf9881fceb15b70604eab27f,4d4561e66db514290f423da34353af88df14ede2..68e0134b2b4a13adee71cc67334f25e73b853131
@@@ -267,1052 -294,743 +294,743 @@@ void GPU_buffer_free(GPUBuffer *buffer
                }
        }
  
-       for( i =pool->size; i > 0; i-- ) {
+       /* shift pool entries up by one */
+       for(i = pool->totbuf; i > 0; i--)
                pool->buffers[i] = pool->buffers[i-1];
-       }
+       /* insert the buffer into the beginning of the pool */
        pool->buffers[0] = buffer;
-       pool->size++;
+       pool->totbuf++;
  }
  
- GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
+ typedef struct GPUVertPointLink {
+       struct GPUVertPointLink *next;
+       /* -1 means uninitialized */
+       int point_index;
+ } GPUVertPointLink;
+ /* add a new point to the list of points related to a particular
+    vertex */
+ static void gpu_drawobject_add_vert_point(GPUDrawObject *gdo, int vert_index, int point_index)
  {
-       GPUDrawObject *object;
-       MFace *mface;
-       int numverts[MAX_MATERIALS];
-       int redir[MAX_MATERIALS];
-       int *index;
-       int i;
-       int curmat, curverts, numfaces;
+       GPUVertPointLink *lnk;
  
-       DEBUG_VBO("GPU_drawobject_new\n");
+       lnk = &gdo->vert_points[vert_index];
  
-       object = MEM_callocN(sizeof(GPUDrawObject),"GPU_drawobject_new_object");
-       object->nindices = dm->getNumVerts(dm);
-       object->indices = MEM_mallocN(sizeof(IndexLink)*object->nindices, "GPU_drawobject_new_indices");
-       object->nedges = dm->getNumEdges(dm);
+       /* if first link is in use, add a new link at the end */
+       if(lnk->point_index != -1) {
+               /* get last link */
+               for(; lnk->next; lnk = lnk->next);
  
-       for( i = 0; i < object->nindices; i++ ) {
-               object->indices[i].element = -1;
-               object->indices[i].next = 0;
+               /* add a new link from the pool */
+               lnk = lnk->next = &gdo->vert_points_mem[gdo->vert_points_usage];
+               gdo->vert_points_usage++;
        }
-       /*object->legacy = 1;*/
-       memset(numverts,0,sizeof(int)*MAX_MATERIALS);
  
-       mface = dm->getTessFaceArray(dm);
+       lnk->point_index = point_index;
+ }
  
-       numfaces= dm->getNumTessFaces(dm);
-       for( i=0; i < numfaces; i++ ) {
-               if( mface[i].v4 )
-                       numverts[mface[i].mat_nr] += 6; /* split every quad into two triangles */
-               else
-                       numverts[mface[i].mat_nr] += 3;
-       }
+ /* update the vert_points and triangle_to_mface fields with a new
+    triangle */
+ static void gpu_drawobject_add_triangle(GPUDrawObject *gdo,
+                                       int base_point_index,
+                                       int face_index,
+                                       int v1, int v2, int v3)
+ {
+       int i, v[3] = {v1, v2, v3};
+       for(i = 0; i < 3; i++)
+               gpu_drawobject_add_vert_point(gdo, v[i], base_point_index + i);
+       gdo->triangle_to_mface[base_point_index / 3] = face_index;
+ }
  
-       for( i = 0; i < MAX_MATERIALS; i++ ) {
-               if( numverts[i] > 0 ) {
-                       object->nmaterials++;
-                       object->nelements += numverts[i];
+ /* for each vertex, build a list of points related to it; these lists
+    are stored in an array sized to the number of vertices */
+ static void gpu_drawobject_init_vert_points(GPUDrawObject *gdo, MFace *f, int totface)
+ {
+       GPUBufferMaterial *mat;
+       int i, mat_orig_to_new[MAX_MATERIALS];
+       /* allocate the array and space for links */
+       gdo->vert_points = MEM_callocN(sizeof(GPUVertPointLink) * gdo->totvert,
+                                      "GPUDrawObject.vert_points");
+       gdo->vert_points_mem = MEM_callocN(sizeof(GPUVertPointLink) * gdo->tot_triangle_point,
+                                             "GPUDrawObject.vert_points_mem");
+       gdo->vert_points_usage = 0;
+       /* build a map from the original material indices to the new
+          GPUBufferMaterial indices */
+       for(i = 0; i < gdo->totmaterial; i++)
+               mat_orig_to_new[gdo->materials[i].mat_nr] = i;
+       /* -1 indicates the link is not yet used */
+       for(i = 0; i < gdo->totvert; i++)
+               gdo->vert_points[i].point_index = -1;
+       for(i = 0; i < totface; i++, f++) {
+               mat = &gdo->materials[mat_orig_to_new[f->mat_nr]];
+               /* add triangle */
+               gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
+                                           i, f->v1, f->v2, f->v3);
+               mat->totpoint += 3;
+               /* add second triangle for quads */
+               if(f->v4) {
+                       gpu_drawobject_add_triangle(gdo, mat->start + mat->totpoint,
+                                                   i, f->v3, f->v4, f->v1);
+                       mat->totpoint += 3;
                }
        }
-       object->materials = MEM_mallocN(sizeof(GPUBufferMaterial)*object->nmaterials,"GPU_drawobject_new_materials");
-       index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_drawobject_new_index");
-       curmat = curverts = 0;
-       for( i = 0; i < MAX_MATERIALS; i++ ) {
-               if( numverts[i] > 0 ) {
-                       object->materials[curmat].mat_nr = i;
-                       object->materials[curmat].start = curverts;
-                       index[curmat] = curverts/3;
-                       object->materials[curmat].end = curverts+numverts[i];
-                       curverts += numverts[i];
-                       curmat++;
+       /* map any unused vertices to loose points */
+       for(i = 0; i < gdo->totvert; i++) {
+               if(gdo->vert_points[i].point_index == -1) {
+                       gdo->vert_points[i].point_index = gdo->tot_triangle_point + gdo->tot_loose_point;
+                       gdo->tot_loose_point++;
                }
        }
-       object->faceRemap = MEM_mallocN(sizeof(int)*object->nelements/3,"GPU_drawobject_new_faceRemap");
-       for( i = 0; i < object->nmaterials; i++ ) {
-               redir[object->materials[i].mat_nr] = i; /* material number -> material index */
-       }
+ }
  
-       object->indexMem = MEM_callocN(sizeof(IndexLink)*object->nelements,"GPU_drawobject_new_indexMem");
-       object->indexMemUsage = 0;
- #define ADDLINK( INDEX, ACTUAL ) \
-               if( object->indices[INDEX].element == -1 ) { \
-                       object->indices[INDEX].element = ACTUAL; \
-               } else { \
-                       IndexLink *lnk = &object->indices[INDEX]; \
-                       while( lnk->next != 0 ) lnk = lnk->next; \
-                       lnk->next = &object->indexMem[object->indexMemUsage]; \
-                       lnk->next->element = ACTUAL; \
-                       object->indexMemUsage++; \
-               }
+ /* see GPUDrawObject's structure definition for a description of the
+    data being initialized here */
+ GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
+ {
+       GPUDrawObject *gdo;
+       MFace *mface;
+       int points_per_mat[MAX_MATERIALS];
+       int i, curmat, curpoint, totface;
  
-       for( i=0; i < numfaces; i++ ) {
-               int curInd = index[redir[mface[i].mat_nr]];
-               object->faceRemap[curInd] = i; 
-               ADDLINK( mface[i].v1, curInd*3 );
-               ADDLINK( mface[i].v2, curInd*3+1 );
-               ADDLINK( mface[i].v3, curInd*3+2 );
-               if( mface[i].v4 ) {
-                       object->faceRemap[curInd+1] = i;
-                       ADDLINK( mface[i].v3, curInd*3+3 );
-                       ADDLINK( mface[i].v4, curInd*3+4 );
-                       ADDLINK( mface[i].v1, curInd*3+5 );
-                       index[redir[mface[i].mat_nr]]+=2;
-               }
-               else {
-                       index[redir[mface[i].mat_nr]]++;
-               }
 -      mface = dm->getFaceArray(dm);
 -      totface= dm->getNumFaces(dm);
++      mface = dm->getTessFaceArray(dm);
++      totface= dm->getNumTessFaces(dm);
+       /* get the number of points used by each material, treating
+          each quad as two triangles */
+       memset(points_per_mat, 0, sizeof(int)*MAX_MATERIALS);
+       for(i = 0; i < totface; i++)
+               points_per_mat[mface[i].mat_nr] += mface[i].v4 ? 6 : 3;
+       /* create the GPUDrawObject */
+       gdo = MEM_callocN(sizeof(GPUDrawObject),"GPUDrawObject");
+       gdo->totvert = dm->getNumVerts(dm);
+       gdo->totedge = dm->getNumEdges(dm);
+       /* count the number of materials used by this DerivedMesh */
+       for(i = 0; i < MAX_MATERIALS; i++) {
+               if(points_per_mat[i] > 0)
+                       gdo->totmaterial++;
        }
  
-       for( i = 0; i < object->nindices; i++ ) {
-               if( object->indices[i].element == -1 ) {
-                       object->indices[i].element = object->nelements + object->nlooseverts;
-                       object->nlooseverts++;
+       /* allocate an array of materials used by this DerivedMesh */
+       gdo->materials = MEM_mallocN(sizeof(GPUBufferMaterial) * gdo->totmaterial,
+                                    "GPUDrawObject.materials");
+       /* initialize the materials array */
+       for(i = 0, curmat = 0, curpoint = 0; i < MAX_MATERIALS; i++) {
+               if(points_per_mat[i] > 0) {
+                       gdo->materials[curmat].start = curpoint;
+                       gdo->materials[curmat].totpoint = 0;
+                       gdo->materials[curmat].mat_nr = i;
+                       curpoint += points_per_mat[i];
+                       curmat++;
                }
        }
- #undef ADDLINK
  
-       MEM_freeN(index);
-       return object;
+       /* store total number of points used for triangles */
+       gdo->tot_triangle_point = curpoint;
+       gdo->triangle_to_mface = MEM_mallocN(sizeof(int) * (gdo->tot_triangle_point / 3),
+                                    "GPUDrawObject.triangle_to_mface");
+       gpu_drawobject_init_vert_points(gdo, mface, totface);
+       return gdo;
  }
  
- void GPU_drawobject_free( DerivedMesh *dm )
+ void GPU_drawobject_free(DerivedMesh *dm)
  {
-       GPUDrawObject *object;
+       GPUDrawObject *gdo;
  
-       DEBUG_VBO("GPU_drawobject_free\n");
-       if( dm == 0 )
-               return;
-       object = dm->drawObject;
-       if( object == 0 )
+       if(!dm || !(gdo = dm->drawObject))
                return;
  
-       MEM_freeN(object->materials);
-       MEM_freeN(object->faceRemap);
-       MEM_freeN(object->indices);
-       MEM_freeN(object->indexMem);
-       GPU_buffer_free( object->vertices, globalPool );
-       GPU_buffer_free( object->normals, globalPool );
-       GPU_buffer_free( object->uv, globalPool );
-       GPU_buffer_free( object->colors, globalPool );
-       GPU_buffer_free( object->edges, globalPool );
-       GPU_buffer_free( object->uvedges, globalPool );
-       MEM_freeN(object);
-       dm->drawObject = 0;
+       MEM_freeN(gdo->materials);
+       MEM_freeN(gdo->triangle_to_mface);
+       MEM_freeN(gdo->vert_points);
+       MEM_freeN(gdo->vert_points_mem);
+       GPU_buffer_free(gdo->points);
+       GPU_buffer_free(gdo->normals);
+       GPU_buffer_free(gdo->uv);
+       GPU_buffer_free(gdo->colors);
+       GPU_buffer_free(gdo->edges);
+       GPU_buffer_free(gdo->uvedges);
+       MEM_freeN(gdo);
+       dm->drawObject = NULL;
  }
  
- /* Convenience struct for building the VBO. */
- typedef struct {
-       float co[3];
-       short no[3];
- } VertexBufferFormat;
+ typedef void (*GPUBufferCopyFunc)(DerivedMesh *dm, float *varray, int *index,
+                                 int *mat_orig_to_new, void *user_data);
  
- typedef struct {
-       /* opengl buffer handles */
-       GLuint vert_buf, index_buf;
-       GLenum index_type;
+ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
+                                  int vector_size, int size, GLenum target,
+                                  void *user, GPUBufferCopyFunc copy_f)
+ {
+       GPUBufferPool *pool;
+       GPUBuffer *buffer;
+       float *varray;
+       int mat_orig_to_new[MAX_MATERIALS];
+       int *cur_index_per_mat;
+       int i;
+       int success;
+       GLboolean uploaded;
  
-       /* mesh pointers in case buffer allocation fails */
-       MFace *mface;
-       MVert *mvert;
-       int *face_indices;
-       int totface;
+       pool = gpu_get_global_buffer_pool();
  
-       /* grid pointers */
-       DMGridData **grids;
-       int *grid_indices;
-       int totgrid;
-       int gridsize;
+       /* alloc a GPUBuffer; fall back to legacy mode on failure */
+       if(!(buffer = GPU_buffer_alloc(size)))
+               dm->drawObject->legacy = 1;
  
-       unsigned int tot_tri, tot_quad;
- } GPU_Buffers;
+       /* nothing to do for legacy mode */
+       if(dm->drawObject->legacy)
+               return 0;
  
- void GPU_update_mesh_buffers(void *buffers_v, MVert *mvert,
-                       int *vert_indices, int totvert)
- {
-       GPU_Buffers *buffers = buffers_v;
-       VertexBufferFormat *vert_data;
-       int i;
+       cur_index_per_mat = MEM_mallocN(sizeof(int)*object->totmaterial,
+                                       "GPU_buffer_setup.cur_index_per_mat");
+       for(i = 0; i < object->totmaterial; i++) {
+               /* for each material, the current index to copy data to */
+               cur_index_per_mat[i] = object->materials[i].start * vector_size;
  
-       if(buffers->vert_buf) {
-               /* Build VBO */
-               glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
-               glBufferDataARB(GL_ARRAY_BUFFER_ARB,
-                                sizeof(VertexBufferFormat) * totvert,
-                                NULL, GL_STATIC_DRAW_ARB);
-               vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+               /* map from original material index to new
+                  GPUBufferMaterial index */
+               mat_orig_to_new[object->materials[i].mat_nr] = i;
+       }
  
-               if(vert_data) {
-                       for(i = 0; i < totvert; ++i) {
-                               MVert *v = mvert + vert_indices[i];
-                               VertexBufferFormat *out = vert_data + i;
+       if(useVBOs) {
+               success = 0;
  
-                               copy_v3_v3(out->co, v->co);
-                               memcpy(out->no, v->no, sizeof(short) * 3);
+               while(!success) {
+                       /* bind the buffer and discard previous data,
+                          avoids stalling gpu */
+                       glBindBufferARB(target, buffer->id);
+                       glBufferDataARB(target, buffer->size, 0, GL_STATIC_DRAW_ARB);
+                       /* attempt to map the buffer */
+                       if(!(varray = glMapBufferARB(target, GL_WRITE_ONLY_ARB))) {
+                               /* failed to map the buffer; delete it */
+                               GPU_buffer_free(buffer);
+                               gpu_buffer_pool_delete_last(pool);
+                               buffer= NULL;
+                               /* try freeing an entry from the pool
+                                  and reallocating the buffer */
+                               if(pool->totbuf > 0) {
+                                       gpu_buffer_pool_delete_last(pool);
+                                       buffer = GPU_buffer_alloc(size);
+                               }
+                               /* allocation still failed; fall back
+                                  to legacy mode */
+                               if(!buffer) {
+                                       dm->drawObject->legacy = 1;
+                                       success = 1;
+                               }
+                       }
+                       else {
+                               success = 1;
                        }
+               }
  
-                       glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+               /* check legacy fallback didn't happen */
+               if(dm->drawObject->legacy == 0) {
+                       uploaded = GL_FALSE;
+                       /* attempt to upload the data to the VBO */
+                       while(uploaded == GL_FALSE) {
+                               (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user);
+                               /* glUnmapBuffer returns GL_FALSE if
+                                  the data store is corrupted; retry
+                                  in that case */
+                               uploaded = glUnmapBufferARB(target);
+                       }
+               }
+               glBindBufferARB(target, 0);
+       }
+       else {
+               /* VBO not supported, use vertex array fallback */
+               if(buffer->pointer) {
+                       varray = buffer->pointer;
+                       (*copy_f)(dm, varray, cur_index_per_mat, mat_orig_to_new, user);
                }
                else {
-                       glDeleteBuffersARB(1, &buffers->vert_buf);
-                       buffers->vert_buf = 0;
+                       dm->drawObject->legacy = 1;
                }
-               glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
        }
  
-       buffers->mvert = mvert;
+       MEM_freeN(cur_index_per_mat);
+       return buffer;
  }
  
- void *GPU_build_mesh_buffers(GHash *map, MVert *mvert, MFace *mface,
-                       int *face_indices, int totface,
-                       int *vert_indices, int tot_uniq_verts,
-                       int totvert)
+ static void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
  {
-       GPU_Buffers *buffers;
-       unsigned short *tri_data;
-       int i, j, k, tottri;
+       MVert *mvert;
+       MFace *f;
+       int i, j, start, totface;
  
-       buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
-       buffers->index_type = GL_UNSIGNED_SHORT;
+       mvert = dm->getVertArray(dm);
 -      f = dm->getFaceArray(dm);
++      f = dm->getTessFaceArray(dm);
  
-       /* Count the number of triangles */
-       for(i = 0, tottri = 0; i < totface; ++i)
-               tottri += mface[face_indices[i]].v4 ? 2 : 1;
-       
-       if(GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
-               glGenBuffersARB(1, &buffers->index_buf);
 -      totface= dm->getNumFaces(dm);
++      totface= dm->getNumTessFaces(dm);
+       for(i = 0; i < totface; i++, f++) {
+               start = index[mat_orig_to_new[f->mat_nr]];
  
-       if(buffers->index_buf) {
-               /* Generate index buffer object */
-               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
-               glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
-                                sizeof(unsigned short) * tottri * 3, NULL, GL_STATIC_DRAW_ARB);
+               /* v1 v2 v3 */
+               copy_v3_v3(&varray[start], mvert[f->v1].co);
+               copy_v3_v3(&varray[start+3], mvert[f->v2].co);
+               copy_v3_v3(&varray[start+6], mvert[f->v3].co);
+               index[mat_orig_to_new[f->mat_nr]] += 9;
  
-               /* Fill the triangle buffer */
-               tri_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
-               if(tri_data) {
-                       for(i = 0; i < totface; ++i) {
-                               MFace *f = mface + face_indices[i];
-                               int v[3];
+               if(f->v4) {
+                       /* v3 v4 v1 */
+                       copy_v3_v3(&varray[start+9], mvert[f->v3].co);
+                       copy_v3_v3(&varray[start+12], mvert[f->v4].co);
+                       copy_v3_v3(&varray[start+15], mvert[f->v1].co);
+                       index[mat_orig_to_new[f->mat_nr]] += 9;
+               }
+       }
  
-                               v[0]= f->v1;
-                               v[1]= f->v2;
-                               v[2]= f->v3;
+       /* copy loose points */
+       j = dm->drawObject->tot_triangle_point*3;
+       for(i = 0; i < dm->drawObject->totvert; i++) {
+               if(dm->drawObject->vert_points[i].point_index >= dm->drawObject->tot_triangle_point) {
+                       copy_v3_v3(&varray[j],mvert[i].co);
+                       j+=3;
+               }
+       }
+ }
  
-                               for(j = 0; j < (f->v4 ? 2 : 1); ++j) {
-                                       for(k = 0; k < 3; ++k) {
-                                               void *value, *key = SET_INT_IN_POINTER(v[k]);
-                                               int vbo_index;
+ static void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
+ {
+       int i, totface;
+       int start;
+       float f_no[3];
  
-                                               value = BLI_ghash_lookup(map, key);
-                                               vbo_index = GET_INT_FROM_POINTER(value);
 -      float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
++      float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
+       MVert *mvert = dm->getVertArray(dm);
 -      MFace *f = dm->getFaceArray(dm);
++      MFace *f = dm->getTessFaceArray(dm);
  
-                                               if(vbo_index < 0) {
-                                                       vbo_index = -vbo_index +
-                                                               tot_uniq_verts - 1;
-                                               }
 -      totface= dm->getNumFaces(dm);
++      totface= dm->getNumTessFaces(dm);
+       for(i = 0; i < totface; i++, f++) {
+               const int smoothnormal = (f->flag & ME_SMOOTH);
  
-                                               *tri_data = vbo_index;
-                                               ++tri_data;
-                                       }
-                                       v[0] = f->v4;
-                                       v[1] = f->v1;
-                                       v[2] = f->v3;
-                               }
+               start = index[mat_orig_to_new[f->mat_nr]];
+               index[mat_orig_to_new[f->mat_nr]] += f->v4 ? 18 : 9;
+               if(smoothnormal) {
+                       /* copy vertex normal */
+                       normal_short_to_float_v3(&varray[start], mvert[f->v1].no);
+                       normal_short_to_float_v3(&varray[start+3], mvert[f->v2].no);
+                       normal_short_to_float_v3(&varray[start+6], mvert[f->v3].no);
+                       if(f->v4) {
+                               normal_short_to_float_v3(&varray[start+9], mvert[f->v3].no);
+                               normal_short_to_float_v3(&varray[start+12], mvert[f->v4].no);
+                               normal_short_to_float_v3(&varray[start+15], mvert[f->v1].no);
                        }
-                       glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
                }
-               else {
-                       glDeleteBuffersARB(1, &buffers->index_buf);
-                       buffers->index_buf = 0;
+               else if(nors) {
+                       /* copy cached face normal */
+                       copy_v3_v3(&varray[start], &nors[i*3]);
+                       copy_v3_v3(&varray[start+3], &nors[i*3]);
+                       copy_v3_v3(&varray[start+6], &nors[i*3]);
+                       if(f->v4) {
+                               copy_v3_v3(&varray[start+9], &nors[i*3]);
+                               copy_v3_v3(&varray[start+12], &nors[i*3]);
+                               copy_v3_v3(&varray[start+15], &nors[i*3]);
+                       }
                }
+               else {
+                       /* calculate face normal */
+                       if(f->v4)
+                               normal_quad_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co, mvert[f->v4].co);
+                       else
+                               normal_tri_v3(f_no, mvert[f->v1].co, mvert[f->v2].co, mvert[f->v3].co);
  
-               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+                       copy_v3_v3(&varray[start], f_no);
+                       copy_v3_v3(&varray[start+3], f_no);
+                       copy_v3_v3(&varray[start+6], f_no);
+                       if(f->v4) {
+                               copy_v3_v3(&varray[start+9], f_no);
+                               copy_v3_v3(&varray[start+12], f_no);
+                               copy_v3_v3(&varray[start+15], f_no);
+                       }
+               }
        }
+ }
  
-       if(buffers->index_buf)
-               glGenBuffersARB(1, &buffers->vert_buf);
-       GPU_update_mesh_buffers(buffers, mvert, vert_indices, totvert);
+ static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
+ {
+       int start;
+       int i, totface;
  
-       buffers->tot_tri = tottri;
+       MTFace *mtface;
+       MFace *f;
  
-       buffers->mface = mface;
-       buffers->face_indices = face_indices;
-       buffers->totface = totface;
+       if(!(mtface = DM_get_face_data_layer(dm, CD_MTFACE)))
+               return;
 -      f = dm->getFaceArray(dm);
++      f = dm->getTessFaceArray(dm);
+               
 -      totface = dm->getNumFaces(dm);
++      totface = dm->getNumTessFaces(dm);
+       for(i = 0; i < totface; i++, f++) {
+               start = index[mat_orig_to_new[f->mat_nr]];
  
-       return buffers;
+               /* v1 v2 v3 */
+               copy_v2_v2(&varray[start],mtface[i].uv[0]);
+               copy_v2_v2(&varray[start+2],mtface[i].uv[1]);
+               copy_v2_v2(&varray[start+4],mtface[i].uv[2]);
+               index[mat_orig_to_new[f->mat_nr]] += 6;
+               if(f->v4) {
+                       /* v3 v4 v1 */
+                       copy_v2_v2(&varray[start+6],mtface[i].uv[2]);
+                       copy_v2_v2(&varray[start+8],mtface[i].uv[3]);
+                       copy_v2_v2(&varray[start+10],mtface[i].uv[0]);
+                       index[mat_orig_to_new[f->mat_nr]] += 6;
+               }
+       }
  }
  
- void GPU_update_grid_buffers(void *buffers_v, DMGridData **grids,
-       int *grid_indices, int totgrid, int gridsize, int smooth)
- {
-       GPU_Buffers *buffers = buffers_v;
-       DMGridData *vert_data;
-       int i, j, k, totvert;
  
-       totvert= gridsize*gridsize*totgrid;
+ static void GPU_buffer_copy_color3(DerivedMesh *dm, float *varray_, int *index, int *mat_orig_to_new, void *user)
+ {
+       int i, totface;
+       unsigned char *varray = (unsigned char *)varray_;
+       unsigned char *mcol = (unsigned char *)user;
 -      MFace *f = dm->getFaceArray(dm);
++      MFace *f = dm->getTessFaceArray(dm);
  
-       /* Build VBO */
-       if(buffers->vert_buf) {
-               glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
-               glBufferDataARB(GL_ARRAY_BUFFER_ARB,
-                                sizeof(DMGridData) * totvert,
-                                NULL, GL_STATIC_DRAW_ARB);
-               vert_data = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
-               if(vert_data) {
-                       for(i = 0; i < totgrid; ++i) {
-                               DMGridData *grid= grids[grid_indices[i]];
-                               memcpy(vert_data, grid, sizeof(DMGridData)*gridsize*gridsize);
 -      totface= dm->getNumFaces(dm);
++      totface= dm->getNumTessFaces(dm);
+       for(i=0; i < totface; i++, f++) {
+               int start = index[mat_orig_to_new[f->mat_nr]];
  
-                               if(!smooth) {
-                                       /* for flat shading, recalc normals and set the last vertex of
-                                          each quad in the index buffer to have the flat normal as
-                                          that is what opengl will use */
-                                       for(j = 0; j < gridsize-1; ++j) {
-                                               for(k = 0; k < gridsize-1; ++k) {
-                                                       normal_quad_v3(vert_data[(j+1)*gridsize + (k+1)].no,
-                                                               vert_data[(j+1)*gridsize + k].co,
-                                                               vert_data[(j+1)*gridsize + k+1].co,
-                                                               vert_data[j*gridsize + k+1].co,
-                                                               vert_data[j*gridsize + k].co);
-                                               }
-                                       }
-                               }
+               /* v1 v2 v3 */
+               VECCOPY(&varray[start], &mcol[i*12]);
+               VECCOPY(&varray[start+3], &mcol[i*12+3]);
+               VECCOPY(&varray[start+6], &mcol[i*12+6]);
+               index[mat_orig_to_new[f->mat_nr]] += 9;
  
-                               vert_data += gridsize*gridsize;
-                       }
-                       glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
-               }
-               else {
-                       glDeleteBuffersARB(1, &buffers->vert_buf);
-                       buffers->vert_buf = 0;
+               if(f->v4) {
+                       /* v3 v4 v1 */
+                       VECCOPY(&varray[start+9], &mcol[i*12+6]);
+                       VECCOPY(&varray[start+12], &mcol[i*12+9]);
+                       VECCOPY(&varray[start+15], &mcol[i*12]);
+                       index[mat_orig_to_new[f->mat_nr]] += 9;
                }
-               glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
        }
+ }
  
-       buffers->grids = grids;
-       buffers->grid_indices = grid_indices;
-       buffers->totgrid = totgrid;
-       buffers->gridsize = gridsize;
-       //printf("node updated %p\n", buffers_v);
+ static void copy_mcol_uc3(unsigned char *v, unsigned char *col)
+ {
+       v[0] = col[3];
+       v[1] = col[2];
+       v[2] = col[1];
  }
  
- void *GPU_build_grid_buffers(DMGridData **UNUSED(grids), int *UNUSED(grid_indices),
                              int totgrid, int gridsize)
+ /* treat varray_ as an array of MCol, four MCol's per face */
static void GPU_buffer_copy_mcol(DerivedMesh *dm, float *varray_, int *index, int *mat_orig_to_new, void *user)
  {
-       GPU_Buffers *buffers;
-       int i, j, k, totquad, offset= 0;
+       int i, totface;
+       unsigned char *varray = (unsigned char *)varray_;
+       unsigned char *mcol = (unsigned char *)user;
 -      MFace *f = dm->getFaceArray(dm);
++      MFace *f = dm->getTessFaceArray(dm);
  
-       buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
 -      totface= dm->getNumFaces(dm);
++      totface= dm->getNumTessFaces(dm);
+       for(i=0; i < totface; i++, f++) {
+               int start = index[mat_orig_to_new[f->mat_nr]];
  
-       /* Count the number of quads */
-       totquad= (gridsize-1)*(gridsize-1)*totgrid;
+               /* v1 v2 v3 */
+               copy_mcol_uc3(&varray[start], &mcol[i*16]);
+               copy_mcol_uc3(&varray[start+3], &mcol[i*16+4]);
+               copy_mcol_uc3(&varray[start+6], &mcol[i*16+8]);
+               index[mat_orig_to_new[f->mat_nr]] += 9;
  
-       /* Generate index buffer object */
-       if(GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
-               glGenBuffersARB(1, &buffers->index_buf);
+               if(f->v4) {
+                       /* v3 v4 v1 */
+                       copy_mcol_uc3(&varray[start+9], &mcol[i*16+8]);
+                       copy_mcol_uc3(&varray[start+12], &mcol[i*16+12]);
+                       copy_mcol_uc3(&varray[start+15], &mcol[i*16]);
+                       index[mat_orig_to_new[f->mat_nr]] += 9;
+               }
+       }
+ }
  
-       if(buffers->index_buf) {
-               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
+ static void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray_, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
+ {
+       MEdge *medge;
+       unsigned int *varray = (unsigned int *)varray_;
+       int i, totedge;
+  
+       medge = dm->getEdgeArray(dm);
+       totedge = dm->getNumEdges(dm);
  
-               if(totquad < USHRT_MAX) {
-                       unsigned short *quad_data;
+       for(i = 0; i < totedge; i++, medge++) {
+               varray[i*2] = dm->drawObject->vert_points[medge->v1].point_index;
+               varray[i*2+1] = dm->drawObject->vert_points[medge->v2].point_index;
+       }
+ }
  
-                       buffers->index_type = GL_UNSIGNED_SHORT;
-                       glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
-                                        sizeof(unsigned short) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
+ static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(mat_orig_to_new), void *UNUSED(user))
+ {
+       MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+       int i, j=0;
  
-                       /* Fill the quad buffer */
-                       quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
-                       if(quad_data) {
-                               for(i = 0; i < totgrid; ++i) {
-                                       for(j = 0; j < gridsize-1; ++j) {
-                                               for(k = 0; k < gridsize-1; ++k) {
-                                                       *(quad_data++)= offset + j*gridsize + k+1;
-                                                       *(quad_data++)= offset + j*gridsize + k;
-                                                       *(quad_data++)= offset + (j+1)*gridsize + k;
-                                                       *(quad_data++)= offset + (j+1)*gridsize + k+1;
-                                               }
-                                       }
+       if(!tf)
+               return;
  
-                                       offset += gridsize*gridsize;
-                               }
-                               glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
-                       }
-                       else {
-                               glDeleteBuffersARB(1, &buffers->index_buf);
-                               buffers->index_buf = 0;
-                       }
-               }
-               else {
-                       unsigned int *quad_data;
+       for(i = 0; i < dm->numFaceData; i++, tf++) {
+               MFace mf;
 -              dm->getFace(dm,i,&mf);
++              dm->getTessFace(dm,i,&mf);
  
-                       buffers->index_type = GL_UNSIGNED_INT;
-                       glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
-                                        sizeof(unsigned int) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
+               copy_v2_v2(&varray[j],tf->uv[0]);
+               copy_v2_v2(&varray[j+2],tf->uv[1]);
  
-                       /* Fill the quad buffer */
-                       quad_data = glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+               copy_v2_v2(&varray[j+4],tf->uv[1]);
+               copy_v2_v2(&varray[j+6],tf->uv[2]);
  
-                       if(quad_data) {
-                               for(i = 0; i < totgrid; ++i) {
-                                       for(j = 0; j < gridsize-1; ++j) {
-                                               for(k = 0; k < gridsize-1; ++k) {
-                                                       *(quad_data++)= offset + j*gridsize + k+1;
-                                                       *(quad_data++)= offset + j*gridsize + k;
-                                                       *(quad_data++)= offset + (j+1)*gridsize + k;
-                                                       *(quad_data++)= offset + (j+1)*gridsize + k+1;
-                                               }
-                                       }
+               if(!mf.v4) {
+                       copy_v2_v2(&varray[j+8],tf->uv[2]);
+                       copy_v2_v2(&varray[j+10],tf->uv[0]);
+                       j+=12;
+               } else {
+                       copy_v2_v2(&varray[j+8],tf->uv[2]);
+                       copy_v2_v2(&varray[j+10],tf->uv[3]);
  
-                                       offset += gridsize*gridsize;
-                               }
-                               glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
-                       }
-                       else {
-                               glDeleteBuffersARB(1, &buffers->index_buf);
-                               buffers->index_buf = 0;
-                       }
+                       copy_v2_v2(&varray[j+12],tf->uv[3]);
+                       copy_v2_v2(&varray[j+14],tf->uv[0]);
+                       j+=16;
                }
+       }
+ }
  
-               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+ /* get the DerivedMesh's MCols; choose (in decreasing order of
+    preference) from CD_ID_MCOL, CD_WEIGHT_MCOL, or CD_MCOL */
+ static MCol *gpu_buffer_color_type(DerivedMesh *dm)
+ {
+       MCol *c;
+       int type;
+       type = CD_ID_MCOL;
+       c = DM_get_face_data_layer(dm, type);
+       if(!c) {
+               type = CD_WEIGHT_MCOL;
+               c = DM_get_face_data_layer(dm, type);
+               if(!c) {
+                       type = CD_MCOL;
+                       c = DM_get_face_data_layer(dm, type);
+               }
        }
  
-       /* Build VBO */
-       if(buffers->index_buf)
-               glGenBuffersARB(1, &buffers->vert_buf);
+       dm->drawObject->colType = type;
+       return c;
+ }
  
-       buffers->tot_quad = totquad;
+ typedef enum {
+       GPU_BUFFER_VERTEX = 0,
+       GPU_BUFFER_NORMAL,
+       GPU_BUFFER_COLOR,
+       GPU_BUFFER_UV,
+       GPU_BUFFER_EDGE,
+       GPU_BUFFER_UVEDGE,
+ } GPUBufferType;
  
-       return buffers;
+ typedef struct {
+       GPUBufferCopyFunc copy;
+       GLenum gl_buffer_type;
+       int vector_size;
+ } GPUBufferTypeSettings;
+ const GPUBufferTypeSettings gpu_buffer_type_settings[] = {
+       {GPU_buffer_copy_vertex, GL_ARRAY_BUFFER_ARB, 3},
+       {GPU_buffer_copy_normal, GL_ARRAY_BUFFER_ARB, 3},
+       {GPU_buffer_copy_mcol, GL_ARRAY_BUFFER_ARB, 3},
+       {GPU_buffer_copy_uv, GL_ARRAY_BUFFER_ARB, 2},
+       {GPU_buffer_copy_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2},
+       {GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4}
+ };
+ /* get the GPUDrawObject buffer associated with a type */
+ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBufferType type)
+ {
+       switch(type) {
+       case GPU_BUFFER_VERTEX:
+               return &gdo->points;
+       case GPU_BUFFER_NORMAL:
+               return &gdo->normals;
+       case GPU_BUFFER_COLOR:
+               return &gdo->colors;
+       case GPU_BUFFER_UV:
+               return &gdo->uv;
+       case GPU_BUFFER_EDGE:
+               return &gdo->edges;
+       case GPU_BUFFER_UVEDGE:
+               return &gdo->uvedges;
+       default:
+               return NULL;
+       }
  }
  
- void GPU_draw_buffers(void *buffers_v)
+ /* get the amount of space to allocate for a buffer of a particular type */
+ static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type)
  {
-       GPU_Buffers *buffers = buffers_v;
-       if(buffers->vert_buf && buffers->index_buf) {
-               glEnableClientState(GL_VERTEX_ARRAY);
-               glEnableClientState(GL_NORMAL_ARRAY);
-               glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffers->vert_buf);
-               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
+       switch(type) {
+       case GPU_BUFFER_VERTEX:
+               return sizeof(float)*3 * (dm->drawObject->tot_triangle_point + dm->drawObject->tot_loose_point);
+       case GPU_BUFFER_NORMAL:
+               return sizeof(float)*3*dm->drawObject->tot_triangle_point;
+       case GPU_BUFFER_COLOR:
+               return sizeof(char)*3*dm->drawObject->tot_triangle_point;
+       case GPU_BUFFER_UV:
+               return sizeof(float)*2*dm->drawObject->tot_triangle_point;
+       case GPU_BUFFER_EDGE:
+               return sizeof(int)*2*dm->drawObject->totedge;
+       case GPU_BUFFER_UVEDGE:
+               /* each face gets 3 points, 3 edges per triangle, and
+                  each edge has its own, non-shared coords, so each
+                  tri corner needs minimum of 4 floats, quads used
+                  less so here we can over allocate and assume all
+                  tris. */
+               return sizeof(float) * dm->drawObject->tot_triangle_point;
+       default:
+               return -1;
+       }
+ }
  
-               if(buffers->tot_quad) {
-                       glVertexPointer(3, GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, co));
-                       glNormalPointer(GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, no));
+ /* call gpu_buffer_setup with settings for a particular type of buffer */
+ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
+ {
+       const GPUBufferTypeSettings *ts;
+       void *user_data = NULL;
+       GPUBuffer *buf;
  
-                       glDrawElements(GL_QUADS, buffers->tot_quad * 4, buffers->index_type, 0);
-               }
-               else {
-                       glVertexPointer(3, GL_FLOAT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, co));
-                       glNormalPointer(GL_SHORT, sizeof(VertexBufferFormat), (void*)offsetof(VertexBufferFormat, no));
+       ts = &gpu_buffer_type_settings[type];
  
-                       glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0);
-               }
+       /* special handling for MCol and UV buffers */
+       if(type == GPU_BUFFER_COLOR) {
+               if(!(user_data = gpu_buffer_color_type(dm)))
+                       return NULL;
+       }
+       else if(type == GPU_BUFFER_UV) {
+               if(!DM_get_face_data_layer(dm, CD_MTFACE))
+                       return NULL;
+       }
  
-               glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
-               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+       buf = gpu_buffer_setup(dm, dm->drawObject, ts->vector_size,
+                              gpu_buffer_size_from_type(dm, type),
+                              ts->gl_buffer_type, user_data, ts->copy);
  
-               glDisableClientState(GL_VERTEX_ARRAY);
-               glDisableClientState(GL_NORMAL_ARRAY);
-       }
-       else if(buffers->totface) {
-               /* fallback if we are out of memory */
-               int i;
+       return buf;
+ }
  
-               for(i = 0; i < buffers->totface; ++i) {
-                       MFace *f = buffers->mface + buffers->face_indices[i];
+ /* get the buffer of `type', initializing the GPUDrawObject and
+    buffer if needed */
+ static GPUBuffer *gpu_buffer_setup_common(DerivedMesh *dm, GPUBufferType type)
+ {
+       GPUBuffer **buf;
+       
+       if(!dm->drawObject)
+               dm->drawObject = GPU_drawobject_new(dm);
  
-                       glBegin((f->v4)? GL_QUADS: GL_TRIANGLES);
-                       glNormal3sv(buffers->mvert[f->v1].no);
-                       glVertex3fv(buffers->mvert[f->v1].co);
-                       glNormal3sv(buffers->mvert[f->v2].no);
-                       glVertex3fv(buffers->mvert[f->v2].co);
-                       glNormal3sv(buffers->mvert[f->v3].no);
-                       glVertex3fv(buffers->mvert[f->v3].co);
-                       if(f->v4) {
-                               glNormal3sv(buffers->mvert[f->v4].no);
-                               glVertex3fv(buffers->mvert[f->v4].co);
-                       }
-                       glEnd();
-               }
-       }
-       else if(buffers->totgrid) {
-               int i, x, y, gridsize = buffers->gridsize;
+       buf = gpu_drawobject_buffer_from_type(dm->drawObject, type);
+       if(!(*buf))
+               *buf = gpu_buffer_setup_type(dm, type);
  
-               for(i = 0; i < buffers->totgrid; ++i) {
-                       DMGridData *grid = buffers->grids[buffers->grid_indices[i]];
+       return *buf;
+ }
  
-                       for(y = 0; y < gridsize-1; y++) {
-                               glBegin(GL_QUAD_STRIP);
-                               for(x = 0; x < gridsize; x++) {
-                                       DMGridData *a = &grid[y*gridsize + x];
-                                       DMGridData *b = &grid[(y+1)*gridsize + x];
+ void GPU_vertex_setup(DerivedMesh *dm)
+ {
+       if(!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX))
+               return;
  
-                                       glNormal3fv(a->no);
-                                       glVertex3fv(a->co);
-                                       glNormal3fv(b->no);
-                                       glVertex3fv(b->co);
-                               }
-                               glEnd();
-                       }
-               }
+       glEnableClientState(GL_VERTEX_ARRAY);
+       if(useVBOs) {
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id);
+               glVertexPointer(3, GL_FLOAT, 0, 0);
+       }
+       else {
+               glVertexPointer(3, GL_FLOAT, 0, dm->drawObject->points->pointer);
        }
+       
+       GLStates |= GPU_BUFFER_VERTEX_STATE;
  }
  
- void GPU_free_buffers(void *buffers_v)
+ void GPU_normal_setup(DerivedMesh *dm)
  {
-       if(buffers_v) {
-               GPU_Buffers *buffers = buffers_v;
-               
-               if(buffers->vert_buf)
-                       glDeleteBuffersARB(1, &buffers->vert_buf);
-               if(buffers->index_buf)
-                       glDeleteBuffersARB(1, &buffers->index_buf);
+       if(!gpu_buffer_setup_common(dm, GPU_BUFFER_NORMAL))
+               return;
  
-               MEM_freeN(buffers);
+       glEnableClientState(GL_NORMAL_ARRAY);
+       if(useVBOs) {
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id);
+               glNormalPointer(GL_FLOAT, 0, 0);
        }
+       else {
+               glNormalPointer(GL_FLOAT, 0, dm->drawObject->normals->pointer);
+       }
+       GLStates |= GPU_BUFFER_NORMAL_STATE;
  }
  
static GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int vector_size, int size, GLenum target, void *user, void (*copy_f)(DerivedMesh *, float *, int *, int *, void *) )
void GPU_uv_setup(DerivedMesh *dm)
  {
-       GPUBuffer *buffer;
-       float *varray;
-       int redir[MAX_MATERIALS];
-       int *index;
-       int i;
-       int success;
-       GLboolean uploaded;
+       if(!gpu_buffer_setup_common(dm, GPU_BUFFER_UV))
+               return;
  
-       DEBUG_VBO("GPU_buffer_setup\n");
+       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+       if(useVBOs) {
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id);
+               glTexCoordPointer(2, GL_FLOAT, 0, 0);
+       }
+       else {
+               glTexCoordPointer(2, GL_FLOAT, 0, dm->drawObject->uv->pointer);
+       }
  
-       if( globalPool == 0 )
-               globalPool = GPU_buffer_pool_new();
+       GLStates |= GPU_BUFFER_TEXCOORD_STATE;
+ }
  
-       buffer = GPU_buffer_alloc(size,globalPool);
-       if( buffer == 0 ) {
-               dm->drawObject->legacy = 1;
+ void GPU_color_setup(DerivedMesh *dm)
+ {
+       if(!gpu_buffer_setup_common(dm, GPU_BUFFER_COLOR))
+               return;
+       glEnableClientState(GL_COLOR_ARRAY);
+       if(useVBOs) {
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id);
+               glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
        }
-       if( dm->drawObject->legacy ) {
-               return 0;
+       else {
+               glColorPointer(3, GL_UNSIGNED_BYTE, 0, dm->drawObject->colors->pointer);
        }
  
-       index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_buffer_setup");
-       for( i = 0; i < object->nmaterials; i++ ) {
-               index[i] = object->materials[i].start*vector_size;
-               redir[object->materials[i].mat_nr] = i;
-       }
+       GLStates |= GPU_BUFFER_COLOR_STATE;
+ }
  
-       if( useVBOs ) {
-               success = 0;
-               while( success == 0 ) {
-                       glBindBufferARB( target, buffer->id );
-                       glBufferDataARB( target, buffer->size, 0, GL_STATIC_DRAW_ARB ); /* discard previous data, avoid stalling gpu */
-                       varray = glMapBufferARB( target, GL_WRITE_ONLY_ARB );
-                       if( varray == 0 ) {
-                               DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
-                               GPU_buffer_free( buffer, globalPool );
-                               GPU_buffer_pool_delete_last( globalPool );
-                               buffer= NULL;
-                               if( globalPool->size > 0 ) {
-                                       GPU_buffer_pool_delete_last( globalPool );
-                                       buffer = GPU_buffer_alloc( size, globalPool );
-                                       if( buffer == 0 ) {
-                                               dm->drawObject->legacy = 1;
-                                               success = 1;
-                                       }
-                               }
-                               else {
-                                       dm->drawObject->legacy = 1;
-                                       success = 1;
-                               }
-                       }
-                       else {
-                               success = 1;
-                       }
-               }
-               if( dm->drawObject->legacy == 0 ) {
-                       uploaded = GL_FALSE;
-                       while( !uploaded ) {
-                               (*copy_f)( dm, varray, index, redir, user );
-                               uploaded = glUnmapBufferARB( target );  /* returns false if data got corruped during transfer */
-                       }
-               }
-               glBindBufferARB(target, 0);
-       }
-       else {
-               if( buffer->pointer != 0 ) {
-                       varray = buffer->pointer;
-                       (*copy_f)( dm, varray, index, redir, user );
-               }
-               else {
-                       dm->drawObject->legacy = 1;
-               }
-       }
-       MEM_freeN(index);
-       return buffer;
- }
- static void GPU_buffer_copy_vertex(DerivedMesh *dm, float *varray, int *index, int *redir, void *UNUSED(user))
- {
-       int start;
-       int i, j, numfaces;
-       MVert *mvert;
-       MFace *mface;
-       DEBUG_VBO("GPU_buffer_copy_vertex\n");
-       mvert = dm->getVertArray(dm);
-       mface = dm->getTessFaceArray(dm);
-       numfaces= dm->getNumTessFaces(dm);
-       for( i=0; i < numfaces; i++ ) {
-               start = index[redir[mface[i].mat_nr]];
-               if( mface[i].v4 )
-                       index[redir[mface[i].mat_nr]] += 18;
-               else
-                       index[redir[mface[i].mat_nr]] += 9;
-               /* v1 v2 v3 */
-               VECCOPY(&varray[start],mvert[mface[i].v1].co);
-               VECCOPY(&varray[start+3],mvert[mface[i].v2].co);
-               VECCOPY(&varray[start+6],mvert[mface[i].v3].co);
-               if( mface[i].v4 ) {
-                       /* v3 v4 v1 */
-                       VECCOPY(&varray[start+9],mvert[mface[i].v3].co);
-                       VECCOPY(&varray[start+12],mvert[mface[i].v4].co);
-                       VECCOPY(&varray[start+15],mvert[mface[i].v1].co);
-               }
-       }
-       j = dm->drawObject->nelements*3;
-       for( i = 0; i < dm->drawObject->nindices; i++ ) {
-               if( dm->drawObject->indices[i].element >= dm->drawObject->nelements ) {
-                       VECCOPY(&varray[j],mvert[i].co);
-                       j+=3;
-               }
-       }
- }
- static GPUBuffer *GPU_buffer_vertex( DerivedMesh *dm )
- {
-       DEBUG_VBO("GPU_buffer_vertex\n");
-       return GPU_buffer_setup( dm, dm->drawObject, 3, sizeof(float)*3*(dm->drawObject->nelements+dm->drawObject->nlooseverts), GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_vertex);
- }
- static void GPU_buffer_copy_normal(DerivedMesh *dm, float *varray, int *index, int *redir, void *UNUSED(user))
- {
-       int i, numfaces;
-       int start;
-       float norm[3];
-       float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
-       MVert *mvert = dm->getVertArray(dm);
-       MFace *mface = dm->getTessFaceArray(dm);
-       DEBUG_VBO("GPU_buffer_copy_normal\n");
-       numfaces= dm->getNumTessFaces(dm);
-       for( i=0; i < numfaces; i++ ) {
-               const int smoothnormal = (mface[i].flag & ME_SMOOTH);
-               start = index[redir[mface[i].mat_nr]];
-               if( mface[i].v4 )
-                       index[redir[mface[i].mat_nr]] += 18;
-               else
-                       index[redir[mface[i].mat_nr]] += 9;
-               /* v1 v2 v3 */
-               if(smoothnormal) {
-                       VECCOPY(&varray[start],mvert[mface[i].v1].no);
-                       VECCOPY(&varray[start+3],mvert[mface[i].v2].no);
-                       VECCOPY(&varray[start+6],mvert[mface[i].v3].no);
-               }
-               else {
-                       if( nors ) {
-                               VECCOPY(&varray[start],&nors[i*3]);
-                               VECCOPY(&varray[start+3],&nors[i*3]);
-                               VECCOPY(&varray[start+6],&nors[i*3]);
-                       }
-                       if( mface[i].v4 )
-                               normal_quad_v3( norm,mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, mvert[mface[i].v4].co);
-                       else
-                               normal_tri_v3( norm,mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co);
-                       VECCOPY(&varray[start],norm);
-                       VECCOPY(&varray[start+3],norm);
-                       VECCOPY(&varray[start+6],norm);
-               }
-               if( mface[i].v4 ) {
-                       /* v3 v4 v1 */
-                       if(smoothnormal) {
-                               VECCOPY(&varray[start+9],mvert[mface[i].v3].no);
-                               VECCOPY(&varray[start+12],mvert[mface[i].v4].no);
-                               VECCOPY(&varray[start+15],mvert[mface[i].v1].no);
-                       }
-                       else {
-                               VECCOPY(&varray[start+9],norm);
-                               VECCOPY(&varray[start+12],norm);
-                               VECCOPY(&varray[start+15],norm);
-                       }
-               }
-       }
- }
- static GPUBuffer *GPU_buffer_normal( DerivedMesh *dm )
- {
-       DEBUG_VBO("GPU_buffer_normal\n");
-       return GPU_buffer_setup( dm, dm->drawObject, 3, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_normal);
- }
- static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *redir, void *UNUSED(user))
- {
-       int start;
-       int i, numfaces;
-       MTFace *mtface;
-       MFace *mface;
-       DEBUG_VBO("GPU_buffer_copy_uv\n");
-       mface = dm->getTessFaceArray(dm);
-       mtface = DM_get_face_data_layer(dm, CD_MTFACE);
-       if( mtface == 0 ) {
-               DEBUG_VBO("Texture coordinates do not exist for this mesh");
-               return;
-       }
-               
-       numfaces= dm->getNumTessFaces(dm);
-       for( i=0; i < numfaces; i++ ) {
-               start = index[redir[mface[i].mat_nr]];
-               if( mface[i].v4 )
-                       index[redir[mface[i].mat_nr]] += 12;
-               else
-                       index[redir[mface[i].mat_nr]] += 6;
-               /* v1 v2 v3 */
-               VECCOPY2D(&varray[start],mtface[i].uv[0]);
-               VECCOPY2D(&varray[start+2],mtface[i].uv[1]);
-               VECCOPY2D(&varray[start+4],mtface[i].uv[2]);
-               if( mface[i].v4 ) {
-                       /* v3 v4 v1 */
-                       VECCOPY2D(&varray[start+6],mtface[i].uv[2]);
-                       VECCOPY2D(&varray[start+8],mtface[i].uv[3]);
-                       VECCOPY2D(&varray[start+10],mtface[i].uv[0]);
-               }
-       }
- }
- static GPUBuffer *GPU_buffer_uv( DerivedMesh *dm )
- {
-       DEBUG_VBO("GPU_buffer_uv\n");
-       if( DM_get_face_data_layer(dm, CD_MTFACE) != 0 )
-               return GPU_buffer_setup( dm, dm->drawObject, 2, sizeof(float)*2*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uv);
-       else
-               return 0;
- }
- static void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
- {
-       int i, numfaces;
-       unsigned char *varray = (unsigned char *)varray_;
-       unsigned char *mcol = (unsigned char *)user;
-       MFace *mface = dm->getTessFaceArray(dm);
-       DEBUG_VBO("GPU_buffer_copy_color3\n");
-       numfaces= dm->getNumTessFaces(dm);
-       for( i=0; i < numfaces; i++ ) {
-               int start = index[redir[mface[i].mat_nr]];
-               if( mface[i].v4 )
-                       index[redir[mface[i].mat_nr]] += 18;
-               else
-                       index[redir[mface[i].mat_nr]] += 9;
-               /* v1 v2 v3 */
-               VECCOPY(&varray[start],&mcol[i*12]);
-               VECCOPY(&varray[start+3],&mcol[i*12+3]);
-               VECCOPY(&varray[start+6],&mcol[i*12+6]);
-               if( mface[i].v4 ) {
-                       /* v3 v4 v1 */
-                       VECCOPY(&varray[start+9],&mcol[i*12+6]);
-                       VECCOPY(&varray[start+12],&mcol[i*12+9]);
-                       VECCOPY(&varray[start+15],&mcol[i*12]);
-               }
-       }
- }
- static void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
- {
-       int i, numfaces;
-       unsigned char *varray = (unsigned char *)varray_;
-       unsigned char *mcol = (unsigned char *)user;
-       MFace *mface = dm->getTessFaceArray(dm);
-       DEBUG_VBO("GPU_buffer_copy_color4\n");
-       numfaces= dm->getNumTessFaces(dm);
-       for( i=0; i < numfaces; i++ ) {
-               int start = index[redir[mface[i].mat_nr]];
-               if( mface[i].v4 )
-                       index[redir[mface[i].mat_nr]] += 18;
-               else
-                       index[redir[mface[i].mat_nr]] += 9;
-               /* v1 v2 v3 */
-               VECCOPY(&varray[start],&mcol[i*16]);
-               VECCOPY(&varray[start+3],&mcol[i*16+4]);
-               VECCOPY(&varray[start+6],&mcol[i*16+8]);
-               if( mface[i].v4 ) {
-                       /* v3 v4 v1 */
-                       VECCOPY(&varray[start+9],&mcol[i*16+8]);
-                       VECCOPY(&varray[start+12],&mcol[i*16+12]);
-                       VECCOPY(&varray[start+15],&mcol[i*16]);
-               }
-       }
- }
- static GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
- {
-       unsigned char *colors;
-       int i, numfaces;
-       MCol *mcol;
-       GPUBuffer *result;
-       DEBUG_VBO("GPU_buffer_color\n");
-       mcol = DM_get_face_data_layer(dm, CD_ID_MCOL);
-       dm->drawObject->colType = CD_ID_MCOL;
-       if(!mcol) {
-               mcol = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
-               dm->drawObject->colType = CD_WEIGHT_MCOL;
-       }
-       if(!mcol) {
-               mcol = DM_get_face_data_layer(dm, CD_MCOL);
-               dm->drawObject->colType = CD_MCOL;
-       }
-       numfaces= dm->getNumTessFaces(dm);
-       colors = MEM_mallocN(numfaces*12*sizeof(unsigned char), "GPU_buffer_color");
-       for( i=0; i < numfaces*4; i++ ) {
-               colors[i*3] = mcol[i].b;
-               colors[i*3+1] = mcol[i].g;
-               colors[i*3+2] = mcol[i].r;
-       }
-       result = GPU_buffer_setup( dm, dm->drawObject, 3, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, colors, GPU_buffer_copy_color3 );
-       MEM_freeN(colors);
-       return result;
- }
- static void GPU_buffer_copy_edge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(redir), void *UNUSED(user))
- {
-       int i;
-       MEdge *medge;
-       unsigned int *varray_ = (unsigned int *)varray;
-       int numedges;
-  
-       DEBUG_VBO("GPU_buffer_copy_edge\n");
-       medge = dm->getEdgeArray(dm);
-       numedges= dm->getNumEdges(dm);
-       for(i = 0; i < numedges; i++) {
-               varray_[i*2] = (unsigned int)dm->drawObject->indices[medge[i].v1].element;
-               varray_[i*2+1] = (unsigned int)dm->drawObject->indices[medge[i].v2].element;
-       }
- }
- static GPUBuffer *GPU_buffer_edge( DerivedMesh *dm )
- {
-       DEBUG_VBO("GPU_buffer_edge\n");
-       return GPU_buffer_setup( dm, dm->drawObject, 2, sizeof(int)*2*dm->drawObject->nedges, GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_edge);
- }
- static void GPU_buffer_copy_uvedge(DerivedMesh *dm, float *varray, int *UNUSED(index), int *UNUSED(redir), void *UNUSED(user))
- {
-       MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
-       int i, j=0;
-       DEBUG_VBO("GPU_buffer_copy_uvedge\n");
-       if(tf) {
-               for(i = 0; i < dm->numFaceData; i++, tf++) {
-                       MFace mf;
-                       dm->getTessFace(dm,i,&mf);
-                       VECCOPY2D(&varray[j],tf->uv[0]);
-                       VECCOPY2D(&varray[j+2],tf->uv[1]);
-                       VECCOPY2D(&varray[j+4],tf->uv[1]);
-                       VECCOPY2D(&varray[j+6],tf->uv[2]);
-                       if(!mf.v4) {
-                               VECCOPY2D(&varray[j+8],tf->uv[2]);
-                               VECCOPY2D(&varray[j+10],tf->uv[0]);
-                               j+=12;
-                       } else {
-                               VECCOPY2D(&varray[j+8],tf->uv[2]);
-                               VECCOPY2D(&varray[j+10],tf->uv[3]);
-                               VECCOPY2D(&varray[j+12],tf->uv[3]);
-                               VECCOPY2D(&varray[j+14],tf->uv[0]);
-                               j+=16;
-                       }
-               }
-       }
-       else {
-               DEBUG_VBO("Could not get MTFACE data layer");
-       }
- }
- static GPUBuffer *GPU_buffer_uvedge( DerivedMesh *dm )
- {
-       DEBUG_VBO("GPU_buffer_uvedge\n");
-       /* logic here:
-        * ...each face gets 3 'nelements'
-        * ...3 edges per triangle
-        * ...each edge has its own, non-shared coords.
-        * so each tri corner needs minimum of 4 floats, quads used less so here we can over allocate and assume all tris.
-        * */
-       return GPU_buffer_setup( dm, dm->drawObject, 4, 4 * sizeof(float) * dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uvedge);
- }
- void GPU_vertex_setup( DerivedMesh *dm )
- {
-       DEBUG_VBO("GPU_vertex_setup\n");
-       if( dm->drawObject == 0 )
-               dm->drawObject = GPU_drawobject_new( dm );
-       if( dm->drawObject->vertices == 0 )
-               dm->drawObject->vertices = GPU_buffer_vertex( dm );
-       if( dm->drawObject->vertices == 0 ) {
-               DEBUG_VBO( "Failed to setup vertices\n" );
-               return;
-       }
-       glEnableClientState( GL_VERTEX_ARRAY );
-       if( useVBOs ) {
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
-               glVertexPointer( 3, GL_FLOAT, 0, 0 );
-       }
-       else {
-               glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
-       }
-       
-       GLStates |= GPU_BUFFER_VERTEX_STATE;
- }
- void GPU_normal_setup( DerivedMesh *dm )
+ void GPU_edge_setup(DerivedMesh *dm)
  {
-       DEBUG_VBO("GPU_normal_setup\n");
-       if( dm->drawObject == 0 )
-               dm->drawObject = GPU_drawobject_new( dm );
-       if( dm->drawObject->normals == 0 )
-               dm->drawObject->normals = GPU_buffer_normal( dm );
-       if( dm->drawObject->normals == 0 ) {
-               DEBUG_VBO( "Failed to setup normals\n" );
+       if(!gpu_buffer_setup_common(dm, GPU_BUFFER_EDGE))
                return;
-       }
-       glEnableClientState( GL_NORMAL_ARRAY );
-       if( useVBOs ) {
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->normals->id );
-               glNormalPointer( GL_FLOAT, 0, 0 );
-       }
-       else {
-               glNormalPointer( GL_FLOAT, 0, dm->drawObject->normals->pointer );
-       }
-       GLStates |= GPU_BUFFER_NORMAL_STATE;
- }
- void GPU_uv_setup( DerivedMesh *dm )
- {
-       DEBUG_VBO("GPU_uv_setup\n");
-       if( dm->drawObject == 0 )
-               dm->drawObject = GPU_drawobject_new( dm );
-       if( dm->drawObject->uv == 0 )
-               dm->drawObject->uv = GPU_buffer_uv( dm );
-       
-       if( dm->drawObject->uv != 0 ) {
-               glEnableClientState( GL_TEXTURE_COORD_ARRAY );
-               if( useVBOs ) {
-                       glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id );
-                       glTexCoordPointer( 2, GL_FLOAT, 0, 0 );
-               }
-               else {
-                       glTexCoordPointer( 2, GL_FLOAT, 0, dm->drawObject->uv->pointer );
-               }
-               GLStates |= GPU_BUFFER_TEXCOORD_STATE;
-       }
- }
  
- void GPU_color_setup( DerivedMesh *dm )
- {
-       DEBUG_VBO("GPU_color_setup\n");
-       if( dm->drawObject == 0 )
-               dm->drawObject = GPU_drawobject_new( dm );
-       if( dm->drawObject->colors == 0 )
-               dm->drawObject->colors = GPU_buffer_color( dm );
-       if( dm->drawObject->colors == 0 ) {
-               DEBUG_VBO( "Failed to setup colors\n" );
-               return;
-       }
-       glEnableClientState( GL_COLOR_ARRAY );
-       if( useVBOs ) {
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->colors->id );
-               glColorPointer( 3, GL_UNSIGNED_BYTE, 0, 0 );
-       }
-       else {
-               glColorPointer( 3, GL_UNSIGNED_BYTE, 0, dm->drawObject->colors->pointer );
-       }
-       GLStates |= GPU_BUFFER_COLOR_STATE;
- }
- void GPU_edge_setup( DerivedMesh *dm )
- {
-       DEBUG_VBO("GPU_edge_setup\n");
-       if( dm->drawObject == 0 )
-               dm->drawObject = GPU_drawobject_new( dm );
-       if( dm->drawObject->edges == 0 )
-               dm->drawObject->edges = GPU_buffer_edge( dm );
-       if( dm->drawObject->edges == 0 ) {
-               DEBUG_VBO( "Failed to setup edges\n" );
-               return;
-       }
-       if( dm->drawObject->vertices == 0 )
-               dm->drawObject->vertices = GPU_buffer_vertex( dm );
-       if( dm->drawObject->vertices == 0 ) {
-               DEBUG_VBO( "Failed to setup vertices\n" );
+       if(!gpu_buffer_setup_common(dm, GPU_BUFFER_VERTEX))
                return;
-       }
  
-       glEnableClientState( GL_VERTEX_ARRAY );
-       if( useVBOs ) {
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->vertices->id );
-               glVertexPointer( 3, GL_FLOAT, 0, 0 );
+       glEnableClientState(GL_VERTEX_ARRAY);
+       if(useVBOs) {
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->points->id);
+               glVertexPointer(3, GL_FLOAT, 0, 0);
        }
        else {
-               glVertexPointer( 3, GL_FLOAT, 0, dm->drawObject->vertices->pointer );
+               glVertexPointer(3, GL_FLOAT, 0, dm->drawObject->points->pointer);
        }
        
        GLStates |= GPU_BUFFER_VERTEX_STATE;
index 2b2b0b79402a17fa6ee5abd742709a6173e449f2,390a780e9e6f4d4380875cce1e283f52f4f33977..7d5c6c7aa7c071bdf341955668cc26ee3471c66a
@@@ -233,25 -236,15 +234,24 @@@ static DerivedMesh *applyModifier(Modif
        float const ofs_new= smd->offset        - (((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
  
        /* weights */
-       MDeformVert *dvert= NULL, *dv= NULL;
+       MDeformVert *dvert, *dv= NULL;
        const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
-       const int defgrp_index= defgroup_name_index(ob, smd->defgrp_name);
+       int defgrp_index;
  
-       if (defgrp_index >= 0)
-               dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+       modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
 -
 -      orig_mface = dm->getFaceArray(dm);
 -      orig_medge = dm->getEdgeArray(dm);
 -      orig_mvert = dm->getVertArray(dm);
 +      
 +      if (!CDDM_Check(dm)) {
 +              DerivedMesh *dm2 = CDDM_copy(dm, 0);
 +              dm = dm2;
 +      }
 +      
 +      numLoops = dm->numLoopData;
 +      newLoops = 0;
 +      
 +      orig_mvert = CDDM_get_verts(dm);
 +      orig_medge = CDDM_get_edges(dm);
 +      orig_mloop = CDDM_get_loops(dm);
 +      orig_mpoly = CDDM_get_polys(dm);
  
        if(smd->flag & MOD_SOLIDIFY_RIM) {
                EdgeHash *edgehash = BLI_edgehash_new();
index d991dbfbdc34c2ac01ed8010491c2c71fb4a3979,b9b5c8a064a1796749445e3b1750e3fc4018d562..07d0ed37d3d274b1c2298ded4b3028899d38597e
@@@ -49,7 -50,8 +50,8 @@@ void get_texture_value(struct Tex *text
  void get_texture_coords(struct MappingInfoModifierData *dmd, struct Object *ob, struct DerivedMesh *dm, float (*co)[3], float (*texco)[3], int numVerts);
  void modifier_vgroup_cache(struct ModifierData *md, float (*vertexCos)[3]);
  void validate_layer_name(const struct CustomData *data, int type, char *name, char *outname);
 -struct DerivedMesh *get_cddm(struct Object *ob, struct EditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3]);
 -struct DerivedMesh *get_dm(struct Object *ob, struct EditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3], int orco);
 +struct DerivedMesh *get_cddm(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3]);
 +struct DerivedMesh *get_dm(struct Object *ob, struct BMEditMesh *em, struct DerivedMesh *dm, float (*vertexCos)[3], int orco);
+ void modifier_get_vgroup(struct Object *ob, DerivedMesh *dm, const char *name, struct MDeformVert **dvert, int *defgrp_index);
  
  #endif /* MOD_UTIL_H */
Simple merge