Merging r38237 through r38264 from trunk into soc-2011-tomato
authorSergey Sharybin <sergey.vfx@gmail.com>
Sat, 9 Jul 2011 17:49:36 +0000 (17:49 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Sat, 9 Jul 2011 17:49:36 +0000 (17:49 +0000)
intern/ghost/test/CMakeLists.txt
intern/ghost/test/multitest/MultiTest.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/node.c
source/blender/editors/armature/poseUtils.c
source/blender/editors/object/object_relations.c
source/blender/gpu/GPU_buffers.h
source/blender/gpu/intern/gpu_buffers.c
source/blender/render/intern/source/convertblender.c
source/blender/windowmanager/intern/wm_init_exit.c

index b8630427b71cfc46f7dfd2faeb36bccec64e8158..a012f6af61cd5739f77fd6af97d3f502879bf451 100644 (file)
@@ -58,11 +58,41 @@ suffix_relpaths(SRC_NEW "${SRC}" "../../guardedalloc/")
 include_directories(${INC_NEW})
 add_library(guardedalloc_lib ${SRC_NEW})
 
+# blenfont 
+include(${CMAKE_SOURCE_DIR}/../../../source/blender/blenfont/CMakeLists.txt)
+suffix_relpaths(INC_NEW "${INC}" "../../../source/blender/blenfont/")
+suffix_relpaths(SRC_NEW "${SRC}" "../../../source/blender/blenfont/")
+include_directories(${INC_NEW})
+add_library(blenfont_lib ${SRC_NEW})
+
+# grr, blenfont needs BLI
+include_directories(
+               "../../../source/blender/blenlib"
+               "../../../source/blender/blenloader"
+               )
+add_library(bli_lib 
+               "../../../source/blender/blenlib/intern/fileops.c"
+               "../../../source/blender/blenlib/intern/rct.c"
+               "../../../source/blender/blenlib/intern/string.c"
+               "../../../source/blender/blenlib/intern/listbase.c"
+               "../../../source/blender/blenlib/intern/storage.c"
+               "../../../source/blender/blenlib/intern/path_util.c"
+               "../../../source/blender/blenlib/intern/BLI_dynstr.c"
+               "../../../source/blender/blenlib/intern/BLI_linklist.c"
+               "../../../source/blender/blenlib/intern/BLI_memarena.c"
+               )
+
+message(STATUS "EEEk ${SRC_NEW}")
+
 
 find_package(OpenGL REQUIRED)
 
+find_package(Freetype REQUIRED)
+
 include_directories(${CMAKE_SOURCE_DIR}/../)
 include_directories(${OPENGL_INCLUDE_DIR})
+include_directories(${FREETYPE_INCLUDE_DIRS})
+include_directories(${CMAKE_SOURCE_DIR}/../../../source/blender/blenfont)
 
 if(UNIX AND NOT APPLE)
        find_package(X11 REQUIRED)
@@ -105,6 +135,7 @@ target_link_libraries(gears_cpp
 
 # MultiTest (C)
 add_executable(multitest_c
+       ${CMAKE_SOURCE_DIR}/../../../source/blender/editors/datafiles/bfont.ttf.c
        ${CMAKE_SOURCE_DIR}/multitest/Basic.c
        ${CMAKE_SOURCE_DIR}/multitest/EventToBuf.c
        ${CMAKE_SOURCE_DIR}/multitest/MultiTest.c
@@ -114,10 +145,13 @@ add_executable(multitest_c
 )
 
 target_link_libraries(multitest_c
+               blenfont_lib
+               bli_lib
                ghost_lib
                string_lib
                guardedalloc_lib
                ${OPENGL_gl_LIBRARY}
                ${OPENGL_glu_LIBRARY}
+               ${FREETYPE_LIBRARY}
                ${PLATFORM_LINKLIBS}
                )
index 848601b2cc705cf3eff91b3ed73ccc4ff8cc520a..00939e907d669dba5ebabacd39263255fe699e03 100644 (file)
 #include "MEM_guardedalloc.h"
 
 #include "GHOST_C-api.h"
-#include "BMF_Api.h"
+
+#ifdef USE_BMF
+#  include "BMF_Api.h"
+#else
+#  include "BLF_api.h"
+   extern int datatoc_bfont_ttf_size;
+   extern char datatoc_bfont_ttf[];
+
+   // XXX, bad, but BLI uses these
+   char bprogname[160]= "";
+char U[1024]= {0};
+#endif
 
 #include "Util.h"
 #include "Basic.h"
@@ -291,7 +302,7 @@ MainWindow *mainwindow_new(MultiTestApp *app) {
        
        win= GHOST_CreateWindow(sys, "MultiTest:Main", 40, 40, 400, 400, 
                GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, 
-               FALSE);
+               FALSE, FALSE);
        
        if (win) {
                MainWindow *mw= MEM_callocN(sizeof(*mw), "mainwindow_new");
@@ -324,8 +335,12 @@ struct _LoggerWindow {
        MultiTestApp            *app;
 
        GHOST_WindowHandle      win;
-       
+
+#ifdef USE_BMF 
        BMF_Font        *font;
+#else
+       int                     font;
+#endif
        int                     fonttexid;
        int                     fontheight;
        
@@ -429,18 +444,26 @@ static void loggerwindow_do_draw(LoggerWindow *lw) {
                char *line= lw->loglines[(lw->nloglines-1)-(i+startline)];
                int x_pos= lw->textarea[0][0] + 4;
                int y_pos= lw->textarea[0][1] + 4 + i*lw->fontheight;
-               
+
+#ifdef USE_BMF         
                if (lw->fonttexid==-1) {
                        glRasterPos2i(x_pos, y_pos);
                        BMF_DrawString(lw->font, line);
                } else {
                        BMF_DrawStringTexture(lw->font, line, x_pos, y_pos, 0.0);
                }
+#else
+               BLF_position(lw->font, x_pos, y_pos, 0.0);
+               BLF_draw(lw->font, line, 256); // XXX
+#endif
        }
+
+#ifdef USE_BMF
        if (lw->fonttexid!=-1) {
                glDisable(GL_TEXTURE_2D);               
                glDisable(GL_BLEND);
        }
+#endif
 
        GHOST_SwapWindowBuffers(lw->win);
 }
@@ -531,19 +554,25 @@ LoggerWindow *loggerwindow_new(MultiTestApp *app) {
        GHOST_GetMainDisplayDimensions(sys, &screensize[0], &screensize[1]);
        win= GHOST_CreateWindow(sys, "MultiTest:Logger", 40, screensize[1]-432,
                800, 300, GHOST_kWindowStateNormal, 
-               GHOST_kDrawingContextTypeOpenGL, FALSE);
+               GHOST_kDrawingContextTypeOpenGL, FALSE, FALSE);
        
        if (win) {
                LoggerWindow *lw= MEM_callocN(sizeof(*lw), "loggerwindow_new");
                int bbox[2][2];
                lw->app= app;
                lw->win= win;
-               
+
+#ifdef USE_BMF
                lw->font= BMF_GetFont(BMF_kScreen12);
                lw->fonttexid= BMF_GetFontTexture(lw->font);
 
                BMF_GetBoundingBox(lw->font, &bbox[0][0], &bbox[0][1], &bbox[1][0], &bbox[1][1]);
                lw->fontheight= rect_height(bbox);
+#else
+               lw->font= BLF_load_mem("default", (unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
+               BLF_size(lw->font, 11, 72);
+               lw->fontheight= BLF_height(lw->font, "A_");
+#endif
                
                lw->nloglines= lw->logsize= 0;
                lw->loglines= MEM_mallocN(sizeof(*lw->loglines)*lw->nloglines, "loglines");
@@ -711,7 +740,7 @@ ExtraWindow *extrawindow_new(MultiTestApp *app) {
        
        win= GHOST_CreateWindow(sys, "MultiTest:Extra", 500, 40, 400, 400, 
                GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL,
-               FALSE);
+               FALSE, FALSE);
        
        if (win) {
                ExtraWindow *ew= MEM_callocN(sizeof(*ew), "mainwindow_new");
@@ -786,7 +815,7 @@ static int multitest_event_handler(GHOST_EventHandle evt, GHOST_TUserDataPtr dat
 MultiTestApp *multitestapp_new(void) {
        MultiTestApp *app= MEM_mallocN(sizeof(*app), "multitestapp_new");
        GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(multitest_event_handler, app);
-       
+
        app->sys= GHOST_CreateSystem();
        if (!app->sys)
                fatal("Unable to create ghost system");
@@ -850,6 +879,10 @@ void multitestapp_free(MultiTestApp *app) {
        /***/
        
 int main(int argc, char **argv) {
+#ifndef USE_BMF
+       BLF_init(11, 72);
+#endif
+
        MultiTestApp *app= multitestapp_new();
        
        multitestapp_run(app);
index 72ee9b55800ff13cc029f2d7d2982e16036fde3f..3abfa05e1fd5bb6ff88f4f7b788fe58dd8c38aba 100644 (file)
@@ -284,8 +284,10 @@ static void cdDM_drawVerts(DerivedMesh *dm)
        else {  /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
                GPU_vertex_setup(dm);
                if( !GPU_buffer_legacy(dm) ) {
-                       if(dm->drawObject->nelements)   glDrawArrays(GL_POINTS,0, dm->drawObject->nelements);
-                       else                                                    glDrawArrays(GL_POINTS,0, dm->drawObject->nlooseverts);
+                       if(dm->drawObject->tot_triangle_point)
+                               glDrawArrays(GL_POINTS,0, dm->drawObject->tot_triangle_point);
+                       else
+                               glDrawArrays(GL_POINTS,0, dm->drawObject->tot_loose_point);
                }
                GPU_buffer_unbind();
        }
@@ -547,9 +549,10 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
                GPU_normal_setup( dm );
                if( !GPU_buffer_legacy(dm) ) {
                        glShadeModel(GL_SMOOTH);
-                       for( a = 0; a < dm->drawObject->nmaterials; a++ ) {
+                       for( a = 0; a < dm->drawObject->totmaterial; a++ ) {
                                if( setMaterial(dm->drawObject->materials[a].mat_nr+1, NULL) )
-                                       glDrawArrays(GL_TRIANGLES, dm->drawObject->materials[a].start, dm->drawObject->materials[a].end-dm->drawObject->materials[a].start);
+                                       glDrawArrays(GL_TRIANGLES, dm->drawObject->materials[a].start,
+                                                    dm->drawObject->materials[a].totpoint);
                        }
                }
                GPU_buffer_unbind( );
@@ -629,13 +632,13 @@ static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned cha
                GPU_color_setup(dm);
                if( !GPU_buffer_legacy(dm) ) {
                        glShadeModel(GL_SMOOTH);
-                       glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->nelements);
+                       glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->tot_triangle_point);
 
                        if( useTwoSided ) {
                                GPU_color4_upload(dm,cp2);
                                GPU_color_setup(dm);
                                glCullFace(GL_FRONT);
-                               glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->nelements);
+                               glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->tot_triangle_point);
                                glCullFace(GL_BACK);
                        }
                }
@@ -787,8 +790,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                        
                        glShadeModel( GL_SMOOTH );
                        lastFlag = 0;
-                       for(i = 0; i < dm->drawObject->nelements/3; i++) {
-                               int actualFace = dm->drawObject->faceRemap[i];
+                       for(i = 0; i < dm->drawObject->tot_triangle_point/3; i++) {
+                               int actualFace = dm->drawObject->triangle_to_mface[i];
                                int flag = 1;
 
                                if(drawParams) {
@@ -819,13 +822,13 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                                        startFace = i;
                                }
                        }
-                       if( startFace < dm->drawObject->nelements/3 ) {
+                       if( startFace < dm->drawObject->tot_triangle_point/3 ) {
                                if( lastFlag != 0 ) { /* if the flag is 0 it means the face is hidden or invisible */
                                        if (lastFlag==1 && col)
                                                GPU_color_switch(1);
                                        else
                                                GPU_color_switch(0);
-                                       glDrawArrays(GL_TRIANGLES,startFace*3,dm->drawObject->nelements-startFace*3);
+                                       glDrawArrays(GL_TRIANGLES, startFace*3, dm->drawObject->tot_triangle_point - startFace*3);
                                }
                        }
                }
@@ -935,7 +938,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
                if( useColors && mc )
                        GPU_color_setup(dm);
                if( !GPU_buffer_legacy(dm) ) {
-                       int tottri = dm->drawObject->nelements/3;
+                       int tottri = dm->drawObject->tot_triangle_point/3;
                        glShadeModel(GL_SMOOTH);
                        
                        if(tottri == 0) {
@@ -947,17 +950,17 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
                        }
                        else {
                                /* we need to check if the next material changes */
-                               int next_actualFace= dm->drawObject->faceRemap[0];
+                               int next_actualFace= dm->drawObject->triangle_to_mface[0];
                                
                                for( i = 0; i < tottri; i++ ) {
-                                       //int actualFace = dm->drawObject->faceRemap[i];
+                                       //int actualFace = dm->drawObject->triangle_to_mface[i];
                                        int actualFace = next_actualFace;
                                        MFace *mface= mf + actualFace;
                                        int drawSmooth= (mface->flag & ME_SMOOTH);
                                        int draw = 1;
 
                                        if(i != tottri-1)
-                                               next_actualFace= dm->drawObject->faceRemap[i+1];
+                                               next_actualFace= dm->drawObject->triangle_to_mface[i+1];
 
                                        orig= (index==NULL) ? actualFace : index[actualFace];
 
@@ -1129,9 +1132,9 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                GPU_normal_setup(dm);
 
                if( !GPU_buffer_legacy(dm) ) {
-                       for( i = 0; i < dm->drawObject->nelements/3; i++ ) {
+                       for( i = 0; i < dm->drawObject->tot_triangle_point/3; i++ ) {
 
-                               a = dm->drawObject->faceRemap[i];
+                               a = dm->drawObject->triangle_to_mface[i];
 
                                mface = mf + a;
                                new_matnr = mface->mat_nr + 1;
@@ -1153,7 +1156,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
 
                                                        if( numdata != 0 ) {
 
-                                                               GPU_buffer_free(buffer, NULL);
+                                                               GPU_buffer_free(buffer);
 
                                                                buffer = NULL;
                                                        }
@@ -1193,7 +1196,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                                }
                                                if( numdata != 0 ) {
                                                        elementsize = GPU_attrib_element_size( datatypes, numdata );
-                                                       buffer = GPU_buffer_alloc( elementsize*dm->drawObject->nelements, NULL );
+                                                       buffer = GPU_buffer_alloc( elementsize*dm->drawObject->tot_triangle_point);
                                                        if( buffer == NULL ) {
                                                                GPU_buffer_unbind();
                                                                dm->drawObject->legacy = 1;
@@ -1202,7 +1205,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                                        varray = GPU_buffer_lock_stream(buffer);
                                                        if( varray == NULL ) {
                                                                GPU_buffer_unbind();
-                                                               GPU_buffer_free(buffer, NULL);
+                                                               GPU_buffer_free(buffer);
                                                                dm->drawObject->legacy = 1;
                                                                return;
                                                        }
@@ -1341,7 +1344,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                        }
                        GPU_buffer_unbind();
                }
-               GPU_buffer_free( buffer, NULL );
+               GPU_buffer_free(buffer);
        }
 
        glShadeModel(GL_FLAT);
index 704af73dd10fc4f70b23a425ab61979564b88328..202a3f28d9ab6750e2871c06628d6a122aee5402 100644 (file)
@@ -2431,6 +2431,7 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
 {
        float *p1,*p2,*p3, pt[3];
        float dx1,dy1,dz1,dx,dy,dz,vx,vy,vz,len,len1,len2;
+       const float eps= 1e-5;
 
        if(bezt->h1==0 && bezt->h2==0) return;
 
@@ -2587,30 +2588,38 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
 
        if(bezt->f1 & SELECT) { /* order of calculation */
                if(bezt->h2==HD_ALIGN) {        /* aligned */
-                       len= len2/len1;
-                       p2[3]= p2[0]+len*(p2[0]-p2[-3]);
-                       p2[4]= p2[1]+len*(p2[1]-p2[-2]);
-                       p2[5]= p2[2]+len*(p2[2]-p2[-1]);
+                       if(len1>eps) {
+                               len= len2/len1;
+                               p2[3]= p2[0]+len*(p2[0]-p2[-3]);
+                               p2[4]= p2[1]+len*(p2[1]-p2[-2]);
+                               p2[5]= p2[2]+len*(p2[2]-p2[-1]);
+                       }
                }
                if(bezt->h1==HD_ALIGN) {
-                       len= len1/len2;
-                       p2[-3]= p2[0]+len*(p2[0]-p2[3]);
-                       p2[-2]= p2[1]+len*(p2[1]-p2[4]);
-                       p2[-1]= p2[2]+len*(p2[2]-p2[5]);
+                       if(len2>eps) {
+                               len= len1/len2;
+                               p2[-3]= p2[0]+len*(p2[0]-p2[3]);
+                               p2[-2]= p2[1]+len*(p2[1]-p2[4]);
+                               p2[-1]= p2[2]+len*(p2[2]-p2[5]);
+                       }
                }
        }
        else {
                if(bezt->h1==HD_ALIGN) {
-                       len= len1/len2;
-                       p2[-3]= p2[0]+len*(p2[0]-p2[3]);
-                       p2[-2]= p2[1]+len*(p2[1]-p2[4]);
-                       p2[-1]= p2[2]+len*(p2[2]-p2[5]);
+                       if(len2>eps) {
+                               len= len1/len2;
+                               p2[-3]= p2[0]+len*(p2[0]-p2[3]);
+                               p2[-2]= p2[1]+len*(p2[1]-p2[4]);
+                               p2[-1]= p2[2]+len*(p2[2]-p2[5]);
+                       }
                }
                if(bezt->h2==HD_ALIGN) {        /* aligned */
-                       len= len2/len1;
-                       p2[3]= p2[0]+len*(p2[0]-p2[-3]);
-                       p2[4]= p2[1]+len*(p2[1]-p2[-2]);
-                       p2[5]= p2[2]+len*(p2[2]-p2[-1]);
+                       if(len1>eps) {
+                               len= len2/len1;
+                               p2[3]= p2[0]+len*(p2[0]-p2[-3]);
+                               p2[4]= p2[1]+len*(p2[1]-p2[-2]);
+                               p2[5]= p2[2]+len*(p2[2]-p2[-1]);
+                       }
                }
        }
 }
index 518ee3c341a61234dbbafbc690daa883fda34375..13469e0b58bcb0a0c93cf942d8af9dd2ac04bf25 100644 (file)
@@ -2418,6 +2418,11 @@ void ntreeBeginExecTree(bNodeTree *ntree)
                
                if(ntree->type==NTREE_COMPOSIT)
                        composit_begin_exec(ntree, ntree->stack);
+               
+               /* ensures only a single output node is enabled, texnode allows multiple though */
+               if(ntree->type!=NTREE_TEXTURE)
+                       ntreeSetOutput(ntree);
+               
        }
        
        ntree->init |= NTREE_EXEC_INIT;
@@ -2765,9 +2770,6 @@ void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
        /* fixed seed, for example noise texture */
        BLI_srandom(rd->cfra);
 
-       /* ensures only a single output node is enabled */
-       ntreeSetOutput(ntree);
-
        /* sets need_exec tags in nodes */
        curnode = totnode= setExecutableNodes(ntree, &thdata);
 
index 7ade93076e5a44f8e07f5db87104f9ea8534fe5b..3c74a816fdbcbf096a9079d375da27ca76fdfa0a 100644 (file)
@@ -121,7 +121,7 @@ static void fcurves_to_pchan_links_get (ListBase *pfLinks, Object *ob, bAction *
                pfl->oldangle = pchan->rotAngle;
                
                /* make copy of custom properties */
-               if (transFlags & ACT_TRANS_PROP)
+               if (pchan->prop && (transFlags & ACT_TRANS_PROP))
                        pfl->oldprops = IDP_CopyProperty(pchan->prop);
        }
 } 
index 285b08c521bac37069d2116a19b448c9356c30f4..f21241b6e7afd0ecd84ac72c14d241c49187a816 100644 (file)
@@ -1319,7 +1319,7 @@ void OBJECT_OT_make_links_scene(wmOperatorType *ot)
 
        /* identifiers */
        ot->name= "Link Objects to Scene";
-       ot->description = "Make linked data local to each object";
+       ot->description = "Link selection to another scene";
        ot->idname= "OBJECT_OT_make_links_scene";
 
        /* api callbacks */
index 7ce166d92bd9844572efcd23ab1782aa70c40d1b..6cee9e95cf6f4f65a096b5331ef93832a8a66aeb 100644 (file)
@@ -37,8 +37,6 @@
 #ifndef __GPU_BUFFERS_H__
 #define __GPU_BUFFERS_H__
 
-#define MAX_FREE_GPU_BUFFERS 8
-
 #ifdef _DEBUG
 /*#define DEBUG_VBO(X) printf(X)*/
 #define DEBUG_VBO(X)
 #define DEBUG_VBO(X)
 #endif
 
-#ifdef _DEBUG
-#define ERROR_VBO(X) printf(X)
-#else
-#define ERROR_VBO(X)
-#endif
-
 struct DerivedMesh;
 struct DMGridData;
 struct GHash;
 struct DMGridData;
+struct GPUVertPointLink;
 
-/* V - vertex, N - normal, T - uv, C - color
-   F - float, UB - unsigned byte */
-#define GPU_BUFFER_INTER_V3F   1
-#define GPU_BUFFER_INTER_N3F   2
-#define GPU_BUFFER_INTER_T2F   3
-#define GPU_BUFFER_INTER_C3UB  4
-#define GPU_BUFFER_INTER_C4UB  5
-#define GPU_BUFFER_INTER_END   -1
-
-typedef struct GPUBuffer
-{
+typedef struct GPUBuffer {
        int size;       /* in bytes */
        void *pointer;  /* used with vertex arrays */
        unsigned int id;        /* used with vertex buffer objects */
 } GPUBuffer;
 
-/* stores deleted buffers so that new buffers wouldn't have to 
-be recreated that often. */
-typedef struct GPUBufferPool
-{
-       int size;               /* number of allocated buffers stored */
-       int maxsize;    /* size of the array */
-       GPUBuffer **buffers;
-} GPUBufferPool;
-
-typedef struct GPUBufferMaterial
-{
-       int start;      /* at which vertex in the buffer the material starts */
-       int end;        /* at which vertex it ends */
-       char mat_nr;
-} GPUBufferMaterial;
+typedef struct GPUBufferMaterial {
+       /* range of points used for this material */
+       int start;
+       int totpoint;
 
-typedef struct IndexLink {
-       int element;
-       struct IndexLink *next;
-} IndexLink;
+       /* original material index */
+       short mat_nr;
+} GPUBufferMaterial;
 
-typedef struct GPUDrawObject
-{
-       GPUBuffer *vertices;
+/* meshes are split up by material since changing materials requires
+   GL state changes that can't occur in the middle of drawing an
+   array.
+
+   some simplifying assumptions are made:
+   * all quads are treated as two triangles.
+   * no vertex sharing is used; each triangle gets its own copy of the
+     vertices it uses (this makes it easy to deal with a vertex used
+     by faces with different properties, such as smooth/solid shading,
+     different MCols, etc.)
+
+   to avoid confusion between the original MVert vertices and the
+   arrays of OpenGL vertices, the latter are referred to here and in
+   the source as `points'. similarly, the OpenGL triangles generated
+   for MFaces are referred to as triangles rather than faces.
+ */
+typedef struct GPUDrawObject {
+       GPUBuffer *points;
        GPUBuffer *normals;
        GPUBuffer *uv;
        GPUBuffer *colors;
        GPUBuffer *edges;
        GPUBuffer *uvedges;
 
-       int     *faceRemap;                     /* at what index was the face originally in DerivedMesh */
-       IndexLink *indices;             /* given an index, find all elements using it */
-       IndexLink *indexMem;    /* for faster memory allocation/freeing */
-       int indexMemUsage;              /* how many are already allocated */
+       /* for each triangle, the original MFace index */
+       int *triangle_to_mface;
+
+       /* for each original vertex, the list of related points */
+       struct GPUVertPointLink *vert_points;
+       /* storage for the vert_points lists */
+       struct GPUVertPointLink *vert_points_mem;
+       int vert_points_usage;
+       
        int colType;
 
        GPUBufferMaterial *materials;
-
-       int nmaterials;
-       int nelements;  /* (number of faces) * 3 */
-       int nlooseverts;
-       int nedges;
-       int nindices;
-       int legacy;     /* if there was a failure allocating some buffer, use old rendering code */
-
+       int totmaterial;
+       
+       int tot_triangle_point;
+       int tot_loose_point;
+       
+       /* caches of the original DerivedMesh values */
+       int totvert;
+       int totedge;
+
+       /* if there was a failure allocating some buffer, use old
+          rendering code */
+       int legacy;
 } GPUDrawObject;
 
 /* used for GLSL materials */
-typedef struct GPUAttrib
-{
+typedef struct GPUAttrib {
        int index;
        int size;
        int type;
 } GPUAttrib;
 
-GPUBufferPool *GPU_buffer_pool_new(void);
-void GPU_buffer_pool_free( GPUBufferPool *pool );
-void GPU_buffer_pool_free_unused( GPUBufferPool *pool );
+void GPU_global_buffer_pool_free(void);
 
-GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool );
-void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool );
+GPUBuffer *GPU_buffer_alloc(int size);
+void GPU_buffer_free(GPUBuffer *buffer);
 
 GPUDrawObject *GPU_drawobject_new( struct DerivedMesh *dm );
 void GPU_drawobject_free( struct DerivedMesh *dm );
 
-/* Buffers for non-DerivedMesh drawing */
-void *GPU_build_mesh_buffers(struct GHash *map, struct MVert *mvert,
-                       struct MFace *mface, int *face_indices,
-                       int totface, int *vert_indices, int uniq_verts,
-                       int totvert);
-void GPU_update_mesh_buffers(void *buffers, struct MVert *mvert,
-                       int *vert_indices, int totvert);
-void *GPU_build_grid_buffers(struct DMGridData **grids,
-       int *grid_indices, int totgrid, int gridsize);
-void GPU_update_grid_buffers(void *buffers_v, struct DMGridData **grids,
-       int *grid_indices, int totgrid, int gridsize, int smooth);
-void GPU_draw_buffers(void *buffers);
-void GPU_free_buffers(void *buffers);
-
 /* called before drawing */
 void GPU_vertex_setup( struct DerivedMesh *dm );
 void GPU_normal_setup( struct DerivedMesh *dm );
@@ -175,6 +153,7 @@ void GPU_color4_upload( struct DerivedMesh *dm, unsigned char *data );
 /* switch color rendering on=1/off=0 */
 void GPU_color_switch( int mode );
 
+/* used for drawing edges */
 void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count );
 
 /* called after drawing */
@@ -183,4 +162,18 @@ void GPU_buffer_unbind(void);
 /* used to check whether to use the old (without buffers) code */
 int GPU_buffer_legacy( struct DerivedMesh *dm );
 
+/* Buffers for non-DerivedMesh drawing */
+void *GPU_build_mesh_buffers(struct GHash *map, struct MVert *mvert,
+                       struct MFace *mface, int *face_indices,
+                       int totface, int *vert_indices, int uniq_verts,
+                       int totvert);
+void GPU_update_mesh_buffers(void *buffers, struct MVert *mvert,
+                       int *vert_indices, int totvert);
+void *GPU_build_grid_buffers(struct DMGridData **grids,
+       int *grid_indices, int totgrid, int gridsize);
+void GPU_update_grid_buffers(void *buffers_v, struct DMGridData **grids,
+       int *grid_indices, int totgrid, int gridsize, int smooth);
+void GPU_draw_buffers(void *buffers);
+void GPU_free_buffers(void *buffers);
+
 #endif
index 3715dbe192c097a27d7f5bac1a15ca1e5858eb8e..4d4561e66db514290f423da34353af88df14ede2 100644 (file)
 
 #include "GPU_buffers.h"
 
-#define GPU_BUFFER_VERTEX_STATE 1
-#define GPU_BUFFER_NORMAL_STATE 2
-#define GPU_BUFFER_TEXCOORD_STATE 4
-#define GPU_BUFFER_COLOR_STATE 8
-#define GPU_BUFFER_ELEMENT_STATE 16
+typedef enum {
+       GPU_BUFFER_VERTEX_STATE = 1,
+       GPU_BUFFER_NORMAL_STATE = 2,
+       GPU_BUFFER_TEXCOORD_STATE = 4,
+       GPU_BUFFER_COLOR_STATE = 8,
+       GPU_BUFFER_ELEMENT_STATE = 16,
+} GPUBufferState;
 
 #define MAX_GPU_ATTRIB_DATA 32
 
 
 /* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
 static int useVBOs = -1;
-static GPUBufferPool *globalPool = 0;
-static int GLStates = 0;
+static GPUBufferState GLStates = 0;
 static GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
 
-GPUBufferPool *GPU_buffer_pool_new(void)
+/* stores recently-deleted buffers so that new buffers won't have to
+   be recreated as often
+
+   only one instance of this pool is created, stored in
+   gpu_buffer_pool
+
+   note that the number of buffers in the pool is usually limited to
+   MAX_FREE_GPU_BUFFERS, but this limit may be exceeded temporarily
+   when a GPUBuffer is released outside the main thread; due to OpenGL
+   restrictions it cannot be immediately released
+ */
+typedef struct GPUBufferPool {
+       /* number of allocated buffers stored */
+       int totbuf;
+       /* actual allocated length of the array */
+       int maxsize;
+       GPUBuffer **buffers;
+} GPUBufferPool;
+#define MAX_FREE_GPU_BUFFERS 8
+
+/* create a new GPUBufferPool */
+static GPUBufferPool *gpu_buffer_pool_new(void)
 {
        GPUBufferPool *pool;
 
-       DEBUG_VBO("GPU_buffer_pool_new\n");
+       /* enable VBOs if supported */
+       if(useVBOs == -1)
+               useVBOs = (GLEW_ARB_vertex_buffer_object ? 1 : 0);
 
-       if( useVBOs < 0 ) {
-               if( GLEW_ARB_vertex_buffer_object ) {
-                       DEBUG_VBO( "Vertex Buffer Objects supported.\n" );
-                       useVBOs = 1;
-               }
-               else {
-                       DEBUG_VBO( "Vertex Buffer Objects NOT supported.\n" );
-                       useVBOs = 0;
-               }
-       }
+       pool = MEM_callocN(sizeof(GPUBufferPool), "GPUBuffer");
 
-       pool = MEM_callocN(sizeof(GPUBufferPool), "GPU_buffer_pool_new");
        pool->maxsize = MAX_FREE_GPU_BUFFERS;
-       pool->buffers = MEM_callocN(sizeof(GPUBuffer*)*pool->maxsize, "GPU_buffer_pool_new buffers");
+       pool->buffers = MEM_callocN(sizeof(GPUBuffer*)*pool->maxsize,
+                                   "GPUBuffer.buffers");
 
        return pool;
 }
 
-static void GPU_buffer_pool_remove( int index, GPUBufferPool *pool )
+/* remove a GPUBuffer from the pool (does not free the GPUBuffer) */
+static void gpu_buffer_pool_remove_index(GPUBufferPool *pool, int index)
 {
        int i;
 
-       if( index >= pool->size || index < 0 ) {
-               ERROR_VBO("Wrong index, out of bounds in call to GPU_buffer_pool_remove");
+       if(!pool || index < 0 || index >= pool->totbuf)
                return;
-       }
-       DEBUG_VBO("GPU_buffer_pool_remove\n");
 
-       for( i = index; i < pool->size-1; i++ ) {
+       /* shift entries down, overwriting the buffer at `index' */
+       for(i = index; i < pool->totbuf - 1; i++)
                pool->buffers[i] = pool->buffers[i+1];
-       }
-       if( pool->size > 0 )
-               pool->buffers[pool->size-1] = 0;
 
-       pool->size--;
+       /* clear the last entry */
+       if(pool->totbuf > 0)
+               pool->buffers[pool->totbuf - 1] = NULL;
+
+       pool->totbuf--;
 }
 
-static void GPU_buffer_pool_delete_last( GPUBufferPool *pool )
+/* delete the last entry in the pool */
+static void gpu_buffer_pool_delete_last(GPUBufferPool *pool)
 {
-       int last;
+       GPUBuffer *last;
 
-       DEBUG_VBO("GPU_buffer_pool_delete_last\n");
+       if(pool->totbuf <= 0)
+               return;
 
-       if( pool->size <= 0 )
+       /* get the last entry */
+       if(!(last = pool->buffers[pool->totbuf - 1]))
                return;
 
-       last = pool->size-1;
+       /* delete the buffer's data */
+       if(useVBOs)
+               glDeleteBuffersARB(1, &last->id);
+       else
+               MEM_freeN(last->pointer);
 
-       if( pool->buffers[last] != 0 ) {
-               if( useVBOs ) {
-                       glDeleteBuffersARB(1,&pool->buffers[last]->id);
-                       MEM_freeN( pool->buffers[last] );
-               }
-               else {
-                       MEM_freeN( pool->buffers[last]->pointer );
-                       MEM_freeN( pool->buffers[last] );
-               }
-               pool->buffers[last] = 0;
-       } else {
-               DEBUG_VBO("Why are we accessing a null buffer?\n");
-       }
-       pool->size--;
+       /* delete the buffer and remove from pool */
+       MEM_freeN(last);
+       pool->totbuf--;
+       pool->buffers[pool->totbuf] = NULL;
 }
 
-void GPU_buffer_pool_free(GPUBufferPool *pool)
+/* free a GPUBufferPool; also frees the data in the pool's
+   GPUBuffers */
+static void gpu_buffer_pool_free(GPUBufferPool *pool)
 {
-       DEBUG_VBO("GPU_buffer_pool_free\n");
-
-       if( pool == 0 )
-               pool = globalPool;
-       if( pool == 0 )
+       if(!pool)
                return;
        
-       while( pool->size )
-               GPU_buffer_pool_delete_last(pool);
+       while(pool->totbuf)
+               gpu_buffer_pool_delete_last(pool);
 
        MEM_freeN(pool->buffers);
        MEM_freeN(pool);
-       /* if we are releasing the global pool, stop keeping a reference to it */
-       if (pool == globalPool)
-               globalPool = NULL;
 }
 
-void GPU_buffer_pool_free_unused(GPUBufferPool *pool)
+static GPUBufferPool *gpu_buffer_pool = NULL;
+static GPUBufferPool *gpu_get_global_buffer_pool(void)
 {
-       DEBUG_VBO("GPU_buffer_pool_free_unused\n");
+       /* initialize the pool */
+       if(!gpu_buffer_pool)
+               gpu_buffer_pool = gpu_buffer_pool_new();
 
-       if( pool == 0 )
-               pool = globalPool;
-       if( pool == 0 )
-               return;
-       
-       while( pool->size > MAX_FREE_GPU_BUFFERS )
-               GPU_buffer_pool_delete_last(pool);
+       return gpu_buffer_pool;
 }
 
-GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool )
+void GPU_global_buffer_pool_free(void)
 {
-       char buffer[60];
-       int i;
-       int cursize;
-       GPUBuffer *allocated;
-       int bestfit = -1;
+       gpu_buffer_pool_free(gpu_buffer_pool);
+       gpu_buffer_pool = NULL;
+}
 
-       DEBUG_VBO("GPU_buffer_alloc\n");
+/* get a GPUBuffer of at least `size' bytes; uses one from the buffer
+   pool if possible, otherwise creates a new one */
+GPUBuffer *GPU_buffer_alloc(int size)
+{
+       GPUBufferPool *pool;
+       GPUBuffer *buf;
+       int i, bufsize, bestfit = -1;
 
-       if( pool == 0 ) {
-               if( globalPool == 0 )
-                       globalPool = GPU_buffer_pool_new();
-               pool = globalPool;
-       }
+       pool = gpu_get_global_buffer_pool();
 
-       for( i = 0; i < pool->size; i++ ) {
-               cursize = pool->buffers[i]->size;
-               if( cursize == size ) {
-                       allocated = pool->buffers[i];
-                       GPU_buffer_pool_remove(i,pool);
-                       DEBUG_VBO("free buffer of exact size found\n");
-                       return allocated;
+       /* not sure if this buffer pool code has been profiled much,
+          seems to me that the graphics driver and system memory
+          management might do this stuff anyway. --nicholas
+       */
+
+       /* check the global buffer pool for a recently-deleted buffer
+          that is at least as big as the request, but not more than
+          twice as big */
+       for(i = 0; i < pool->totbuf; i++) {
+               bufsize = pool->buffers[i]->size;
+
+               /* check for an exact size match */
+               if(bufsize == size) {
+                       bestfit = i;
+                       break;
                }
-               /* smaller buffers won't fit data and buffers at least twice as big are a waste of memory */
-               else if( cursize > size && size > cursize/2 ) {
-                       /* is it closer to the required size than the last appropriate buffer found. try to save memory */
-                       if( bestfit == -1 || pool->buffers[bestfit]->size > cursize ) {
+               /* smaller buffers won't fit data and buffers at least
+                  twice as big are a waste of memory */
+               else if(bufsize > size && size > (bufsize / 2)) {
+                       /* is it closer to the required size than the
+                          last appropriate buffer found. try to save
+                          memory */
+                       if(bestfit == -1 || pool->buffers[bestfit]->size > bufsize) {
                                bestfit = i;
                        }
                }
        }
-       if( bestfit == -1 ) {
-               DEBUG_VBO("allocating a new buffer\n");
-
-               allocated = MEM_mallocN(sizeof(GPUBuffer), "GPU_buffer_alloc");
-               allocated->size = size;
-               if( useVBOs == 1 ) {
-                       glGenBuffersARB( 1, &allocated->id );
-                       glBindBufferARB( GL_ARRAY_BUFFER_ARB, allocated->id );
-                       glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, 0, GL_STATIC_DRAW_ARB );
-                       glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
-               }
-               else {
-                       allocated->pointer = MEM_mallocN(size, "GPU_buffer_alloc_vertexarray");
-                       while( allocated->pointer == 0 && pool->size > 0 ) {
-                               GPU_buffer_pool_delete_last(pool);
-                               allocated->pointer = MEM_mallocN(size, "GPU_buffer_alloc_vertexarray");
-                       }
-                       if( allocated->pointer == 0 && pool->size == 0 ) {
-                               return 0;
-                       }
-               }
+
+       /* if an acceptable buffer was found in the pool, remove it
+          from the pool and return it */
+       if(bestfit != -1) {
+               buf = pool->buffers[bestfit];
+               gpu_buffer_pool_remove_index(pool, bestfit);
+               return buf;
        }
-       else {
-               sprintf(buffer,"free buffer found. Wasted %d bytes\n", pool->buffers[bestfit]->size-size);
-               DEBUG_VBO(buffer);
 
-               allocated = pool->buffers[bestfit];
-               GPU_buffer_pool_remove(bestfit,pool);
+       /* no acceptable buffer found in the pool, create a new one */
+       buf = MEM_callocN(sizeof(GPUBuffer), "GPUBuffer");
+       buf->size = size;
+
+       if(useVBOs == 1) {
+               /* create a new VBO and initialize it to the requested
+                  size */
+               glGenBuffersARB(1, &buf->id);
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, buf->id);
+               glBufferDataARB(GL_ARRAY_BUFFER_ARB, size, 0, GL_STATIC_DRAW_ARB);
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+       }
+       else {
+               buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer");
+               
+               /* purpose of this seems to be dealing with
+                  out-of-memory errors? looks a bit iffy to me
+                  though, at least on Linux I expect malloc() would
+                  just overcommit. --nicholas */
+               while(!buf->pointer && pool->totbuf > 0) {
+                       gpu_buffer_pool_delete_last(pool);
+                       buf->pointer = MEM_mallocN(size, "GPUBuffer.pointer");
+               }
+               if(!buf->pointer)
+                       return NULL;
        }
-       return allocated;
+
+       return buf;
 }
 
-void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool )
+/* release a GPUBuffer; does not free the actual buffer or its data,
+   but rather moves it to the pool of recently-free'd buffers for
+   possible re-use*/
+void GPU_buffer_free(GPUBuffer *buffer)
 {
+       GPUBufferPool *pool;
        int i;
 
-       DEBUG_VBO("GPU_buffer_free\n");
-
-       if( buffer == 0 )
+       if(!buffer)
                return;
-       if( pool == 0 )
-               pool = globalPool;
-       if( pool == 0 )
-               pool = globalPool = GPU_buffer_pool_new();
+
+       pool = gpu_get_global_buffer_pool();
 
        /* free the last used buffer in the queue if no more space, but only
           if we are in the main thread. for e.g. rendering or baking it can
           happen that we are in other thread and can't call OpenGL, in that
           case cleanup will be done GPU_buffer_pool_free_unused */
-       if( BLI_thread_is_main() ) {
-               while( pool->size >= MAX_FREE_GPU_BUFFERS )
-                       GPU_buffer_pool_delete_last( pool );
+       if(BLI_thread_is_main()) {
+               /* in main thread, safe to decrease size of pool back
+                  down to MAX_FREE_GPU_BUFFERS */
+               while(pool->totbuf >= MAX_FREE_GPU_BUFFERS)
+                       gpu_buffer_pool_delete_last(pool);
        }
        else {
-               if( pool->maxsize == pool->size ) {
+               /* outside of main thread, can't safely delete the
+                  buffer, so increase pool size */
+               if(pool->maxsize == pool->totbuf) {
                        pool->maxsize += MAX_FREE_GPU_BUFFERS;
-                       pool->buffers = MEM_reallocN(pool->buffers, sizeof(GPUBuffer*)*pool->maxsize);
+                       pool->buffers = MEM_reallocN(pool->buffers,
+                                                    sizeof(GPUBuffer*) * pool->maxsize);
                }
        }
 
-       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->getFaceArray(dm);
+       lnk->point_index = point_index;
+}
 
-       numfaces= dm->getNumFaces(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);
+
+       /* 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);
 
-       /* 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);
+       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);
+       MVert *mvert = dm->getVertArray(dm);
+       MFace *f = dm->getFaceArray(dm);
 
-                                               if(vbo_index < 0) {
-                                                       vbo_index = -vbo_index +
-                                                               tot_uniq_verts - 1;
-                                               }
+       totface= dm->getNumFaces(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);
+               
+       totface = dm->getNumFaces(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);
 
-       /* 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);
+       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);
 
-       buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
+       totface= dm->getNumFaces(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);
 
-                       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->getFaceArray(dm);
-
-       numfaces= dm->getNumFaces(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->getFaceDataArray(dm, CD_NORMAL);
-       MVert *mvert = dm->getVertArray(dm);
-       MFace *mface = dm->getFaceArray(dm);
-
-       DEBUG_VBO("GPU_buffer_copy_normal\n");
-
-       numfaces= dm->getNumFaces(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->getFaceArray(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->getNumFaces(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->getFaceArray(dm);
-
-       DEBUG_VBO("GPU_buffer_copy_color3\n");
-
-       numfaces= dm->getNumFaces(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->getFaceArray(dm);
-
-       DEBUG_VBO("GPU_buffer_copy_color4\n");
-
-       numfaces= dm->getNumFaces(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->getNumFaces(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->getFace(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;
 
-       if( useVBOs ) {
-               glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id );
-       }
+       if(useVBOs)
+               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id);
 
        GLStates |= GPU_BUFFER_ELEMENT_STATE;
 }
 
-void GPU_uvedge_setup( DerivedMesh *dm )
+void GPU_uvedge_setup(DerivedMesh *dm)
 {
-       DEBUG_VBO("GPU_uvedge_setup\n");
-       if( dm->drawObject == 0 )
-               dm->drawObject = GPU_drawobject_new( dm );
-       if( dm->drawObject->uvedges == 0 )
-               dm->drawObject->uvedges = GPU_buffer_uvedge( dm );
-       if( dm->drawObject->uvedges == 0 ) {
-               DEBUG_VBO( "Failed to setup UV edges\n" );
+       if(!gpu_buffer_setup_common(dm, GPU_BUFFER_UVEDGE))
                return;
-       }
 
-       glEnableClientState( GL_VERTEX_ARRAY );
-       if( useVBOs ) {
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id );
-               glVertexPointer( 2, GL_FLOAT, 0, 0 );
+       glEnableClientState(GL_VERTEX_ARRAY);
+       if(useVBOs) {
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uvedges->id);
+               glVertexPointer(2, GL_FLOAT, 0, 0);
        }
        else {
-               glVertexPointer( 2, GL_FLOAT, 0, dm->drawObject->uvedges->pointer );
+               glVertexPointer(2, GL_FLOAT, 0, dm->drawObject->uvedges->pointer);
        }
        
        GLStates |= GPU_BUFFER_VERTEX_STATE;
 }
 
-void GPU_interleaved_setup( GPUBuffer *buffer, int data[] ) {
-       int i;
-       int elementsize = 0;
-       intptr_t offset = 0;
-
-       DEBUG_VBO("GPU_interleaved_setup\n");
-
-       for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
-               switch( data[i] ) {
-                       case GPU_BUFFER_INTER_V3F:
-                               elementsize += 3*sizeof(float);
-                               break;
-                       case GPU_BUFFER_INTER_N3F:
-                               elementsize += 3*sizeof(float);
-                               break;
-                       case GPU_BUFFER_INTER_T2F:
-                               elementsize += 2*sizeof(float);
-                               break;
-                       case GPU_BUFFER_INTER_C3UB:
-                               elementsize += 3*sizeof(unsigned char);
-                               break;
-                       case GPU_BUFFER_INTER_C4UB:
-                               elementsize += 4*sizeof(unsigned char);
-                               break;
-                       default:
-                               DEBUG_VBO( "Unknown element in data type array in GPU_interleaved_setup\n" );
-               }
-       }
-
-       if( useVBOs ) {
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
-               for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
-                       switch( data[i] ) {
-                               case GPU_BUFFER_INTER_V3F:
-                                       glEnableClientState( GL_VERTEX_ARRAY );
-                                       glVertexPointer( 3, GL_FLOAT, elementsize, (void *)offset );
-                                       GLStates |= GPU_BUFFER_VERTEX_STATE;
-                                       offset += 3*sizeof(float);
-                                       break;
-                               case GPU_BUFFER_INTER_N3F:
-                                       glEnableClientState( GL_NORMAL_ARRAY );
-                                       glNormalPointer( GL_FLOAT, elementsize, (void *)offset );
-                                       GLStates |= GPU_BUFFER_NORMAL_STATE;
-                                       offset += 3*sizeof(float);
-                                       break;
-                               case GPU_BUFFER_INTER_T2F:
-                                       glEnableClientState( GL_TEXTURE_COORD_ARRAY );
-                                       glTexCoordPointer( 2, GL_FLOAT, elementsize, (void *)offset );
-                                       GLStates |= GPU_BUFFER_TEXCOORD_STATE;
-                                       offset += 2*sizeof(float);
-                                       break;
-                               case GPU_BUFFER_INTER_C3UB:
-                                       glEnableClientState( GL_COLOR_ARRAY );
-                                       glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
-                                       GLStates |= GPU_BUFFER_COLOR_STATE;
-                                       offset += 3*sizeof(unsigned char);
-                                       break;
-                               case GPU_BUFFER_INTER_C4UB:
-                                       glEnableClientState( GL_COLOR_ARRAY );
-                                       glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, (void *)offset );
-                                       GLStates |= GPU_BUFFER_COLOR_STATE;
-                                       offset += 4*sizeof(unsigned char);
-                                       break;
-                       }
-               }
-       }
-       else {
-               for( i = 0; data[i] != GPU_BUFFER_INTER_END; i++ ) {
-                       switch( data[i] ) {
-                               case GPU_BUFFER_INTER_V3F:
-                                       glEnableClientState( GL_VERTEX_ARRAY );
-                                       glVertexPointer( 3, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
-                                       GLStates |= GPU_BUFFER_VERTEX_STATE;
-                                       offset += 3*sizeof(float);
-                                       break;
-                               case GPU_BUFFER_INTER_N3F:
-                                       glEnableClientState( GL_NORMAL_ARRAY );
-                                       glNormalPointer( GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
-                                       GLStates |= GPU_BUFFER_NORMAL_STATE;
-                                       offset += 3*sizeof(float);
-                                       break;
-                               case GPU_BUFFER_INTER_T2F:
-                                       glEnableClientState( GL_TEXTURE_COORD_ARRAY );
-                                       glTexCoordPointer( 2, GL_FLOAT, elementsize, offset+(char *)buffer->pointer );
-                                       GLStates |= GPU_BUFFER_TEXCOORD_STATE;
-                                       offset += 2*sizeof(float);
-                                       break;
-                               case GPU_BUFFER_INTER_C3UB:
-                                       glEnableClientState( GL_COLOR_ARRAY );
-                                       glColorPointer( 3, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
-                                       GLStates |= GPU_BUFFER_COLOR_STATE;
-                                       offset += 3*sizeof(unsigned char);
-                                       break;
-                               case GPU_BUFFER_INTER_C4UB:
-                                       glEnableClientState( GL_COLOR_ARRAY );
-                                       glColorPointer( 4, GL_UNSIGNED_BYTE, elementsize, offset+(char *)buffer->pointer );
-                                       GLStates |= GPU_BUFFER_COLOR_STATE;
-                                       offset += 4*sizeof(unsigned char);
-                                       break;
-                       }
-               }
-       }
-}
-
-static int GPU_typesize( int type ) {
-       switch( type ) {
-               case GL_FLOAT:
-                       return sizeof(float);
-               case GL_INT:
-                       return sizeof(int);
-               case GL_UNSIGNED_INT:
-                       return sizeof(unsigned int);
-               case GL_BYTE:
-                       return sizeof(char);
-               case GL_UNSIGNED_BYTE:
-                       return sizeof(unsigned char);
-               default:
-                       return 0;
+static int GPU_typesize(int type) {
+       switch(type) {
+       case GL_FLOAT:
+               return sizeof(float);
+       case GL_INT:
+               return sizeof(int);
+       case GL_UNSIGNED_INT:
+               return sizeof(unsigned int);
+       case GL_BYTE:
+               return sizeof(char);
+       case GL_UNSIGNED_BYTE:
+               return sizeof(unsigned char);
+       default:
+               return 0;
        }
 }
 
-int GPU_attrib_element_size( GPUAttrib data[], int numdata ) {
+int GPU_attrib_element_size(GPUAttrib data[], int numdata) {
        int i, elementsize = 0;
 
-       for( i = 0; i < numdata; i++ ) {
+       for(i = 0; i < numdata; i++) {
                int typesize = GPU_typesize(data[i].type);
-               if( typesize == 0 )
-                       DEBUG_VBO( "Unknown element in data type array in GPU_attrib_element_size\n" );
-               else {
+               if(typesize != 0)
                        elementsize += typesize*data[i].size;
-               }
        }
        return elementsize;
 }
 
-void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numdata ) {
+void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numdata) {
        int i;
        int elementsize;
        intptr_t offset = 0;
 
-       DEBUG_VBO("GPU_interleaved_attrib_setup\n");
-
-       for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
-               if( attribData[i].index != -1 ) {
-                       glDisableVertexAttribArrayARB( attribData[i].index );
+       for(i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
+               if(attribData[i].index != -1) {
+                       glDisableVertexAttribArrayARB(attribData[i].index);
                }
                else
                        break;
        }
-       elementsize = GPU_attrib_element_size( data, numdata );
+       elementsize = GPU_attrib_element_size(data, numdata);
 
-       if( useVBOs ) {
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
-               for( i = 0; i < numdata; i++ ) {
-                       glEnableVertexAttribArrayARB( data[i].index );
-                       glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_FALSE, elementsize, (void *)offset );
+       if(useVBOs) {
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
+               for(i = 0; i < numdata; i++) {
+                       glEnableVertexAttribArrayARB(data[i].index);
+                       glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type,
+                                                GL_FALSE, elementsize, (void *)offset);
                        offset += data[i].size*GPU_typesize(data[i].type);
 
                        attribData[i].index = data[i].index;
@@ -1513,9 +1115,10 @@ void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numd
                attribData[numdata].index = -1;
        }
        else {
-               for( i = 0; i < numdata; i++ ) {
-                       glEnableVertexAttribArrayARB( data[i].index );
-                       glVertexAttribPointerARB( data[i].index, data[i].size, data[i].type, GL_FALSE, elementsize, (char *)buffer->pointer + offset );
+               for(i = 0; i < numdata; i++) {
+                       glEnableVertexAttribArrayARB(data[i].index);
+                       glVertexAttribPointerARB(data[i].index, data[i].size, data[i].type,
+                                                GL_FALSE, elementsize, (char *)buffer->pointer + offset);
                        offset += data[i].size*GPU_typesize(data[i].type);
                }
        }
@@ -1525,93 +1128,99 @@ void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numd
 void GPU_buffer_unbind(void)
 {
        int i;
-       DEBUG_VBO("GPU_buffer_unbind\n");
-
-       if( GLStates & GPU_BUFFER_VERTEX_STATE )
-               glDisableClientState( GL_VERTEX_ARRAY );
-       if( GLStates & GPU_BUFFER_NORMAL_STATE )
-               glDisableClientState( GL_NORMAL_ARRAY );
-       if( GLStates & GPU_BUFFER_TEXCOORD_STATE )
-               glDisableClientState( GL_TEXTURE_COORD_ARRAY );
-       if( GLStates & GPU_BUFFER_COLOR_STATE )
-               glDisableClientState( GL_COLOR_ARRAY );
-       if( GLStates & GPU_BUFFER_ELEMENT_STATE ) {
-               if( useVBOs ) {
-                       glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 0 );
+
+       if(GLStates & GPU_BUFFER_VERTEX_STATE)
+               glDisableClientState(GL_VERTEX_ARRAY);
+       if(GLStates & GPU_BUFFER_NORMAL_STATE)
+               glDisableClientState(GL_NORMAL_ARRAY);
+       if(GLStates & GPU_BUFFER_TEXCOORD_STATE)
+               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+       if(GLStates & GPU_BUFFER_COLOR_STATE)
+               glDisableClientState(GL_COLOR_ARRAY);
+       if(GLStates & GPU_BUFFER_ELEMENT_STATE) {
+               if(useVBOs) {
+                       glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
                }
        }
-       GLStates &= !(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE | GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE);
+       GLStates &= !(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE |
+                     GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE |
+                     GPU_BUFFER_ELEMENT_STATE);
 
-       for( i = 0; i < MAX_GPU_ATTRIB_DATA; i++ ) {
-               if( attribData[i].index != -1 ) {
-                       glDisableVertexAttribArrayARB( attribData[i].index );
+       for(i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
+               if(attribData[i].index != -1) {
+                       glDisableVertexAttribArrayARB(attribData[i].index);
                }
                else
                        break;
        }
-       if( GLStates != 0 ) {
-               DEBUG_VBO( "Some weird OpenGL state is still set. Why?" );
-       }
-       if( useVBOs )
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
+
+       if(useVBOs)
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
 }
 
-void GPU_color3_upload( DerivedMesh *dm, unsigned char *data )
+/* confusion: code in cdderivedmesh calls both GPU_color_setup and
+   GPU_color3_upload; both of these set the `colors' buffer, so seems
+   like it will just needlessly overwrite? --nicholas */
+void GPU_color3_upload(DerivedMesh *dm, unsigned char *data)
 {
-       if( dm->drawObject == 0 )
+       if(dm->drawObject == 0)
                dm->drawObject = GPU_drawobject_new(dm);
-       GPU_buffer_free(dm->drawObject->colors,globalPool);
-       dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, 3, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3 );
+       GPU_buffer_free(dm->drawObject->colors);
+
+       dm->drawObject->colors = gpu_buffer_setup(dm, dm->drawObject, 3,
+                                                 sizeof(char)*3*dm->drawObject->tot_triangle_point,
+                                                 GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3);
 }
-void GPU_color4_upload( DerivedMesh *dm, unsigned char *data )
+
+/* this is used only in cdDM_drawFacesColored, which I think is no
+   longer used, so can probably remove this --nicholas */
+void GPU_color4_upload(DerivedMesh *UNUSED(dm), unsigned char *UNUSED(data))
 {
-       if( dm->drawObject == 0 )
+       /*if(dm->drawObject == 0)
                dm->drawObject = GPU_drawobject_new(dm);
-       GPU_buffer_free(dm->drawObject->colors,globalPool);
-       dm->drawObject->colors = GPU_buffer_setup( dm, dm->drawObject, 3, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4 );
+       GPU_buffer_free(dm->drawObject->colors);
+       dm->drawObject->colors = gpu_buffer_setup(dm, dm->drawObject, 3,
+                                                 sizeof(char)*3*dm->drawObject->tot_triangle_point,
+                                                 GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4);*/
 }
 
-void GPU_color_switch( int mode )
+void GPU_color_switch(int mode)
 {
-       if( mode ) {
-               if( !(GLStates & GPU_BUFFER_COLOR_STATE) )
-                       glEnableClientState( GL_COLOR_ARRAY );
+       if(mode) {
+               if(!(GLStates & GPU_BUFFER_COLOR_STATE))
+                       glEnableClientState(GL_COLOR_ARRAY);
                GLStates |= GPU_BUFFER_COLOR_STATE;
        }
        else {
-               if( GLStates & GPU_BUFFER_COLOR_STATE )
-                       glDisableClientState( GL_COLOR_ARRAY );
+               if(GLStates & GPU_BUFFER_COLOR_STATE)
+                       glDisableClientState(GL_COLOR_ARRAY);
                GLStates &= (!GPU_BUFFER_COLOR_STATE);
        }
 }
 
-int GPU_buffer_legacy( DerivedMesh *dm )
+/* return 1 if drawing should be done using old immediate-mode
+   code, 0 otherwise */
+int GPU_buffer_legacy(DerivedMesh *dm)
 {
        int test= (U.gameflags & USER_DISABLE_VBO);
-       if( test )
+       if(test)
                return 1;
 
-       if( dm->drawObject == 0 )
+       if(dm->drawObject == 0)
                dm->drawObject = GPU_drawobject_new(dm);
        return dm->drawObject->legacy;
 }
 
-void *GPU_buffer_lock( GPUBuffer *buffer )
+void *GPU_buffer_lock(GPUBuffer *buffer)
 {
        float *varray;
 
-       DEBUG_VBO("GPU_buffer_lock\n");
-       if( buffer == 0 ) {
-               DEBUG_VBO( "Failed to lock NULL buffer\n" );
+       if(!buffer)
                return 0;
-       }
 
-       if( useVBOs ) {
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
-               varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
-               if( varray == 0 ) {
-                       DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
-               }
+       if(useVBOs) {
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
+               varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
                return varray;
        }
        else {
@@ -1619,23 +1228,18 @@ void *GPU_buffer_lock( GPUBuffer *buffer )
        }
 }
 
-void *GPU_buffer_lock_stream( GPUBuffer *buffer )
+void *GPU_buffer_lock_stream(GPUBuffer *buffer)
 {
        float *varray;
 
-       DEBUG_VBO("GPU_buffer_lock_stream\n");
-       if( buffer == 0 ) {
-               DEBUG_VBO( "Failed to lock NULL buffer\n" );
+       if(!buffer)
                return 0;
-       }
 
-       if( useVBOs ) {
-               glBindBufferARB( GL_ARRAY_BUFFER_ARB, buffer->id );
-               glBufferDataARB( GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB );    /* discard previous data, avoid stalling gpu */
-               varray = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
-               if( varray == 0 ) {
-                       DEBUG_VBO( "Failed to map buffer to client address space\n" ); 
-               }
+       if(useVBOs) {
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, buffer->id);
+               /* discard previous data, avoid stalling gpu */
+               glBufferDataARB(GL_ARRAY_BUFFER_ARB, buffer->size, 0, GL_STREAM_DRAW_ARB);
+               varray = glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
                return varray;
        }
        else {
@@ -1643,25 +1247,404 @@ void *GPU_buffer_lock_stream( GPUBuffer *buffer )
        }
 }
 
-void GPU_buffer_unlock( GPUBuffer *buffer )
+void GPU_buffer_unlock(GPUBuffer *buffer)
 {
-       DEBUG_VBO( "GPU_buffer_unlock\n" ); 
-       if( useVBOs ) {
-               if( buffer != 0 ) {
-                       if( glUnmapBufferARB( GL_ARRAY_BUFFER_ARB ) == 0 ) {
-                               DEBUG_VBO( "Failed to copy new data\n" ); 
-                       }
+       if(useVBOs) {
+               if(buffer) {
+                       /* note: this operation can fail, could return
+                          an error code from this function? */
+                       glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
                }
                glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
        }
 }
 
-void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count )
+/* used for drawing edges */
+void GPU_buffer_draw_elements(GPUBuffer *elements, unsigned int mode, int start, int count)
+{
+       glDrawElements(mode, count, GL_UNSIGNED_INT,
+                      (useVBOs ?
+                       (void*)(start * sizeof(unsigned int)) :
+                       ((int*)elements->pointer) + start));
+}
+
+
+/* XXX: the rest of the code in this file is used for optimized PBVH
+   drawing and doesn't interact at all with the buffer code above */
+
+/* Convenience struct for building the VBO. */
+typedef struct {
+       float co[3];
+       short no[3];
+} VertexBufferFormat;
+
+typedef struct {
+       /* opengl buffer handles */
+       GLuint vert_buf, index_buf;
+       GLenum index_type;
+
+       /* mesh pointers in case buffer allocation fails */
+       MFace *mface;
+       MVert *mvert;
+       int *face_indices;
+       int totface;
+
+       /* grid pointers */
+       DMGridData **grids;
+       int *grid_indices;
+       int totgrid;
+       int gridsize;
+
+       unsigned int tot_tri, tot_quad;
+} GPU_Buffers;
+
+void GPU_update_mesh_buffers(void *buffers_v, MVert *mvert,
+                       int *vert_indices, int totvert)
 {
-       if( useVBOs ) {
-               glDrawElements( mode, count, GL_UNSIGNED_INT, (void *)(start*sizeof(unsigned int)) );
+       GPU_Buffers *buffers = buffers_v;
+       VertexBufferFormat *vert_data;
+       int i;
+
+       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);
+
+               if(vert_data) {
+                       for(i = 0; i < totvert; ++i) {
+                               MVert *v = mvert + vert_indices[i];
+                               VertexBufferFormat *out = vert_data + i;
+
+                               copy_v3_v3(out->co, v->co);
+                               memcpy(out->no, v->no, sizeof(short) * 3);
+                       }
+
+                       glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+               }
+               else {
+                       glDeleteBuffersARB(1, &buffers->vert_buf);
+                       buffers->vert_buf = 0;
+               }
+
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
        }
-       else {
-               glDrawElements( mode, count, GL_UNSIGNED_INT, ((int *)elements->pointer)+start );
+
+       buffers->mvert = mvert;
+}
+
+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)
+{
+       GPU_Buffers *buffers;
+       unsigned short *tri_data;
+       int i, j, k, tottri;
+
+       buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
+       buffers->index_type = GL_UNSIGNED_SHORT;
+
+       /* 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);
+
+       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);
+
+               /* 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];
+
+                               v[0]= f->v1;
+                               v[1]= f->v2;
+                               v[2]= f->v3;
+
+                               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;
+
+                                               value = BLI_ghash_lookup(map, key);
+                                               vbo_index = GET_INT_FROM_POINTER(value);
+
+                                               if(vbo_index < 0) {
+                                                       vbo_index = -vbo_index +
+                                                               tot_uniq_verts - 1;
+                                               }
+
+                                               *tri_data = vbo_index;
+                                               ++tri_data;
+                                       }
+                                       v[0] = f->v4;
+                                       v[1] = f->v1;
+                                       v[2] = f->v3;
+                               }
+                       }
+                       glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+               }
+               else {
+                       glDeleteBuffersARB(1, &buffers->index_buf);
+                       buffers->index_buf = 0;
+               }
+
+               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
        }
+
+       if(buffers->index_buf)
+               glGenBuffersARB(1, &buffers->vert_buf);
+       GPU_update_mesh_buffers(buffers, mvert, vert_indices, totvert);
+
+       buffers->tot_tri = tottri;
+
+       buffers->mface = mface;
+       buffers->face_indices = face_indices;
+       buffers->totface = totface;
+
+       return buffers;
 }
+
+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;
+
+       /* 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);
+
+                               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);
+                                               }
+                                       }
+                               }
+
+                               vert_data += gridsize*gridsize;
+                       }
+                       glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
+               }
+               else {
+                       glDeleteBuffersARB(1, &buffers->vert_buf);
+                       buffers->vert_buf = 0;
+               }
+               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);
+}
+
+void *GPU_build_grid_buffers(DMGridData **UNUSED(grids), int *UNUSED(grid_indices),
+                               int totgrid, int gridsize)
+{
+       GPU_Buffers *buffers;
+       int i, j, k, totquad, offset= 0;
+
+       buffers = MEM_callocN(sizeof(GPU_Buffers), "GPU_Buffers");
+
+       /* Count the number of quads */
+       totquad= (gridsize-1)*(gridsize-1)*totgrid;
+
+       /* Generate index buffer object */
+       if(GLEW_ARB_vertex_buffer_object && !(U.gameflags & USER_DISABLE_VBO))
+               glGenBuffersARB(1, &buffers->index_buf);
+
+       if(buffers->index_buf) {
+               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, buffers->index_buf);
+
+               if(totquad < USHRT_MAX) {
+                       unsigned short *quad_data;
+
+                       buffers->index_type = GL_UNSIGNED_SHORT;
+                       glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
+                                        sizeof(unsigned short) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
+
+                       /* 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;
+                                               }
+                                       }
+
+                                       offset += gridsize*gridsize;
+                               }
+                               glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+                       }
+                       else {
+                               glDeleteBuffersARB(1, &buffers->index_buf);
+                               buffers->index_buf = 0;
+                       }
+               }
+               else {
+                       unsigned int *quad_data;
+
+                       buffers->index_type = GL_UNSIGNED_INT;
+                       glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
+                                        sizeof(unsigned int) * totquad * 4, NULL, GL_STATIC_DRAW_ARB);
+
+                       /* 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;
+                                               }
+                                       }
+
+                                       offset += gridsize*gridsize;
+                               }
+                               glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB);
+                       }
+                       else {
+                               glDeleteBuffersARB(1, &buffers->index_buf);
+                               buffers->index_buf = 0;
+                       }
+               }
+
+               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+       }
+
+       /* Build VBO */
+       if(buffers->index_buf)
+               glGenBuffersARB(1, &buffers->vert_buf);
+
+       buffers->tot_quad = totquad;
+
+       return buffers;
+}
+
+void GPU_draw_buffers(void *buffers_v)
+{
+       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);
+
+               if(buffers->tot_quad) {
+                       glVertexPointer(3, GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, co));
+                       glNormalPointer(GL_FLOAT, sizeof(DMGridData), (void*)offsetof(DMGridData, no));
+
+                       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));
+
+                       glDrawElements(GL_TRIANGLES, buffers->tot_tri * 3, buffers->index_type, 0);
+               }
+
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+               glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
+
+               glDisableClientState(GL_VERTEX_ARRAY);
+               glDisableClientState(GL_NORMAL_ARRAY);
+       }
+       else if(buffers->totface) {
+               /* fallback if we are out of memory */
+               int i;
+
+               for(i = 0; i < buffers->totface; ++i) {
+                       MFace *f = buffers->mface + buffers->face_indices[i];
+
+                       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;
+
+               for(i = 0; i < buffers->totgrid; ++i) {
+                       DMGridData *grid = buffers->grids[buffers->grid_indices[i]];
+
+                       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];
+
+                                       glNormal3fv(a->no);
+                                       glVertex3fv(a->co);
+                                       glNormal3fv(b->no);
+                                       glVertex3fv(b->co);
+                               }
+                               glEnd();
+                       }
+               }
+       }
+}
+
+void GPU_free_buffers(void *buffers_v)
+{
+       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);
+
+               MEM_freeN(buffers);
+       }
+}
+
index 2c9aa4dece5385f7ed90761e629e64303c89f718..4c0ce24e3e756178aee0579f842f7300d683419b 100644 (file)
@@ -2932,8 +2932,10 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
                                                vlr->v3= RE_findOrAddVert(obr, startvert+index[2]);
                                                vlr->v4= NULL;
 
-                                               normal_tri_v3(tmp, vlr->v3->co, vlr->v2->co, vlr->v1->co);
-                                               add_v3_v3(n, tmp);
+                                               if(area_tri_v3(vlr->v3->co, vlr->v2->co, vlr->v1->co)>FLT_EPSILON) {
+                                                       normal_tri_v3(tmp, vlr->v3->co, vlr->v2->co, vlr->v1->co);
+                                                       add_v3_v3(n, tmp);
+                                               }
 
                                                vlr->mat= matar[ dl->col ];
                                                vlr->flag= 0;
index 0bc2e5da1c5360c77b79dfcf741419fec4c89828..ed28696ef69e291fe34bfbf2d39c0383d9d692b7 100644 (file)
@@ -416,7 +416,7 @@ void WM_exit(bContext *C)
        BPY_python_end();
 #endif
 
-       GPU_buffer_pool_free(NULL);
+       GPU_global_buffer_pool_free();
        GPU_free_unused_buffers();
        GPU_extensions_exit();