imbusy GSoC'09 branch merge (Vertex Buffer Object support)
authorLukas Steiblys <imbusy@imbusy.org>
Sat, 3 Oct 2009 15:35:01 +0000 (15:35 +0000)
committerLukas Steiblys <imbusy@imbusy.org>
Sat, 3 Oct 2009 15:35:01 +0000 (15:35 +0000)
19 files changed:
release/scripts/ui/space_userpref.py
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/customdata.c
source/blender/editors/include/BIF_glutil.h
source/blender/editors/screen/glutil.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/drawobject.c
source/blender/gpu/gpu_buffers.h [new file with mode: 0644]
source/blender/gpu/intern/gpu_buffers.c [new file with mode: 0644]
source/blender/makesdna/DNA_customdata_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesrna/intern/rna_userdef.c
source/blender/windowmanager/intern/wm_init_exit.c
source/blender/windowmanager/intern/wm_subwindow.c
source/blender/windowmanager/wm_subwindow.h

index 9798e0ccab6090ef623dd4db4fd73fd1a3099396..a9126d2c7f14a3a30fc2467d5f07cada89c5c95f 100644 (file)
@@ -314,6 +314,7 @@ class USERPREF_PT_system(bpy.types.Panel):
                sub1.itemL(text="OpenGL:")
                sub1.itemR(system, "clip_alpha", slider=True)
                sub1.itemR(system, "use_mipmaps")
+               sub1.itemR(system, "use_vbos")
                sub1.itemL(text="Window Draw Method:")
                sub1.row().itemR(system, "window_draw_method", expand=True)
                sub1.itemL(text="Textures:")
index 06103596be1026ebb02bb158837dac4df76dd05e..076747cb8454cf498b1e9fd2f3945ffeb39a2c95 100644 (file)
@@ -58,6 +58,7 @@ struct ModifierData;
 struct MCol;
 struct ColorBand;
 struct GPUVertexAttribs;
+struct GPUDrawObject;
 
 /* number of sub-elements each mesh element has (for interpolation) */
 #define SUB_ELEMS_VERT 0
@@ -72,6 +73,7 @@ struct DerivedMesh {
        int needsFree; /* checked on ->release, is set to 0 for cached results */
        int deformedOnly; /* set by modifier stack if only deformed from original */
        BVHCache bvhCache;
+       struct GPUDrawObject *drawObject;
 
        /* Misc. Queries */
 
index 7dc9e4499c6cdf9670fe05cee091d1ee5ead2890..ba42aca18724864098a46c798672f0bf78518ee3 100644 (file)
@@ -88,6 +88,8 @@ typedef struct SculptSession {
 
        struct SculptStroke *stroke;
        struct StrokeCache *cache;
+
+       struct GPUDrawObject *drawobject;
 } SculptSession;
 
 void free_sculptsession(SculptSession **);
index 43b9a63a2c14050aa8fd20ae27ce7889ef1a614e..86c272e3799f15d953513c7524c6c936221d9727 100644 (file)
@@ -84,6 +84,7 @@
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 
+#include "gpu_buffers.h"
 #include "GPU_draw.h"
 #include "GPU_extensions.h"
 #include "GPU_material.h"
@@ -218,7 +219,7 @@ int DM_release(DerivedMesh *dm)
 {
        if (dm->needsFree) {
                bvhcache_free(&dm->bvhCache);
-
+               GPU_drawobject_free( dm );
                CustomData_free(&dm->vertData, dm->numVertData);
                CustomData_free(&dm->edgeData, dm->numEdgeData);
                CustomData_free(&dm->faceData, dm->numFaceData);
@@ -491,14 +492,55 @@ static void emDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *us
                }
                glEnd();
        } else {
-               glBegin(GL_LINES);
-               for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
-                       if(!setDrawOptions || setDrawOptions(userData, i)) {
-                               glVertex3fv(eed->v1->co);
-                               glVertex3fv(eed->v2->co);
+               GPUBuffer *buffer = 0;
+               float *varray;
+               if( setDrawOptions == 0 ) {
+                       buffer = GPU_buffer_alloc( sizeof(float)*3*2*emdm->em->totedge, 0 );
+               }
+               if( buffer != 0 && (varray = GPU_buffer_lock_stream( buffer )) ) {
+                       int prevdraw = 0;
+                       int numedges = 0;
+                       int draw = 0;
+                       int datatype[] = { GPU_BUFFER_INTER_V3F, GPU_BUFFER_INTER_END };
+                       GPU_buffer_unlock( buffer );
+                       GPU_interleaved_setup( buffer, datatype );
+                       varray = GPU_buffer_lock_stream( buffer );
+                       for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
+                               if(!setDrawOptions || setDrawOptions(userData, i)) {
+                                       draw = 1;
+                               } else {
+                                       draw = 0;
+                               }
+                               if( prevdraw != draw && prevdraw != 0 && numedges > 0) {
+                                       GPU_buffer_unlock( buffer );
+                                       glDrawArrays(GL_LINES,0,numedges*2);
+                                       varray = GPU_buffer_lock_stream( buffer );
+                                       numedges = 0;
+                               }
+                               if( draw != 0 ) {
+                                       VECCOPY(&varray[numedges*6],eed->v1->co);
+                                       VECCOPY(&varray[numedges*6+3],eed->v2->co);
+                                       numedges++;
+                               }
+                               prevdraw = draw;
+                       }
+                       GPU_buffer_unlock( buffer );
+                       if( prevdraw != 0 && numedges > 0) {
+                               glDrawArrays(GL_LINES,0,numedges*2);
+                       }
+                       GPU_buffer_unbind();
+               } else {
+                       glBegin(GL_LINES);
+                       for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
+                               if(!setDrawOptions || setDrawOptions(userData, i)) {
+                                       glVertex3fv(eed->v1->co);
+                                       glVertex3fv(eed->v2->co);
+                               }
                        }
+                       glEnd();
                }
-               glEnd();
+               if( buffer != 0 )
+                       GPU_buffer_free( buffer, 0 );
        }
 }
 static void emDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
@@ -627,8 +669,8 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
                        draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth);
                        if(draw) {
                                if (draw==2) { /* enabled with stipple */
-                                       glEnable(GL_POLYGON_STIPPLE);
-                                       glPolygonStipple(stipple_quarttone);
+                                       glEnable(GL_POLYGON_STIPPLE);
+                                       glPolygonStipple(stipple_quarttone);
                                }
                                
                                glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
@@ -659,41 +701,135 @@ static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
                        }
                }
        } else {
-               for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
-                       int drawSmooth = (efa->flag & ME_SMOOTH);
-                       draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth);
-                       if(draw) {
-                               if (draw==2) { /* enabled with stipple */
-                                       glEnable(GL_POLYGON_STIPPLE);
-                                       glPolygonStipple(stipple_quarttone);
+               GPUBuffer *buffer = 0;
+               float *varray;
+               if( setDrawOptions == 0 ) {
+                       /* 3 floats for position, 3 for normal and times two because the faces may actually be quads instead of triangles */
+                       buffer = GPU_buffer_alloc( sizeof(float)*6*emdm->em->totface*3*2, 0 );
+               }
+               if( buffer != 0 && (varray = GPU_buffer_lock_stream( buffer )) ) {
+                       int prevdraw = 0;
+                       int numfaces = 0;
+                       int datatype[] = { GPU_BUFFER_INTER_V3F, GPU_BUFFER_INTER_N3F, GPU_BUFFER_INTER_END };
+                       GPU_buffer_unlock( buffer );
+                       GPU_interleaved_setup( buffer, datatype );
+                       glShadeModel(GL_SMOOTH);
+                       varray = GPU_buffer_lock_stream( buffer );
+                       for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
+                               int drawSmooth = (efa->flag & ME_SMOOTH);
+                               draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth);
+                               if( prevdraw != draw && prevdraw != 0 && numfaces > 0) {
+                                       if( prevdraw==2 ) {
+                                               glEnable(GL_POLYGON_STIPPLE);
+                                               glPolygonStipple(stipple_quarttone);
+                                       }
+                                       GPU_buffer_unlock( buffer );
+                                       glDrawArrays(GL_TRIANGLES,0,numfaces*3);
+                                       if( prevdraw==2 ) {
+                                               glDisable(GL_POLYGON_STIPPLE);
+                                       }
+                                       varray = GPU_buffer_lock_stream( buffer );
+                                       numfaces = 0;
                                }
-                               glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
-
-                               glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
-                               if (!drawSmooth) {
-                                       glNormal3fv(efa->n);
-                                       glVertex3fv(efa->v1->co);
-                                       glVertex3fv(efa->v2->co);
-                                       glVertex3fv(efa->v3->co);
-                                       if(efa->v4) glVertex3fv(efa->v4->co);
-                               } else {
-                                       glNormal3fv(efa->v1->no);
-                                       glVertex3fv(efa->v1->co);
-                                       glNormal3fv(efa->v2->no);
-                                       glVertex3fv(efa->v2->co);
-                                       glNormal3fv(efa->v3->no);
-                                       glVertex3fv(efa->v3->co);
-                                       if(efa->v4) {
-                                               glNormal3fv(efa->v4->no);
-                                               glVertex3fv(efa->v4->co);
+                               if( draw != 0 ) {
+                                       if(!drawSmooth) {
+                                               VECCOPY(&varray[numfaces*18],efa->v1->co);
+                                               VECCOPY(&varray[numfaces*18+3],efa->n);
+
+                                               VECCOPY(&varray[numfaces*18+6],efa->v2->co);
+                                               VECCOPY(&varray[numfaces*18+9],efa->n);
+
+                                               VECCOPY(&varray[numfaces*18+12],efa->v3->co);
+                                               VECCOPY(&varray[numfaces*18+15],efa->n);
+                                               numfaces++;
+                                               if( efa->v4 ) {
+                                                       VECCOPY(&varray[numfaces*18],efa->v3->co);
+                                                       VECCOPY(&varray[numfaces*18+3],efa->n);
+
+                                                       VECCOPY(&varray[numfaces*18+6],efa->v4->co);
+                                                       VECCOPY(&varray[numfaces*18+9],efa->n);
+
+                                                       VECCOPY(&varray[numfaces*18+12],efa->v1->co);
+                                                       VECCOPY(&varray[numfaces*18+15],efa->n);
+                                                       numfaces++;
+                                               }
+                                       }
+                                       else {
+                                               VECCOPY(&varray[numfaces*18],efa->v1->co);
+                                               VECCOPY(&varray[numfaces*18+3],efa->v1->no);
+
+                                               VECCOPY(&varray[numfaces*18+6],efa->v2->co);
+                                               VECCOPY(&varray[numfaces*18+9],efa->v2->no);
+
+                                               VECCOPY(&varray[numfaces*18+12],efa->v3->co);
+                                               VECCOPY(&varray[numfaces*18+15],efa->v3->no);
+                                               numfaces++;
+                                               if( efa->v4 ) {
+                                                       VECCOPY(&varray[numfaces*18],efa->v3->co);
+                                                       VECCOPY(&varray[numfaces*18+3],efa->v3->no);
+
+                                                       VECCOPY(&varray[numfaces*18+6],efa->v4->co);
+                                                       VECCOPY(&varray[numfaces*18+9],efa->v4->no);
+
+                                                       VECCOPY(&varray[numfaces*18+12],efa->v1->co);
+                                                       VECCOPY(&varray[numfaces*18+15],efa->v1->no);
+                                                       numfaces++;
+                                               }
                                        }
                                }
-                               glEnd();
-                               
-                               if (draw==2)
+                               prevdraw = draw;
+                       }
+                       GPU_buffer_unlock( buffer );
+                       if( prevdraw != 0 && numfaces > 0) {
+                               if( prevdraw==2 ) {
+                                       glEnable(GL_POLYGON_STIPPLE);
+                                       glPolygonStipple(stipple_quarttone);
+                               }
+                               glDrawArrays(GL_TRIANGLES,0,numfaces*3);
+                               if( prevdraw==2 ) {
                                        glDisable(GL_POLYGON_STIPPLE);
+                               }
+                       }
+                       GPU_buffer_unbind();
+               } else {
+                       for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
+                               int drawSmooth = (efa->flag & ME_SMOOTH);
+                               draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth);
+                               if(draw) {
+                                       if (draw==2) { /* enabled with stipple */
+                                               glEnable(GL_POLYGON_STIPPLE);
+                                               glPolygonStipple(stipple_quarttone);
+                                       }
+                                       glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+
+                                       glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+                                       if (!drawSmooth) {
+                                               glNormal3fv(efa->n);
+                                               glVertex3fv(efa->v1->co);
+                                               glVertex3fv(efa->v2->co);
+                                               glVertex3fv(efa->v3->co);
+                                               if(efa->v4) glVertex3fv(efa->v4->co);
+                                       } else {
+                                               glNormal3fv(efa->v1->no);
+                                               glVertex3fv(efa->v1->co);
+                                               glNormal3fv(efa->v2->no);
+                                               glVertex3fv(efa->v2->co);
+                                               glNormal3fv(efa->v3->no);
+                                               glVertex3fv(efa->v3->co);
+                                               if(efa->v4) {
+                                                       glNormal3fv(efa->v4->no);
+                                                       glVertex3fv(efa->v4->co);
+                                               }
+                                       }
+                                       glEnd();
+                                       
+                                       if (draw==2)
+                                               glDisable(GL_POLYGON_STIPPLE);
+                               }
                        }
                }
+               if( buffer != 0 )
+                       GPU_buffer_free( buffer, 0 );
        }
 }
 
index b20da0962a7931f9bc33b0eef2be7c600dae84bc..b9aa842b6dc0620310e8c0c664b21d9cabf895c0 100644 (file)
@@ -60,6 +60,7 @@
 
 #include "MEM_guardedalloc.h"
 
+#include "gpu_buffers.h"
 #include "GPU_draw.h"
 #include "GPU_extensions.h"
 #include "GPU_material.h"
@@ -176,10 +177,19 @@ static void cdDM_drawVerts(DerivedMesh *dm)
        MVert *mv = cddm->mvert;
        int i;
 
-       glBegin(GL_POINTS);
-       for(i = 0; i < dm->numVertData; i++, mv++)
-               glVertex3fv(mv->co);
-       glEnd();
+       if( GPU_buffer_legacy(dm) ) {
+               glBegin(GL_POINTS);
+               for(i = 0; i < dm->numVertData; i++, mv++)
+                       glVertex3fv(mv->co);
+               glEnd();
+       }
+       else {  /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
+               GPU_vertex_setup(dm);
+               if( !GPU_buffer_legacy(dm) ) {
+                       glDrawArrays(GL_POINTS,0,dm->drawObject->nelements);
+               }
+               GPU_buffer_unbind();
+       }
 }
 
 static void cdDM_drawUVEdges(DerivedMesh *dm)
@@ -190,28 +200,65 @@ static void cdDM_drawUVEdges(DerivedMesh *dm)
        int i;
 
        if(mf) {
-               glBegin(GL_LINES);
-               for(i = 0; i < dm->numFaceData; i++, mf++, tf++) {
-                       if(!(mf->flag&ME_HIDE)) {
-                               glVertex2fv(tf->uv[0]);
-                               glVertex2fv(tf->uv[1]);
-
-                               glVertex2fv(tf->uv[1]);
-                               glVertex2fv(tf->uv[2]);
-
-                               if(!mf->v4) {
-                                       glVertex2fv(tf->uv[2]);
+               if( GPU_buffer_legacy(dm) ) {
+                       glBegin(GL_LINES);
+                       for(i = 0; i < dm->numFaceData; i++, mf++, tf++) {
+                               if(!(mf->flag&ME_HIDE)) {
                                        glVertex2fv(tf->uv[0]);
-                               } else {
+                                       glVertex2fv(tf->uv[1]);
+
+                                       glVertex2fv(tf->uv[1]);
                                        glVertex2fv(tf->uv[2]);
-                                       glVertex2fv(tf->uv[3]);
 
-                                       glVertex2fv(tf->uv[3]);
-                                       glVertex2fv(tf->uv[0]);
+                                       if(!mf->v4) {
+                                               glVertex2fv(tf->uv[2]);
+                                               glVertex2fv(tf->uv[0]);
+                                       } else {
+                                               glVertex2fv(tf->uv[2]);
+                                               glVertex2fv(tf->uv[3]);
+
+                                               glVertex2fv(tf->uv[3]);
+                                               glVertex2fv(tf->uv[0]);
+                                       }
                                }
                        }
+                       glEnd();
+               }
+               else {
+                       int prevstart = 0;
+                       int prevdraw = 1;
+                       int draw = 1;
+                       int curpos = 0;
+
+                       GPU_uvedge_setup(dm);
+                       if( !GPU_buffer_legacy(dm) ) {
+                               for(i = 0; i < dm->numFaceData; i++, mf++) {
+                                       if(mf->flag&ME_LOOSEEDGE) {
+                                               draw = 1;
+                                       } 
+                                       else {
+                                               draw = 0;
+                                       }
+                                       if( prevdraw != draw ) {
+                                               if( prevdraw > 0 && (curpos-prevstart) > 0) {
+                                                       glDrawArrays(GL_LINES,prevstart,curpos-prevstart);
+                                               }
+                                               prevstart = curpos;
+                                       }
+                                       if( mf->v4 ) {
+                                               curpos += 8;
+                                       }
+                                       else {
+                                               curpos += 6;
+                                       }
+                                       prevdraw = draw;
+                               }
+                               if( prevdraw > 0 && (curpos-prevstart) > 0 ) {
+                                       glDrawArrays(GL_LINES,prevstart,curpos-prevstart);
+                               }
+                       }
+                       GPU_buffer_unbind();
                }
-               glEnd();
        }
 }
 
@@ -221,16 +268,48 @@ static void cdDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
        MVert *mvert = cddm->mvert;
        MEdge *medge = cddm->medge;
        int i;
-               
-       glBegin(GL_LINES);
-       for(i = 0; i < dm->numEdgeData; i++, medge++) {
-               if((medge->flag&ME_EDGEDRAW)
-                  && (drawLooseEdges || !(medge->flag&ME_LOOSEEDGE))) {
-                       glVertex3fv(mvert[medge->v1].co);
-                       glVertex3fv(mvert[medge->v2].co);
+       
+       if( GPU_buffer_legacy(dm) ) {
+               DEBUG_VBO( "Using legacy code. cdDM_drawEdges\n" );
+               glBegin(GL_LINES);
+               for(i = 0; i < dm->numEdgeData; i++, medge++) {
+                       if((medge->flag&ME_EDGEDRAW)
+                          && (drawLooseEdges || !(medge->flag&ME_LOOSEEDGE))) {
+                               glVertex3fv(mvert[medge->v1].co);
+                               glVertex3fv(mvert[medge->v2].co);
+                       }
                }
+               glEnd();
+       }
+       else {  /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
+               int prevstart = 0;
+               int prevdraw = 1;
+               int draw = 1;
+
+               GPU_edge_setup(dm);
+               if( !GPU_buffer_legacy(dm) ) {
+                       for(i = 0; i < dm->numEdgeData; i++, medge++) {
+                               if((medge->flag&ME_EDGEDRAW)
+                                  && (drawLooseEdges || !(medge->flag&ME_LOOSEEDGE))) {
+                                       draw = 1;
+                               } 
+                               else {
+                                       draw = 0;
+                               }
+                               if( prevdraw != draw ) {
+                                       if( prevdraw > 0 && (i-prevstart) > 0 ) {
+                                               GPU_buffer_draw_elements( dm->drawObject->edges, GL_LINES, prevstart*2, (i-prevstart)*2  );
+                                       }
+                                       prevstart = i;
+                               }
+                               prevdraw = draw;
+                       }
+                       if( prevdraw > 0 && (i-prevstart) > 0 ) {
+                               GPU_buffer_draw_elements( dm->drawObject->edges, GL_LINES, prevstart*2, (i-prevstart)*2  );
+                       }
+               }
+               GPU_buffer_unbind();
        }
-       glEnd();
 }
 
 static void cdDM_drawLooseEdges(DerivedMesh *dm)
@@ -240,14 +319,45 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm)
        MEdge *medge = cddm->medge;
        int i;
 
-       glBegin(GL_LINES);
-       for(i = 0; i < dm->numEdgeData; i++, medge++) {
-               if(medge->flag&ME_LOOSEEDGE) {
-                       glVertex3fv(mvert[medge->v1].co);
-                       glVertex3fv(mvert[medge->v2].co);
+       if( GPU_buffer_legacy(dm) ) {
+               DEBUG_VBO( "Using legacy code. cdDM_drawLooseEdges\n" );
+               glBegin(GL_LINES);
+               for(i = 0; i < dm->numEdgeData; i++, medge++) {
+                       if(medge->flag&ME_LOOSEEDGE) {
+                               glVertex3fv(mvert[medge->v1].co);
+                               glVertex3fv(mvert[medge->v2].co);
+                       }
                }
+               glEnd();
+       }
+       else {  /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
+               int prevstart = 0;
+               int prevdraw = 1;
+               int draw = 1;
+
+               GPU_edge_setup(dm);
+               if( !GPU_buffer_legacy(dm) ) {
+                       for(i = 0; i < dm->numEdgeData; i++, medge++) {
+                               if(medge->flag&ME_LOOSEEDGE) {
+                                       draw = 1;
+                               } 
+                               else {
+                                       draw = 0;
+                               }
+                               if( prevdraw != draw ) {
+                                       if( prevdraw > 0 && (i-prevstart) > 0) {
+                                               GPU_buffer_draw_elements( dm->drawObject->edges, GL_LINES, prevstart*2, (i-prevstart)*2  );
+                                       }
+                                       prevstart = i;
+                               }
+                               prevdraw = draw;
+                       }
+                       if( prevdraw > 0 && (i-prevstart) > 0 ) {
+                               GPU_buffer_draw_elements( dm->drawObject->edges, GL_LINES, prevstart*2, (i-prevstart)*2  );
+                       }
+               }
+               GPU_buffer_unbind();
        }
-       glEnd();
 }
 
 static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *attribs))
@@ -266,58 +376,73 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int, void *a
        glVertex3fv(mvert[index].co);   \
 }
 
-       glBegin(glmode = GL_QUADS);
-       for(a = 0; a < dm->numFaceData; a++, mface++) {
-               int new_glmode, new_matnr, new_shademodel;
+       if( GPU_buffer_legacy(dm) ) {
+               DEBUG_VBO( "Using legacy code. cdDM_drawFacesSolid\n" );
+               glBegin(glmode = GL_QUADS);
+               for(a = 0; a < dm->numFaceData; a++, mface++) {
+                       int new_glmode, new_matnr, new_shademodel;
 
-               new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
-               new_matnr = mface->mat_nr + 1;
-               new_shademodel = (mface->flag & ME_SMOOTH)?GL_SMOOTH:GL_FLAT;
-               
-               if(new_glmode != glmode || new_matnr != matnr
-                  || new_shademodel != shademodel) {
-                       glEnd();
+                       new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
+                       new_matnr = mface->mat_nr + 1;
+                       new_shademodel = (mface->flag & ME_SMOOTH)?GL_SMOOTH:GL_FLAT;
+                       
+                       if(new_glmode != glmode || new_matnr != matnr
+                          || new_shademodel != shademodel) {
+                               glEnd();
 
-                       drawCurrentMat = setMaterial(matnr = new_matnr, NULL);
+                               drawCurrentMat = setMaterial(matnr = new_matnr, NULL);
 
-                       glShadeModel(shademodel = new_shademodel);
-                       glBegin(glmode = new_glmode);
-               } 
-               
-               if(drawCurrentMat) {
-                       if(shademodel == GL_FLAT) {
-                               if (nors) {
-                                       glNormal3fv(nors);
-                               }
-                               else {
-                                       /* TODO make this better (cache facenormals as layer?) */
-                                       float nor[3];
-                                       if(mface->v4) {
-                                               CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co,
-                                                                          mvert[mface->v3].co, mvert[mface->v4].co,
-                                                                          nor);
-                                       } else {
-                                               CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co,
-                                                                         mvert[mface->v3].co, nor);
+                               glShadeModel(shademodel = new_shademodel);
+                               glBegin(glmode = new_glmode);
+                       } 
+                       
+                       if(drawCurrentMat) {
+                               if(shademodel == GL_FLAT) {
+                                       if (nors) {
+                                               glNormal3fv(nors);
+                                       }
+                                       else {
+                                               /* TODO make this better (cache facenormals as layer?) */
+                                               float nor[3];
+                                               if(mface->v4) {
+                                                       CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co,
+                                                                                  mvert[mface->v3].co, mvert[mface->v4].co,
+                                                                                  nor);
+                                               } else {
+                                                       CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co,
+                                                                                 mvert[mface->v3].co, nor);
+                                               }
+                                               glNormal3fv(nor);
                                        }
-                                       glNormal3fv(nor);
+                               }
+
+                               PASSVERT(mface->v1);
+                               PASSVERT(mface->v2);
+                               PASSVERT(mface->v3);
+                               if(mface->v4) {
+                                       PASSVERT(mface->v4);
                                }
                        }
 
-                       PASSVERT(mface->v1);
-                       PASSVERT(mface->v2);
-                       PASSVERT(mface->v3);
-                       if(mface->v4) {
-                               PASSVERT(mface->v4);
+                       if(nors) nors += 3;
+               }
+               glEnd();
+       }
+       else {  /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
+               GPU_vertex_setup( dm );
+               GPU_normal_setup( dm );
+               if( !GPU_buffer_legacy(dm) ) {
+                       glShadeModel(GL_SMOOTH);
+                       for( a = 0; a < dm->drawObject->nmaterials; 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);
                        }
                }
-
-               if(nors) nors += 3;
+               GPU_buffer_unbind( );
        }
-       glEnd();
 
-       glShadeModel(GL_FLAT);
 #undef PASSVERT
+       glShadeModel(GL_FLAT);
 }
 
 static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2)
@@ -341,43 +466,64 @@ static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned cha
        /* we need that as mesh option builtin, next to double sided lighting */
        if(col1 && col2)
                glEnable(GL_CULL_FACE);
-       
-       glShadeModel(GL_SMOOTH);
-       glBegin(glmode = GL_QUADS);
-       for(a = 0; a < dm->numFaceData; a++, mface++, cp1 += 16) {
-               int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
 
-               if(new_glmode != glmode) {
-                       glEnd();
-                       glBegin(glmode = new_glmode);
-               }
-                       
-               glColor3ub(cp1[0], cp1[1], cp1[2]);
-               glVertex3fv(mvert[mface->v1].co);
-               glColor3ub(cp1[4], cp1[5], cp1[6]);
-               glVertex3fv(mvert[mface->v2].co);
-               glColor3ub(cp1[8], cp1[9], cp1[10]);
-               glVertex3fv(mvert[mface->v3].co);
-               if(mface->v4) {
-                       glColor3ub(cp1[12], cp1[13], cp1[14]);
-                       glVertex3fv(mvert[mface->v4].co);
-               }
-                       
-               if(useTwoSided) {
-                       glColor3ub(cp2[8], cp2[9], cp2[10]);
-                       glVertex3fv(mvert[mface->v3].co );
-                       glColor3ub(cp2[4], cp2[5], cp2[6]);
-                       glVertex3fv(mvert[mface->v2].co );
-                       glColor3ub(cp2[0], cp2[1], cp2[2]);
-                       glVertex3fv(mvert[mface->v1].co );
+       if( GPU_buffer_legacy(dm) ) {
+               DEBUG_VBO( "Using legacy code. cdDM_drawFacesColored\n" );
+               glShadeModel(GL_SMOOTH);
+               glBegin(glmode = GL_QUADS);
+               for(a = 0; a < dm->numFaceData; a++, mface++, cp1 += 16) {
+                       int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
+
+                       if(new_glmode != glmode) {
+                               glEnd();
+                               glBegin(glmode = new_glmode);
+                       }
+                               
+                       glColor3ub(cp1[0], cp1[1], cp1[2]);
+                       glVertex3fv(mvert[mface->v1].co);
+                       glColor3ub(cp1[4], cp1[5], cp1[6]);
+                       glVertex3fv(mvert[mface->v2].co);
+                       glColor3ub(cp1[8], cp1[9], cp1[10]);
+                       glVertex3fv(mvert[mface->v3].co);
                        if(mface->v4) {
-                               glColor3ub(cp2[12], cp2[13], cp2[14]);
-                               glVertex3fv(mvert[mface->v4].co );
+                               glColor3ub(cp1[12], cp1[13], cp1[14]);
+                               glVertex3fv(mvert[mface->v4].co);
                        }
+                               
+                       if(useTwoSided) {
+                               glColor3ub(cp2[8], cp2[9], cp2[10]);
+                               glVertex3fv(mvert[mface->v3].co );
+                               glColor3ub(cp2[4], cp2[5], cp2[6]);
+                               glVertex3fv(mvert[mface->v2].co );
+                               glColor3ub(cp2[0], cp2[1], cp2[2]);
+                               glVertex3fv(mvert[mface->v1].co );
+                               if(mface->v4) {
+                                       glColor3ub(cp2[12], cp2[13], cp2[14]);
+                                       glVertex3fv(mvert[mface->v4].co );
+                               }
+                       }
+                       if(col2) cp2 += 16;
                }
-               if(col2) cp2 += 16;
+               glEnd();
+       }
+       else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
+               GPU_color4_upload(dm,cp1);
+               GPU_vertex_setup(dm);
+               GPU_color_setup(dm);
+               if( !GPU_buffer_legacy(dm) ) {
+                       glShadeModel(GL_SMOOTH);
+                       glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->nelements);
+
+                       if( useTwoSided ) {
+                               GPU_color4_upload(dm,cp2);
+                               GPU_color_setup(dm);
+                               glCullFace(GL_FRONT);
+                               glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->nelements);
+                               glCullFace(GL_BACK);
+                       }
+               }
+               GPU_buffer_unbind();
        }
-       glEnd();
 
        glShadeModel(GL_FLAT);
        glDisable(GL_CULL_FACE);
@@ -390,85 +536,172 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mv = cddm->mvert;
-       MFace *mf = cddm->mface;
-       MCol *mcol = dm->getFaceDataArray(dm, CD_MCOL);
+       MFace *mf = DM_get_face_data_layer(dm, CD_MFACE);
+       MCol *realcol = dm->getFaceDataArray(dm, CD_TEXTURE_MCOL);
        float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
        MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
-       int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+       int i, j, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+       int startFace = 0, lastFlag = 0xdeadbeef;
+       MCol *mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
+       if(!mcol)
+               mcol = dm->getFaceDataArray(dm, CD_MCOL);
+
+       if( GPU_buffer_legacy(dm) ) {
+               DEBUG_VBO( "Using legacy code. cdDM_drawFacesTex_common\n" );
+               for(i = 0; i < dm->numFaceData; i++, mf++) {
+                       MVert *mvert;
+                       int flag;
+                       unsigned char *cp = NULL;
 
-       for(i = 0; i < dm->numFaceData; i++, mf++) {
-               MVert *mvert;
-               int flag;
-               unsigned char *cp = NULL;
+                       if(drawParams) {
+                               flag = drawParams(tf? &tf[i]: NULL, mcol? &mcol[i*4]: NULL, mf->mat_nr);
+                       }
+                       else {
+                               if(index) {
+                                       orig = *index++;
+                                       if(orig == ORIGINDEX_NONE)              { if(nors) nors += 3; continue; }
+                                       if(drawParamsMapped) flag = drawParamsMapped(userData, orig);
+                                       else    { if(nors) nors += 3; continue; }
+                               }
+                               else
+                                       if(drawParamsMapped) flag = drawParamsMapped(userData, i);
+                                       else    { if(nors) nors += 3; continue; }
+                       }
+                       
+                       if(flag != 0) {
+                               if (flag==1 && mcol)
+                                       cp= (unsigned char*) &mcol[i*4];
+
+                               if(!(mf->flag&ME_SMOOTH)) {
+                                       if (nors) {
+                                               glNormal3fv(nors);
+                                       }
+                                       else {
+                                               float nor[3];
+                                               if(mf->v4) {
+                                                       CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
+                                                                                  mv[mf->v3].co, mv[mf->v4].co,
+                                                                                  nor);
+                                               } else {
+                                                       CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
+                                                                                 mv[mf->v3].co, nor);
+                                               }
+                                               glNormal3fv(nor);
+                                       }
+                               }
+
+                               glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
+                               if(tf) glTexCoord2fv(tf[i].uv[0]);
+                               if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+                               mvert = &mv[mf->v1];
+                               if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+                               glVertex3fv(mvert->co);
+                                       
+                               if(tf) glTexCoord2fv(tf[i].uv[1]);
+                               if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+                               mvert = &mv[mf->v2];
+                               if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+                               glVertex3fv(mvert->co);
 
-               if(drawParams) {
-                       flag = drawParams(tf? &tf[i]: NULL, mcol? &mcol[i*4]: NULL, mf->mat_nr);
+                               if(tf) glTexCoord2fv(tf[i].uv[2]);
+                               if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+                               mvert = &mv[mf->v3];
+                               if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+                               glVertex3fv(mvert->co);
+
+                               if(mf->v4) {
+                                       if(tf) glTexCoord2fv(tf[i].uv[3]);
+                                       if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+                                       mvert = &mv[mf->v4];
+                                       if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+                                       glVertex3fv(mvert->co);
+                               }
+                               glEnd();
+                       }
+                       
+                       if(nors) nors += 3;
                }
-               else {
-                       if(index) {
-                               orig = *index++;
-                               if(orig == ORIGINDEX_NONE)              { if(nors) nors += 3; continue; }
-                               if(drawParamsMapped) flag = drawParamsMapped(userData, orig);
-                               else    { if(nors) nors += 3; continue; }
+       } else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
+               MCol *col = realcol;
+               if(!col)
+                       col = mcol;
+
+               GPU_vertex_setup( dm );
+               GPU_normal_setup( dm );
+               GPU_uv_setup( dm );
+               if( col != 0 ) {
+                       /*if( realcol && dm->drawObject->colType == CD_TEXTURE_MCOL )  {
+                               col = 0;
+                       } else if( mcol && dm->drawObject->colType == CD_MCOL ) {
+                               col = 0;
                        }
-                       else
-                               if(drawParamsMapped) flag = drawParamsMapped(userData, i);
-                               else    { if(nors) nors += 3; continue; }
+                       
+                       if( col != 0 ) {*/
+                               unsigned char *colors = MEM_mallocN(dm->getNumFaces(dm)*4*3*sizeof(unsigned char), "cdDM_drawFacesTex_common");
+                               for( i=0; i < dm->getNumFaces(dm); i++ ) {
+                                       for( j=0; j < 4; j++ ) {
+                                               colors[i*12+j*3] = col[i*4+j].r;
+                                               colors[i*12+j*3+1] = col[i*4+j].g;
+                                               colors[i*12+j*3+2] = col[i*4+j].b;
+                                       }
+                               }
+                               GPU_color3_upload(dm,colors);
+                               MEM_freeN(colors);
+                               if(realcol)
+                                       dm->drawObject->colType = CD_TEXTURE_MCOL;
+                               else if(mcol)
+                                       dm->drawObject->colType = CD_MCOL;
+                       //}
+                       GPU_color_setup( dm );
                }
-               
-               if(flag != 0) { /* if the flag is 0 it means the face is hidden or invisible */
-                       if (flag==1 && mcol)
-                               cp= (unsigned char*) &mcol[i*4];
 
-                       if(!(mf->flag&ME_SMOOTH)) {
-                               if (nors) {
-                                       glNormal3fv(nors);
+               if( !GPU_buffer_legacy(dm) ) {
+                       glShadeModel( GL_SMOOTH );
+                       for(i = 0; i < dm->drawObject->nelements/3; i++) {
+                               int actualFace = dm->drawObject->faceRemap[i];
+                               int flag = 1;
+                               unsigned char *cp = NULL;
+
+                               if(drawParams) {
+                                       flag = drawParams(tf? &tf[actualFace]: NULL, mcol? &mcol[actualFace*4]: NULL, mf[actualFace].mat_nr);
                                }
                                else {
-                                       /* TODO make this better (cache facenormals as layer?) */
-                                       float nor[3];
-                                       if(mf->v4) {
-                                               CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
-                                                                          mv[mf->v3].co, mv[mf->v4].co,
-                                                                          nor);
-                                       } else {
-                                               CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
-                                                                         mv[mf->v3].co, nor);
+                                       if(index) {
+                                               orig = index[actualFace];
+                                               if(drawParamsMapped)
+                                                       flag = drawParamsMapped(userData, orig);
                                        }
-                                       glNormal3fv(nor);
+                                       else
+                                               if(drawParamsMapped)
+                                                       flag = drawParamsMapped(userData, actualFace);
+                               }
+                               if( flag != lastFlag ) {
+                                       if( startFace < i ) {
+                                               if( lastFlag != 0 ) { /* if the flag is 0 it means the face is hidden or invisible */
+                                                       if (lastFlag==1 && mcol)
+                                                               GPU_color_switch(1);
+                                                       else
+                                                               GPU_color_switch(0);
+                                                       glDrawArrays(GL_TRIANGLES,startFace*3,(i-startFace)*3);
+                                               }
+                                       }
+                                       lastFlag = flag;
+                                       startFace = i;
                                }
                        }
-
-                       glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
-                       if(tf) glTexCoord2fv(tf[i].uv[0]);
-                       if(cp) glColor3ub(cp[3], cp[2], cp[1]);
-                       mvert = &mv[mf->v1];
-                       if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
-                       glVertex3fv(mvert->co);
-                               
-                       if(tf) glTexCoord2fv(tf[i].uv[1]);
-                       if(cp) glColor3ub(cp[7], cp[6], cp[5]);
-                       mvert = &mv[mf->v2];
-                       if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
-                       glVertex3fv(mvert->co);
-
-                       if(tf) glTexCoord2fv(tf[i].uv[2]);
-                       if(cp) glColor3ub(cp[11], cp[10], cp[9]);
-                       mvert = &mv[mf->v3];
-                       if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
-                       glVertex3fv(mvert->co);
-
-                       if(mf->v4) {
-                               if(tf) glTexCoord2fv(tf[i].uv[3]);
-                               if(cp) glColor3ub(cp[15], cp[14], cp[13]);
-                               mvert = &mv[mf->v4];
-                               if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
-                               glVertex3fv(mvert->co);
+                       if( startFace < dm->drawObject->nelements/3 ) {
+                               if( lastFlag != 0 ) { /* if the flag is 0 it means the face is hidden or invisible */
+                                       if (lastFlag==1 && mcol)
+                                               GPU_color_switch(1);
+                                       else
+                                               GPU_color_switch(0);
+                                       glDrawArrays(GL_TRIANGLES,startFace*3,dm->drawObject->nelements-startFace*3);
+                               }
                        }
-                       glEnd();
                }
-               
-               if(nors) nors += 3;
+
+               GPU_buffer_unbind();
+               glShadeModel( GL_FLAT );
        }
 }
 
@@ -486,79 +719,131 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
        float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
        int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
 
-       mc = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
+
+       mc = DM_get_face_data_layer(dm, CD_ID_MCOL);
+       if(!mc)
+               mc = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
        if(!mc)
                mc = DM_get_face_data_layer(dm, CD_MCOL);
 
-       for(i = 0; i < dm->numFaceData; i++, mf++) {
-               int drawSmooth = (mf->flag & ME_SMOOTH);
+       if( GPU_buffer_legacy(dm) ) {
+               DEBUG_VBO( "Using legacy code. cdDM_drawMappedFaces\n" );
+               for(i = 0; i < dm->numFaceData; i++, mf++) {
+                       int drawSmooth = (mf->flag & ME_SMOOTH);
 
-               if(index) {
-                       orig = *index++;
-                       if(setDrawOptions && orig == ORIGINDEX_NONE)
-                               { if(nors) nors += 3; continue; }
-               }
-               else
-                       orig = i;
+                       if(index) {
+                               orig = *index++;
+                               if(setDrawOptions && orig == ORIGINDEX_NONE)
+                                       { if(nors) nors += 3; continue; }
+                       }
+                       else
+                               orig = i;
 
-               if(!setDrawOptions || setDrawOptions(userData, orig, &drawSmooth)) {
-                       unsigned char *cp = NULL;
+                       if(!setDrawOptions || setDrawOptions(userData, orig, &drawSmooth)) {
+                               unsigned char *cp = NULL;
 
-                       if(useColors && mc)
-                               cp = (unsigned char *)&mc[i * 4];
+                               if(useColors && mc)
+                                       cp = (unsigned char *)&mc[i * 4];
 
-                       glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
-                       glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
+                               glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+                               glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
 
-                       if (!drawSmooth) {
-                               if (nors) {
-                                       glNormal3fv(nors);
-                               }
-                               else {
-                                       /* TODO make this better (cache facenormals as layer?) */
-                                       float nor[3];
+                               if (!drawSmooth) {
+                                       if (nors) {
+                                               glNormal3fv(nors);
+                                       }
+                                       else {
+                                               float nor[3];
+                                               if(mf->v4) {
+                                                       CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
+                                                                                  mv[mf->v3].co, mv[mf->v4].co,
+                                                                                  nor);
+                                               } else {
+                                                       CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
+                                                                                 mv[mf->v3].co, nor);
+                                               }
+                                               glNormal3fv(nor);
+                                       }
+
+                                       if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+                                       glVertex3fv(mv[mf->v1].co);
+                                       if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+                                       glVertex3fv(mv[mf->v2].co);
+                                       if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+                                       glVertex3fv(mv[mf->v3].co);
                                        if(mf->v4) {
-                                               CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
-                                                                          mv[mf->v3].co, mv[mf->v4].co,
-                                                                          nor);
-                                       } else {
-                                               CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
-                                                                         mv[mf->v3].co, nor);
+                                               if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+                                               glVertex3fv(mv[mf->v4].co);
+                                       }
+                               } else {
+                                       if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+                                       glNormal3sv(mv[mf->v1].no);
+                                       glVertex3fv(mv[mf->v1].co);
+                                       if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+                                       glNormal3sv(mv[mf->v2].no);
+                                       glVertex3fv(mv[mf->v2].co);
+                                       if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+                                       glNormal3sv(mv[mf->v3].no);
+                                       glVertex3fv(mv[mf->v3].co);
+                                       if(mf->v4) {
+                                               if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+                                               glNormal3sv(mv[mf->v4].no);
+                                               glVertex3fv(mv[mf->v4].co);
                                        }
-                                       glNormal3fv(nor);
                                }
 
-                               if(cp) glColor3ub(cp[3], cp[2], cp[1]);
-                               glVertex3fv(mv[mf->v1].co);
-                               if(cp) glColor3ub(cp[7], cp[6], cp[5]);
-                               glVertex3fv(mv[mf->v2].co);
-                               if(cp) glColor3ub(cp[11], cp[10], cp[9]);
-                               glVertex3fv(mv[mf->v3].co);
-                               if(mf->v4) {
-                                       if(cp) glColor3ub(cp[15], cp[14], cp[13]);
-                                       glVertex3fv(mv[mf->v4].co);
+                               glEnd();
+                       }
+                       
+                       if (nors) nors += 3;
+               }
+       }
+       else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
+               int state = 1;
+               int prevstate = 1;
+               int prevstart = 0;
+               GPU_vertex_setup(dm);
+               GPU_normal_setup(dm);
+               if( useColors && mc )
+                       GPU_color_setup(dm);
+               if( !GPU_buffer_legacy(dm) ) {
+                       glShadeModel(GL_SMOOTH);
+                       for( i = 0; i < dm->drawObject->nelements/3; i++ ) {
+                               int actualFace = dm->drawObject->faceRemap[i];
+                               int drawSmooth = (mf[actualFace].flag & ME_SMOOTH);
+                               int dontdraw = 0;
+                               if(index) {
+                                       orig = index[actualFace];
+                                       if(setDrawOptions && orig == ORIGINDEX_NONE)
+                                               dontdraw = 1;
                                }
-                       } else {
-                               if(cp) glColor3ub(cp[3], cp[2], cp[1]);
-                               glNormal3sv(mv[mf->v1].no);
-                               glVertex3fv(mv[mf->v1].co);
-                               if(cp) glColor3ub(cp[7], cp[6], cp[5]);
-                               glNormal3sv(mv[mf->v2].no);
-                               glVertex3fv(mv[mf->v2].co);
-                               if(cp) glColor3ub(cp[11], cp[10], cp[9]);
-                               glNormal3sv(mv[mf->v3].no);
-                               glVertex3fv(mv[mf->v3].co);
-                               if(mf->v4) {
-                                       if(cp) glColor3ub(cp[15], cp[14], cp[13]);
-                                       glNormal3sv(mv[mf->v4].no);
-                                       glVertex3fv(mv[mf->v4].co);
+                               else
+                                       orig = i;
+                               if( dontdraw ) {
+                                       state = 0;
+                               }
+                               else {
+                                       if(!setDrawOptions || setDrawOptions(userData, orig, &drawSmooth)) {
+                                               state = 1;
+                                       }
+                                       else {
+                                               state = 0;
+                                       }
                                }
+                               if( prevstate != state && prevstate == 1 ) {
+                                       if( i-prevstart > 0 ) {
+                                               glDrawArrays(GL_TRIANGLES,prevstart*3,(i-prevstart)*3);
+                                       }
+                                       prevstart = i;
+                               }
+                               prevstate = state;
                        }
-
-                       glEnd();
+                       if(state==1) {
+                               glDrawArrays(GL_TRIANGLES,prevstart*3,dm->drawObject->nelements-prevstart*3);
+                       }
+                       glShadeModel(GL_FLAT);
                }
-               
-               if (nors) nors += 3;
+               GPU_buffer_unbind();
        }
 }
 
@@ -586,106 +871,309 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
        transp = GPU_get_material_blend_mode();
        orig_transp = transp;
 
-       memset(&attribs, 0, sizeof(attribs));
-
        glShadeModel(GL_SMOOTH);
-       glBegin(GL_QUADS);
 
-       for(a = 0; a < dm->numFaceData; a++, mface++) {
-               new_matnr = mface->mat_nr + 1;
+       if( GPU_buffer_legacy(dm) || setDrawOptions != 0 ) {
+               DEBUG_VBO( "Using legacy code. cdDM_drawMappedFacesGLSL\n" );
+               memset(&attribs, 0, sizeof(attribs));
 
-               if(new_matnr != matnr) {
-                       glEnd();
+               glBegin(GL_QUADS);
 
-                       dodraw = setMaterial(matnr = new_matnr, &gattribs);
-                       if(dodraw)
-                               DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+               for(a = 0; a < dm->numFaceData; a++, mface++) {
+                       new_matnr = mface->mat_nr + 1;
 
-                       glBegin(GL_QUADS);
-               }
+                       if(new_matnr != matnr) {
+                               glEnd();
 
-               if(!dodraw) {
-                       continue;
-               }
-               else if(setDrawOptions) {
-                       orig = index[a];
+                               dodraw = setMaterial(matnr = new_matnr, &gattribs);
+                               if(dodraw)
+                                       DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
 
-                       if(orig == ORIGINDEX_NONE)
-                               continue;
-                       else if(!setDrawOptions(userData, orig))
+                               glBegin(GL_QUADS);
+                       }
+
+                       if(!dodraw) {
                                continue;
-               }
+                       }
+                       else if(setDrawOptions) {
+                               orig = index[a];
+
+                               if(orig == ORIGINDEX_NONE)
+                                       continue;
+                               else if(!setDrawOptions(userData, orig))
+                                       continue;
+                       }
 
-               if(tf) {
-                       new_transp = tf[a].transp;
+                       if(tf) {
+                               new_transp = tf[a].transp;
 
-                       if(new_transp != transp) {
-                               glEnd();
+                               if(new_transp != transp) {
+                                       glEnd();
 
-                               if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
-                                       GPU_set_material_blend_mode(orig_transp);
-                               else
-                                       GPU_set_material_blend_mode(new_transp);
-                               transp = new_transp;
+                                       if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
+                                               GPU_set_material_blend_mode(orig_transp);
+                                       else
+                                               GPU_set_material_blend_mode(new_transp);
+                                       transp = new_transp;
 
-                               glBegin(GL_QUADS);
+                                       glBegin(GL_QUADS);
+                               }
                        }
-               }
 
-               smoothnormal = (mface->flag & ME_SMOOTH);
+                       smoothnormal = (mface->flag & ME_SMOOTH);
 
-               if(!smoothnormal) {
-                       if(nors) {
-                               glNormal3fv(nors[a]);
-                       }
-                       else {
-                               /* TODO ideally a normal layer should always be available */
-                               float nor[3];
-                               if(mface->v4) {
-                                       CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co,
-                                                                  mvert[mface->v3].co, mvert[mface->v4].co,
-                                                                  nor);
-                               } else {
-                                       CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co,
-                                                                 mvert[mface->v3].co, nor);
+                       if(!smoothnormal) {
+                               if(nors) {
+                                       glNormal3fv(nors[a]);
+                               }
+                               else {
+                                       /* TODO ideally a normal layer should always be available */
+                                       float nor[3];
+                                       if(mface->v4) {
+                                               CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co,
+                                                                          mvert[mface->v3].co, mvert[mface->v4].co,
+                                                                          nor);
+                                       } else {
+                                               CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co,
+                                                                         mvert[mface->v3].co, nor);
+                                       }
+                                       glNormal3fv(nor);
                                }
-                               glNormal3fv(nor);
                        }
-               }
 
 #define PASSVERT(index, vert) {                                                                                                        \
-       if(attribs.totorco)                                                                                                                     \
-               glVertexAttrib3fvARB(attribs.orco.glIndex, attribs.orco.array[index]);  \
-       for(b = 0; b < attribs.tottface; b++) {                                                                         \
-               MTFace *tf = &attribs.tface[b].array[a];                                                                \
-               glVertexAttrib2fvARB(attribs.tface[b].glIndex, tf->uv[vert]);                   \
-       }                                                                                                                                                       \
-       for(b = 0; b < attribs.totmcol; b++) {                                                                          \
-               MCol *cp = &attribs.mcol[b].array[a*4 + vert];                                                  \
-               GLubyte col[4];                                                                                                                 \
-               col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a;                             \
-               glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, col);                                    \
-       }                                                                                                                                                       \
-       if(attribs.tottang) {                                                                                                           \
-               float *tang = attribs.tang.array[a*4 + vert];                                                   \
-               glVertexAttrib3fvARB(attribs.tang.glIndex, tang);                                               \
-       }                                                                                                                                                       \
-       if(smoothnormal)                                                                                                                        \
-               glNormal3sv(mvert[index].no);                                                                                   \
-       glVertex3fv(mvert[index].co);                                                                                           \
-}
-
-               PASSVERT(mface->v1, 0);
-               PASSVERT(mface->v2, 1);
-               PASSVERT(mface->v3, 2);
-               if(mface->v4)
-                       PASSVERT(mface->v4, 3)
-               else
-                       PASSVERT(mface->v3, 2)
+               if(attribs.totorco)                                                                                                                     \
+                       glVertexAttrib3fvARB(attribs.orco.glIndex, attribs.orco.array[index]);  \
+               for(b = 0; b < attribs.tottface; b++) {                                                                         \
+                       MTFace *tf = &attribs.tface[b].array[a];                                                                \
+                       glVertexAttrib2fvARB(attribs.tface[b].glIndex, tf->uv[vert]);                   \
+               }                                                                                                                                                       \
+               for(b = 0; b < attribs.totmcol; b++) {                                                                          \
+                       MCol *cp = &attribs.mcol[b].array[a*4 + vert];                                                  \
+                       GLubyte col[4];                                                                                                                 \
+                       col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a;                             \
+                       glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, col);                                    \
+               }                                                                                                                                                       \
+               if(attribs.tottang) {                                                                                                           \
+                       float *tang = attribs.tang.array[a*4 + vert];                                                   \
+                       glVertexAttrib3fvARB(attribs.tang.glIndex, tang);                                               \
+               }                                                                                                                                                       \
+               if(smoothnormal)                                                                                                                        \
+                       glNormal3sv(mvert[index].no);                                                                                   \
+               glVertex3fv(mvert[index].co);                                                                                           \
+       }
+
+                       PASSVERT(mface->v1, 0);
+                       PASSVERT(mface->v2, 1);
+                       PASSVERT(mface->v3, 2);
+                       if(mface->v4)
+                               PASSVERT(mface->v4, 3)
+                       else
+                               PASSVERT(mface->v3, 2)
 
 #undef PASSVERT
+               }
+               glEnd();
+       }
+       else {
+               GPUBuffer *buffer = 0;
+               char *varray = 0;
+               int numdata = 0, elementsize = 0, offset;
+               int start = 0, numfaces = 0, prevdraw = 0, curface = 0;
+               GPUAttrib datatypes[32];
+               memset(&attribs, 0, sizeof(attribs));
+
+               GPU_vertex_setup(dm);
+               GPU_normal_setup(dm);
+
+               if( !GPU_buffer_legacy(dm) ) {
+                       for(a = 0; a < dm->numFaceData; a++, mface++) {
+                               new_matnr = mface->mat_nr + 1;
+
+                               if(new_matnr != matnr ) {
+                                       numfaces = curface - start;
+                                       if( numfaces > 0 ) {
+                                               if( prevdraw ) {
+                                                       GPU_buffer_unlock(buffer);
+                                                       GPU_interleaved_attrib_setup(buffer,datatypes,numdata);
+                                                       glDrawArrays(GL_TRIANGLES,start*3,numfaces*3);
+                                                       GPU_buffer_free(buffer,0);
+                                               }
+                                       }
+                                       start = curface;
+                                       prevdraw = dodraw;
+                                       dodraw = setMaterial(matnr = new_matnr, &gattribs);
+                                       if(dodraw) {
+                                               DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+
+                                               if(attribs.totorco) {
+                                                       datatypes[numdata].index = attribs.orco.glIndex;
+                                                       datatypes[numdata].size = 3;
+                                                       datatypes[numdata].type = GL_FLOAT;
+                                                       numdata++;
+                                               }
+                                               for(b = 0; b < attribs.tottface; b++) {
+                                                       datatypes[numdata].index = attribs.tface[b].glIndex;
+                                                       datatypes[numdata].size = 2;
+                                                       datatypes[numdata].type = GL_FLOAT;
+                                                       numdata++;
+                                               }       
+                                               for(b = 0; b < attribs.totmcol; b++) {
+                                                       datatypes[numdata].index = attribs.mcol[b].glIndex;
+                                                       datatypes[numdata].size = 4;
+                                                       datatypes[numdata].type = GL_UNSIGNED_BYTE;
+                                                       numdata++;
+                                               }       
+                                               if(attribs.tottang) {
+                                                       datatypes[numdata].index = attribs.tang.glIndex;
+                                                       datatypes[numdata].size = 3;
+                                                       datatypes[numdata].type = GL_FLOAT;
+                                                       numdata++;
+                                               }
+                                               if( numdata != 0 ) {
+                                                       elementsize = GPU_attrib_element_size( datatypes, numdata );
+                                                       buffer = GPU_buffer_alloc( elementsize*dm->drawObject->nelements, 0 );
+                                                       if( buffer == 0 ) {
+                                                               GPU_buffer_unbind();
+                                                               dm->drawObject->legacy = 1;
+                                                               return;
+                                                       }
+                                                       varray = GPU_buffer_lock_stream(buffer);
+                                                       if( varray == 0 ) {
+                                                               GPU_buffer_unbind();
+                                                               GPU_buffer_free(buffer, 0);
+                                                               dm->drawObject->legacy = 1;
+                                                               return;
+                                                       }
+                                               }
+                                       }
+                               }
+                               if(!dodraw) {
+                                       continue;
+                               }
+
+                               if(tf) {
+                                       new_transp = tf[a].transp;
+
+                                       if(new_transp != transp) {
+                                               numfaces = curface - start;
+                                               if( numfaces > 0 ) {
+                                                       if( dodraw ) {
+                                                               if( numdata != 0 ) {
+                                                                       GPU_buffer_unlock(buffer);
+                                                                       GPU_interleaved_attrib_setup(buffer,datatypes,numdata);
+                                                               }
+                                                               glDrawArrays(GL_TRIANGLES,start*3,(curface-start)*3);
+                                                               if( numdata != 0 ) {
+                                                                       varray = GPU_buffer_lock_stream(buffer);
+                                                               }
+                                                       }
+                                               }
+                                               start = curface;
+
+                                               if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
+                                                       GPU_set_material_blend_mode(orig_transp);
+                                               else
+                                                       GPU_set_material_blend_mode(new_transp);
+                                               transp = new_transp;
+                                       }
+                               }
+                               
+                               if( numdata != 0 ) {
+                                       offset = 0;
+                                       if(attribs.totorco) {
+                                               VECCOPY((float *)&varray[elementsize*curface*3],(float *)attribs.orco.array[mface->v1]);
+                                               VECCOPY((float *)&varray[elementsize*curface*3+elementsize],(float *)attribs.orco.array[mface->v2]);
+                                               VECCOPY((float *)&varray[elementsize*curface*3+elementsize*2],(float *)attribs.orco.array[mface->v3]);
+                                               offset += sizeof(float)*3;
+                                       }
+                                       for(b = 0; b < attribs.tottface; b++) {
+                                               MTFace *tf = &attribs.tface[b].array[a];
+                                               VECCOPY((float *)&varray[elementsize*curface*3+offset],tf->uv[0]);
+                                               VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize],tf->uv[1]);
+                                               VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2],tf->uv[2]);
+                                               offset += sizeof(float)*2;
+                                       }
+                                       for(b = 0; b < attribs.totmcol; b++) {
+                                               MCol *cp = &attribs.mcol[b].array[a*4 + 0];
+                                               GLubyte col[4];
+                                               col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a;
+                                               QUATCOPY((unsigned char *)&varray[elementsize*curface*3+offset], col);
+                                               cp = &attribs.mcol[b].array[a*4 + 1];
+                                               col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a;
+                                               QUATCOPY((unsigned char *)&varray[elementsize*curface*3+offset+elementsize], col);
+                                               cp = &attribs.mcol[b].array[a*4 + 2];
+                                               col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a;
+                                               QUATCOPY((unsigned char *)&varray[elementsize*curface*3+offset+elementsize*2], col);
+                                               offset += sizeof(unsigned char)*4;
+                                       }       
+                                       if(attribs.tottang) {
+                                               float *tang = attribs.tang.array[a*4 + 0];
+                                               VECCOPY((float *)&varray[elementsize*curface*3+offset], tang);
+                                               tang = attribs.tang.array[a*4 + 1];
+                                               VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize], tang);
+                                               tang = attribs.tang.array[a*4 + 2];
+                                               VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize], tang);
+                                               offset += sizeof(float)*3;
+                                       }
+                               }
+                               curface++;
+                               if(mface->v4) {
+                                       if( numdata != 0 ) {
+                                               offset = 0;
+                                               if(attribs.totorco) {
+                                                       VECCOPY((float *)&varray[elementsize*curface*3],(float *)attribs.orco.array[mface->v3]);
+                                                       VECCOPY((float *)&varray[elementsize*curface*3+elementsize],(float *)attribs.orco.array[mface->v4]);
+                                                       VECCOPY((float *)&varray[elementsize*curface*3+elementsize*2],(float *)attribs.orco.array[mface->v1]);
+                                                       offset += sizeof(float)*3;
+                                               }
+                                               for(b = 0; b < attribs.tottface; b++) {
+                                                       MTFace *tf = &attribs.tface[b].array[a];
+                                                       VECCOPY((float *)&varray[elementsize*curface*3+offset],tf->uv[2]);
+                                                       VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize],tf->uv[3]);
+                                                       VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2],tf->uv[0]);
+                                                       offset += sizeof(float)*2;
+                                               }
+                                               for(b = 0; b < attribs.totmcol; b++) {
+                                                       MCol *cp = &attribs.mcol[b].array[a*4 + 2];
+                                                       GLubyte col[4];
+                                                       col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a;
+                                                       QUATCOPY((unsigned char *)&varray[elementsize*curface*3+offset], col);
+                                                       cp = &attribs.mcol[b].array[a*4 + 3];
+                                                       col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a;
+                                                       QUATCOPY((unsigned char *)&varray[elementsize*curface*3+offset+elementsize], col);
+                                                       cp = &attribs.mcol[b].array[a*4 + 0];
+                                                       col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a;
+                                                       QUATCOPY((unsigned char *)&varray[elementsize*curface*3+offset+elementsize*2], col);
+                                                       offset += sizeof(unsigned char)*4;
+                                               }       
+                                               if(attribs.tottang) {
+                                                       float *tang = attribs.tang.array[a*4 + 2];
+                                                       VECCOPY((float *)&varray[elementsize*curface*3+offset], tang);
+                                                       tang = attribs.tang.array[a*4 + 3];
+                                                       VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize], tang);
+                                                       tang = attribs.tang.array[a*4 + 0];
+                                                       VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize], tang);
+                                                       offset += sizeof(float)*3;
+                                               }
+                                       }
+                                       curface++;
+                               }
+                       }
+                       numfaces = curface - start;
+                       if( numfaces > 0 ) {
+                               if( dodraw ) {
+                                       if( numdata != 0 ) {
+                                               GPU_buffer_unlock(buffer);
+                                               GPU_interleaved_attrib_setup(buffer,datatypes,numdata);
+                                       }
+                                       glDrawArrays(GL_TRIANGLES,start*3,(curface-start)*3);
+                               }
+                       }
+                       GPU_buffer_unbind();
+               }
+               GPU_buffer_free( buffer, 0 );
        }
-       glEnd();
 
        glShadeModel(GL_FLAT);
 }
index 705d0b66d7ff8b8ab1a98e63660afa2c70c9c73b..28aaadea9c337c02560e72dcd162849bdd7ffbed 100644 (file)
@@ -726,6 +726,10 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
         layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL},
        {sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol,
         layerSwap_mcol, layerDefault_mcol},
+        {sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol,
+        layerSwap_mcol, layerDefault_mcol},
+        {sizeof(MCol)*4, "MCol", 4, "TexturedCol", NULL, NULL, layerInterp_mcol,
+        layerSwap_mcol, layerDefault_mcol},
 };
 
 const char *LAYERTYPENAMES[CD_NUMTYPES] = {
index deee3e3c8b4234023e5b5b4b212f2005e8377b3d..e394de613e41bded4fda3aa689b3a40d36c0edee 100644 (file)
@@ -197,6 +197,7 @@ void gla2DSetMap(gla2DDrawInfo *di, struct rctf *rect);
 /* use this for platform hacks. glPointSize is solved here */
 void bglBegin(int mode);
 void bglEnd(void);
+int bglPointHack();
 void bglVertex3fv(float *vec);
 void bglVertex3f(float x, float y, float z);
 void bglVertex2fv(float *vec);
index 5312ca269061d3897409549341a183ac8fd96cd9..1445c6b5cf87ffd1b50031949c95a9e79e3035f3 100644 (file)
@@ -720,6 +720,18 @@ void bglBegin(int mode)
        }
 }
 
+int bglPointHack() {
+       float value[4];
+       int pointhack;
+       glGetFloatv(GL_POINT_SIZE_RANGE, value);
+       if(value[1]<2.0) {
+               glGetFloatv(GL_POINT_SIZE, value);
+               pointhack= floor(value[0]+0.5);
+               if(pointhack>4) pointhack= 4;
+               return pointhack;
+       }
+       return 0;
+}
 
 void bglVertex3fv(float *vec)
 {
index 64af39ea497500248d249538eda10d56fd17c62d..e41231442baa19972f21f126ac1b345146384a96 100644 (file)
@@ -91,6 +91,7 @@
 #include "RE_shader_ext.h" /*for multitex_ext*/
 
 #include "GPU_draw.h"
+#include "gpu_buffers.h"
 
 #include <math.h>
 #include <stdlib.h>
@@ -304,21 +305,34 @@ static void calc_area_normal(Sculpt *sd, SculptSession *ss, float out[3], const
 static void do_draw_brush(Sculpt *sd, SculptSession *ss, const ListBase* active_verts)
 {
        float area_normal[3];
+       int j;
        ActiveData *node= active_verts->first;
+       float* buffer;
 
        calc_area_normal(sd, ss, area_normal, active_verts);
        
+       buffer = (float *)GPU_buffer_lock( ss->drawobject->vertices );
        while(node){
                float *co= ss->mvert[node->Index].co;
 
                const float val[3]= {co[0]+area_normal[0]*ss->cache->radius*node->Fade*ss->cache->scale[0],
                                     co[1]+area_normal[1]*ss->cache->radius*node->Fade*ss->cache->scale[1],
                                     co[2]+area_normal[2]*ss->cache->radius*node->Fade*ss->cache->scale[2]};
-                                    
+
+               if( buffer != 0 ) {
+                       IndexLink *cur = &ss->drawobject->indices[node->Index];
+                       while( cur != 0 && cur->element != -1 ) {
+                               sculpt_clip(sd, ss, &buffer[cur->element*3], val);
+                               cur = cur->next;
+                       }
+               }
+
                sculpt_clip(sd, ss, co, val);
-               
+
                node= node->next;
        }
+       if( buffer != 0 )
+               GPU_buffer_unlock( ss->drawobject->vertices );
 }
 
 /* For the smooth brush, uses the neighboring vertices around vert to calculate
@@ -368,6 +382,7 @@ static void neighbor_average(SculptSession *ss, float avg[3], const int vert)
 static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
 {
        ActiveData *node= active_verts->first;
+       float *buffer = (float *)GPU_buffer_lock( ss->drawobject->vertices );
        int i;
        
        for(i = 0; i < 2; ++i) {
@@ -380,24 +395,45 @@ static void do_smooth_brush(Sculpt *s, SculptSession *ss, const ListBase* active
                        val[1] = co[1]+(avg[1]-co[1])*node->Fade;
                        val[2] = co[2]+(avg[2]-co[2])*node->Fade;
                        
-                       sculpt_clip(s, ss, co, val);
+                       sculpt_clip(s, ss, co, val);                    
+                       if( buffer != 0 ) {                             
+                               IndexLink *cur = &ss->drawobject->indices[node->Index]; 
+                               while( cur != 0 && cur->element != -1 ) {
+                                       sculpt_clip(s, ss, &buffer[cur->element*3], val);
+                                       cur = cur->next;
+                               }
+                       }
                        node= node->next;
                }
        }
+       if( buffer != 0 )
+               GPU_buffer_unlock( ss->drawobject->vertices );
 }
 
 static void do_pinch_brush(Sculpt *s, SculptSession *ss, const ListBase* active_verts)
 {
        ActiveData *node= active_verts->first;
+       float *buffer = (float *)GPU_buffer_lock( ss->drawobject->vertices );
 
        while(node) {
                float *co= ss->mvert[node->Index].co;
                const float val[3]= {co[0]+(ss->cache->location[0]-co[0])*node->Fade,
                                     co[1]+(ss->cache->location[1]-co[1])*node->Fade,
                                     co[2]+(ss->cache->location[2]-co[2])*node->Fade};
+
+               if( buffer != 0 ) {
+                       IndexLink *cur = &ss->drawobject->indices[node->Index];
+                       while( cur != 0 && cur->element != -1 ) {
+                               sculpt_clip(s, ss, &buffer[cur->element*3], val);
+                               cur = cur->next;
+                       }
+               }
+
                sculpt_clip(s, ss, co, val);
                node= node->next;
        }
+       if( buffer != 0 )
+               GPU_buffer_unlock( ss->drawobject->vertices );
 }
 
 static void do_grab_brush(Sculpt *sd, SculptSession *ss)
@@ -405,6 +441,7 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss)
        ActiveData *node= ss->cache->grab_active_verts[ss->cache->symmetry].first;
        float add[3];
        float grab_delta[3];
+       float *buffer = (float *)GPU_buffer_lock( ss->drawobject->vertices );
        
        VecCopyf(grab_delta, ss->cache->grab_delta_symmetry);
        
@@ -414,10 +451,21 @@ static void do_grab_brush(Sculpt *sd, SculptSession *ss)
                VecCopyf(add, grab_delta);
                VecMulf(add, node->Fade);
                VecAddf(add, add, co);
+
+               if( buffer != 0 ) {
+                       IndexLink *cur = &ss->drawobject->indices[node->Index];
+                       while( cur != 0 && cur->element != -1 ) {
+                               sculpt_clip(sd, ss, &buffer[cur->element*3], add);
+                               cur = cur->next;
+                       }
+               }
+
                sculpt_clip(sd, ss, co, add);
 
                node= node->next;
        }
+       if( buffer != 0 )
+               GPU_buffer_unlock( ss->drawobject->vertices );
        
 }
 
@@ -425,6 +473,7 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active
 {
        float area_normal[3];
        ActiveData *node= active_verts->first;
+       float *buffer;
        float lim= ss->cache->radius / 4;
 
        if(ss->cache->flip)
@@ -432,6 +481,7 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active
 
        calc_area_normal(sd, ss, area_normal, active_verts);
 
+       buffer = (float *)GPU_buffer_lock( ss->drawobject->vertices );
        while(node){
                float *disp= &ss->layer_disps[node->Index];
                float *co= ss->mvert[node->Index].co;
@@ -447,17 +497,28 @@ static void do_layer_brush(Sculpt *sd, SculptSession *ss, const ListBase *active
                val[1] = ss->mesh_co_orig[node->Index][1]+area_normal[1] * *disp*ss->cache->scale[1];
                val[2] = ss->mesh_co_orig[node->Index][2]+area_normal[2] * *disp*ss->cache->scale[2];
 
+               if( buffer != 0 ) {
+                       IndexLink *cur = &ss->drawobject->indices[node->Index];
+                       while( cur != 0 && cur->element != -1 ) {
+                               sculpt_clip(sd, ss, &buffer[cur->element*3], val);
+                               cur = cur->next;
+                       }
+               }
+
                sculpt_clip(sd, ss, co, val);
 
                node= node->next;
        }
+       if( buffer != 0 )
+               GPU_buffer_unlock( ss->drawobject->vertices );
 }
 
 static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *active_verts)
 {
        ActiveData *node= active_verts->first;
        float add[3];
-       
+       float *buffer = (float *)GPU_buffer_lock( ss->drawobject->vertices );
+
        while(node) {
                float *co= ss->mvert[node->Index].co;
                short *no= ss->mvert[node->Index].no;
@@ -471,10 +532,20 @@ static void do_inflate_brush(Sculpt *s, SculptSession *ss, const ListBase *activ
                add[2]*= ss->cache->scale[2];
                VecAddf(add, add, co);
                
+               if( buffer != 0 ) {
+                       IndexLink *cur = &ss->drawobject->indices[node->Index];
+                       while( cur != 0 && cur->element != -1 ) {
+                               sculpt_clip(s, ss, &buffer[cur->element*3], add);
+                               cur = cur->next;
+                       }
+               }
+
                sculpt_clip(s, ss, co, add);
 
                node= node->next;
        }
+       if( buffer != 0 )
+               GPU_buffer_unlock( ss->drawobject->vertices );
 }
 
 static void calc_flatten_center(SculptSession *ss, ActiveData *node, float co[3])
@@ -535,7 +606,7 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase
        float area_normal[3];
        float cntr[3], cntr2[3], bstr = 0;
        int flip = 0;
-
+       float *buffer;
        calc_area_normal(sd, ss, area_normal, active_verts);
        calc_flatten_center(ss, node, cntr);
 
@@ -547,7 +618,9 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase
                cntr2[2]=cntr[2]+area_normal[2]*bstr*ss->cache->scale[2];
                flip = bstr < 0;
        }
-       
+
+       buffer = (float *)GPU_buffer_lock( ss->drawobject->vertices );  
+
        while(node){
                float *co= ss->mvert[node->Index].co;
                float intr[3], val[3];
@@ -573,11 +646,21 @@ static void do_flatten_clay_brush(Sculpt *sd, SculptSession *ss, const ListBase
 
                        VecAddf(val, val, co);
 
+                       if( buffer != 0 ) {
+                               IndexLink *cur = &ss->drawobject->indices[node->Index];
+                               while( cur != 0 && cur->element != -1 ) {
+                                       sculpt_clip(sd, ss, &buffer[cur->element*3], val);
+                                       cur = cur->next;
+                               }
+                       }                       
                        sculpt_clip(sd, ss, co, val);
+
                }
                
                node= node->next;
        }
+       if( buffer != 0 )
+               GPU_buffer_unlock( ss->drawobject->vertices );
 }
 
 /* Uses symm to selectively flip any axis of a coordinate. */
@@ -898,7 +981,8 @@ static void add_face_normal(vec3f *norm, MVert *mvert, const MFace* face, float
 static void update_damaged_vert(SculptSession *ss, ListBase *lb)
 {
        ActiveData *vert;
-       
+    
+       float *buffer = (float *)GPU_buffer_lock( ss->drawobject->normals );
        for(vert= lb->first; vert; vert= vert->next) {
                vec3f norm= {0,0,0};            
                IndexNode *face= ss->fmap[vert->Index].first;
@@ -915,7 +999,32 @@ static void update_damaged_vert(SculptSession *ss, ListBase *lb)
                ss->mvert[vert->Index].no[0]=norm.x*32767;
                ss->mvert[vert->Index].no[1]=norm.y*32767;
                ss->mvert[vert->Index].no[2]=norm.z*32767;
+
+               if( buffer != 0 ) {
+                       IndexLink *cur = &ss->drawobject->indices[vert->Index];
+                       while( cur != 0 && cur->element != -1 ) {
+                               int i = ss->drawobject->faceRemap[cur->element/3];
+                               if( ss->mface[i].flag & ME_SMOOTH ) {
+                                       VECCOPY(&buffer[cur->element*3],ss->mvert[vert->Index].no);
+                               }
+                               else {
+                                       float norm[3];
+                                       if( ss->mface[i].v4 )
+                                               CalcNormFloat4(ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co, ss->mvert[ss->mface[i].v4].co, norm);
+                                       else
+                                               CalcNormFloat(ss->mvert[ss->mface[i].v1].co, ss->mvert[ss->mface[i].v2].co, ss->mvert[ss->mface[i].v3].co, norm);
+                                       VECCOPY(&buffer[cur->element*3],norm);
+                                       VECCOPY(&buffer[cur->element*3],norm);
+                                       VECCOPY(&buffer[cur->element*3],norm);
+                               }
+
+                               //VECCOPY(&buffer[cur->element*3],ss->mvert[vert->Index].no);
+                               cur = cur->next;
+                       }
+               }
        }
+       if( buffer != 0 )
+               GPU_buffer_unlock( ss->drawobject->normals );
 }
 
 static void calc_damaged_verts(SculptSession *ss)
@@ -1004,9 +1113,10 @@ static void sculpt_update_mesh_elements(bContext *C)
        Object *ob = CTX_data_active_object(C);
        SculptSession *ss = ob->sculpt;
        int oldtotvert = ss->totvert;
+       DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
 
        if((ss->multires = sculpt_multires_active(ob))) {
-               DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
+               //DerivedMesh *dm = mesh_get_derived_final(CTX_data_scene(C), ob, CD_MASK_BAREMESH);
                ss->totvert = dm->getNumVerts(dm);
                ss->totface = dm->getNumFaces(dm);
                ss->mvert = dm->getVertDataArray(dm, CD_MVERT);
@@ -1021,6 +1131,12 @@ static void sculpt_update_mesh_elements(bContext *C)
                ss->mface = me->mface;
                ss->face_normals = NULL;
        }
+       if( GPU_buffer_legacy( dm ) ) {
+               ss->drawobject = 0;
+       }
+       else {
+               ss->drawobject = dm->drawObject;
+       }
 
        if(ss->totvert != oldtotvert) {
                if(ss->projverts) MEM_freeN(ss->projverts);
@@ -1332,16 +1448,27 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss)
 {
        StrokeCache *cache = ss->cache;
        Brush *brush = paint_brush(&sd->paint);
+       float *buffer;
        int i;
-       
+
        /* Restore the mesh before continuing with anchored stroke */
        if((brush->flag & BRUSH_ANCHORED) && ss->mesh_co_orig) {
+               buffer = (float *)GPU_buffer_lock( ss->drawobject->normals );
                for(i = 0; i < ss->totvert; ++i) {
                        VecCopyf(ss->mvert[i].co, ss->mesh_co_orig[i]);
                        ss->mvert[i].no[0] = cache->orig_norms[i][0];
                        ss->mvert[i].no[1] = cache->orig_norms[i][1];
                        ss->mvert[i].no[2] = cache->orig_norms[i][2];
+                       if( buffer != 0 ) {
+                               IndexLink *cur = &ss->drawobject->indices[i];
+                               while( cur != 0 && cur->element != -1 ) {
+                                       VECCOPY(&buffer[cur->element*3],cache->orig_norms[i]);
+                                       cur = cur->next;
+                               }
+                       }
                }
+               if( buffer != 0 )
+                       GPU_buffer_unlock( ss->drawobject->normals );
 
                if(ss->face_normals) {
                        float *fn = ss->face_normals;
index da67bd8707e504916b92423988051f68b7042c54..a4d7ae802f622d33e2f4639d075b0ae8db6dd831 100644 (file)
@@ -70,6 +70,7 @@
 #include "UI_resources.h"
 #include "UI_interface_icons.h"
 
+#include "gpu_buffers.h"
 #include "GPU_extensions.h"
 #include "GPU_draw.h"
 
@@ -398,8 +399,7 @@ static void draw_textured_end()
        glPopMatrix();
 }
 
-
-static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr)
+static int draw_tface__set_draw_legacy(MTFace *tface, MCol *mcol, int matnr)
 {
        if (tface && (tface->mode&TF_INVISIBLE)) return 0;
 
@@ -421,6 +421,87 @@ static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr)
                return 1; /* Set color from mcol */
        }
 }
+static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr)
+{
+       if (tface && (tface->mode&TF_INVISIBLE)) return 0;
+
+       if (tface && set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE)) {
+               return 2; /* Don't set color */
+       } else if (tface && tface->mode&TF_OBCOL) {
+               return 2; /* Don't set color */
+       } else if (!mcol) {
+               return 2; /* Don't set color */
+       } else {
+               return 1; /* Set color from mcol */
+       }
+}
+static void add_tface_color_layer(DerivedMesh *dm)
+{
+       MTFace *tface = DM_get_face_data_layer(dm, CD_MTFACE);
+       MFace *mface = DM_get_face_data_layer(dm, CD_MFACE);
+       MCol *finalCol;
+       int i,j;
+       MCol *mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
+       if(!mcol)
+               mcol = dm->getFaceDataArray(dm, CD_MCOL);
+
+       finalCol = MEM_mallocN(sizeof(MCol)*4*dm->getNumFaces(dm),"add_tface_color_layer");
+       for(i=0;i<dm->getNumFaces(dm);i++) {
+               if (tface && (tface->mode&TF_INVISIBLE)) {
+                       if( mcol )
+                               memcpy(&finalCol[i*4],&mcol[i*4],sizeof(MCol)*4);
+                       else
+                               for(j=0;j<4;j++) {
+                                       finalCol[i*4+j].b = 255;
+                                       finalCol[i*4+j].g = 255;
+                                       finalCol[i*4+j].r = 255;
+                               }
+               }
+               else if (tface && mface && set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, mface[i].mat_nr, TF_TWOSIDE)) {
+                       for(j=0;j<4;j++) {
+                               finalCol[i*4+j].b = 255;
+                               finalCol[i*4+j].g = 0;
+                               finalCol[i*4+j].r = 255;
+                       }
+               } else if (tface && tface->mode&TF_OBCOL) {
+                       for(j=0;j<4;j++) {
+                               finalCol[i*4+j].r = Gtexdraw.obcol[0];
+                               finalCol[i*4+j].g = Gtexdraw.obcol[1];
+                               finalCol[i*4+j].b = Gtexdraw.obcol[2];
+                       }
+               } else if (!mcol) {
+                       if (tface) {
+                               for(j=0;j<4;j++) {
+                                       finalCol[i*4+j].b = 255;
+                                       finalCol[i*4+j].g = 255;
+                                       finalCol[i*4+j].r = 255;
+                               }
+                       }
+                       else {
+                               Material *ma= give_current_material(Gtexdraw.ob, mface[i].mat_nr+1);
+                               if(ma) 
+                                       for(j=0;j<4;j++) {
+                                               finalCol[i*4+j].b = ma->b;
+                                               finalCol[i*4+j].g = ma->g;
+                                               finalCol[i*4+j].r = ma->r;
+                                       }
+                               else
+                                       for(j=0;j<4;j++) {
+                                               finalCol[i*4+j].b = 255;
+                                               finalCol[i*4+j].g = 255;
+                                               finalCol[i*4+j].r = 255;
+                                       }
+                       }
+               } else {
+                       for(j=0;j<4;j++) {
+                               finalCol[i*4+j].b = mcol[i*4+j].r;
+                               finalCol[i*4+j].g = mcol[i*4+j].g;
+                               finalCol[i*4+j].r = mcol[i*4+j].b;
+                       }
+               }
+       }
+       CustomData_add_layer( &dm->faceData, CD_TEXTURE_MCOL, CD_ASSIGN, finalCol, dm->numFaceData );
+}
 
 static int draw_tface_mapped__set_draw(void *userData, int index)
 {
@@ -561,6 +642,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o
        draw_textured_begin(scene, v3d, rv3d, ob);
 
        if(ob == scene->obedit) {
+               glColor4f(1.0f,1.0f,1.0f,1.0f);
                dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_mesh);
        } else if(faceselect) {
                if(ob->mode & OB_MODE_WEIGHT_PAINT)
@@ -569,7 +651,14 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o
                        dm->drawMappedFacesTex(dm, draw_tface_mapped__set_draw, me);
        }
        else {
-               dm->drawFacesTex(dm, draw_tface__set_draw);
+               if( GPU_buffer_legacy(dm) )
+                       dm->drawFacesTex(dm, draw_tface__set_draw_legacy);
+               else {
+                       glColor4f(1.0f,1.0f,1.0f,1.0f);
+                       if( !CustomData_has_layer(&dm->faceData,CD_TEXTURE_MCOL) )
+                               add_tface_color_layer(dm);
+                       dm->drawFacesTex(dm, draw_tface__set_draw);
+               }
        }
 
        /* draw game engine text hack */
index db3b7130ab3d06ad3b2ee674af970719e334adad..53e87d61ad3ab804c95ce3d295756ae575bbc9ca 100644 (file)
 #include "GPU_draw.h"
 #include "GPU_material.h"
 #include "GPU_extensions.h"
+#include "gpu_buffers.h"
 
 #include "ED_mesh.h"
 #include "ED_particle.h"
 #include "UI_interface_icons.h"
 
 #include "WM_api.h"
+#include "wm_subwindow.h"
 #include "BLF_api.h"
 
 #include "view3d_intern.h"     // own include
@@ -1550,15 +1552,72 @@ static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *
                }
        }
 }
+/* originally defined in DerivedMesh.c */
+typedef struct {
+       DerivedMesh dm;
+
+       EditMesh *em;
+       float (*vertexCos)[3];
+       float (*vertexNos)[3];
+       float (*faceNos)[3];
+} EditMeshDerivedMesh;
+
 static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act)
 {
        struct { int sel; EditVert *eve_act; } data;
+       GPUBuffer *buffer;
+       float *varray;
        data.sel = sel;
        data.eve_act = eve_act;
-       
-       bglBegin(GL_POINTS);
-       dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
-       bglEnd();
+
+       /* first come the unselected vertices, then the selected */
+       buffer = GPU_buffer_alloc( sizeof(float)*3*dm->getNumVerts(dm)*2, 0 );
+
+       if( (varray = GPU_buffer_lock_stream( buffer )) && bglPointHack() == 0 ) {
+               EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+               EditVert *eve;
+               int i;
+               int numverts = 0, numselected = 0;
+               int datatype[] = { GPU_BUFFER_INTER_V3F, GPU_BUFFER_INTER_END };
+               GPU_buffer_unlock( buffer );
+               GPU_interleaved_setup( buffer, datatype );
+               varray = GPU_buffer_lock_stream( buffer );
+
+               glBegin(GL_POINTS);
+               for (i=0,eve= emdm->em->verts.first; eve; i++,eve=eve->next) {
+                       if (eve->h==0 && (eve->f&SELECT)==data.sel) {
+                               if (eve==data.eve_act) {
+                                       if (emdm->vertexCos) {
+                                               VECCOPY(&varray[3*(dm->getNumVerts(dm)+numselected)],emdm->vertexCos[i]);
+                                       }
+                                       else {
+                                               VECCOPY(&varray[3*(dm->getNumVerts(dm)+numselected)],eve->co);
+                                       }
+                                       numselected++;
+                               } else {
+                                       if (emdm->vertexCos) {
+                                               VECCOPY(&varray[3*numverts],emdm->vertexCos[i]);
+                                       } else {
+                                               VECCOPY(&varray[3*numverts],eve->co);
+                                       }
+                                       numverts++;
+                               }
+                       }
+               }
+               glEnd();
+               GPU_buffer_unlock( buffer );
+               glDrawArrays(GL_POINTS,0,numverts);
+               UI_ThemeColor4(TH_EDITMESH_ACTIVE);
+               glDrawArrays(GL_POINTS,dm->getNumVerts(dm),numselected);
+               UI_ThemeColor4(data.sel?TH_VERTEX_SELECT:TH_VERTEX);
+               GPU_buffer_unbind();
+       }
+       else {
+               bglBegin(GL_POINTS);
+               dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
+               bglEnd();
+       }
+       GPU_buffer_free( buffer, 0 );
 }
 
        /* Draw edges with color set based on selection */
@@ -1626,12 +1685,57 @@ static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int i
                                col0[2] + (col1[2]-col0[2])*t,
                                col0[3] + (col1[3]-col0[3])*t);
 }
+
 static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
 {
        unsigned char *cols[2];
+       int elemsize = sizeof(float)*3+sizeof(unsigned char)*4;
+       EditMeshDerivedMesh *emdm = (EditMeshDerivedMesh *)dm;
+       EditMesh *em= emdm->em;
+       unsigned char *varray;
+       int i;
+       GPUBuffer *buffer;
        cols[0] = baseCol;
        cols[1] = selCol;
-       dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
+
+       buffer = GPU_buffer_alloc( elemsize*em->totedge*2, 0 );
+       if( (varray = GPU_buffer_lock_stream( buffer )) ) {
+               EditEdge *eed;
+               int numedges = 0;
+               int datatype[] = { GPU_BUFFER_INTER_V3F, GPU_BUFFER_INTER_C4UB, GPU_BUFFER_INTER_END };
+               GPU_buffer_unlock( buffer );
+               GPU_interleaved_setup( buffer, datatype );
+               varray = GPU_buffer_lock_stream( buffer );
+               for (i=0,eed= em->edges.first; eed; i++,eed= eed->next) {
+                       if(eed->h==0) {
+                               unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0];
+                               unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0];
+
+                               if( emdm->vertexCos ) {
+                                       VECCOPY(((float *)&varray[elemsize*numedges*2]),emdm->vertexCos[(int) eed->v1->tmp.l]);
+                               }
+                               else {
+                                       VECCOPY(((float *)&varray[elemsize*numedges*2]),eed->v1->co);
+                               }
+                               QUATCOPY(&varray[elemsize*numedges*2+sizeof(float)*3],col0);
+                               if( emdm->vertexCos ) {
+                                       VECCOPY(((float *)&varray[elemsize*numedges*2+elemsize]),emdm->vertexCos[(int) eed->v2->tmp.l]);
+                               }
+                               else {
+                                       VECCOPY(((float *)&varray[elemsize*numedges*2+elemsize]),eed->v2->co);
+                               }
+                               QUATCOPY(&varray[elemsize*numedges*2+elemsize+sizeof(float)*3],col1);
+                               numedges++;
+                       }
+               }
+               GPU_buffer_unlock( buffer );
+               glDrawArrays(GL_LINES,0,numedges*2);
+               GPU_buffer_unbind();
+       }
+       else {
+               dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
+       }
+       GPU_buffer_free( buffer, 0 );
 }
 
        /* Draw only seam edges */
@@ -1685,12 +1789,237 @@ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *dra
 static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act) 
 {
        struct { unsigned char *cols[3]; EditFace *efa_act; } data;
+       //EditMeshDerivedMesh *emdm = (EditMeshDerivedMesh *)dm;
+       EditFace *efa;
+       unsigned char *col;
+       unsigned char *colors;
+       GPUBuffer *buffer;
+       unsigned char *varray;
+       unsigned char black[] = { 0, 0, 0, 0 };
+       int i,j,draw=0;
+       int elemsize = (sizeof(float)*6+sizeof(unsigned char)*4);
        data.cols[0] = baseCol;
        data.cols[1] = selCol;
        data.cols[2] = actCol;
        data.efa_act = efa_act;
-       
-       dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0);
+
+
+       buffer = GPU_buffer_alloc( elemsize*dm->getNumFaces(dm)*3*2, 0 );
+       if( dm->getVertCos == 0 && (varray = GPU_buffer_lock_stream( buffer )) ) {
+               int prevdraw = 0;
+               int numfaces = 0;
+               int datatype[] = { GPU_BUFFER_INTER_V3F, GPU_BUFFER_INTER_N3F, GPU_BUFFER_INTER_C4UB, GPU_BUFFER_INTER_END };
+               GPU_buffer_unlock( buffer );
+               GPU_interleaved_setup( buffer, datatype );
+               glShadeModel(GL_SMOOTH);
+               varray = GPU_buffer_lock_stream( buffer );
+               for (i=0,efa= efa_act; efa; i++,efa= efa->next) {
+                       int drawSmooth = (efa->flag & ME_SMOOTH);
+                       if (efa->h==0) {
+                               if (efa == data.efa_act) {
+                                       draw = 2;
+                               } else {
+                                       col = data.cols[(efa->f&SELECT)?1:0];
+                                       if (col[3]==0) draw = 0;
+                                       else draw = 1;
+                               }
+                       }
+                       else {
+                               draw = 0;
+                       }
+                       if( prevdraw != draw && prevdraw != 0 && numfaces > 0) {
+                               if( prevdraw==2 ) {
+                                       glEnable(GL_POLYGON_STIPPLE);
+                                       glPolygonStipple(stipple_quarttone);
+                               }
+                               GPU_buffer_unlock( buffer );
+                               glDrawArrays(GL_TRIANGLES,0,numfaces*3);
+                               if( prevdraw==2 ) {
+                                       glDisable(GL_POLYGON_STIPPLE);
+                               }
+                               varray = GPU_buffer_lock_stream( buffer );
+                               numfaces = 0;
+                       }
+
+                       if( draw != 0 ) {
+                               if(!drawSmooth) {
+                                       /*if (emdm->vertexCos) {
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces],emdm->vertexCos[(int) efa->v1->tmp.l]);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+sizeof(float)*3],emdm->faceNos[i]);
+
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize],emdm->vertexCos[(int) efa->v2->tmp.l]);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize+sizeof(float)*3],emdm->faceNos[i]);
+
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2],emdm->vertexCos[(int) efa->v3->tmp.l]);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*3],emdm->faceNos[i]);
+                                       }
+                                       else {*/
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces],efa->v1->co);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+sizeof(float)*3],efa->n);
+
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize],efa->v2->co);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize+sizeof(float)*3],efa->n);
+
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2],efa->v3->co);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*3],efa->n);
+                                       /*}*/
+                                       if( draw == 2 ) {
+                                               QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],data.cols[2]);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],data.cols[2]);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],data.cols[2]);
+                                       }
+                                       else if( draw == 1 ) {
+                                               QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                       }
+                                       else {
+                                               QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],black);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],black);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],black);
+                                       }
+
+                                       numfaces++;
+                                       if( efa->v4 ) {
+                                               /*if (emdm->vertexCos) {
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces],emdm->vertexCos[(int) efa->v3->tmp.l]);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+sizeof(float)*3],emdm->faceNos[i]);
+
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize],emdm->vertexCos[(int) efa->v4->tmp.l]);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize+sizeof(float)*3],emdm->faceNos[i]);
+
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2],emdm->vertexCos[(int) efa->v1->tmp.l]);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*3],emdm->faceNos[i]);
+                                               }
+                                               else {*/
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces],efa->v3->co);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+sizeof(float)*3],efa->n);
+
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize],efa->v4->co);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize+sizeof(float)*3],efa->n);
+
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2],efa->v1->co);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*3],efa->n);
+                                               /*}*/
+
+                                               if( draw == 2 ) {
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],data.cols[2]);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],data.cols[2]);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],data.cols[2]);
+                                               }
+                                               else if( draw == 1 ) {
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                               }
+                                               else {
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],black);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],black);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],black);
+                                               }
+
+                                               numfaces++;
+                                       }
+                               }
+                               else {
+                                       /*if (emdm->vertexCos) {
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces],emdm->vertexCos[(int) efa->v1->tmp.l]);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+sizeof(float)*3],emdm->vertexNos[(int) efa->v1->tmp.l]);
+
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize],emdm->vertexCos[(int) efa->v2->tmp.l]);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize+sizeof(float)*3],emdm->vertexNos[(int) efa->v2->tmp.l]);
+
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2],emdm->vertexCos[(int) efa->v3->tmp.l]);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*3],emdm->vertexNos[(int) efa->v3->tmp.l]);
+                                       }
+                                       else {*/
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces],efa->v1->co);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+sizeof(float)*3],efa->v1->no);
+
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize],efa->v2->co);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize+sizeof(float)*3],efa->v2->no);
+
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2],efa->v3->co);
+                                               VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*3],efa->v3->no);
+                                       /*}*/
+
+                                       if( draw == 2 ) {
+                                               QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],data.cols[2]);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],data.cols[2]);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],data.cols[2]);
+                                       }
+                                       else if( draw == 1 ) {
+                                               QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                       }
+                                       else {
+                                               QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],black);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],black);
+                                               QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],black);
+                                       }
+
+                                       numfaces++;
+                                       if( efa->v4 ) {
+                                               /*if (emdm->vertexCos) {
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces],emdm->vertexCos[(int) efa->v3->tmp.l]);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+sizeof(float)*3],emdm->vertexNos[(int) efa->v1->tmp.l]);
+
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize],emdm->vertexCos[(int) efa->v4->tmp.l]);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize+sizeof(float)*3],emdm->vertexNos[(int) efa->v2->tmp.l]);
+
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2],emdm->vertexCos[(int) efa->v1->tmp.l]);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*3],emdm->vertexNos[(int) efa->v3->tmp.l]);
+                                               }
+                                               else {*/
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces],efa->v3->co);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+sizeof(float)*3],efa->v3->no);
+
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize],efa->v4->co);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize+sizeof(float)*3],efa->v4->no);
+
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2],efa->v1->co);
+                                                       VECCOPY((float *)&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*3],efa->v1->no);
+                                               /*}*/
+
+                                               if( draw == 2 ) {
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],data.cols[2]);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],data.cols[2]);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],data.cols[2]);
+                                               }
+                                               else if( draw == 1 ) {
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],data.cols[(efa->f&SELECT)?1:0]);
+                                               }
+                                               else {
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+sizeof(float)*6],black);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize+sizeof(float)*6],black);
+                                                       QUATCOPY(&varray[elemsize*3*numfaces+elemsize*2+sizeof(float)*6],black);
+                                               }
+
+                                               numfaces++;
+                                       }
+                               }
+                       }
+                       prevdraw = draw;
+               }
+               GPU_buffer_unlock( buffer );
+               if( prevdraw != 0 && numfaces > 0) {
+                       if( prevdraw==2 ) {
+                               glEnable(GL_POLYGON_STIPPLE);
+                               glPolygonStipple(stipple_quarttone);
+                       }
+                       glDrawArrays(GL_TRIANGLES,0,numfaces*3);
+                       if( prevdraw==2 ) {
+                               glDisable(GL_POLYGON_STIPPLE);
+                       }
+               }
+               GPU_buffer_unbind();
+       } else {
+               dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0);
+       }
+       GPU_buffer_free( buffer, 0 );
 }
 
 static int draw_dm_creases__setDrawOptions(void *userData, int index)
@@ -2103,12 +2432,115 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
                        }
                }
                else {
+                       /* 3 floats for position, 3 for normal and times two because the faces may actually be quads instead of triangles */
+                       GPUBuffer *buffer = GPU_buffer_alloc( sizeof(float)*6*em->totface*3*2, 0 );
+                       float *varray;
+                       EditFace *efa;
+                       int i, curmat = 0, draw = 0;
+
                        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED);
 
                        glEnable(GL_LIGHTING);
                        glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
 
-                       finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0);
+                       if( finalDM->getVertCos == 0 && (varray = GPU_buffer_lock_stream( buffer )) ) {
+                               int prevdraw = 0, prevmat = 0;
+                               int numfaces = 0;
+                               int datatype[] = { GPU_BUFFER_INTER_V3F, GPU_BUFFER_INTER_N3F, GPU_BUFFER_INTER_END };
+                               GPU_buffer_unlock( buffer );
+                               GPU_interleaved_setup( buffer, datatype );
+                               glShadeModel(GL_SMOOTH);
+                               varray = GPU_buffer_lock_stream( buffer );
+                               for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
+                                       int drawSmooth = (efa->flag & ME_SMOOTH);
+                                       if( efa->h == 0 ) {
+                                               curmat = efa->mat_nr+1;
+                                               draw = 1;
+                                       } 
+                                       else {
+                                               draw = 0;
+                                       }
+                                       if( ((prevdraw != draw) || (curmat != prevmat)) && prevdraw != 0 && numfaces > 0) {
+                                               if( prevdraw==2 ) {
+                                                       glEnable(GL_POLYGON_STIPPLE);
+                                                       glPolygonStipple(stipple_quarttone);
+                                               }
+                                               GPU_buffer_unlock( buffer );
+                                               GPU_enable_material(prevmat, NULL);
+                                               glDrawArrays(GL_TRIANGLES,0,numfaces*3);
+                                               if( prevdraw==2 ) {
+                                                       glDisable(GL_POLYGON_STIPPLE);
+                                               }
+                                               varray = GPU_buffer_lock_stream( buffer );
+                                               numfaces = 0;
+                                       }
+                                       if( draw != 0 ) {
+                                               if(!drawSmooth) {
+                                                       VECCOPY(&varray[numfaces*18],efa->v1->co);
+                                                       VECCOPY(&varray[numfaces*18+3],efa->n);
+
+                                                       VECCOPY(&varray[numfaces*18+6],efa->v2->co);
+                                                       VECCOPY(&varray[numfaces*18+9],efa->n);
+
+                                                       VECCOPY(&varray[numfaces*18+12],efa->v3->co);
+                                                       VECCOPY(&varray[numfaces*18+15],efa->n);
+                                                       numfaces++;
+                                                       if( efa->v4 ) {
+                                                               VECCOPY(&varray[numfaces*18],efa->v3->co);
+                                                               VECCOPY(&varray[numfaces*18+3],efa->n);
+
+                                                               VECCOPY(&varray[numfaces*18+6],efa->v4->co);
+                                                               VECCOPY(&varray[numfaces*18+9],efa->n);
+
+                                                               VECCOPY(&varray[numfaces*18+12],efa->v1->co);
+                                                               VECCOPY(&varray[numfaces*18+15],efa->n);
+                                                               numfaces++;
+                                                       }
+                                               }
+                                               else {
+                                                       VECCOPY(&varray[numfaces*18],efa->v1->co);
+                                                       VECCOPY(&varray[numfaces*18+3],efa->v1->no);
+
+                                                       VECCOPY(&varray[numfaces*18+6],efa->v2->co);
+                                                       VECCOPY(&varray[numfaces*18+9],efa->v2->no);
+
+                                                       VECCOPY(&varray[numfaces*18+12],efa->v3->co);
+                                                       VECCOPY(&varray[numfaces*18+15],efa->v3->no);
+                                                       numfaces++;
+                                                       if( efa->v4 ) {
+                                                               VECCOPY(&varray[numfaces*18],efa->v3->co);
+                                                               VECCOPY(&varray[numfaces*18+3],efa->v3->no);
+
+                                                               VECCOPY(&varray[numfaces*18+6],efa->v4->co);
+                                                               VECCOPY(&varray[numfaces*18+9],efa->v4->no);
+
+                                                               VECCOPY(&varray[numfaces*18+12],efa->v1->co);
+                                                               VECCOPY(&varray[numfaces*18+15],efa->v1->no);
+                                                               numfaces++;
+                                                       }
+                                               }
+                                       }
+                                       prevdraw = draw;
+                                       prevmat = curmat;
+                               }
+                               GPU_buffer_unlock( buffer );
+                               if( prevdraw != 0 && numfaces > 0) {
+                                       if( prevdraw==2 ) {
+                                               glEnable(GL_POLYGON_STIPPLE);
+                                               glPolygonStipple(stipple_quarttone);
+                                       }
+                                       GPU_enable_material(prevmat, NULL);
+                                       glDrawArrays(GL_TRIANGLES,0,numfaces*3);
+                                       if( prevdraw==2 ) {
+                                               glDisable(GL_POLYGON_STIPPLE);
+                                       }
+                               }
+                               GPU_buffer_unbind();
+                       }
+                       else {
+                               finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0);
+                       }
+                       GPU_buffer_free(buffer,0);
 
                        glFrontFace(GL_CCW);
                        glDisable(GL_LIGHTING);
@@ -5607,6 +6039,16 @@ static int bbs_mesh_solid__setDrawOpts(void *userData, int index, int *drawSmoot
 {
        Mesh *me = userData;
 
+       if (!(me->mface[index].flag&ME_HIDE)) {
+               return 1;
+       } else {
+               return 0;
+       }
+}
+static int bbs_mesh_solid__setDrawOpts_legacy(void *userData, int index, int *drawSmooth_r)
+{
+       Mesh *me = userData;
+
        if (!(me->mface[index].flag&ME_HIDE)) {
                WM_set_framebuffer_index_color(index+1);
                return 1;
@@ -5620,9 +6062,41 @@ static void bbs_mesh_solid(Scene *scene, View3D *v3d, Object *ob)
 {
        DerivedMesh *dm = mesh_get_derived_final(scene, ob, v3d->customdata_mask);
        Mesh *me = (Mesh*)ob->data;
+       MCol *colors;
+       int i,j;
        
        glColor3ub(0, 0, 0);
-       dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, me, 0);
+               
+       if( !GPU_buffer_legacy(dm) ) {
+               int *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+               int ind;
+               colors = MEM_mallocN(dm->getNumFaces(dm)*sizeof(MCol)*4,"bbs_mesh_solid");
+               for(i=0;i<dm->getNumFaces(dm);i++) {
+                       if( index != 0 )
+                               ind = index[i];
+                       else
+                               ind = i;
+                       if (!(me->mface[ind].flag&ME_HIDE)) {
+                               unsigned int fbindex = index_to_framebuffer(ind+1);
+                               for(j=0;j<4;j++) {
+                                       colors[i*4+j].b = ((fbindex)&0xFF);
+                                       colors[i*4+j].g = (((fbindex)>>8)&0xFF);
+                                       colors[i*4+j].r = (((fbindex)>>16)&0xFF);
+                               }
+                       }
+                       else {
+                               memset(&colors[i*4],0,sizeof(MCol)*4);
+                       }
+               }
+
+               CustomData_add_layer( &dm->faceData, CD_ID_MCOL, CD_ASSIGN, colors, dm->numFaceData );
+               GPU_buffer_free(dm->drawObject->colors,0);
+               dm->drawObject->colors = 0;
+               dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, me, 1);
+       }
+       else {
+               dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts_legacy, me, 0);
+       }
 
        dm->release(dm);
 }
diff --git a/source/blender/gpu/gpu_buffers.h b/source/blender/gpu/gpu_buffers.h
new file mode 100644 (file)
index 0000000..d71c8e4
--- /dev/null
@@ -0,0 +1,157 @@
+/**
+ * $Id: gpu_buffers.h 20687 2009-06-07 11:26:46Z imbusy $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#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)
+#else
+#define DEBUG_VBO(X)
+#endif
+
+struct DerivedMesh;
+
+/* 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
+{
+       int size;       /* in bytes */
+       void *pointer;  /* used with vertex arrays */
+       unsigned int id;        /* used with vertex buffer objects */
+} GPUBuffer;
+
+typedef struct GPUBufferPool
+{
+       int size;       /* number of allocated buffers stored */
+       int start;      /* for a queue like structure */
+                               /* when running out of space for storing buffers,
+                               the last one used will be thrown away */
+
+       GPUBuffer* buffers[MAX_FREE_GPU_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 IndexLink {
+       int element;
+       struct IndexLink *next;
+} IndexLink;
+
+typedef struct GPUDrawObject
+{
+       GPUBuffer *vertices;
+       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 */
+       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 */
+
+} GPUDrawObject;
+
+typedef struct GPUAttrib
+{
+       int index;
+       int size;
+       int type;
+} GPUAttrib;
+
+GPUBufferPool *GPU_buffer_pool_new();
+void GPU_buffer_pool_free( GPUBufferPool *pool );      /* TODO: Find a place where to call this function on exit */
+
+GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool );
+void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool );
+
+GPUDrawObject *GPU_drawobject_new( struct DerivedMesh *dm );
+void GPU_drawobject_free( struct DerivedMesh *dm );
+
+/* called before drawing */
+void GPU_vertex_setup( struct DerivedMesh *dm );
+void GPU_normal_setup( struct DerivedMesh *dm );
+void GPU_uv_setup( struct DerivedMesh *dm );
+void GPU_color_setup( struct DerivedMesh *dm );
+void GPU_edge_setup( struct DerivedMesh *dm ); /* does not mix with other data */
+void GPU_uvedge_setup( struct DerivedMesh *dm );
+void GPU_interleaved_setup( GPUBuffer *buffer, int data[] );
+int GPU_attrib_element_size( GPUAttrib data[], int numdata );
+void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numdata );
+
+/* can't lock more than one buffer at once */
+void *GPU_buffer_lock( GPUBuffer *buffer );    
+void *GPU_buffer_lock_stream( GPUBuffer *buffer );
+void GPU_buffer_unlock( GPUBuffer *buffer );
+
+/* upload three unsigned chars, representing RGB colors, for each vertex. Resets dm->drawObject->colType to -1 */
+void GPU_color3_upload( struct DerivedMesh *dm, char *data );
+/* upload four unsigned chars, representing RGBA colors, for each vertex. Resets dm->drawObject->colType to -1 */
+void GPU_color4_upload( struct DerivedMesh *dm, char *data );
+/* switch color rendering on=1/off=0 */
+void GPU_color_switch( int mode );
+
+void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count );
+
+/* called after drawing */
+void GPU_buffer_unbind();
+
+int GPU_buffer_legacy( struct DerivedMesh *dm );
+
+#endif
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
new file mode 100644 (file)
index 0000000..5781c85
--- /dev/null
@@ -0,0 +1,1248 @@
+/**
+ * $Id: gpu_buffers.c 19820 2009-04-20 15:06:46Z imbusy $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License.  See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Brecht Van Lommel.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#include "GL/glew.h"
+
+#include "DNA_userdef_types.h"
+
+#include "gpu_buffers.h"
+#include "MEM_guardedalloc.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_utildefines.h"
+#include "DNA_meshdata_types.h"
+#include "BLI_arithb.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
+
+#define MAX_GPU_ATTRIB_DATA 32
+
+/* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
+int useVBOs = -1;
+GPUBufferPool *globalPool = 0;
+int GLStates = 0;
+GPUAttrib attribData[MAX_GPU_ATTRIB_DATA] = { { -1, 0, 0 } };
+
+GPUBufferPool *GPU_buffer_pool_new()
+{
+       GPUBufferPool *pool;
+
+       DEBUG_VBO("GPU_buffer_pool_new\n");
+
+       if( useVBOs < 0 ) {
+               if( GL_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), "GPU_buffer_pool_new");
+
+       return pool;
+}
+
+void GPU_buffer_pool_free(GPUBufferPool *pool)
+{
+       int i;
+
+       DEBUG_VBO("GPU_buffer_pool_free\n");
+
+       if( pool == 0 )
+               pool = globalPool;
+       if( pool == 0 )
+               return;
+
+       while( pool->start < 0 )
+               pool->start += MAX_FREE_GPU_BUFFERS;
+
+       for( i = 0; i < pool->size; i++ ) {
+               if( useVBOs ) {
+                       glDeleteBuffersARB( 1, &pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]->id );
+               }
+               else {
+                       MEM_freeN( pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]->pointer );
+               }
+               MEM_freeN(pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS]);
+       }
+       MEM_freeN(pool);
+}
+
+void GPU_buffer_pool_remove( int index, GPUBufferPool *pool )
+{
+       int i;
+
+       DEBUG_VBO("GPU_buffer_pool_remove\n");
+
+       while( pool->start < 0 )
+               pool->start += MAX_FREE_GPU_BUFFERS;
+       for( i = index; i < pool->size-1; i++ ) {
+               pool->buffers[(pool->start+i)%MAX_FREE_GPU_BUFFERS] = pool->buffers[(pool->start+i+1)%MAX_FREE_GPU_BUFFERS];
+       }
+       pool->size--;
+}
+
+void GPU_buffer_pool_delete_last( GPUBufferPool *pool )
+{
+       int last;
+
+       DEBUG_VBO("GPU_buffer_pool_delete_last\n");
+
+       if( pool->size == 0 )
+               return;
+
+       last = pool->start+pool->size-1;
+       while( last < 0 )
+               last += MAX_FREE_GPU_BUFFERS;
+       last = (last+MAX_FREE_GPU_BUFFERS)%MAX_FREE_GPU_BUFFERS;
+
+       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->size--;
+}
+
+GPUBuffer *GPU_buffer_alloc( int size, GPUBufferPool *pool )
+{
+       char buffer[60];
+       int i;
+       int cursize;
+       GPUBuffer *allocated;
+       int bestfit = -1;
+
+       DEBUG_VBO("GPU_buffer_alloc\n");
+
+       if( pool == 0 ) {
+               if( globalPool == 0 )
+                       globalPool = GPU_buffer_pool_new();
+               pool = globalPool;
+       }
+
+       while( pool->start < 0 )
+               pool->start += MAX_FREE_GPU_BUFFERS;
+
+       for( i = 0; i < pool->size; i++ ) {
+               int actuali = (pool->start+i)%MAX_FREE_GPU_BUFFERS;
+               cursize = pool->buffers[actuali]->size;
+               if( cursize == size ) {
+                       allocated = pool->buffers[actuali];
+                       GPU_buffer_pool_remove(i,pool);
+                       DEBUG_VBO("free buffer of exact size found\n");
+                       return allocated;
+               }
+               /* 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[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS]->size > cursize ) {
+                               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;
+                       }
+               }
+       }
+       else {
+               sprintf(buffer,"free buffer found. Wasted %d bytes\n", pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS]->size-size);
+               DEBUG_VBO(buffer);
+
+               allocated = pool->buffers[(pool->start+bestfit)%MAX_FREE_GPU_BUFFERS];
+               GPU_buffer_pool_remove(bestfit,pool);
+       }
+       return allocated;
+}
+
+void GPU_buffer_free( GPUBuffer *buffer, GPUBufferPool *pool )
+{
+       int place;
+
+       DEBUG_VBO("GPU_buffer_free\n");
+
+       if( buffer == 0 )
+               return;
+       if( pool == 0 )
+               pool = globalPool;
+       if( pool == 0 )
+               globalPool = GPU_buffer_pool_new();
+
+       while( pool->start < 0 )
+               pool->start += MAX_FREE_GPU_BUFFERS;
+       place = (pool->start-1 + MAX_FREE_GPU_BUFFERS)%MAX_FREE_GPU_BUFFERS;
+
+       /* free the last used buffer in the queue if no more space */
+       if( pool->size == MAX_FREE_GPU_BUFFERS ) {
+               GPU_buffer_pool_delete_last( pool );
+       }
+
+       pool->size++;
+       pool->start = place;
+       pool->buffers[place] = buffer;
+}
+
+GPUDrawObject *GPU_drawobject_new( DerivedMesh *dm )
+{
+       GPUDrawObject *object;
+       MVert *mvert;
+       MFace *mface;
+       int numverts[32768];    /* material number is an 16-bit short so there's at most 32768 materials */
+       int redir[32768];               /* material number is an 16-bit short so there's at most 32768 materials */
+       int *index;
+       int i;
+       int curmat, curverts;
+
+       DEBUG_VBO("GPU_drawobject_new\n");
+
+       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);
+
+       for( i = 0; i < object->nindices; i++ ) {
+               object->indices[i].element = -1;
+               object->indices[i].next = 0;
+       }
+       /*object->legacy = 1;*/
+       memset(numverts,0,sizeof(int)*32768);
+
+       mvert = dm->getVertArray(dm);
+       mface = dm->getFaceArray(dm);
+
+       for( i=0; i < dm->getNumFaces(dm); i++ ) {
+               if( mface[i].v4 )
+                       numverts[mface[i].mat_nr+16383] += 6;   /* split every quad into two triangles */
+               else
+                       numverts[mface[i].mat_nr+16383] += 3;
+       }
+
+       for( i = 0; i < 32768; i++ ) {
+               if( numverts[i] > 0 ) {
+                       object->nmaterials++;
+                       object->nelements += numverts[i];
+               }
+       }
+       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 < 32768; i++ ) {
+               if( numverts[i] > 0 ) {
+                       object->materials[curmat].mat_nr = i-16383;
+                       object->materials[curmat].start = curverts;
+                       index[curmat] = curverts/3;
+                       object->materials[curmat].end = curverts+numverts[i];
+                       curverts += numverts[i];
+                       curmat++;
+               }
+       }
+       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+16383] = 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++; \
+               }
+
+       for( i=0; i < dm->getNumFaces(dm); i++ ) {
+               int curInd = index[redir[mface[i].mat_nr+16383]];
+               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+16383]]+=2;
+               }
+               else {
+                       index[redir[mface[i].mat_nr+16383]]++;
+               }
+       }
+
+       for( i = 0; i < object->nindices; i++ ) {
+               if( object->indices[i].element == -1 ) {
+                       object->indices[i].element = object->nelements + object->nlooseverts;
+                       object->nlooseverts++;
+               }
+       }
+#undef ADDLINK
+
+       MEM_freeN(index);
+       return object;
+}
+
+void GPU_drawobject_free( DerivedMesh *dm )
+{
+       GPUDrawObject *object;
+
+       DEBUG_VBO("GPU_drawobject_free\n");
+
+       if( dm == 0 )
+               return;
+       object = dm->drawObject;
+       if( object == 0 )
+               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;
+}
+
+GPUBuffer *GPU_buffer_setup( DerivedMesh *dm, GPUDrawObject *object, int size, GLenum target, void *user, void (*copy_f)(DerivedMesh *, float *, int *, int *, void *) )
+{
+       GPUBuffer *buffer;
+       float *varray;
+       int redir[32768];
+       int *index;
+       int i;
+       int success;
+       GLboolean uploaded;
+
+       DEBUG_VBO("GPU_buffer_setup\n");
+
+       if( globalPool == 0 ) {
+               globalPool = GPU_buffer_pool_new();
+
+               /* somehow GL_NORMAL_ARRAY is enabled on startup and causes edge drawing code to crash */
+               glDisableClientState( GL_VERTEX_ARRAY );
+               glDisableClientState( GL_NORMAL_ARRAY );
+               glDisableClientState( GL_TEXTURE_COORD_ARRAY );
+               glDisableClientState( GL_COLOR_ARRAY );
+       }
+       buffer = GPU_buffer_alloc(size,globalPool);
+       if( buffer == 0 ) {
+               dm->drawObject->legacy = 1;
+       }
+       if( dm->drawObject->legacy ) {
+               return 0;
+       }
+
+       index = MEM_mallocN(sizeof(int)*object->nmaterials,"GPU_buffer_setup");
+       for( i = 0; i < object->nmaterials; i++ ) {
+               index[i] = object->materials[i].start*3;
+               redir[object->materials[i].mat_nr+16383] = i;
+       }
+
+       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 );
+                               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;
+}
+
+void GPU_buffer_copy_vertex( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+       int start;
+       int i, j;
+
+       MVert *mvert;
+       MFace *mface;
+
+       DEBUG_VBO("GPU_buffer_copy_vertex\n");
+
+       mvert = dm->getVertArray(dm);
+       mface = dm->getFaceArray(dm);
+
+       for( i=0; i < dm->getNumFaces(dm); i++ ) {
+               start = index[redir[mface[i].mat_nr+16383]];
+               if( mface[i].v4 )
+                       index[redir[mface[i].mat_nr+16383]] += 18;
+               else
+                       index[redir[mface[i].mat_nr+16383]] += 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;
+               }
+       }
+}
+
+GPUBuffer *GPU_buffer_vertex( DerivedMesh *dm )
+{
+       DEBUG_VBO("GPU_buffer_vertex\n");
+
+       return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*(dm->drawObject->nelements+dm->drawObject->nlooseverts), GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_vertex);
+}
+
+void GPU_buffer_copy_normal( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+       int i;
+       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");
+
+       for( i=0; i < dm->getNumFaces(dm); i++ ) {
+               start = index[redir[mface[i].mat_nr+16383]];
+               if( mface[i].v4 )
+                       index[redir[mface[i].mat_nr+16383]] += 18;
+               else
+                       index[redir[mface[i].mat_nr+16383]] += 9;
+
+               /* v1 v2 v3 */
+               if( mface[i].flag & ME_SMOOTH ) {
+                       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 )
+                               CalcNormFloat4(mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, mvert[mface[i].v4].co, norm);
+                       else
+                               CalcNormFloat(mvert[mface[i].v1].co, mvert[mface[i].v2].co, mvert[mface[i].v3].co, norm);
+                       VECCOPY(&varray[start],norm);
+                       VECCOPY(&varray[start+3],norm);
+                       VECCOPY(&varray[start+6],norm);
+               }
+
+               if( mface[i].v4 ) {
+                       /* v3 v4 v1 */
+                       if( mface[i].flag & ME_SMOOTH ) {
+                               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);
+                       }
+               }
+       }
+}
+
+GPUBuffer *GPU_buffer_normal( DerivedMesh *dm )
+{
+       DEBUG_VBO("GPU_buffer_normal\n");
+
+       return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_normal);
+}
+
+void GPU_buffer_copy_uv( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+       int start;
+       int i;
+
+       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;
+       }
+               
+       for( i=0; i < dm->getNumFaces(dm); i++ ) {
+               start = index[redir[mface[i].mat_nr+16383]];
+               if( mface[i].v4 )
+                       index[redir[mface[i].mat_nr+16383]] += 12;
+               else
+                       index[redir[mface[i].mat_nr+16383]] += 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]);
+               }
+       }
+}
+
+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, sizeof(float)*2*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_uv);
+       else
+               return 0;
+}
+
+void GPU_buffer_copy_color3( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
+{
+       int i;
+       unsigned char *varray = (unsigned char *)varray_;
+       unsigned char *mcol = (unsigned char *)user;
+       MFace *mface = dm->getFaceArray(dm);
+
+       DEBUG_VBO("GPU_buffer_copy_color3\n");
+
+       for( i=0; i < dm->getNumFaces(dm); i++ ) {
+               int start = index[redir[mface[i].mat_nr+16383]];
+               if( mface[i].v4 )
+                       index[redir[mface[i].mat_nr+16383]] += 18;
+               else
+                       index[redir[mface[i].mat_nr+16383]] += 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]);
+               }
+       }
+}
+
+void GPU_buffer_copy_color4( DerivedMesh *dm, float *varray_, int *index, int *redir, void *user )
+{
+       int i;
+       unsigned char *varray = (unsigned char *)varray_;
+       unsigned char *mcol = (unsigned char *)user;
+       MFace *mface = dm->getFaceArray(dm);
+
+       DEBUG_VBO("GPU_buffer_copy_color4\n");
+
+       for( i=0; i < dm->getNumFaces(dm); i++ ) {
+               int start = index[redir[mface[i].mat_nr+16383]];
+               if( mface[i].v4 )
+                       index[redir[mface[i].mat_nr+16383]] += 18;
+               else
+                       index[redir[mface[i].mat_nr+16383]] += 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]);
+               }
+       }
+}
+
+GPUBuffer *GPU_buffer_color( DerivedMesh *dm )
+{
+       unsigned char *colors;
+       int i;
+       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;
+       }
+
+       colors = MEM_mallocN(dm->getNumFaces(dm)*12*sizeof(unsigned char), "GPU_buffer_color");
+       for( i=0; i < dm->getNumFaces(dm)*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, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, colors, GPU_buffer_copy_color3 );
+
+       MEM_freeN(colors);
+       return result;
+}
+
+void GPU_buffer_copy_edge( DerivedMesh *dm, float *varray, int *index, int *redir, void *user )
+{
+       int i;
+
+       MVert *mvert;
+       MEdge *medge;
+       unsigned int *varray_ = (unsigned int *)varray;
+       DEBUG_VBO("GPU_buffer_copy_edge\n");
+
+       mvert = dm->getVertArray(dm);
+       medge = dm->getEdgeArray(dm);
+
+       for(i = 0; i < dm->getNumEdges(dm); 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;
+       }
+}
+
+GPUBuffer *GPU_buffer_edge( DerivedMesh *dm )
+{
+       DEBUG_VBO("GPU_buffer_edge\n");
+
+       return GPU_buffer_setup( dm, dm->drawObject, sizeof(int)*2*dm->drawObject->nedges, GL_ELEMENT_ARRAY_BUFFER_ARB, 0, GPU_buffer_copy_edge);
+}
+
+void GPU_buffer_copy_uvedge( DerivedMesh *dm, float *varray, int *index, int *redir, void *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");
+       }
+}
+
+GPUBuffer *GPU_buffer_uvedge( DerivedMesh *dm )
+{
+       DEBUG_VBO("GPU_buffer_uvedge\n");
+
+       return GPU_buffer_setup( dm, dm->drawObject, sizeof(float)*2*(dm->drawObject->nelements/3)*2, 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 )
+{
+       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" );
+               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" );
+               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;
+
+       if( useVBOs ) {
+               glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, dm->drawObject->edges->id );
+       }
+
+       GLStates |= GPU_BUFFER_ELEMENT_STATE;
+}
+
+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" );
+               return;
+       }
+
+       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 );
+       }
+       
+       GLStates |= GPU_BUFFER_VERTEX_STATE;
+}
+
+void GPU_interleaved_setup( GPUBuffer *buffer, int data[] ) {
+       int i;
+       int elementsize = 0;
+       int 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;
+       }
+}
+
+int GPU_attrib_element_size( GPUAttrib data[], int numdata ) {
+       int i, elementsize = 0;
+
+       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 {
+                       elementsize += typesize*data[i].size;
+               }
+       }
+       return elementsize;
+}
+
+void GPU_interleaved_attrib_setup( GPUBuffer *buffer, GPUAttrib data[], int numdata ) {
+       int i;
+       int elementsize;
+       int 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 );
+               }
+               else
+                       break;
+       }
+       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_TRUE, elementsize, (void *)offset );
+                       offset += data[i].size*GPU_typesize(data[i].type);
+
+                       attribData[i].index = data[i].index;
+                       attribData[i].size = data[i].size;
+                       attribData[i].type = data[i].type;
+               }
+               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_TRUE, elementsize, (char *)buffer->pointer + offset );
+                       offset += data[i].size*GPU_typesize(data[i].type);
+               }
+       }
+}
+
+
+void GPU_buffer_unbind()
+{
+       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 );
+               }
+       }
+       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 );
+               }
+               else
+                       break;
+       }
+       if( GLStates != 0 )
+               DEBUG_VBO( "Some weird OpenGL state is still set. Why?" );
+       if( useVBOs )
+               glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
+}
+
+void GPU_color3_upload( DerivedMesh *dm, char *data )
+{
+       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, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color3 );
+}
+void GPU_color4_upload( DerivedMesh *dm, char *data )
+{
+       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, sizeof(char)*3*dm->drawObject->nelements, GL_ARRAY_BUFFER_ARB, data, GPU_buffer_copy_color4 );
+}
+
+void GPU_color_switch( int mode )
+{
+       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 );
+               GLStates &= (!GPU_BUFFER_COLOR_STATE);
+       }
+}
+
+int GPU_buffer_legacy( DerivedMesh *dm )
+{
+       int test= (U.gameflags & USER_DISABLE_VBO);
+       if( test )
+               return 1;
+
+       if( dm->drawObject == 0 )
+               dm->drawObject = GPU_drawobject_new(dm);
+       return dm->drawObject->legacy;
+}
+
+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" );
+               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" ); 
+               }
+               return varray;
+       }
+       else {
+               return buffer->pointer;
+       }
+}
+
+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" );
+               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" ); 
+               }
+               return varray;
+       }
+       else {
+               return buffer->pointer;
+       }
+}
+
+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" ); 
+                       }
+               }
+               glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
+       }
+}
+
+void GPU_buffer_draw_elements( GPUBuffer *elements, unsigned int mode, int start, int count )
+{
+       if( useVBOs ) {
+               glDrawElements( mode, count, GL_UNSIGNED_INT, (void *)(start*sizeof(unsigned int)) );
+       }
+       else {
+               glDrawElements( mode, count, GL_UNSIGNED_INT, ((int *)elements->pointer)+start );
+       }
+}
\ No newline at end of file
index 18c18d9e9ddce108dd30acbfcc75c7dfbe4a03c2..ad686e3709776440e6f76bd1497ed01b2104f33c 100644 (file)
@@ -76,7 +76,9 @@ typedef struct CustomData {
 #define CD_TANGENT             18
 #define CD_MDISPS              19
 #define CD_WEIGHT_MCOL 20 /* for displaying weightpaint colors */
-#define CD_NUMTYPES            21
+#define CD_ID_MCOL             21
+#define CD_TEXTURE_MCOL        22
+#define CD_NUMTYPES            23
 
 /* Bits for CustomDataMask */
 #define CD_MASK_MVERT          (1 << CD_MVERT)
index 826eea43a4d72e1f5300aa3e0e3ba50943f2b11b..16ab3e1e9bd01bfe2790aff3b96cc051a8b7a8ed 100644 (file)
@@ -446,6 +446,7 @@ extern UserDef U; /* from blenkernel blender.c */
 #define USER_DEPRECATED_FLAG   1
 #define USER_DISABLE_SOUND             2
 #define USER_DISABLE_MIPMAP            4
+#define USER_DISABLE_VBO               8
 
 /* wm draw method */
 #define USER_DRAW_TRIPLE               0
index e9fcb299c5337d3c24af6aa3928509d456db0b3e..25448d0c2dee96c6fae29e9aeb2dadc4c32cc983 100644 (file)
@@ -2173,6 +2173,10 @@ static void rna_def_userdef_system(BlenderRNA *brna)
        RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflags", USER_DISABLE_MIPMAP);
        RNA_def_property_ui_text(prop, "Mipmaps", "Scale textures for the 3d View (looks nicer but uses more memory and slows image reloading.)");
 
+       prop= RNA_def_property(srna, "use_vbos", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflags", USER_DISABLE_VBO);
+       RNA_def_property_ui_text(prop, "VBOs", "Use Vertex Buffer Objects (or Vertex Arrays, if unsupported) for viewport rendering.");
+
        prop= RNA_def_property(srna, "gl_texture_limit", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_sdna(prop, NULL, "glreslimit");
        RNA_def_property_enum_items(prop, gl_texture_clamp_items);
index f8985fd65313f55f189af76f9cf7de16b8734079..b4328d12e81dd5b119fd73d36d73af19d60f1add 100644 (file)
@@ -86,6 +86,7 @@
 #include "UI_interface.h"
 #include "BLF_api.h"
 
+#include "gpu_buffers.h"
 #include "GPU_extensions.h"
 #include "GPU_draw.h"
 
@@ -252,6 +253,7 @@ void WM_exit(bContext *C)
 // XXX         UI_filelist_free_icons();
        }
        
+       GPU_buffer_pool_free(0);
        GPU_extensions_exit();
        
 //     if (copybuf) MEM_freeN(copybuf);
index dc2aca7b15b23001180ade13c4e654527735bb3f..081125bf7f6c6806ab303b1a5aabbb8414bc6d6c 100644 (file)
@@ -434,7 +434,7 @@ static int wm_get_colordepth(void)
 
 /* apple seems to round colors to below and up on some configs */
 
-static unsigned int index_to_framebuffer(int index)
+unsigned int index_to_framebuffer(int index)
 {
        unsigned int i= index;
 
@@ -464,7 +464,7 @@ static unsigned int index_to_framebuffer(int index)
 
 /* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
 
-static unsigned int index_to_framebuffer(int index)
+unsigned int index_to_framebuffer(int index)
 {
        unsigned int i= index;
        
index c0c492018ff7951c58d44f9c894165e778345510..78d73b596b218d80d1d07b14b0dc79aa35b60cb7 100644 (file)
@@ -45,6 +45,7 @@ void  wm_subwindow_getsize(wmWindow *win, int swinid, int *x, int *y);
 void   wm_subwindow_getorigin(wmWindow *win, int swinid, int *x, int *y);
 void   wm_subwindow_getmatrix(wmWindow *win, int swinid, float mat[][4]);
 
+unsigned int index_to_framebuffer(int index);
 
 #endif /* WM_SUBWINDOW_H */