Sculpt: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r24095...
[blender.git] / source / blender / editors / space_view3d / drawobject.c
index 3641ff435dd60fb170e2bab541fc3aa6d31b56c6..f7dba10200a0dbfe5bd463c13acbf06752179b0b 100644 (file)
@@ -37,7 +37,7 @@
 #include "IMB_imbuf.h"
 
 
-#include "MTC_matrixops.h"
+
 
 #include "DNA_armature_types.h"
 #include "DNA_boid_types.h"
 #include "BKE_mball.h"
 #include "BKE_modifier.h"
 #include "BKE_object.h"
+#include "BKE_paint.h"
 #include "BKE_particle.h"
+#include "BKE_pointcache.h"
 #include "BKE_property.h"
 #include "BKE_smoke.h"
+#include "BKE_unit.h"
 #include "BKE_utildefines.h"
 #include "smoke_API.h"
 
 #include "GPU_draw.h"
 #include "GPU_material.h"
 #include "GPU_extensions.h"
+#include "gpu_buffers.h"
 
 #include "ED_mesh.h"
 #include "ED_particle.h"
 #include "ED_screen.h"
+#include "ED_sculpt.h"
 #include "ED_types.h"
 #include "ED_util.h"
 
 #include "UI_interface_icons.h"
 
 #include "WM_api.h"
+#include "wm_subwindow.h"
 #include "BLF_api.h"
 
 #include "view3d_intern.h"     // own include
@@ -134,7 +140,9 @@ static void draw_empty_sphere(float size);
 static void draw_empty_cone(float size);
 
 
-/* ************* only use while object drawing ************** */
+/* ************* only use while object drawing **************
+ * or after running ED_view3d_init_mats_rv3d
+ * */
 static void view3d_project_short_clip(ARegion *ar, float *vec, short *adr)
 {
        RegionView3D *rv3d= ar->regiondata;
@@ -205,17 +213,16 @@ static void view3d_project_short_noclip(ARegion *ar, float *vec, short *adr)
 
 int draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, int dt)
 {
-       if(!GPU_extensions_minimum_support())
+       if(!GPU_glsl_support())
                return 0;
        if(G.f & G_PICKSEL)
                return 0;
        if(!CHECK_OB_DRAWTEXTURE(v3d, dt))
                return 0;
-       if(ob==OBACT && (G.f & G_WEIGHTPAINT))
+       if(ob==OBACT && (ob && ob->mode & OB_MODE_WEIGHT_PAINT))
                return 0;
        
-       return ((G.fileflags & G_FILE_GAME_MAT) &&
-          (G.fileflags & G_FILE_GAME_MAT_GLSL) && (dt >= OB_SHADED));
+       return (scene->gm.matmode == GAME_MAT_GLSL) && (dt >= OB_SHADED);
 }
 
 static int check_material_alpha(Base *base, Mesh *me, int glsl)
@@ -432,11 +439,11 @@ void drawaxes(float size, int flag, char drawtype)
                        // patch for 3d cards crashing on glSelect for text drawing (IBM)
                        if((flag & DRAW_PICKING) == 0) {
                                if (axis==0)
-                                       view3d_object_text_draw_add(v2[0], v2[1], v2[2], "x", 0);
+                                       view3d_cached_text_draw_add(v2[0], v2[1], v2[2], "x", 0);
                                else if (axis==1)
-                                       view3d_object_text_draw_add(v2[0], v2[1], v2[2], "y", 0);
+                                       view3d_cached_text_draw_add(v2[0], v2[1], v2[2], "y", 0);
                                else
-                                       view3d_object_text_draw_add(v2[0], v2[1], v2[2], "z", 0);
+                                       view3d_cached_text_draw_add(v2[0], v2[1], v2[2], "z", 0);
                        }
                }
                break;
@@ -494,23 +501,32 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, float *vec, int se
        if(v3d->zbuf)  glDepthFunc(GL_LEQUAL);
 }
 
-/* *********** text drawing for object ************* */
-static ListBase strings= {NULL, NULL};
+/* *********** text drawing for object/particles/armature ************* */
+
+static ListBase CachedText[3];
+static int CachedTextLevel= 0;
 
-typedef struct ViewObjectString {
-       struct ViewObjectString *next, *prev;
+typedef struct ViewCachedString {
+       struct ViewCachedString *next, *prev;
        float vec[3], col[4];
        char str[128]; 
        short mval[2];
        short xoffs;
-} ViewObjectString;
+} ViewCachedString;
 
+void view3d_cached_text_draw_begin()
+{
+       ListBase *strings= &CachedText[CachedTextLevel];
+       strings->first= strings->last= NULL;
+       CachedTextLevel++;
+}
 
-void view3d_object_text_draw_add(float x, float y, float z, char *str, short xoffs)
+void view3d_cached_text_draw_add(float x, float y, float z, char *str, short xoffs)
 {
-       ViewObjectString *vos= MEM_callocN(sizeof(ViewObjectString), "ViewObjectString");
+       ListBase *strings= &CachedText[CachedTextLevel-1];
+       ViewCachedString *vos= MEM_callocN(sizeof(ViewCachedString), "ViewCachedString");
 
-       BLI_addtail(&strings, vos);
+       BLI_addtail(strings, vos);
        BLI_strncpy(vos->str, str, 128);
        vos->vec[0]= x;
        vos->vec[1]= y;
@@ -519,22 +535,23 @@ void view3d_object_text_draw_add(float x, float y, float z, char *str, short xof
        vos->xoffs= xoffs;
 }
 
-static void view3d_object_text_draw(View3D *v3d, ARegion *ar)
+void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, float mat[][4])
 {
-       ViewObjectString *vos;
-       int tot= 0;
+       RegionView3D *rv3d= ar->regiondata;
+       ListBase *strings= &CachedText[CachedTextLevel-1];
+       ViewCachedString *vos;
+       int a, tot= 0;
        
        /* project first and test */
-       for(vos= strings.first; vos; vos= vos->next) {
+       for(vos= strings->first; vos; vos= vos->next) {
+               if(mat)
+                       Mat4MulVecfl(mat, vos->vec);
                view3d_project_short_clip(ar, vos->vec, vos->mval);
                if(vos->mval[0]!=IS_CLIPPED)
                        tot++;
        }
-       
+
        if(tot) {
-               RegionView3D *rv3d= ar->regiondata;
-               int a;
-               
                if(rv3d->rflag & RV3D_CLIPPING)
                        for(a=0; a<6; a++)
                                glDisable(GL_CLIP_PLANE0+a);
@@ -542,16 +559,22 @@ static void view3d_object_text_draw(View3D *v3d, ARegion *ar)
                wmPushMatrix();
                ED_region_pixelspace(ar);
                
-               if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
+               if(depth_write) {
+                       if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
+               }
+               else glDepthMask(0);
                
-               for(vos= strings.first; vos; vos= vos->next) {
+               for(vos= strings->first; vos; vos= vos->next) {
                        if(vos->mval[0]!=IS_CLIPPED) {
                                glColor3fv(vos->col);
-                               BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], 0.0, vos->str);
+                               BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], (depth_write)? 0.0f: 2.0f, vos->str);
                        }
                }
                
-               if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
+               if(depth_write) {
+                       if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
+               }
+               else glDepthMask(1);
                
                wmPopMatrix();
 
@@ -560,10 +583,14 @@ static void view3d_object_text_draw(View3D *v3d, ARegion *ar)
                                glEnable(GL_CLIP_PLANE0+a);
        }
        
-       if(strings.first) 
-               BLI_freelistN(&strings);
+       if(strings->first) 
+               BLI_freelistN(strings);
+       
+       CachedTextLevel--;
 }
 
+/* ******************** primitive drawing ******************* */
+
 static void drawcube(void)
 {
 
@@ -896,11 +923,11 @@ static void drawlamp(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob)
                /* draw the circle/square representing spotbl */
                if(la->type==LA_SPOT) {
                        float spotblcirc = fabs(z)*(1 - pow(la->spotblend, 2));
-                       /* make sure the line is always visible - prevent it from reaching the outer border (or 0) 
-                        * values are kinda arbitrary - just what seemed to work well */
-                       if (spotblcirc == 0) spotblcirc = 0.15;
-                       else if (spotblcirc == fabs(z)) spotblcirc = fabs(z) - 0.07;
-                       circ(0.0, 0.0, spotblcirc);
+                       /* hide line if it is zero size or overlaps with outer border,
+                          previously it adjusted to always to show it but that seems
+                          confusing because it doesn't show the actual blend size */
+                       if (spotblcirc != 0 && spotblcirc != fabs(z))
+                               circ(0.0, 0.0, spotblcirc);
                }
                
        }
@@ -1122,7 +1149,7 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob
                        Mat4Ortho(vec);
                        wmMultMatrix(vec);
 
-                       MTC_Mat4SwapMat4(rv3d->persmat, tmat);
+                       Mat4SwapMat4(rv3d->persmat, tmat);
                        wmGetSingleMatrix(rv3d->persmat);
 
                        if(cam->flag & CAM_SHOWLIMITS) {
@@ -1135,7 +1162,7 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob
                        if(cam->flag & CAM_SHOWMIST) 
                                if(wrld) draw_limit_line(wrld->miststa, wrld->miststa+wrld->mistdist, 0xFFFFFF);
                                
-                       MTC_Mat4SwapMat4(rv3d->persmat, tmat);
+                       Mat4SwapMat4(rv3d->persmat, tmat);
                }
        }
 }
@@ -1196,7 +1223,7 @@ static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, i
 
        if(use_wcol) {
                float col[3];
-               MDeformWeight *mdw= get_defweight (lt->dvert+index, use_wcol-1);
+               MDeformWeight *mdw= ED_vgroup_weight_get (lt->dvert+index, use_wcol-1);
                
                weight_to_rgb(mdw?mdw->weight:0.0f, col, col+1, col+2);
                glColor3fv(col);
@@ -1275,6 +1302,10 @@ static void drawlattice(Scene *scene, View3D *v3d, Object *ob)
 
 /* ***************** ******************** */
 
+/* Note! - foreach funcs should be called while drawing or directly after
+ * if not, ED_view3d_init_mats_rv3d() can be used for selection tools
+ * but would not give correct results with dupli's for eg. which dont
+ * use the object matrix in the useual way */
 static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
 {
        struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
@@ -1390,12 +1421,13 @@ void nurbs_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, Nurb
        int i;
 
        for (nu= cu->editnurb->first; nu; nu=nu->next) {
-               if((nu->type & 7)==CU_BEZIER) {
+               if(nu->type == CU_BEZIER) {
                        for (i=0; i<nu->pntsu; i++) {
                                BezTriple *bezt = &nu->bezt[i];
 
                                if(bezt->hide==0) {
-                                       if (G.f & G_HIDDENHANDLES) {
+                                       
+                                       if(cu->drawflag & CU_HIDE_HANDLES) {
                                                view3d_project_short_clip(vc->ar, bezt->vec[1], s);
                                                if (s[0] != IS_CLIPPED)
                                                        func(userData, nu, NULL, bezt, 1, s[0], s[1]);
@@ -1527,15 +1559,83 @@ static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *
                }
        }
 }
+
+/* disabled because it crashes combined with e.g. subsurf modifier,
+ * the derivedmesh can't be assumed to be an EditMeshDerivedMesh,
+ * nor should this struct be copied around, it should be defined in
+ * a single place only to avoid them getting out of sync */
+#if 0
+/* originally defined in DerivedMesh.c */
+typedef struct {
+       DerivedMesh dm;
+
+       EditMesh *em;
+       float (*vertexCos)[3];
+       float (*vertexNos)[3];
+       float (*faceNos)[3];
+} EditMeshDerivedMesh;
+#endif
+
 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();
+
+#if 0
+       /* first come the unselected vertices, then the selected */
+       buffer = GPU_buffer_legacy(dm)?0: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();
+       }
+       {
+#endif
+               bglBegin(GL_POINTS);
+               dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
+               bglEnd();
+#if 0
+       }
+       GPU_buffer_free( buffer, 0 );
+#endif
 }
 
        /* Draw edges with color set based on selection */
@@ -1603,12 +1703,59 @@ 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];
-       cols[0] = baseCol;
-       cols[1] = selCol;
-       dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
+       unsigned char *cols[2] = {baseCol, selCol};
+#if 0
+       int elemsize = sizeof(float)*3+sizeof(unsigned char)*4;
+       EditMeshDerivedMesh *emdm = (EditMeshDerivedMesh *)dm;
+       EditMesh *em= emdm->em;
+       unsigned char *varray;
+       int i;
+       GPUBuffer *buffer;
+
+       buffer = GPU_buffer_legacy(dm)?0: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 {
+#endif
+               dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
+#if 0
+       }
+       GPU_buffer_free( buffer, 0 );
+#endif
 }
 
        /* Draw only seam edges */
@@ -1662,12 +1809,236 @@ 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;
+       GPUBuffer *buffer;
+       unsigned char *varray;
+       unsigned char black[] = { 0, 0, 0, 0 };
+       int i, 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_legacy(dm)?0: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)
@@ -1849,7 +2220,7 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh
        }
 }      
 
-static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em)
+static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, UnitSettings *unit)
 {
        Mesh *me= ob->data;
        EditEdge *eed;
@@ -1859,18 +2230,20 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E
        char val[32]; /* Stores the measurement display text here */
        char conv_float[5]; /* Use a float conversion matching the grid size */
        float area, col[3]; /* area of the face,  color of the text to draw */
-       
+       float grid= unit->system ? unit->scale_length : v3d->grid;
+       int do_split= unit->flag & USER_UNIT_OPT_SPLIT;
        if(G.f & (G_RENDER_OGL|G_RENDER_SHADOW))
                return;
 
        /* make the precission of the pronted value proportionate to the gridsize */
-       if ((v3d->grid) < 0.01)
+
+       if (grid < 0.01f)
                strcpy(conv_float, "%.6f");
-       else if ((v3d->grid) < 0.1)
+       else if (grid < 0.1f)
                strcpy(conv_float, "%.5f");
-       else if ((v3d->grid) < 1.0)
+       else if (grid < 1.0f)
                strcpy(conv_float, "%.4f");
-       else if ((v3d->grid) < 10.0)
+       else if (grid < 10.0f)
                strcpy(conv_float, "%.3f");
        else
                strcpy(conv_float, "%.2f");
@@ -1879,13 +2252,13 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E
        if(v3d->zbuf && (v3d->flag & V3D_ZBUF_SELECT)==0)
                glDisable(GL_DEPTH_TEST);
 
-       if(v3d->zbuf) bglPolygonOffset(rv3d->dist, 5.0);
+       if(v3d->zbuf) bglPolygonOffset(rv3d->dist, 5.0f);
        
        if(me->drawflag & ME_DRAW_EDGELEN) {
                UI_GetThemeColor3fv(TH_TEXT, col);
                /* make color a bit more red */
-               if(col[0]> 0.5) {col[1]*=0.7; col[2]*= 0.7;}
-               else col[0]= col[0]*0.7 + 0.3;
+               if(col[0]> 0.5f) {col[1]*=0.7f; col[2]*= 0.7f;}
+               else col[0]= col[0]*0.7f + 0.3f;
                glColor3fv(col);
                
                for(eed= em->edges.first; eed; eed= eed->next) {
@@ -1894,17 +2267,20 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E
                                VECCOPY(v1, eed->v1->co);
                                VECCOPY(v2, eed->v2->co);
                                
-                               x= 0.5*(v1[0]+v2[0]);
-                               y= 0.5*(v1[1]+v2[1]);
-                               z= 0.5*(v1[2]+v2[2]);
+                               x= 0.5f*(v1[0]+v2[0]);
+                               y= 0.5f*(v1[1]+v2[1]);
+                               z= 0.5f*(v1[2]+v2[2]);
                                
                                if(v3d->flag & V3D_GLOBAL_STATS) {
                                        Mat4MulVecfl(ob->obmat, v1);
                                        Mat4MulVecfl(ob->obmat, v2);
                                }
+                               if(unit->system)
+                                       bUnit_AsString(val, sizeof(val), VecLenf(v1, v2)*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE);
+                               else
+                                       sprintf(val, conv_float, VecLenf(v1, v2));
                                
-                               sprintf(val, conv_float, VecLenf(v1, v2));
-                               view3d_object_text_draw_add(x, y, z, val, 0);
+                               view3d_cached_text_draw_add(x, y, z, val, 0);
                        }
                }
        }
@@ -1914,8 +2290,8 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E
                
                UI_GetThemeColor3fv(TH_TEXT, col);
                /* make color a bit more green */
-               if(col[1]> 0.5) {col[0]*=0.7; col[2]*= 0.7;}
-               else col[1]= col[1]*0.7 + 0.3;
+               if(col[1]> 0.5f) {col[0]*=0.7f; col[2]*= 0.7f;}
+               else col[1]= col[1]*0.7f + 0.3f;
                glColor3fv(col);
                
                for(efa= em->faces.first; efa; efa= efa->next) {
@@ -1938,8 +2314,12 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E
                                else
                                        area = AreaT3Dfl(v1, v2, v3);
 
-                               sprintf(val, conv_float, area);
-                               view3d_object_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0);
+                               if(unit->system)
+                                       bUnit_AsString(val, sizeof(val), area*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); // XXX should be B_UNIT_AREA
+                               else
+                                       sprintf(val, conv_float, area);
+
+                               view3d_cached_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0);
                        }
                }
        }
@@ -1949,8 +2329,8 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E
                
                UI_GetThemeColor3fv(TH_TEXT, col);
                /* make color a bit more blue */
-               if(col[2]> 0.5) {col[0]*=0.7; col[1]*= 0.7;}
-               else col[2]= col[2]*0.7 + 0.3;
+               if(col[2]> 0.5f) {col[0]*=0.7f; col[1]*= 0.7f;}
+               else col[2]= col[2]*0.7f + 0.3f;
                glColor3fv(col);
                
                for(efa= em->faces.first; efa; efa= efa->next) {
@@ -1979,31 +2359,31 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E
                                
                        if( (e4->f & e1->f & SELECT) || (G.moving && (efa->v1->f & SELECT)) ) {
                                /* Vec 1 */
-                               sprintf(val,"%.3f", VecAngle3(v4, v1, v2));
-                               VecLerpf(fvec, efa->cent, efa->v1->co, 0.8);
-                               view3d_object_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0);
+                               sprintf(val,"%.3f", RAD2DEG(VecAngle3(v4, v1, v2)));
+                               VecLerpf(fvec, efa->cent, efa->v1->co, 0.8f);
+                               view3d_cached_text_draw_add(efa->cent[0], efa->cent[1], efa->cent[2], val, 0);
                        }
                        if( (e1->f & e2->f & SELECT) || (G.moving && (efa->v2->f & SELECT)) ) {
                                /* Vec 2 */
-                               sprintf(val,"%.3f", VecAngle3(v1, v2, v3));
-                               VecLerpf(fvec, efa->cent, efa->v2->co, 0.8);
-                               view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0);
+                               sprintf(val,"%.3f", RAD2DEG(VecAngle3(v1, v2, v3)));
+                               VecLerpf(fvec, efa->cent, efa->v2->co, 0.8f);
+                               view3d_cached_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0);
                        }
                        if( (e2->f & e3->f & SELECT) || (G.moving && (efa->v3->f & SELECT)) ) {
                                /* Vec 3 */
                                if(efa->v4) 
-                                       sprintf(val,"%.3f", VecAngle3(v2, v3, v4));
+                                       sprintf(val,"%.3f", RAD2DEG(VecAngle3(v2, v3, v4)));
                                else
-                                       sprintf(val,"%.3f", VecAngle3(v2, v3, v1));
-                               VecLerpf(fvec, efa->cent, efa->v3->co, 0.8);
-                               view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0);
+                                       sprintf(val,"%.3f", RAD2DEG(VecAngle3(v2, v3, v1)));
+                               VecLerpf(fvec, efa->cent, efa->v3->co, 0.8f);
+                               view3d_cached_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0);
                        }
                                /* Vec 4 */
                        if(efa->v4) {
                                if( (e3->f & e4->f & SELECT) || (G.moving && (efa->v4->f & SELECT)) ) {
-                                       sprintf(val,"%.3f", VecAngle3(v3, v4, v1));
-                                       VecLerpf(fvec, efa->cent, efa->v4->co, 0.8);
-                                       view3d_object_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0);
+                                       sprintf(val,"%.3f", RAD2DEG(VecAngle3(v3, v4, v1)));
+                                       VecLerpf(fvec, efa->cent, efa->v4->co, 0.8f);
+                                       view3d_cached_text_draw_add(fvec[0], fvec[1], fvec[2], val, 0);
                                }
                        }
                }
@@ -2011,7 +2391,7 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E
        
        if(v3d->zbuf) {
                glEnable(GL_DEPTH_TEST);
-               bglPolygonOffset(rv3d->dist, 0.0);
+               bglPolygonOffset(rv3d->dist, 0.0f);
        }
 }
 
@@ -2071,12 +2451,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_legacy(em->derivedFinal)?0: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);
@@ -2096,7 +2579,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
                }
        }
        
-       if((me->drawflag & (ME_DRAWFACES)) || FACESEL_PAINT_TEST) {     /* transp faces */
+       if((me->drawflag & (ME_DRAWFACES)) || paint_facesel_test(ob)) { /* transp faces */
                unsigned char col1[4], col2[4], col3[4];
                        
                UI_GetThemeColor4ubv(TH_FACE, (char *)col1);
@@ -2184,7 +2667,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
                }
 
                if(me->drawflag & (ME_DRAW_EDGELEN|ME_DRAW_FACEAREA|ME_DRAW_EDGEANG))
-                       draw_em_measure_stats(v3d, rv3d, ob, em);
+                       draw_em_measure_stats(v3d, rv3d, ob, em, &scene->unit);
        }
 
        if(dt>OB_WIRE) {
@@ -2209,7 +2692,7 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
                   drawFacesSolid() doesn't draw the transparent faces */
                if(ob->dtx & OB_DRAWTRANSP) {
                        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 
-                       dm->drawFacesSolid(dm, GPU_enable_material);
+                       dm->drawFacesSolid(dm, NULL, GPU_enable_material);
                        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                        GPU_disable_material();
                }
@@ -2228,7 +2711,7 @@ static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmoot
        return 1;
 }
 
-static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
+static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
 {
        Object *ob= base->object;
        Mesh *me = ob->data;
@@ -2255,7 +2738,7 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
 
                // Unwanted combination.
-       if (ob==OBACT && FACESEL_PAINT_TEST) draw_wire = 0;
+       if (ob==OBACT && paint_facesel_test(ob)) draw_wire = 0;
 
        if(dt==OB_BOUNDBOX) {
                draw_bounding_volume(scene, ob);
@@ -2268,12 +2751,12 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
        else if(dt==OB_WIRE || totface==0) {
                draw_wire = 1; /* draw wire only, no depth buffer stuff  */
        }
-       else if(        (ob==OBACT && (G.f & G_TEXTUREPAINT || FACESEL_PAINT_TEST)) ||
+       else if(        (ob==OBACT && (ob->mode & OB_MODE_TEXTURE_PAINT || paint_facesel_test(ob))) ||
                                CHECK_OB_DRAWTEXTURE(v3d, dt))
        {
-               int faceselect= (ob==OBACT && FACESEL_PAINT_TEST);
+               int faceselect= (ob==OBACT && paint_facesel_test(ob));
 
-               if ((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !(G.f&G_PICKSEL || FACESEL_PAINT_TEST) && !draw_wire) {
+               if ((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !(G.f&G_PICKSEL || paint_facesel_test(ob)) && !draw_wire) {
                        draw_mesh_object_outline(v3d, ob, dm);
                }
 
@@ -2301,7 +2784,7 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                }
        }
        else if(dt==OB_SOLID) {
-               if((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire)
+               if((v3d->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire && !ob->sculpt)
                        draw_mesh_object_outline(v3d, ob, dm);
 
                glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED );
@@ -2309,7 +2792,21 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                glEnable(GL_LIGHTING);
                glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
 
-               dm->drawFacesSolid(dm, GPU_enable_material);
+               if(ob->sculpt) {
+                       float planes[4][4];
+                       float (*fpl)[4] = NULL;
+
+                       if(ob->sculpt->partial_redraw) {
+                               sculpt_get_redraw_planes(planes, ar, rv3d, ob);
+                               fpl = planes;
+                               ob->sculpt->partial_redraw = 0;
+                       }
+
+                       dm->drawFacesSolid(dm, fpl, GPU_enable_material);
+               }
+               else
+                       dm->drawFacesSolid(dm, NULL, GPU_enable_material);
+
                GPU_disable_material();
 
                glFrontFace(GL_CCW);
@@ -2320,14 +2817,15 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                } else {
                        UI_ThemeColor(TH_WIRE);
                }
-               dm->drawLooseEdges(dm);
+               if(!ob->sculpt)
+                       dm->drawLooseEdges(dm);
        }
        else if(dt==OB_SHADED) {
                int do_draw= 1; /* to resolve all G.f settings below... */
                
                if(ob==OBACT) {
                        do_draw= 0;
-                       if( (G.f & G_WEIGHTPAINT)) {
+                       if(ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
                                /* enforce default material settings */
                                GPU_enable_material(0, NULL);
                                
@@ -2347,12 +2845,13 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
 
                                GPU_disable_material();
                        }
-                       else if((G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) && me->mcol) {
-                               dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1);
-                       }
-                       else if(G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) {
-                               glColor3f(1.0f, 1.0f, 1.0f);
-                               dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0);
+                       else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)) {
+                               if(me->mcol)
+                                       dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1);
+                               else {
+                                       glColor3f(1.0f, 1.0f, 1.0f);
+                                       dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0);
+                               }
                        }
                        else do_draw= 1;
                }
@@ -2437,7 +2936,7 @@ static void draw_mesh_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
 }
 
 /* returns 1 if nothing was drawn, for detecting to draw an object center */
-static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
+static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, Base *base, int dt, int flag)
 {
        Object *ob= base->object;
        Object *obedit= scene->obedit;
@@ -2487,7 +2986,7 @@ static int draw_mesh_object(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                                        (check_alpha)? &do_alpha_pass: NULL);
                        }
 
-                       draw_mesh_fancy(scene, v3d, rv3d, base, dt, flag);
+                       draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, flag);
 
                        GPU_end_object_materials();
                        
@@ -2785,7 +3284,7 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas
                if(solid) {
                        dl= lb->first;
                        if(dl==NULL) return 1;
-                       
+
                        if(dl->nors==0) addnormalsDispList(ob, lb);
                        index3_nors_incr= 0;
                        
@@ -2826,7 +3325,7 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas
                }
                break;
        case OB_SURF:
-       
+
                lb= &((Curve *)ob->data)->disp;
                
                if(solid) {
@@ -2892,82 +3391,31 @@ static int drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *bas
        return retval;
 }
 
-/* *********** text drawing for particles ************* */
-static ListBase pstrings= {NULL, NULL};
-
-typedef struct ViewParticleString {
-       struct ViewParticleString *next, *prev;
-       float vec[3], col[4];
-       char str[128]; 
-       short mval[2];
-       short xoffs;
-} ViewParticleString;
-
-
-void view3d_particle_text_draw_add(float x, float y, float z, char *str, short xoffs)
-{
-       ViewObjectString *vos= MEM_callocN(sizeof(ViewObjectString), "ViewObjectString");
-
-       BLI_addtail(&pstrings, vos);
-       BLI_strncpy(vos->str, str, 128);
-       vos->vec[0]= x;
-       vos->vec[1]= y;
-       vos->vec[2]= z;
-       glGetFloatv(GL_CURRENT_COLOR, vos->col);
-       vos->xoffs= xoffs;
-}
-
-static void view3d_particle_text_draw(View3D *v3d, ARegion *ar)
+/* *********** drawing for particles ************* */
+static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int select)
 {
-       ViewObjectString *vos;
-       int tot= 0;
-       
-       /* project first and test */
-       for(vos= pstrings.first; vos; vos= vos->next) {
-               project_short(ar, vos->vec, vos->mval);
-               if(vos->mval[0]!=IS_CLIPPED)
-                       tot++;
-       }
-       
-       if(tot) {
-               RegionView3D *rv3d= ar->regiondata;
-               int a;
-               
-               if(rv3d->rflag & RV3D_CLIPPING)
-                       for(a=0; a<6; a++)
-                               glDisable(GL_CLIP_PLANE0+a);
-               
-               wmPushMatrix();
-               ED_region_pixelspace(ar);
-               
-               if(v3d->zbuf) glDepthMask(0);
-
-               for(vos= pstrings.first; vos; vos= vos->next) {
-                       if(vos->mval[0]!=IS_CLIPPED) {
-                               glColor3fv(vos->col);
-                               BLF_draw_default((float)vos->mval[0]+vos->xoffs, (float)vos->mval[1], 2.0, vos->str);
-                       }
-               }
-               
-               if(v3d->zbuf) glDepthMask(1);
-               
-               wmPopMatrix();
+       /* draw created data arrays */
+       switch(draw_as){
+               case PART_DRAW_AXIS:
+               case PART_DRAW_CROSS:
+                       glDrawArrays(GL_LINES, 0, 6*totpoint);
+                       break;
+               case PART_DRAW_LINE:
+                       glDrawArrays(GL_LINES, 0, 2*totpoint);
+                       break;
+               case PART_DRAW_BB:
+                       if(ob_dt<=OB_WIRE || select)
+                               glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
+                       else
+                               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 
 
-               if(rv3d->rflag & RV3D_CLIPPING)
-                       for(a=0; a<6; a++)
-                               glEnable(GL_CLIP_PLANE0+a);
+                       glDrawArrays(GL_QUADS, 0, 4*totpoint);
+                       break;
+               default:
+                       glDrawArrays(GL_POINTS, 0, totpoint);
+                       break;
        }
-       
-       if(pstrings.first) 
-               BLI_freelistN(&pstrings);
 }
-typedef struct ParticleDrawData {
-       float *vdata, *vd;
-       float *ndata, *nd;
-       float *cdata, *cd;
-       float *vedata, *ved;
-       float *ma_r, *ma_g, *ma_b;
-} ParticleDrawData;
 static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize, float imat[4][4], float *draw_line, ParticleBillboardData *bb, ParticleDrawData *pdd)
 {
        float vec[3], vec2[3];
@@ -3010,7 +3458,7 @@ static void draw_particle(ParticleKey *state, int draw_as, short draw, float pix
                                cd[7]=cd[10]=1.0;
                                cd[13]=cd[12]=cd[15]=cd[16]=0.0;
                                cd[14]=cd[17]=1.0;
-                               cd+=18;
+                               pdd->cd+=18;
 
                                VECCOPY(vec2,state->co);
                        }
@@ -3127,11 +3575,13 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 {
        Object *ob=base->object;
        ParticleSystemModifierData *psmd;
+       ParticleEditSettings *pset = PE_settings(scene);
        ParticleSettings *part;
        ParticleData *pars, *pa;
        ParticleKey state, *states=0;
        ParticleBillboardData bb;
-       ParticleDrawData pdd;
+       ParticleSimulationData sim = {scene, ob, psys, NULL};
+       ParticleDrawData *pdd = psys->pdd;
        Material *ma;
        float vel[3], imat[4][4];
        float timestep, pixsize=1.0, pa_size, r_tilt, r_length;
@@ -3155,17 +3605,24 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
        if(pars==0) return;
 
-       // XXX what logic is this?
-       if(!scene->obedit && psys_in_edit_mode(scene, psys)
-               && psys->flag & PSYS_HAIR_DONE && part->draw_as==PART_DRAW_PATH)
+       /* don't draw normal paths in edit mode */
+       if(psys_in_edit_mode(scene, psys) && (pset->flag & PE_DRAW_PART)==0)
                return;
                
-       if(part->draw_as==PART_DRAW_NOT) return;
+       if(part->draw_as == PART_DRAW_REND)
+               draw_as = part->ren_as;
+       else
+               draw_as = part->draw_as;
+
+       if(draw_as == PART_DRAW_NOT)
+               return;
 
 /* 2. */
+       sim.psmd = psmd = psys_get_modifier(ob,psys);
+
        if(part->phystype==PART_PHYS_KEYED){
                if(psys->flag&PSYS_KEYED){
-                       psys_count_keyed_targets(ob,psys);
+                       psys_count_keyed_targets(&sim);
                        if(psys->totkeyed==0)
                                return;
                }
@@ -3183,34 +3640,28 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                totchild=0;
        else
                totchild=psys->totchild*part->disp/100;
-       
-       memset(&pdd, 0, sizeof(ParticleDrawData));
 
        ma= give_current_material(ob,part->omat);
 
        if(v3d->zbuf) glDepthMask(1);
 
-       if(select)
-               cpack(0xFFFFFF);
-       else if((ma) && (part->draw&PART_DRAW_MAT_COL)) {
+       if((ma) && (part->draw&PART_DRAW_MAT_COL)) {
                glColor3f(ma->r,ma->g,ma->b);
 
                ma_r = ma->r;
                ma_g = ma->g;
                ma_b = ma->b;
-
-               pdd.ma_r = &ma_r;
-               pdd.ma_g = &ma_g;
-               pdd.ma_b = &ma_b;
-
-               create_cdata = 1;
        }
        else
                cpack(0);
 
-       psmd= psys_get_modifier(ob,psys);
+       if(pdd) {
+               pdd->ma_r = &ma_r;
+               pdd->ma_g = &ma_g;
+               pdd->ma_b = &ma_b;
+       }
 
-       timestep= psys_get_timestep(part);
+       timestep= psys_get_timestep(&sim);
 
        if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) {
                float mat[4][4];
@@ -3220,15 +3671,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
        totpart=psys->totpart;
 
-       if(part->draw_as==PART_DRAW_REND)
-               draw_as = part->ren_as;
-       else
-               draw_as = part->draw_as;
-
        //if(part->flag&PART_GLOB_TIME)
        cfra=bsystem_time(scene, 0, (float)CFRA, 0.0f);
 
-       if(draw_as==PART_DRAW_PATH && psys->pathcache==NULL)
+       if(draw_as==PART_DRAW_PATH && psys->pathcache==NULL && psys->childcache==NULL)
                draw_as=PART_DRAW_DOT;
 
 /* 3. */
@@ -3254,6 +3700,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                pixsize*=2.0;
                        else
                                pixsize*=part->draw_size;
+
+                       if(draw_as==PART_DRAW_AXIS)
+                               create_cdata = 1;
                        break;
                case PART_DRAW_OB:
                        if(part->dup_ob==0)
@@ -3301,57 +3750,73 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                Normalize(imat[1]);
        }
 
+       if(!create_cdata && pdd && pdd->cdata) {
+               MEM_freeN(pdd->cdata);
+               pdd->cdata = pdd->cd = NULL;
+       }
+
 /* 4. */
-       if(draw_as && draw_as!=PART_DRAW_PATH) {
+       if(draw_as && ELEM(draw_as, PART_DRAW_PATH, PART_DRAW_CIRC)==0) {
                int tot_vec_size = (totpart + totchild) * 3 * sizeof(float);
-               
+               int create_ndata = 0;
+
+               if(!pdd)
+                       pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticlDrawData");
+
                if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
                        tot_vec_size *= part->trail_count;
                        psys_make_temp_pointcache(ob, psys);
                }
 
-               if(draw_as!=PART_DRAW_CIRC) {
-                       switch(draw_as) {
-                               case PART_DRAW_AXIS:
-                               case PART_DRAW_CROSS:
-                                       if(draw_as != PART_DRAW_CROSS || create_cdata)
-                                               pdd.cdata = MEM_callocN(tot_vec_size * 6, "particle_cdata");
-                                       pdd.vdata = MEM_callocN(tot_vec_size * 6, "particle_vdata");
-                                       break;
-                               case PART_DRAW_LINE:
-                                       if(create_cdata)
-                                               pdd.cdata = MEM_callocN(tot_vec_size * 2, "particle_cdata");
-                                       pdd.vdata = MEM_callocN(tot_vec_size * 2, "particle_vdata");
-                                       break;
-                               case PART_DRAW_BB:
-                                       if(create_cdata)
-                                               pdd.cdata = MEM_callocN(tot_vec_size * 4, "particle_cdata");
-                                       pdd.vdata = MEM_callocN(tot_vec_size * 4, "particle_vdata");
-                                       pdd.ndata = MEM_callocN(tot_vec_size * 4, "particle_vdata");
-                                       break;
-                               default:
-                                       if(create_cdata)
-                                               pdd.cdata=MEM_callocN(tot_vec_size, "particle_cdata");
-                                       pdd.vdata=MEM_callocN(tot_vec_size, "particle_vdata");
-                       }
+               switch(draw_as) {
+                       case PART_DRAW_AXIS:
+                       case PART_DRAW_CROSS:
+                               tot_vec_size *= 6;
+                               if(draw_as != PART_DRAW_CROSS)
+                                       create_cdata = 1;
+                               break;
+                       case PART_DRAW_LINE:
+                               tot_vec_size *= 2;
+                               break;
+                       case PART_DRAW_BB:
+                               tot_vec_size *= 4;
+                               create_ndata = 1;
+                               break;
                }
 
+               if(pdd->tot_vec_size != tot_vec_size)
+                       psys_free_pdd(psys);
+
+               if(!pdd->vdata)
+                       pdd->vdata = MEM_callocN(tot_vec_size, "particle_vdata");
+               if(create_cdata && !pdd->cdata)
+                       pdd->cdata = MEM_callocN(tot_vec_size, "particle_cdata");
+               if(create_ndata && !pdd->ndata)
+                       pdd->ndata = MEM_callocN(tot_vec_size, "particle_vdata");
+
                if(part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) {
-                       pdd.vedata = MEM_callocN(tot_vec_size * 2, "particle_vedata");
+                       if(!pdd->vedata)
+                               pdd->vedata = MEM_callocN(2 * (totpart + totchild) * 3 * sizeof(float), "particle_vedata");
+
                        need_v = 1;
                }
 
-               pdd.vd= pdd.vdata;
-               pdd.ved= pdd.vedata;
-               pdd.cd= pdd.cdata;
-               pdd.nd= pdd.ndata;
-
-               psys->lattice= psys_get_lattice(scene, ob, psys);
+               pdd->vd= pdd->vdata;
+               pdd->ved= pdd->vedata;
+               pdd->cd= pdd->cdata;
+               pdd->nd= pdd->ndata;
+               pdd->tot_vec_size= tot_vec_size;
        }
 
-       if(draw_as){
+       psys->lattice= psys_get_lattice(&sim);
+
+       if(pdd && draw_as!=PART_DRAW_PATH){
 /* 5. */
-               for(a=0,pa=pars; a<totpart+totchild; a++, pa++){
+               if((pdd->flag & PARTICLE_DRAW_DATA_UPDATED)
+                       && (pdd->vedata || part->draw & (PART_DRAW_SIZE|PART_DRAW_NUM|PART_DRAW_HEALTH))==0) {
+                       totpoint = pdd->totpoint; /* draw data is up to date */
+               }
+               else for(a=0,pa=pars; a<totpart+totchild; a++, pa++){
                        /* setup per particle individual stuff */
                        if(a<totpart){
                                if(totchild && (part->draw&PART_DRAW_PARENT)==0) continue;
@@ -3362,7 +3827,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                pa_dietime = pa->dietime;
                                pa_size=pa->size;
                                if(part->phystype==PART_PHYS_BOIDS)
-                                       pa_health = pa->boid->health;
+                                       pa_health = pa->boid->data.health;
                                else
                                        pa_health = -1.0;
 
@@ -3397,8 +3862,8 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                                }
 #endif // XXX old animation system
 
-                               r_tilt = 1.0f + pa->r_ave[0];
-                               r_length = 0.5f * (1.0f + pa->r_ave[1]);
+                               r_tilt = 2.0f*(PSYS_FRAND(a + 21) - 0.5f);
+                               r_length = PSYS_FRAND(a + 22);
                        }
                        else{
                                ChildParticle *cpa= &psys->child[a-totpart];
@@ -3429,160 +3894,145 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
                                pa_health = -1.0;
 
-                               r_tilt = 2.0f * cpa->rand[2];
-                               r_length = cpa->rand[1];
+                               r_tilt = 2.0f*(PSYS_FRAND(a + 21) - 0.5f);
+                               r_length = PSYS_FRAND(a + 22);
                        }
 
-                       if(draw_as!=PART_DRAW_PATH){
-                               drawn = 0;
-                               if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
-                                       float length = part->path_end * (1.0 - part->randlength * r_length);
-                                       int trail_count = part->trail_count * (1.0 - part->randlength * r_length);
-                                       float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length;
-                                       float dt = length / (trail_count ? (float)trail_count : 1.0f);
-                                       int i=0;
-
-                                       ct+=dt;
-                                       for(i=0; i < trail_count; i++, ct += dt) {
-                                               if(part->draw & PART_ABS_PATH_TIME) {
-                                                       if(ct < pa_birthtime || ct > pa_dietime)
-                                                               continue;
-                                               }
-                                               else if(ct < 0.0f || ct > 1.0f)
+                       drawn = 0;
+                       if(part->draw_as == PART_DRAW_REND && part->trail_count > 1) {
+                               float length = part->path_end * (1.0 - part->randlength * r_length);
+                               int trail_count = part->trail_count * (1.0 - part->randlength * r_length);
+                               float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length;
+                               float dt = length / (trail_count ? (float)trail_count : 1.0f);
+                               int i=0;
+
+                               ct+=dt;
+                               for(i=0; i < trail_count; i++, ct += dt) {
+                                       if(part->draw & PART_ABS_PATH_TIME) {
+                                               if(ct < pa_birthtime || ct > pa_dietime)
                                                        continue;
+                                       }
+                                       else if(ct < 0.0f || ct > 1.0f)
+                                               continue;
 
-                                               state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime));
-                                               psys_get_particle_on_path(scene,ob,psys,a,&state,need_v);
-                                               
-                                               if(psys->parent)
-                                                       Mat4MulVecfl(psys->parent->obmat, state.co);
-
-                                               /* create actiual particle data */
-                                               if(draw_as == PART_DRAW_BB) {
-                                                       bb.size = pa_size;
-                                                       bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
-                                                       bb.time = ct;
-                                               }
+                                       state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime));
+                                       psys_get_particle_on_path(&sim,a,&state,need_v);
+                                       
+                                       if(psys->parent)
+                                               Mat4MulVecfl(psys->parent->obmat, state.co);
+
+                                       /* create actiual particle data */
+                                       if(draw_as == PART_DRAW_BB) {
+                                               bb.size = pa_size;
+                                               bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
+                                               bb.time = ct;
+                                       }
 
-                                               draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, &pdd);
+                                       draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, psys->pdd);
 
-                                               totpoint++;
-                                               drawn = 1;
-                                       }
+                                       totpoint++;
+                                       drawn = 1;
                                }
-                               else
-                               {
-                                       state.time=cfra;
-                                       if(psys_get_particle_state(scene,ob,psys,a,&state,0)){
-                                               if(psys->parent)
-                                                       Mat4MulVecfl(psys->parent->obmat, state.co);
-
-                                               /* create actiual particle data */
-                                               if(draw_as == PART_DRAW_BB) {
-                                                       bb.size = pa_size;
-                                                       bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
-                                                       bb.time = pa_time;
-                                               }
+                       }
+                       else
+                       {
+                               state.time=cfra;
+                               if(psys_get_particle_state(&sim,a,&state,0)){
+                                       if(psys->parent)
+                                               Mat4MulVecfl(psys->parent->obmat, state.co);
+
+                                       /* create actiual particle data */
+                                       if(draw_as == PART_DRAW_BB) {
+                                               bb.size = pa_size;
+                                               bb.tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt);
+                                               bb.time = pa_time;
+                                       }
 
-                                               draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, &pdd);
+                                       draw_particle(&state, draw_as, part->draw, pixsize, imat, part->draw_line, &bb, pdd);
 
-                                               totpoint++;
-                                               drawn = 1;
-                                       }
+                                       totpoint++;
+                                       drawn = 1;
                                }
+                       }
 
-                               if(drawn) {
-                                       /* additional things to draw for each particle  */
-                                       /* (velocity, size and number)                                  */
-                                       if(pdd.vedata){
-                                               VECCOPY(pdd.ved,state.co);
-                                               pdd.ved+=3;
-                                               VECCOPY(vel,state.vel);
-                                               VecMulf(vel,timestep);
-                                               VECADD(pdd.ved,state.co,vel);
-                                               pdd.ved+=3;
-
-                                               totve++;
-                                       }
+                       if(drawn) {
+                               /* additional things to draw for each particle  */
+                               /* (velocity, size and number)                                  */
+                               if(pdd->vedata){
+                                       VECCOPY(pdd->ved,state.co);
+                                       pdd->ved+=3;
+                                       VECCOPY(vel,state.vel);
+                                       VecMulf(vel,timestep);
+                                       VECADD(pdd->ved,state.co,vel);
+                                       pdd->ved+=3;
+
+                                       totve++;
+                               }
 
-                                       if(part->draw & PART_DRAW_SIZE){
-                                               setlinestyle(3);
-                                               drawcircball(GL_LINE_LOOP, state.co, pa_size, imat);
-                                               setlinestyle(0);
-                                       }
+                               if(part->draw & PART_DRAW_SIZE){
+                                       setlinestyle(3);
+                                       drawcircball(GL_LINE_LOOP, state.co, pa_size, imat);
+                                       setlinestyle(0);
+                               }
 
-                                       if((part->draw&PART_DRAW_NUM || part->draw&PART_DRAW_HEALTH) && !(G.f & G_RENDER_SHADOW)){
-                                               strcpy(val, "");
-                                               
-                                               if(part->draw&PART_DRAW_NUM)
-                                                       sprintf(val, " %i", a);
+                               if((part->draw&PART_DRAW_NUM || part->draw&PART_DRAW_HEALTH) && !(G.f & G_RENDER_SHADOW)){
+                                       val[0]= '\0';
+                                       
+                                       if(part->draw&PART_DRAW_NUM)
+                                               sprintf(val, " %i", a);
 
-                                               if(part->draw&PART_DRAW_NUM && part->draw&PART_DRAW_HEALTH)
-                                                       sprintf(val, "%s:", val);
+                                       if(part->draw&PART_DRAW_NUM && part->draw&PART_DRAW_HEALTH)
+                                               sprintf(val, "%s:", val);
 
-                                               if(part->draw&PART_DRAW_HEALTH && a < totpart && part->phystype==PART_PHYS_BOIDS)
-                                                       sprintf(val, "%s %.2f", val, pa_health);
+                                       if(part->draw&PART_DRAW_HEALTH && a < totpart && part->phystype==PART_PHYS_BOIDS)
+                                               sprintf(val, "%s %.2f", val, pa_health);
 
-                                               /* in path drawing state.co is the end point */
-                                               view3d_particle_text_draw_add(state.co[0],  state.co[1],  state.co[2], val, 0);
-                                       }
+                                       /* in path drawing state.co is the end point */
+                                       view3d_cached_text_draw_add(state.co[0],  state.co[1],  state.co[2], val, 0);
                                }
                        }
                }
+       }
 /* 6. */
 
-               glGetIntegerv(GL_POLYGON_MODE, polygonmode);
-               glDisableClientState(GL_NORMAL_ARRAY);
-
-               if(draw_as==PART_DRAW_PATH){
-                       ParticleCacheKey **cache, *path;
-                       float *cd2=0,*cdata2=0;
-
-                       glEnableClientState(GL_VERTEX_ARRAY);
+       glGetIntegerv(GL_POLYGON_MODE, polygonmode);
+       glDisableClientState(GL_NORMAL_ARRAY);
 
-                       /* setup gl flags */
-                       if(ob_dt > OB_WIRE) {
-                               glEnableClientState(GL_NORMAL_ARRAY);
+       if(draw_as==PART_DRAW_PATH){
+               ParticleCacheKey **cache, *path;
+               float *cd2=0,*cdata2=0;
 
-                               if(part->draw&PART_DRAW_MAT_COL)
-                                       glEnableClientState(GL_COLOR_ARRAY);
+               glEnableClientState(GL_VERTEX_ARRAY);
 
-                               glEnable(GL_LIGHTING);
-                               glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
-                               glEnable(GL_COLOR_MATERIAL);
-                       }
-                       else {
-                               glDisableClientState(GL_NORMAL_ARRAY);
+               /* setup gl flags */
+               if(ob_dt > OB_WIRE) {
+                       glEnableClientState(GL_NORMAL_ARRAY);
 
-                               glDisable(GL_COLOR_MATERIAL);
-                               glDisable(GL_LIGHTING);
-                               UI_ThemeColor(TH_WIRE);
-                       }
+                       if(part->draw&PART_DRAW_MAT_COL)
+                               glEnableClientState(GL_COLOR_ARRAY);
 
-                       if(totchild && (part->draw&PART_DRAW_PARENT)==0)
-                               totpart=0;
+                       glEnable(GL_LIGHTING);
+                       glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+                       glEnable(GL_COLOR_MATERIAL);
+               }
+               else {
+                       glDisableClientState(GL_NORMAL_ARRAY);
 
-                       /* draw actual/parent particles */
-                       cache=psys->pathcache;
-                       for(a=0, pa=psys->particles; a<totpart; a++, pa++){
-                               path=cache[a];
-                               if(path->steps > 0) {
-                                       glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
+                       glDisable(GL_COLOR_MATERIAL);
+                       glDisable(GL_LIGHTING);
+                       UI_ThemeColor(TH_WIRE);
+               }
 
-                                       if(ob_dt > OB_WIRE) {
-                                               glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
-                                               if(part->draw&PART_DRAW_MAT_COL)
-                                                       glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
-                                       }
+               if(totchild && (part->draw&PART_DRAW_PARENT)==0)
+                       totpart=0;
+               else if(psys->pathcache==NULL)
+                       totpart=0;
 
-                                       glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
-                               }
-                       }
-                       
-                       /* draw child particles */
-                       cache=psys->childcache;
-                       for(a=0; a<totchild; a++){
-                               path=cache[a];
+               /* draw actual/parent particles */
+               cache=psys->pathcache;
+               for(a=0, pa=psys->particles; a<totpart; a++, pa++){
+                       path=cache[a];
+                       if(path->steps > 0) {
                                glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
 
                                if(ob_dt > OB_WIRE) {
@@ -3593,83 +4043,103 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
                                glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
                        }
+               }
+               
+               /* draw child particles */
+               cache=psys->childcache;
+               for(a=0; a<totchild; a++){
+                       path=cache[a];
+                       glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
 
-
-                       /* restore & clean up */
                        if(ob_dt > OB_WIRE) {
+                               glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
                                if(part->draw&PART_DRAW_MAT_COL)
-                                       glDisable(GL_COLOR_ARRAY);
-                               glDisable(GL_COLOR_MATERIAL);
+                                       glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
                        }
 
-                       if(cdata2)
-                               MEM_freeN(cdata2);
-                       cd2=cdata2=0;
+                       glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
+               }
 
-                       glLineWidth(1.0f);
+
+               /* restore & clean up */
+               if(ob_dt > OB_WIRE) {
+                       if(part->draw&PART_DRAW_MAT_COL)
+                               glDisable(GL_COLOR_ARRAY);
+                       glDisable(GL_COLOR_MATERIAL);
                }
-               else if(draw_as!=PART_DRAW_CIRC){
-                       glDisableClientState(GL_COLOR_ARRAY);
 
-                       /* setup created data arrays */
-                       if(pdd.vdata){
-                               glEnableClientState(GL_VERTEX_ARRAY);
-                               glVertexPointer(3, GL_FLOAT, 0, pdd.vdata);
-                       }
+               if(cdata2)
+                       MEM_freeN(cdata2);
+               cd2=cdata2=0;
+
+               glLineWidth(1.0f);
+       }
+       else if(pdd && ELEM(draw_as, 0, PART_DRAW_CIRC)==0){
+               glDisableClientState(GL_COLOR_ARRAY);
+
+               /* enable point data array */
+               if(pdd->vdata){
+                       glEnableClientState(GL_VERTEX_ARRAY);
+                       glVertexPointer(3, GL_FLOAT, 0, pdd->vdata);
+               }
+               else
+                       glDisableClientState(GL_VERTEX_ARRAY);
+
+               if(select) {
+                       UI_ThemeColor(TH_ACTIVE);
+                       
+                       if(part->draw_size)
+                               glPointSize(part->draw_size + 2);
                        else
-                               glDisableClientState(GL_VERTEX_ARRAY);
+                               glPointSize(4.0);
 
-                       /* billboards are drawn this way */
-                       if(pdd.ndata && ob_dt>OB_WIRE){
-                               glEnableClientState(GL_NORMAL_ARRAY);
-                               glNormalPointer(GL_FLOAT, 0, pdd.ndata);
-                               glEnable(GL_LIGHTING);
-                       }
-                       else{
-                               glDisableClientState(GL_NORMAL_ARRAY);
-                               glDisable(GL_LIGHTING);
-                       }
+                       glLineWidth(3.0);
 
-                       if(pdd.cdata){
-                               glEnableClientState(GL_COLOR_ARRAY);
-                               glColorPointer(3, GL_FLOAT, 0, pdd.cdata);
-                       }
+                       draw_particle_arrays(draw_as, totpoint, ob_dt, 1);
+               }
 
-                       /* draw created data arrays */
-                       switch(draw_as){
-                               case PART_DRAW_AXIS:
-                               case PART_DRAW_CROSS:
-                                       glDrawArrays(GL_LINES, 0, 6*totpoint);
-                                       break;
-                               case PART_DRAW_LINE:
-                                       glDrawArrays(GL_LINES, 0, 2*totpoint);
-                                       break;
-                               case PART_DRAW_BB:
-                                       if(ob_dt<=OB_WIRE)
-                                               glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
-
-                                       glDrawArrays(GL_QUADS, 0, 4*totpoint);
-                                       break;
-                               default:
-                                       glDrawArrays(GL_POINTS, 0, totpoint);
-                                       break;
-                       }
+               /* restore from select */
+               glColor3f(ma_r,ma_g,ma_b);
+               glPointSize(part->draw_size ? part->draw_size : 2.0);
+               glLineWidth(1.0);
+
+               /* enable other data arrays */
+
+               /* billboards are drawn this way */
+               if(pdd->ndata && ob_dt>OB_WIRE){
+                       glEnableClientState(GL_NORMAL_ARRAY);
+                       glNormalPointer(GL_FLOAT, 0, pdd->ndata);
+                       glEnable(GL_LIGHTING);
+               }
+               else{
+                       glDisableClientState(GL_NORMAL_ARRAY);
+                       glDisable(GL_LIGHTING);
                }
 
-               if(pdd.vedata){
-                       glDisableClientState(GL_COLOR_ARRAY);
-                       cpack(0xC0C0C0);
-                       
-                       glEnableClientState(GL_VERTEX_ARRAY);
-                       glVertexPointer(3, GL_FLOAT, 0, pdd.vedata);
-                       
-                       glDrawArrays(GL_LINES, 0, 2*totve);
+               if(pdd->cdata){
+                       glEnableClientState(GL_COLOR_ARRAY);
+                       glColorPointer(3, GL_FLOAT, 0, pdd->cdata);
                }
 
-               glPolygonMode(GL_FRONT, polygonmode[0]);
-               glPolygonMode(GL_BACK, polygonmode[1]);
+               draw_particle_arrays(draw_as, totpoint, ob_dt, 0);
+
+               pdd->flag |= PARTICLE_DRAW_DATA_UPDATED;
+               pdd->totpoint = totpoint;
        }
 
+       if(pdd && pdd->vedata){
+               glDisableClientState(GL_COLOR_ARRAY);
+               cpack(0xC0C0C0);
+               
+               glEnableClientState(GL_VERTEX_ARRAY);
+               glVertexPointer(3, GL_FLOAT, 0, pdd->vedata);
+               
+               glDrawArrays(GL_LINES, 0, 2*totve);
+       }
+
+       glPolygonMode(GL_FRONT, polygonmode[0]);
+       glPolygonMode(GL_BACK, polygonmode[1]);
+
 /* 7. */
        
        glDisable(GL_LIGHTING);
@@ -3678,17 +4148,15 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
 
        if(states)
                MEM_freeN(states);
-       if(pdd.vdata)
-               MEM_freeN(pdd.vdata);
-       if(pdd.vedata)
-               MEM_freeN(pdd.vedata);
-       if(pdd.cdata)
-               MEM_freeN(pdd.cdata);
-       if(pdd.ndata)
-               MEM_freeN(pdd.ndata);
 
        psys->flag &= ~PSYS_DRAWING;
 
+       /* draw data can't be saved for billboards as they must update to target changes */
+       if(draw_as == PART_DRAW_BB) {
+               psys_free_pdd(psys);
+               pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED;
+       }
+
        if(psys->lattice){
                end_latt_deform(psys->lattice);
                psys->lattice= NULL;
@@ -3698,33 +4166,31 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
                wmLoadMatrix(rv3d->viewmat);
 }
 
-static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, ParticleSystem *psys, int dt)
+static void draw_ptcache_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, PTCacheEdit *edit, int dt)
 {
-       ParticleEdit *edit = psys->edit;
-       ParticleData *pa;
-       ParticleCacheKey **path;
-       ParticleEditKey *key;
+       ParticleCacheKey **cache, *path, *pkey;
+       PTCacheEditPoint *point;
+       PTCacheEditKey *key;
        ParticleEditSettings *pset = PE_settings(scene);
-       int i, k, totpart = psys->totpart, totchild=0, timed = pset->draw_timed;
+       int i, k, totpoint = edit->totpoint, timed = pset->flag & PE_FADE_TIME ? pset->fade_frames : 0;
+       int steps=1;
        char nosel[4], sel[4];
        float sel_col[3];
        float nosel_col[3];
-       char val[32];
+       float *pathcol = NULL, *pcol;
+
+
+       if(edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED)
+               PE_update_object(scene, ob, 0);
 
        /* create path and child path cache if it doesn't exist already */
-       if(psys->pathcache==0){
-               PE_hide_keys_time(scene, psys,CFRA);
-               psys_cache_paths(scene, ob, psys, CFRA,0);
-       }
-       if(psys->pathcache==0)
+       if(edit->pathcache==0)
+               psys_cache_edit_paths(scene, ob, edit, CFRA);
+
+       if(edit->pathcache==0)
                return;
 
-       if(pset->flag & PE_SHOW_CHILD && psys->part->draw_as == PART_DRAW_PATH) {
-               if(psys->childcache==0)
-                       psys_cache_child_paths(scene, ob, psys, CFRA, 0);
-       }
-       else if(!(pset->flag & PE_SHOW_CHILD) && psys->childcache)
-               free_child_path_cache(psys);
+       PE_hide_keys_time(scene, edit, CFRA);
 
        /* opengl setup */
        if((v3d->flag & V3D_ZBUF_SELECT)==0)
@@ -3740,129 +4206,115 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob
        nosel_col[1]=(float)nosel[1]/255.0f;
        nosel_col[2]=(float)nosel[2]/255.0f;
 
-       if(psys->childcache)
-               totchild = psys->totchildcache;
-
        /* draw paths */
-       if(timed)
+       if(timed) {
                glEnable(GL_BLEND);
+               steps = (*edit->pathcache)->steps + 1;
+               pathcol = MEM_callocN(steps*4*sizeof(float), "particle path color data");
+       }
 
        glEnableClientState(GL_VERTEX_ARRAY);
+       glDisableClientState(GL_NORMAL_ARRAY);
+       glEnableClientState(GL_COLOR_ARRAY);
 
-       if(dt > OB_WIRE) {
-               /* solid shaded with lighting */
-               glEnableClientState(GL_NORMAL_ARRAY);
-               glEnableClientState(GL_COLOR_ARRAY);
-
-               glEnable(GL_COLOR_MATERIAL);
-               glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
-       }
-       else {
-               /* flat wire color */
-               glDisableClientState(GL_NORMAL_ARRAY);
-               glDisable(GL_LIGHTING);
-               UI_ThemeColor(TH_WIRE);
-       }
+       glEnable(GL_COLOR_MATERIAL);
+       glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
 
-       /* only draw child paths with lighting */
-       if(dt > OB_WIRE)
-               glEnable(GL_LIGHTING);
+       cache=edit->pathcache;
+       for(i=0; i<totpoint; i++){
+               path = cache[i];
+               glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
 
-       if(psys->part->draw_as == PART_DRAW_PATH) {
-               for(i=0, path=psys->childcache; i<totchild; i++,path++){
-                       glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->co);
-                       if(dt > OB_WIRE) {
-                               glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), (*path)->vel);
-                               glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->col);
+               if(timed) {
+                       for(k=0, pcol=pathcol, pkey=path; k<steps; k++, pkey++, pcol+=4){
+                               VECCOPY(pcol, pkey->col);
+                               pcol[3] = 1.0f - fabs((float)CFRA - pkey->time)/(float)pset->fade_frames;
                        }
 
-                       glDrawArrays(GL_LINE_STRIP, 0, (int)(*path)->steps + 1);
+                       glColorPointer(4, GL_FLOAT, 4*sizeof(float), pathcol);
                }
-       }
-
-       if(dt > OB_WIRE)
-               glDisable(GL_LIGHTING);
+               else
+                       glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
 
-       if(pset->brushtype == PE_BRUSH_WEIGHT) {
-               glLineWidth(2.0f);
-               glEnableClientState(GL_COLOR_ARRAY);
-               glDisable(GL_LIGHTING);
+               glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
        }
 
-       /* draw parents last without lighting */
-       for(i=0, pa=psys->particles, path = psys->pathcache; i<totpart; i++, pa++, path++){
-               glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->co);
-               if(dt > OB_WIRE)
-                       glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), (*path)->vel);
-               if(dt > OB_WIRE || pset->brushtype == PE_BRUSH_WEIGHT)
-                       glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), (*path)->col);
+       if(pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; }
 
-               glDrawArrays(GL_LINE_STRIP, 0, (int)(*path)->steps + 1);
-       }
 
        /* draw edit vertices */
        if(pset->selectmode!=SCE_SELECT_PATH){
-               glDisableClientState(GL_NORMAL_ARRAY);
-               glEnableClientState(GL_COLOR_ARRAY);
-               glDisable(GL_LIGHTING);
                glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
 
                if(pset->selectmode==SCE_SELECT_POINT){
+                       float *pd=0,*pdata=0;
                        float *cd=0,*cdata=0;
-                       cd=cdata=MEM_callocN(edit->totkeys*(timed?4:3)*sizeof(float), "particle edit color data");
+                       int totkeys = 0;
+
+                       for (i=0, point=edit->points; i<totpoint; i++, point++)
+                               if(!(point->flag & PEP_HIDE))
+                                       totkeys += point->totkey;
+
+                       if(edit->points && !(edit->points->keys->flag & PEK_USE_WCO))
+                               pd=pdata=MEM_callocN(totkeys*3*sizeof(float), "particle edit point data");
+                       cd=cdata=MEM_callocN(totkeys*(timed?4:3)*sizeof(float), "particle edit color data");
+
+                       for(i=0, point=edit->points; i<totpoint; i++, point++){
+                               if(point->flag & PEP_HIDE)
+                                       continue;
+
+                               for(k=0, key=point->keys; k<point->totkey; k++, key++){
+                                       if(pd) {
+                                               VECCOPY(pd, key->co);
+                                               pd += 3;
+                                       }
 
-                       for(i=0, pa=psys->particles; i<totpart; i++, pa++){
-                               for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++){
                                        if(key->flag&PEK_SELECT){
                                                VECCOPY(cd,sel_col);
                                        }
                                        else{
                                                VECCOPY(cd,nosel_col);
                                        }
+
                                        if(timed)
-                                               *(cd+3) = (key->flag&PEK_HIDE)?0.0f:1.0f;
+                                               *(cd+3) = 1.0f - fabs((float)CFRA - *key->time)/(float)pset->fade_frames;
+
                                        cd += (timed?4:3);
                                }
                        }
                        cd=cdata;
-                       for(i=0, pa=psys->particles; i<totpart; i++, pa++){
-                               if((pa->flag & PARS_HIDE)==0){
-                                       glVertexPointer(3, GL_FLOAT, sizeof(ParticleEditKey), edit->keys[i]->world_co);
-                                       glColorPointer((timed?4:3), GL_FLOAT, (timed?4:3)*sizeof(float), cd);
-                                       glDrawArrays(GL_POINTS, 0, pa->totkey);
-                               }
-                               cd += (timed?4:3) * pa->totkey;
+                       pd=pdata;
+                       for(i=0, point=edit->points; i<totpoint; i++, point++){
+                               if(point->flag & PEP_HIDE)
+                                       continue;
 
-                               if((pset->flag&PE_SHOW_TIME) && (pa->flag&PARS_HIDE)==0 && !(G.f & G_RENDER_SHADOW)){
-                                       for(k=0, key=edit->keys[i]+k; k<pa->totkey; k++, key++){
-                                               if(key->flag & PEK_HIDE) continue;
+                               if(point->keys->flag & PEK_USE_WCO)
+                                       glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co);
+                               else
+                                       glVertexPointer(3, GL_FLOAT, 3*sizeof(float), pd);
 
-                                               sprintf(val," %.1f",*key->time);
-                                               view3d_particle_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0);
-                                       }
-                               }
+                               glColorPointer((timed?4:3), GL_FLOAT, (timed?4:3)*sizeof(float), cd);
+
+                               glDrawArrays(GL_POINTS, 0, point->totkey);
+
+                               pd += pd ? 3 * point->totkey : 0;
+                               cd += (timed?4:3) * point->totkey;
                        }
-                       if(cdata)
-                               MEM_freeN(cdata);
-                       cd=cdata=0;
+                       if(pdata) { MEM_freeN(pdata); pd=pdata=0; }
+                       if(cdata) { MEM_freeN(cdata); cd=cdata=0; }
                }
                else if(pset->selectmode == SCE_SELECT_END){
-                       for(i=0, pa=psys->particles; i<totpart; i++, pa++){
-                               if((pa->flag & PARS_HIDE)==0){
-                                       key = edit->keys[i] + pa->totkey - 1;
+                       for(i=0, point=edit->points; i<totpoint; i++, point++){
+                               if((point->flag & PEP_HIDE)==0){
+                                       key = point->keys + point->totkey - 1;
                                        if(key->flag & PEK_SELECT)
                                                glColor3fv(sel_col);
                                        else
                                                glColor3fv(nosel_col);
                                        /* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/
                                        glBegin(GL_POINTS);
-                                       glVertex3fv(key->world_co);
+                                       glVertex3fv(key->flag & PEK_USE_WCO ? key->world_co : key->co);
                                        glEnd();
-
-                                       if((pset->flag & PE_SHOW_TIME) && !(G.f & G_RENDER_SHADOW)){
-                                               sprintf(val," %.1f",*key->time);
-                                               view3d_particle_text_draw_add(key->world_co[0], key->world_co[1], key->world_co[2], val, 0);
-                                       }
                                }
                        }
                }
@@ -3882,18 +4334,18 @@ static void draw_particle_edit(Scene *scene, View3D *v3d, RegionView3D *rv3d, Ob
 unsigned int nurbcol[8]= {
        0, 0x9090, 0x409030, 0x603080, 0, 0x40fff0, 0x40c033, 0xA090F0 };
 
-static void tekenhandlesN(Nurb *nu, short sel)
+static void tekenhandlesN(Nurb *nu, short sel, short hide_handles)
 {
        BezTriple *bezt;
        float *fp;
        unsigned int *col;
        int a;
        
-       if(nu->hide || (G.f & G_HIDDENHANDLES)) return;
+       if(nu->hide || hide_handles) return;
        
        glBegin(GL_LINES); 
        
-       if( (nu->type & 7)==CU_BEZIER) {
+       if(nu->type == CU_BEZIER) {
                if(sel) col= nurbcol+4;
                else col= nurbcol;
 
@@ -3933,7 +4385,7 @@ static void tekenhandlesN(Nurb *nu, short sel)
        glEnd();
 }
 
-static void tekenvertsN(Nurb *nu, short sel)
+static void tekenvertsN(Nurb *nu, short sel, short hide_handles)
 {
        BezTriple *bezt;
        BPoint *bp;
@@ -3950,13 +4402,13 @@ static void tekenvertsN(Nurb *nu, short sel)
        
        bglBegin(GL_POINTS);
        
-       if((nu->type & 7)==CU_BEZIER) {
+       if(nu->type == CU_BEZIER) {
 
                bezt= nu->bezt;
                a= nu->pntsu;
                while(a--) {
                        if(bezt->hide==0) {
-                               if (G.f & G_HIDDENHANDLES) {
+                               if (hide_handles) {
                                        if((bezt->f2 & SELECT)==sel) bglVertex3fv(bezt->vec[1]);
                                } else {
                                        if((bezt->f1 & SELECT)==sel) bglVertex3fv(bezt->vec[0]);
@@ -3991,7 +4443,7 @@ static void draw_editnurb(Object *ob, Nurb *nurb, int sel)
        nu= nurb;
        while(nu) {
                if(nu->hide==0) {
-                       switch(nu->type & 7) {
+                       switch(nu->type) {
                        case CU_POLY:
                                cpack(nurbcol[3]);
                                bp= nu->bp;
@@ -4088,6 +4540,7 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
        Curve *cu = ob->data;
        Nurb *nu;
        BevList *bl;
+       short hide_handles = (cu->drawflag & CU_HIDE_HANDLES);
 
 // XXX retopo_matrix_update(v3d);
 
@@ -4099,23 +4552,25 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
        
        /* first non-selected handles */
        for(nu=nurb; nu; nu=nu->next) {
-               if((nu->type & 7)==CU_BEZIER) {
-                       tekenhandlesN(nu, 0);
+               if(nu->type == CU_BEZIER) {
+                       tekenhandlesN(nu, 0, hide_handles);
                }
        }
        draw_editnurb(ob, nurb, 0);
        draw_editnurb(ob, nurb, 1);
        /* selected handles */
        for(nu=nurb; nu; nu=nu->next) {
-               if((nu->type & 7)==1) tekenhandlesN(nu, 1);
-               tekenvertsN(nu, 0);
+               if(nu->type == CU_BEZIER && (cu->drawflag & CU_HIDE_HANDLES)==0)
+                       tekenhandlesN(nu, 1, hide_handles);
+               tekenvertsN(nu, 0, hide_handles);
        }
        
        if(v3d->zbuf) glEnable(GL_DEPTH_TEST);
 
        /*      direction vectors for 3d curve paths
                when at its lowest, dont render normals */
-       if(cu->flag & CU_3D && ts->normalsize > 0.0015) {
+       if(cu->flag & CU_3D && ts->normalsize > 0.0015 && (cu->drawflag & CU_HIDE_NORMALS)==0) {
+
                UI_ThemeColor(TH_WIRE);
                for (bl=cu->bev.first,nu=nurb; nu && bl; bl=bl->next,nu=nu->next) {
                        BevPoint *bevp= (BevPoint *)(bl+1);             
@@ -4124,21 +4579,21 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
                        
                        while (nr-->0) { /* accounts for empty bevel lists */
                                float fac= bevp->radius * ts->normalsize;
-                               float ox,oy,oz; // Offset perpendicular to the curve
-                               float dx,dy,dz; // Delta along the curve
+                               float vec_a[3] = { fac,0, 0}; // Offset perpendicular to the curve
+                               float vec_b[3] = {-fac,0, 0}; // Delta along the curve
+
+                               QuatMulVecf(bevp->quat, vec_a);
+                               QuatMulVecf(bevp->quat, vec_b);
+                               VecAddf(vec_a, vec_a, bevp->vec);
+                               VecAddf(vec_b, vec_b, bevp->vec);
                                
-                               ox = fac*bevp->mat[0][0];
-                               oy = fac*bevp->mat[0][1];
-                               oz = fac*bevp->mat[0][2];
-                       
-                               dx = fac*bevp->mat[2][0];
-                               dy = fac*bevp->mat[2][1];
-                               dz = fac*bevp->mat[2][2];
+                               VECSUBFAC(vec_a, vec_a, bevp->dir, fac);
+                               VECSUBFAC(vec_b, vec_b, bevp->dir, fac);
 
                                glBegin(GL_LINE_STRIP);
-                               glVertex3f(bevp->x - ox - dx, bevp->y - oy - dy, bevp->z - oz - dz);
-                               glVertex3f(bevp->x, bevp->y, bevp->z);
-                               glVertex3f(bevp->x + ox - dx, bevp->y + oy - dy, bevp->z + oz - dz);
+                               glVertex3fv(vec_a);
+                               glVertex3fv(bevp->vec);
+                               glVertex3fv(vec_b);
                                glEnd();
                                
                                bevp += skip+1;
@@ -4150,7 +4605,7 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
        if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
        
        for(nu=nurb; nu; nu=nu->next) {
-               tekenvertsN(nu, 1);
+               tekenvertsN(nu, 1, hide_handles);
        }
        
        if(v3d->zbuf) glEnable(GL_DEPTH_TEST); 
@@ -4541,13 +4996,13 @@ static void draw_forcefield(Scene *scene, Object *ob)
 
                        /*path end*/
                        setlinestyle(3);
-                       where_on_path(ob, 1.0f, guidevec1, guidevec2);
+                       where_on_path(ob, 1.0f, guidevec1, guidevec2, NULL, NULL);
                        UI_ThemeColorBlend(curcol, TH_BACK, 0.5);
                        drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
 
                        /*path beginning*/
                        setlinestyle(0);
-                       where_on_path(ob, 0.0f, guidevec1, guidevec2);
+                       where_on_path(ob, 0.0f, guidevec1, guidevec2, NULL, NULL);
                        UI_ThemeColorBlend(curcol, TH_BACK, 0.5);
                        drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
                        
@@ -4757,8 +5212,9 @@ static void drawtexspace(Object *ob)
 }
 
 /* draws wire outline */
-static void drawSolidSelect(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base) 
+static void drawSolidSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base) 
 {
+       RegionView3D *rv3d= ar->regiondata;
        Object *ob= base->object;
        
        glLineWidth(2.0);
@@ -4776,8 +5232,8 @@ static void drawSolidSelect(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
                        drawDispListwire(&ob->disp);
        }
        else if(ob->type==OB_ARMATURE) {
-               if(!(ob->flag & OB_POSEMODE))
-                       draw_armature(scene, v3d, rv3d, base, OB_WIRE, 0);
+               if(!(ob->mode & OB_MODE_POSE))
+                       draw_armature(scene, v3d, ar, base, OB_WIRE, 0);
        }
 
        glLineWidth(1.0);
@@ -4887,11 +5343,11 @@ void drawRBpivot(bRigidBodyJointConstraint *data)
                glVertex3fv(v);                 
                glEnd();
                if (axis==0)
-                       view3d_object_text_draw_add(v[0], v[1], v[2], "px", 0);
+                       view3d_cached_text_draw_add(v[0], v[1], v[2], "px", 0);
                else if (axis==1)
-                       view3d_object_text_draw_add(v[0], v[1], v[2], "py", 0);
+                       view3d_cached_text_draw_add(v[0], v[1], v[2], "py", 0);
                else
-                       view3d_object_text_draw_add(v[0], v[1], v[2], "pz", 0);
+                       view3d_cached_text_draw_add(v[0], v[1], v[2], "pz", 0);
        }
        glLineWidth (1.0f);
        setlinestyle(0);
@@ -4925,7 +5381,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
        /* xray delay? */
        if((flag & DRAW_PICKING)==0 && (base->flag & OB_FROMDUPLI)==0) {
                /* don't do xray in particle mode, need the z-buffer */
-               if(!(G.f & G_PARTICLEEDIT)) {
+               if(!(ob->mode & OB_MODE_PARTICLE_EDIT)) {
                        /* xray and transp are set when it is drawing the 2nd/3rd pass */
                        if(!v3d->xray && !v3d->transp && (ob->dtx & OB_DRAWXRAY) && !(ob->dtx & OB_DRAWTRANSP)) {
                                add_view3d_after(v3d, base, V3D_XRAY, flag);
@@ -4934,6 +5390,9 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
                }
        }
 
+       /* no return after this point, otherwise leaks */
+       view3d_cached_text_draw_begin();
+
        /* draw keys? */
 #if 0 // XXX old animation system
        if(base==(scene->basact) || (base->flag & (SELECT+BA_WAS_SEL))) {
@@ -5012,12 +5471,13 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
 
        /* patch? children objects with a timeoffs change the parents. How to solve! */
        /* if( ((int)ob->ctime) != F_(scene->r.cfra)) where_is_object(scene, ob); */
+       
+       /* draw paths... */
+       // TODO...
 
-       /* multiply view with object matrix */
-       wmMultMatrix(ob->obmat);
-       /* local viewmat and persmat, to calculate projections */
-       wmGetMatrix(rv3d->viewmatob);
-       wmGetSingleMatrix(rv3d->persmatob);
+       /* multiply view with object matrix.
+        * local viewmat and persmat, to calculate projections */
+       ED_view3d_init_mats_rv3d(ob, rv3d);
 
        /* which wire color */
        if((flag & DRAW_CONSTCOLOR) == 0) {
@@ -5071,10 +5531,10 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
        dtx= 0;
 
        /* faceselect exception: also draw solid when dt==wire, except in editmode */
-       if(ob==OBACT && (G.f & (G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT))) {
+       if(ob==OBACT && (ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))) {
                if(ob->type==OB_MESH) {
 
-                       if(ob==scene->obedit);
+                       if(ob->mode & OB_MODE_EDIT);
                        else {
                                if(dt<OB_SOLID)
                                        zbufoff= 1;
@@ -5096,7 +5556,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
        if(dt>=OB_BOUNDBOX ) {
 
                dtx= ob->dtx;
-               if(scene->obedit==ob) {
+               if(ob->mode & OB_MODE_EDIT) {
                        // the only 2 extra drawtypes alowed in editmode
                        dtx= dtx & (OB_DRAWWIRE|OB_TEXSPACE);
                }
@@ -5112,20 +5572,18 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
        
        /* draw outline for selected solid objects, mesh does itself */
        if((v3d->flag & V3D_SELECT_OUTLINE) && ob->type!=OB_MESH) {
-               if(dt>OB_WIRE && dt<OB_TEXTURE && ob!=scene->obedit && (flag && DRAW_SCENESET)==0) {
+               if(dt>OB_WIRE && dt<OB_TEXTURE && (ob->mode & OB_MODE_EDIT)==0 && (flag & DRAW_SCENESET)==0) {
                        if (!(ob->dtx&OB_DRAWWIRE) && (ob->flag&SELECT) && !(flag&DRAW_PICKING)) {
                                
-                               drawSolidSelect(scene, v3d, rv3d, base);
+                               drawSolidSelect(scene, v3d, ar, base);
                        }
                }
        }
 
        switch( ob->type) {
                case OB_MESH:
-                       if (!(base->flag&OB_RADIO)) {
-                               empty_object= draw_mesh_object(scene, v3d, rv3d, base, dt, flag);
-                               if(flag!=DRAW_CONSTCOLOR) dtx &= ~OB_DRAWWIRE; // mesh draws wire itself
-                       }
+                       empty_object= draw_mesh_object(scene, ar, v3d, rv3d, base, dt, flag);
+                       if(flag!=DRAW_CONSTCOLOR) dtx &= ~OB_DRAWWIRE; // mesh draws wire itself
 
                        break;
                case OB_FONT:
@@ -5261,7 +5719,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
                        break;
                case OB_ARMATURE:
                        if(dt>OB_WIRE) GPU_enable_material(0, NULL); // we use default material
-                       empty_object= draw_armature(scene, v3d, rv3d, base, dt, flag);
+                       empty_object= draw_armature(scene, v3d, ar, base, dt, flag);
                        if(dt>OB_WIRE) GPU_disable_material();
                        break;
                default:
@@ -5269,6 +5727,22 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
        }
        if(ob->pd && ob->pd->forcefield) draw_forcefield(scene, ob);
 
+       /* particle mode has to be drawn first so that possible child particles get cached in edit mode */
+       if(             (warning_recursive==0) &&
+                       (flag & DRAW_PICKING)==0 &&
+                       (!scene->obedit)        
+         ) {
+
+               if(ob->mode & OB_MODE_PARTICLE_EDIT && ob==OBACT) {
+                       PTCacheEdit *edit = PE_get_current(scene, ob);
+                       if(edit) {
+                               wmLoadMatrix(rv3d->viewmat);
+                               draw_ptcache_edit(scene, v3d, rv3d, ob, edit, dt);
+                               wmMultMatrix(ob->obmat);
+                       }
+               }
+       }
+
        /* code for new particle system */
        if(             (warning_recursive==0) &&
                        (ob->particlesystem.first) &&
@@ -5281,15 +5755,12 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
 
                wmLoadMatrix(rv3d->viewmat);
                
+               view3d_cached_text_draw_begin();
+
                for(psys=ob->particlesystem.first; psys; psys=psys->next)
                        draw_new_particle_system(scene, v3d, rv3d, base, psys, dt);
                
-               if(G.f & G_PARTICLEEDIT && ob==OBACT) {
-                       psys= PE_get_current(scene, ob);
-                       if(psys && !scene->obedit && psys_in_edit_mode(scene, psys))
-                               draw_particle_edit(scene, v3d, rv3d, ob, psys, dt);
-               }
-               view3d_particle_text_draw(v3d, ar);
+               view3d_cached_text_draw_end(v3d, ar, 0, NULL);
 
                wmMultMatrix(ob->obmat);
                
@@ -5298,15 +5769,14 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
        }
 
        /* draw code for smoke */
-       if(md = modifiers_findByType(ob, eModifierType_Smoke))
+       if((md = modifiers_findByType(ob, eModifierType_Smoke)))
        {
                SmokeModifierData *smd = (SmokeModifierData *)md;
 
                // draw collision objects
                if((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)
                {
-                       SmokeCollSettings *scs = smd->coll;
-                       /*
+                       /*SmokeCollSettings *scs = smd->coll;
                        if(scs->points)
                        {
                                size_t i;
@@ -5341,314 +5811,65 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
                // only draw domains
                if(smd->domain && smd->domain->fluid)
                {
-                       int x, y, z, i;
-                       float viewnormal[3];
-                       int mainaxis[3] = {0,0,0};
-                       float align = 0, signed_align = 0;
-                       int max_textures = 0, counter_textures = 0;
-                       float *buffer = NULL;
-                       int res[3];
-                       float bigfactor = 1.0;
-                       int big = (smd->domain->flags & MOD_SMOKE_HIGHRES) && (smd->domain->viewsettings & MOD_SMOKE_VIEW_USEBIG);
-                       int new = 0;
-                       int have_lamp = 0;
-                       
-                       // GUI sent redraw event
-                       if(smd->domain->flags & MOD_SMOKE_VIEW_REDRAWNICE)
-                       {
-                               new = 1;
-                               smd->domain->flags &= ~MOD_SMOKE_VIEW_REDRAWNICE;
-                       }
-                       
-                       if(!big)
-                       {
-                               res[0] = smd->domain->res[0];
-                               res[1] = smd->domain->res[1];
-                               res[2] = smd->domain->res[2];
-                       }
-                       else
+                       if(!smd->domain->wt || !(smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG))
                        {
-                               smoke_turbulence_get_res(smd->domain->wt, res);
-                               bigfactor = 1.0 / (smd->domain->amplify + 1);
-                       }
+// #if 0
+                               smd->domain->tex = NULL;
+                               GPU_create_smoke(smd, 0);
+                               draw_volume(scene, ar, v3d, base, smd->domain->tex, smd->domain->p0, smd->domain->p1, smd->domain->res, smd->domain->dx, smd->domain->tex_shadow);
+                               GPU_free_smoke(smd);
+// #endif
+#if 0
+                               int x, y, z;
+                               float *density = smoke_get_density(smd->domain->fluid);
 
-                       wmLoadMatrix(rv3d->viewmat);
+                               wmLoadMatrix(rv3d->viewmat);
+                               // wmMultMatrix(ob->obmat);     
 
-                       if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); /* for visibility, also while wpaint */
-                       glDepthMask(GL_FALSE);
-                       glEnable(GL_BLEND);
+                               if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); 
+                               glDepthMask(GL_FALSE);
+                               glEnable(GL_BLEND);
+                               
 
-                       // get view vector
-                       VECCOPY(viewnormal, rv3d->viewinv[2]);
-                       Normalize(viewnormal);
-                       for(i = 0; i < 3; i++)
-                       {
-                               if(ABS(viewnormal[i]) > align)
-                               {
-                                       mainaxis[0] = i;
-                                       align = ABS(viewnormal[i]);
-                                       signed_align = viewnormal[i];
-                               }
-                       }
-                       mainaxis[1] = (mainaxis[0] + 1) % 3;
-                       mainaxis[2] = (mainaxis[0] + 2) % 3;
-                       
-                       if(!smd->domain->bind)
-                       {
-                               smd->domain->bind = MEM_callocN(sizeof(GLuint)*256, "Smoke_bind");
-                               if(big)
-                                       smd->domain->viewsettings |= MOD_SMOKE_VIEW_CHANGETOBIG;
-                               new = 3;
-                       }
-                       
-                       // check if view axis / mode has been changed
-                       if(smd->domain->viewsettings)
-                       {
-                               if(big)
-                               {
-                                       if(!(smd->domain->viewsettings & MOD_SMOKE_VIEW_BIG))
-                                               new = 2;
-                                       else if(!(smd->domain->viewsettings & MOD_SMOKE_VIEW_CHANGETOBIG))
-                                               new = 1;
-                                       
-                                       smd->domain->viewsettings |= MOD_SMOKE_VIEW_CHANGETOBIG;
-                               }
-                               else
-                               {
-                                       if(!(smd->domain->viewsettings & MOD_SMOKE_VIEW_SMALL))
-                                               new = 2;
-                                       else if(smd->domain->viewsettings & MOD_SMOKE_VIEW_CHANGETOBIG)
-                                               new = 1;
-                                       
-                                       smd->domain->viewsettings &= ~MOD_SMOKE_VIEW_CHANGETOBIG;
-                               }
-       
-                               if(!new)
-                               {
-                                       if((mainaxis[0] == 0) && !(smd->domain->viewsettings & MOD_SMOKE_VIEW_X))
-                                               new = 1;
-                                       else if((mainaxis[0] == 1) && !(smd->domain->viewsettings & MOD_SMOKE_VIEW_Y))
-                                               new = 1;
-                                       else if((mainaxis[0] == 2) && !(smd->domain->viewsettings & MOD_SMOKE_VIEW_Z))
-                                               new = 1;
-                                       
-                                       // printf("check axis\n");
-                               }
-                       }
-                       else
-                               new = 3;
-                       
-                       if(new > 1)
-                       {
-                               float light[3] = {0.0,0.0,0.0}; // TODO: take real LAMP coordinates - dg
-                               Base *base_tmp = NULL;
+                               // glPointSize(3.0);
+                               bglBegin(GL_POINTS);
 
-                               for(base_tmp = scene->base.first; base_tmp; base_tmp= base_tmp->next) 
+                               for(x = 0; x < smd->domain->res[0]; x++)
+                                       for(y = 0; y < smd->domain->res[1]; y++)
+                                               for(z = 0; z < smd->domain->res[2]; z++)
                                {
-                                       if(base_tmp->object->type == OB_LAMP) 
-                                       {
-                                               Lamp *la = (Lamp *)base_tmp->object->data;
-                                               
-                                               if(la->type == LA_LOCAL)
-                                               {
-                                                       VECCOPY(light, base_tmp->object->obmat[3]);
-                                                       have_lamp = 1;
-                                                       break;
-                                               }
-                                       }
-                               }
+                                       float tmp[3];
+                                       int index = smoke_get_index(x, smd->domain->res[0], y, smd->domain->res[1], z);
 
-                               if(!big && !(smd->domain->viewsettings & MOD_SMOKE_VIEW_SMALL))
-                               {
-                                       smoke_prepare_View(smd, light);
-                                       // printf("prepared View!\n");
-                               }
-                               else if(big && !(smd->domain->viewsettings & MOD_SMOKE_VIEW_BIG))
-                               {
-                                       smoke_prepare_bigView(smd, light);
-                                       // printf("prepared bigView!\n");
-                               }
-                       }
-                       
-                       // printf("big: %d, new: %d\n", big, new);
-                       
-                       // only create buffer if we need to create new textures
-                       if(new) 
-                               buffer = MEM_mallocN(sizeof(float)*res[mainaxis[1]]*res[mainaxis[2]]*4, "SmokeDrawBuffer");
-                       
-                       if(buffer || smd->domain->viewsettings)
-                       {
-                               int mod_texture = 0;
-                               
-                               // printf("if(buffer || smd->domain->viewsettings)\n");
-                               
-                               max_textures = (res[mainaxis[0]] > 256) ? 256 : res[mainaxis[0]];
-                               
-                               if(!smd->domain->viewsettings) // new frame or new start
-                               {
-                                       smd->domain->max_textures = max_textures;
-                                       glGenTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind);
-                                       new = 1;
-                                       // printf("glGenTextures\n");
-                               }
-                               else
-                               {
-                                       if(new)
+                                       if(density[index] > FLT_EPSILON)
                                        {
-                                               // printf("glDeleteTextures\n");
-                                               glDeleteTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind);
-                                               smd->domain->max_textures = max_textures;
-                                               glGenTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind);
+                                               float color[3];
+                                               VECCOPY(tmp, smd->domain->p0);
+                                               tmp[0] += smd->domain->dx * x + smd->domain->dx * 0.5;
+                                               tmp[1] += smd->domain->dx * y + smd->domain->dx * 0.5;
+                                               tmp[2] += smd->domain->dx * z + smd->domain->dx * 0.5;
+                                               color[0] = color[1] = color[2] = density[index];
+                                               glColor3fv(color);
+                                               bglVertex3fv(tmp);
                                        }
                                }
 
-                               mod_texture = MAX3(1, smd->domain->visibility, (int)(res[mainaxis[0]] / smd->domain->max_textures ));
-                               
-                               // align order of billboards to be front or backview (e.g. +x or -x axis)
-                               if(signed_align < 0)
-                               {
-                                       z = res[mainaxis[0]] - 1;
-                               }
-                               else
-                               {
-                                       z = 0;
-                               }
-
-                               for (; signed_align > 0 ? (z < res[mainaxis[0]]) : (z >= 0); signed_align > 0 ? z++ : z--) // 2
-                               {
-                                       float quad[4][3];
-
-                                       if(new)
-                                       {
-                                               for (y = 0; y < res[mainaxis[1]]; y++) // 1
-                                               {
-                                                       for (x = 0; x < res[mainaxis[2]]; x++) // 0
-                                                       {
-                                                               size_t index;
-                                                               size_t image_index;
-                                                               float tray, tvox;
-
-                                                               image_index = smoke_get_index2d(y, res[mainaxis[1]], x);
-               
-                                                               if(mainaxis[0] == 0)
-                                                               {
-                                                                       // mainaxis[1] == 1, mainaxis[2] == 2
-                                                                       index = smoke_get_index(z, res[mainaxis[0]], y, res[mainaxis[1]], x);
-                                                               }
-                                                               else if(mainaxis[0] == 1)
-                                                               {
-                                                                       // mainaxis[1] == 2, mainaxis[2] == 0
-                                                                       index = smoke_get_index(x, res[mainaxis[2]], z, res[mainaxis[0]], y);
-                                                               }
-                                                               else // mainaxis[0] == 2
-                                                               {
-                                                                       // mainaxis[1] == 0, mainaxis[2] == 1
-                                                                       index = smoke_get_index(y, res[mainaxis[1]], x, res[mainaxis[2]], z);
-                                                               }
-                                                               
-                                                               if(!big)
-                                                               {
-                                                                       tvox =  smoke_get_tvox(smd, index);
-                                                                       tray = smoke_get_tray(smd, index);
-                                                               }
-                                                               else
-                                                               {
-                                                                       tvox =  smoke_get_bigtvox(smd, index);
-                                                                       tray = smoke_get_bigtray(smd, index);
-                                                               }
+                               bglEnd();
+                               glPointSize(1.0);
 
-                                                               if(!have_lamp)
-                                                                       tvox = 1.0;
-                                                               
-                                                               // fill buffer with luminance and alpha
-                                                               // 1 - T_vox
-                                                               buffer[image_index*4 + 3] = 1.0 - tvox; // 0 = transparent => d.h. tvox = 1
-               
-                                                               // L_vox = Omega * L_light * (1 - T_vox) * T_ray
-                                                               buffer[image_index*4] = buffer[image_index*4 + 1] = buffer[image_index*4 + 2] = smd->domain->omega * 1.0 * tvox * tray; 
-                                                       }
-                                               }
-                                       }
-                                       glBindTexture(GL_TEXTURE_2D, smd->domain->bind[counter_textures]);
-                                       glEnable(GL_TEXTURE_2D);
-       
-                                       if(new)
-                                       {
-                                               glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, res[mainaxis[1]], res[mainaxis[2]], 0, GL_RGBA, GL_FLOAT, buffer);
-                                               glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Linear Filtering
-                                               glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // Linear Filtering
-                                       }
-                                       
-                                       if((z % mod_texture) == 0 )
-                                       {
-                                               // botttom left
-                                               quad[3][mainaxis[0]] =  smd->domain->p0[mainaxis[0]] + z * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5;
-                                               quad[3][mainaxis[1]] =  smd->domain->p0[mainaxis[1]] + smd->domain->dx * bigfactor * 0.5;
-                                               quad[3][mainaxis[2]] =  smd->domain->p0[mainaxis[2]] + smd->domain->dx * bigfactor * 0.5;
-               
-                                               // top right
-                                               quad[1][mainaxis[0]] =  smd->domain->p0[mainaxis[0]] + z * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5;
-                                               quad[1][mainaxis[1]] =  smd->domain->p0[mainaxis[1]] + (res[mainaxis[1]] - 1) * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5;
-                                               quad[1][mainaxis[2]] =  smd->domain->p0[mainaxis[2]] + (res[mainaxis[2]] - 1) * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5;
-               
-                                               // top left
-                                               quad[2][mainaxis[0]] =  smd->domain->p0[mainaxis[0]] + z * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5;
-                                               quad[2][mainaxis[1]] =  smd->domain->p0[mainaxis[1]] + smd->domain->dx * bigfactor * 0.5;
-                                               quad[2][mainaxis[2]] =  smd->domain->p0[mainaxis[2]] + (res[mainaxis[2]] - 1) * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5;
-               
-                                               // bottom right
-                                               quad[0][mainaxis[0]] =  smd->domain->p0[mainaxis[0]] + z * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5;
-                                               quad[0][mainaxis[1]] =  smd->domain->p0[mainaxis[1]] + (res[mainaxis[1]] - 1) * smd->domain->dx * bigfactor + smd->domain->dx * bigfactor * 0.5;
-                                               quad[0][mainaxis[2]] =  smd->domain->p0[mainaxis[2]] + smd->domain->dx * bigfactor * 0.5;
-               
-                                               glBegin(GL_QUADS); // Start Drawing Quads
-               
-                                               glTexCoord2f(1.0f, 0.0f);
-                                               glVertex3fv(quad[0]);   // Left And Up 1 Unit (Top Left)
-                                               glTexCoord2f(1.0f, 1.0f);
-                                               glVertex3fv(quad[1]);   // Right And Up 1 Unit (Top Right)
-                                               glTexCoord2f(0.0f, 1.0f);
-                                               glVertex3fv(quad[2]);   // Right And Down One Unit (Bottom Right)
-                                               glTexCoord2f(0.0f, 0.0f);
-                                               glVertex3fv(quad[3]);   // Left And Down One Unit (Bottom Left)
-               
-                                               glEnd();
-                                       }
-                                       counter_textures++;
-                               }
-                       }
-                       if(buffer)
-                       {
-                               MEM_freeN(buffer);
-                               buffer = NULL;
+                               wmMultMatrix(ob->obmat);
+                               glDisable(GL_BLEND);
+                               glDepthMask(GL_TRUE);
+                               if(col) cpack(col);
+#endif
                        }
-                       
-                       // set correct flag for viewsettings
-                       if(1)
+                       else if(smd->domain->wt && (smd->domain->viewsettings & MOD_SMOKE_VIEW_SHOWBIG))
                        {
-                               // do not clear BIG/SMALL flag
-                               smd->domain->viewsettings &= ~MOD_SMOKE_VIEW_X;
-                               smd->domain->viewsettings &= ~MOD_SMOKE_VIEW_Y;
-                               smd->domain->viewsettings &= ~MOD_SMOKE_VIEW_Z;
-                               
-                               // set what caches we have
-                               if(big)
-                                       smd->domain->viewsettings |= MOD_SMOKE_VIEW_BIG;
-                               else
-                                       smd->domain->viewsettings |= MOD_SMOKE_VIEW_SMALL;
-       
-                               if(mainaxis[0] == 0)
-                                       smd->domain->viewsettings |= MOD_SMOKE_VIEW_X;
-                               else if(mainaxis[0] == 1)
-                                       smd->domain->viewsettings |= MOD_SMOKE_VIEW_Y;
-                               else if(mainaxis[0] == 2)
-                                       smd->domain->viewsettings |= MOD_SMOKE_VIEW_Z;
+                               smd->domain->tex = NULL;
+                               GPU_create_smoke(smd, 1);
+                               draw_volume(scene, ar, v3d, base, smd->domain->tex, smd->domain->p0, smd->domain->p1, smd->domain->res_wt, smd->domain->dx_wt, smd->domain->tex_shadow);
+                               GPU_free_smoke(smd);
                        }
-
-                       wmMultMatrix(ob->obmat);
-                       glDisable(GL_BLEND);
-                       glDepthMask(GL_TRUE);
-                       if(col) cpack(col);
                }
        }
 
@@ -5676,7 +5897,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
                        /* patch for several 3d cards (IBM mostly) that crash on glSelect with text drawing */
                        /* but, we also dont draw names for sets or duplicators */
                        if(flag == 0) {
-                               view3d_object_text_draw_add(0.0f, 0.0f, 0.0f, ob->id.name+2, 10);
+                               view3d_cached_text_draw_add(0.0f, 0.0f, 0.0f, ob->id.name+2, 10);
                        }
                }
                /*if(dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);*/
@@ -5699,18 +5920,18 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag)
        }
        
        /* return warning, this is cached text draw */
-       view3d_object_text_draw(v3d, ar);
+       view3d_cached_text_draw_end(v3d, ar, 1, NULL);
 
        wmLoadMatrix(rv3d->viewmat);
 
        if(zbufoff) glDisable(GL_DEPTH_TEST);
 
        if(warning_recursive) return;
-       if(base->flag & (OB_FROMDUPLI|OB_RADIO)) return;
+       if(base->flag & OB_FROMDUPLI) return;
        if(G.f & G_RENDER_SHADOW) return;
 
        /* object centers, need to be drawn in viewmat space for speed, but OK for picking select */
-       if(ob!=OBACT || (G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))==0) {
+       if(ob!=OBACT || !(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))) {
                int do_draw_center= -1; /* defines below are zero or positive... */
 
                if((scene->basact)==base) 
@@ -5881,7 +6102,24 @@ static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh
        }
 }
 
-static int bbs_mesh_solid__setDrawOpts(void *userData, int index, int *drawSmooth_r)
+static int bbs_mesh_solid_hide__setDrawOpts(void *userData, int index, int *drawSmooth_r)
+{
+       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)
+{
+       WM_set_framebuffer_index_color(index+1);
+       return 1;
+}
+
+static int bbs_mesh_solid_hide__setDrawOpts_legacy(void *userData, int index, int *drawSmooth_r)
 {
        Mesh *me = userData;
 
@@ -5893,14 +6131,49 @@ static int bbs_mesh_solid__setDrawOpts(void *userData, int index, int *drawSmoot
        }
 }
 
-/* TODO remove this - since face select mode now only works with painting */
 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;
+       int face_sel_mode = (me->flag & ME_EDIT_PAINT_MASK) ? 1:0;
        
        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 (face_sel_mode==0 || !(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;
+
+               if(face_sel_mode)       dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, me, 1);
+               else                            dm->drawMappedFaces(dm, NULL, me, 1);
+       }
+       else {
+               if(face_sel_mode)       dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts_legacy, me, 0);
+               else                            dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts_legacy, me, 0);
+       }
 
        dm->release(dm);
 }
@@ -5917,7 +6190,7 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
        switch( ob->type) {
        case OB_MESH:
        {
-               if(ob == scene->obedit) {
+               if(ob->mode & OB_MODE_EDIT) {
                        Mesh *me= ob->data;
                        EditMesh *em= me->edit_mesh;
 
@@ -5973,7 +6246,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
        DerivedMesh *dm=NULL, *edm=NULL;
        int glsl;
        
-       if(ob == scene->obedit)
+       if(ob->mode & OB_MODE_EDIT)
                edm= editmesh_get_derived_base(ob, me->edit_mesh);
        else 
                dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
@@ -6003,7 +6276,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
                glEnable(GL_LIGHTING);
                
                if(dm) {
-                       dm->drawFacesSolid(dm, GPU_enable_material);
+                       dm->drawFacesSolid(dm, NULL, GPU_enable_material);
                        GPU_end_object_materials();
                }
                else if(edm)