diff options
19 files changed, 3118 insertions, 367 deletions
diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py index 9798e0ccab6..a9126d2c7f1 100644 --- a/release/scripts/ui/space_userpref.py +++ b/release/scripts/ui/space_userpref.py @@ -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:") diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 06103596be1..076747cb845 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -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 */ diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 7dc9e4499c6..ba42aca1872 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -88,6 +88,8 @@ typedef struct SculptSession { struct SculptStroke *stroke; struct StrokeCache *cache; + + struct GPUDrawObject *drawobject; } SculptSession; void free_sculptsession(SculptSession **); diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 43b9a63a2c1..86c272e3799 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -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 ); } } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index b20da0962a7..b9aa842b6dc 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -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); } diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 705d0b66d7f..28aaadea9c3 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -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] = { diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index deee3e3c8b4..e394de613e4 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -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); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 5312ca26906..1445c6b5cf8 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -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) { diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 64af39ea497..e41231442ba 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -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; diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index da67bd8707e..a4d7ae802f6 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -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 */ diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index db3b7130ab3..53e87d61ad3 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -102,6 +102,7 @@ #include "GPU_draw.h" #include "GPU_material.h" #include "GPU_extensions.h" +#include "gpu_buffers.h" #include "ED_mesh.h" #include "ED_particle.h" @@ -113,6 +114,7 @@ #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); @@ -5608,6 +6040,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; } else { @@ -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 index 00000000000..d71c8e49acd --- /dev/null +++ b/source/blender/gpu/gpu_buffers.h @@ -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 index 00000000000..5781c852657 --- /dev/null +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -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 diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 18c18d9e9dd..ad686e37097 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -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) diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 826eea43a4d..16ab3e1e9bd 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -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 diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index e9fcb299c53..25448d0c2de 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -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); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index f8985fd6531..b4328d12e81 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -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); diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index dc2aca7b15b..081125bf7f6 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -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; diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h index c0c492018ff..78d73b596b2 100644 --- a/source/blender/windowmanager/wm_subwindow.h +++ b/source/blender/windowmanager/wm_subwindow.h @@ -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 */ |