=bmesh= merge from trunk at r36529
[blender.git] / source / blender / editors / mesh / editface.c
index a6c5e5beccf051fc0ba5d4cc5736c48487ecb63d..06eb1f1ead406e86e028bb486c87150f5fa7d4a9 100644 (file)
@@ -1,4 +1,4 @@
-/**
+/*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/editors/mesh/editface.c
+ *  \ingroup edmesh
+ */
+
+
 
 #include <math.h>
 #include <string.h>
 #include "MEM_guardedalloc.h"
 
 #include "BLI_blenlib.h"
-#include "BLI_arithb.h"
+#include "BLI_math.h"
 #include "BLI_heap.h"
 #include "BLI_edgehash.h"
 #include "BLI_editVert.h"
+#include "BLI_utildefines.h"
 
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 
-#include "DNA_image_types.h"
-#include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
-#include "DNA_space_types.h"
-#include "DNA_screen_types.h"
 #include "DNA_scene_types.h"
-#include "DNA_view3d_types.h"
 
-#include "BKE_brush.h"
-#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
 #include "BKE_DerivedMesh.h"
-#include "BKE_displist.h"
 #include "BKE_global.h"
 #include "BKE_mesh.h"
-#include "BKE_object.h"
-#include "BKE_texture.h"
-#include "BKE_utildefines.h"
-#include "BKE_customdata.h"
+#include "BKE_context.h"
+#include "BKE_tessmesh.h"
 
 #include "BIF_gl.h"
-#include "BIF_glutil.h"
-
-#include "GPU_draw.h"
-
-#ifndef DISABLE_PYTHON
-//#include "BPY_extern.h"
-//#include "BPY_menus.h"
-#endif
 
 #include "ED_mesh.h"
-#include "ED_object.h"
+#include "ED_screen.h"
 #include "ED_view3d.h"
 
 #include "WM_api.h"
 /* own include */
 #include "mesh_intern.h"
 
-/* ***************** XXX **************** */
-static int sample_backbuf_rect() {return 0;}
-static int sample_backbuf() {return 0;}
-static void error() {}
-static int pupmenu() {return 0;}
-/* ***************** XXX **************** */
+/* copy the face flags, most importantly selection from the mesh to the final derived mesh,
+ * use in object mode when selecting faces (while painting) */
+void paintface_flush_flags(Object *ob)
+{
+       Mesh *me= get_mesh(ob);
+       DerivedMesh *dm= ob->derivedFinal;
+       MPoly *mf_orig;
+       DMFaceIter *fiter;
+       int *index = NULL;
+       int totface;
+       int i;
+       
+       if(me==NULL || dm==NULL)
+               return;
 
+       fiter = dm->newFaceIter(dm);
+       totface = dm->getNumFaces(dm);
+
+       for (i=0; !fiter->done; fiter->step(fiter), i++) {
+               index = fiter->getCDData(fiter, CD_ORIGINDEX, -1);
+               if (!index) {
+                       fiter->free(fiter);
+                       return;
+               }
+               
+               mf_orig = me->mpoly + *index;
+               fiter->flags = mf_orig->flag; 
+       }
+
+       fiter->free(fiter);
+}
 
 /* returns 0 if not found, otherwise 1 */
-int facesel_face_pick(View3D *v3d, Mesh *me, short *mval, unsigned int *index, short rect)
+static int facesel_face_pick(struct bContext *C, Mesh *me, Object *ob, const short mval[2], unsigned int *index, short rect)
 {
-       if (!me || me->totface==0)
+       Scene *scene = CTX_data_scene(C);
+       ViewContext vc;
+       view3d_set_viewcontext(C, &vc);
+
+       if (!me || me->totpoly==0)
                return 0;
 
-       if (v3d->flag & V3D_NEEDBACKBUFDRAW) {
+       /*we can't assume mfaces have a correct origindex layer that indices to mpolys.
+         so instead we have to regenerate the tesselation faces altogether.
+         
+         the final 0, 0 paramters causes it to use the index of each mpoly, instead
+         of reading from the origindex layer.*/
+       me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, &me->pdata, 
+               me->mvert, me->totface, me->totloop, me->totpoly, 0, 0);
+       mesh_update_customdata_pointers(me);
+       makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH, 0);
+
+       // XXX  if (v3d->flag & V3D_INVALID_BACKBUF) {
 // XXX drawview.c!             check_backbuf();
 // XXX         persp(PERSP_VIEW);
-       }
+// XXX         }
 
        if (rect) {
                /* sample rect to increase changes of selecting, so that when clicking
                   on an edge in the backbuf, we can still select a face */
+
                int dist;
-               *index = sample_backbuf_rect(mval, 3, 1, me->totface+1, &dist,0,NULL);
+               *index = view3d_sample_backbuf_rect(&vc, mval, 3, 1, me->totface+1, &dist,0,NULL, NULL);
        }
-       else
+       else {
                /* sample only on the exact position */
-               *index = sample_backbuf(mval[0], mval[1]);
+               *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
+       }
 
-       if ((*index)<=0 || (*index)>(unsigned int)me->totface)
+       if ((*index)<=0 || (*index)>(unsigned int)me->totpoly)
                return 0;
 
        (*index)--;
@@ -120,41 +147,64 @@ int facesel_face_pick(View3D *v3d, Mesh *me, short *mval, unsigned int *index, s
 
 /* last_sel, use em->act_face otherwise get the last selected face in the editselections
  * at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */
-MTFace *EM_get_active_mtface(EditMesh *em, EditFace **act_efa, MCol **mcol, int sloppy)
+MTexPoly *EDBM_get_active_mtface(BMEditMesh *em, BMFace **act_efa, int sloppy)
 {
-       EditFace *efa = NULL;
+       BMFace *efa = NULL;
        
-       if(!EM_texFaceCheck(em))
+       if(!EDBM_texFaceCheck(em))
                return NULL;
        
-       efa = EM_get_actFace(em, sloppy);
+       efa = EDBM_get_actFace(em, sloppy);
        
        if (efa) {
-               if (mcol) {
-                       if (CustomData_has_layer(&em->fdata, CD_MCOL))
-                               *mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
-                       else
-                               *mcol = NULL;
-               }
                if (act_efa) *act_efa = efa; 
-               return CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+               return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
        }
+
        if (act_efa) *act_efa= NULL;
-       if(mcol) *mcol = NULL;
        return NULL;
 }
 
-void reveal_tface(Scene *scene)
+void paintface_hide(Object *ob, const int unselected)
 {
        Mesh *me;
-       MFace *mface;
+       MPoly *mface;
        int a;
        
-       me= get_mesh(OBACT);
-       if(me==0 || me->totface==0) return;
+       me= get_mesh(ob);
+       if(me==NULL || me->totpoly==0) return;
+
+       mface= me->mpoly;
+       a= me->totpoly;
+       while(a--) {
+               if((mface->flag & ME_HIDE) == 0) {
+                       if(unselected) {
+                               if( (mface->flag & ME_FACE_SEL)==0) mface->flag |= ME_HIDE;
+                       }
+                       else {
+                               if( (mface->flag & ME_FACE_SEL)) mface->flag |= ME_HIDE;
+                       }
+               }
+               if(mface->flag & ME_HIDE) mface->flag &= ~ME_FACE_SEL;
+               
+               mface++;
+       }
        
-       mface= me->mface;
-       a= me->totface;
+       paintface_flush_flags(ob);
+}
+
+
+void paintface_reveal(Object *ob)
+{
+       Mesh *me;
+       MPoly *mface;
+       int a;
+
+       me= get_mesh(ob);
+       if(me==NULL || me->totpoly==0) return;
+
+       mface= me->mpoly;
+       a= me->totpoly;
        while(a--) {
                if(mface->flag & ME_HIDE) {
                        mface->flag |= ME_FACE_SEL;
@@ -163,168 +213,232 @@ void reveal_tface(Scene *scene)
                mface++;
        }
 
-// XXX notifier!       object_tface_flags_changed(OBACT, 0);
+       paintface_flush_flags(ob);
 }
 
-void hide_tface(Scene *scene)
+/* Set tface seams based on edge data, uses hash table to find seam edges. */
+
+static void hash_add_face(EdgeHash *ehash, MPoly *mf, MLoop *mloop)
 {
-       Mesh *me;
-       MFace *mface;
-       int a;
-       int shift=0, alt= 0; // XXX
-       
-       me= get_mesh(OBACT);
-       if(me==0 || me->totface==0) return;
-       
-       if(alt) {
-               reveal_tface(scene);
-               return;
+       MLoop *ml, *ml2;
+       int i;
+
+       for (i=0, ml=mloop; i<mf->totloop; i++, ml++) {
+               ml2 = mloop + (i+1) % mf->totloop;
+               BLI_edgehash_insert(ehash, ml->v, ml2->v, NULL);
        }
-       
-       mface= me->mface;
-       a= me->totface;
-       while(a--) {
-               if(mface->flag & ME_HIDE);
-               else {
-                       if(shift) {
-                               if( (mface->flag & ME_FACE_SEL)==0) mface->flag |= ME_HIDE;
+}
+
+
+static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
+{
+       EdgeHash *ehash, *seamhash;
+       MPoly *mf;
+       MLoop *ml;
+       MEdge *med;
+       char *linkflag;
+       int a, b, doit=1, mark=0;
+
+       ehash= BLI_edgehash_new();
+       seamhash = BLI_edgehash_new();
+       linkflag= MEM_callocN(sizeof(char)*me->totpoly, "linkflaguv");
+
+       for(med=me->medge, a=0; a < me->totedge; a++, med++)
+               if(med->flag & ME_SEAM)
+                       BLI_edgehash_insert(seamhash, med->v1, med->v2, NULL);
+
+       if (mode==0 || mode==1) {
+               /* only put face under cursor in array */
+               mf= ((MPoly*)me->mpoly) + index;
+               hash_add_face(ehash, mf, me->mloop + mf->loopstart);
+               linkflag[index]= 1;
+       }
+       else {
+               /* fill array by selection */
+               mf= me->mpoly;
+               for(a=0; a<me->totpoly; a++, mf++) {
+                       if(mf->flag & ME_HIDE);
+                       else if(mf->flag & ME_FACE_SEL) {
+                               hash_add_face(ehash, mf, me->mloop + mf->loopstart);
+                               linkflag[a]= 1;
                        }
-                       else {
-                               if( (mface->flag & ME_FACE_SEL)) mface->flag |= ME_HIDE;
+               }
+       }
+
+       while(doit) {
+               doit= 0;
+
+               /* expand selection */
+               mf= me->mpoly;
+               for(a=0; a<me->totpoly; a++, mf++) {
+                       if(mf->flag & ME_HIDE)
+                               continue;
+
+                       if(!linkflag[a]) {
+                               MLoop *mnextl;
+                               mark= 0;
+
+                               ml = me->mloop + mf->loopstart;
+                               for (b=0; b<mf->totloop; b++, ml++) {
+                                       mnextl = b < mf->totloop-1 ? ml - 1 : me->mloop + mf->loopstart;
+                                       if (!BLI_edgehash_haskey(seamhash, ml->v, mnextl->v))
+                                               if (!BLI_edgehash_haskey(ehash, ml->v, mnextl->v))
+                                                       mark = 1;
+                               }
+
+                               if(mark) {
+                                       linkflag[a]= 1;
+                                       hash_add_face(ehash, mf, me->mloop + mf->loopstart);
+                                       doit= 1;
+                               }
                        }
                }
-               if(mface->flag & ME_HIDE) mface->flag &= ~ME_FACE_SEL;
-               
-               mface++;
+
        }
 
-// XXX notifier!               object_tface_flags_changed(OBACT, 0);
+       BLI_edgehash_free(ehash, NULL);
+       BLI_edgehash_free(seamhash, NULL);
+
+       if(mode==0 || mode==2) {
+               for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
+                       if(linkflag[a])
+                               mf->flag |= ME_FACE_SEL;
+                       else
+                               mf->flag &= ~ME_FACE_SEL;
+       }
+       else if(mode==1) {
+               for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
+                       if(linkflag[a] && (mf->flag & ME_FACE_SEL))
+                               break;
+
+               if (a<me->totpoly) {
+                       for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
+                               if(linkflag[a])
+                                       mf->flag &= ~ME_FACE_SEL;
+               }
+               else {
+                       for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
+                               if(linkflag[a])
+                                       mf->flag |= ME_FACE_SEL;
+               }
+       }
+
+       MEM_freeN(linkflag);
 }
 
-void select_linked_tfaces(Scene *scene, View3D *v3d, int mode)
+void paintface_select_linked(bContext *UNUSED(C), Object *ob, short UNUSED(mval[2]), int mode)
 {
-       Object *ob;
        Mesh *me;
-       short mval[2];
        unsigned int index=0;
 
-       ob = OBACT;
        me = get_mesh(ob);
-       if(me==0 || me->totface==0) return;
+       if(me==NULL || me->totpoly==0) return;
 
        if (mode==0 || mode==1) {
-               if (!(ob->lay & v3d->lay))
-                       error("The active object is not in this layer");
-                       
-// XXX         getmouseco_areawin(mval);
-               if (!facesel_face_pick(v3d, me, mval, &index, 1)) return;
+               // XXX - Causes glitches, not sure why
+               /*
+               if (!facesel_face_pick(C, me, mval, &index, 1))
+                       return;
+               */
        }
 
-// XXX unwrapper.c     select_linked_tfaces_with_seams(mode, me, index);
+       select_linked_tfaces_with_seams(mode, me, index);
+
+       paintface_flush_flags(ob);
 }
 
-void deselectall_tface(Scene *scene)
+/* note: caller needs to run paintface_flush_flags(ob) after this */
+void paintface_deselect_all_visible(Object *ob, int action, short flush_flags)
 {
        Mesh *me;
-       MFace *mface;
-       int a, sel;
-               
-       me= get_mesh(OBACT);
-       if(me==0) return;
-       
-       mface= me->mface;
-       a= me->totface;
-       sel= 0;
-       while(a--) {
-               if(mface->flag & ME_HIDE);
-               else if(mface->flag & ME_FACE_SEL) sel= 1;
-               mface++;
-       }
+       MPoly *mface;
+       int a;
+
+       me= get_mesh(ob);
+       if(me==NULL) return;
        
-       mface= me->mface;
-       a= me->totface;
-       while(a--) {
-               if(mface->flag & ME_HIDE);
-               else {
-                       if(sel) mface->flag &= ~ME_FACE_SEL;
-                       else mface->flag |= ME_FACE_SEL;
+       if(action == SEL_INVERT) {
+               mface= me->mpoly;
+               a= me->totpoly;
+               while(a--) {
+                       if((mface->flag & ME_HIDE) == 0) {
+                               mface->flag ^= ME_FACE_SEL;
+                       }
+                       mface++;
+               }
+       } else {
+               if (action == SEL_TOGGLE) {
+                       action = SEL_SELECT;
+
+                       mface= me->mpoly;
+                       a= me->totpoly;
+                       while(a--) {
+                               if((mface->flag & ME_HIDE) == 0 && mface->flag & ME_FACE_SEL) {
+                                       action = SEL_DESELECT;
+                                       break;
+                               }
+                               mface++;
+                       }
                }
-               mface++;
        }
 
+       //BMESH_TODO object_facesel_flush_dm(ob);
 // XXX notifier!               object_tface_flags_changed(OBACT, 0);
 }
 
 void selectswap_tface(Scene *scene)
 {
        Mesh *me;
-       MFace *mface;
+       MPoly *mface;
        int a;
                
        me= get_mesh(OBACT);
        if(me==0) return;
        
-       mface= me->mface;
-       a= me->totface;
+       mface= me->mpoly;
+       a= me->totpoly;
        while(a--) {
                if(mface->flag & ME_HIDE);
                else {
                        if(mface->flag & ME_FACE_SEL) mface->flag &= ~ME_FACE_SEL;
                        else mface->flag |= ME_FACE_SEL;
                }
-               mface++;
        }
-
-// XXX notifier!               object_tface_flags_changed(OBACT, 0);
 }
 
-int minmax_tface(Scene *scene, float *min, float *max)
+int paintface_minmax(Object *ob, float *min, float *max)
 {
-       Object *ob;
        Mesh *me;
-       MFace *mf;
-       MTFace *tf;
+       MPoly *mf;
+       MTexPoly *tf;
+       MLoop *ml;
        MVert *mv;
-       int a, ok=0;
+       int a, b, ok=0;
        float vec[3], bmat[3][3];
-       
-       ob = OBACT;
-       if (ob==0) return ok;
+
        me= get_mesh(ob);
-       if(me==0 || me->mtface==0) return ok;
+       if(!me || !me->mtpoly) return ok;
        
-       Mat3CpyMat4(bmat, ob->obmat);
+       copy_m3_m4(bmat, ob->obmat);
 
        mv= me->mvert;
-       mf= me->mface;
-       tf= me->mtface;
-       for (a=me->totface; a>0; a--, mf++, tf++) {
+       mf= me->mpoly;
+       tf= me->mtpoly;
+       for (a=me->totpoly; a>0; a--, mf++, tf++) {
                if (mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL))
                        continue;
 
-               VECCOPY(vec, (mv+mf->v1)->co);
-               Mat3MulVecfl(bmat, vec);
-               VecAddf(vec, vec, ob->obmat[3]);
-               DO_MINMAX(vec, min, max);               
-
-               VECCOPY(vec, (mv+mf->v2)->co);
-               Mat3MulVecfl(bmat, vec);
-               VecAddf(vec, vec, ob->obmat[3]);
-               DO_MINMAX(vec, min, max);               
-
-               VECCOPY(vec, (mv+mf->v3)->co);
-               Mat3MulVecfl(bmat, vec);
-               VecAddf(vec, vec, ob->obmat[3]);
-               DO_MINMAX(vec, min, max);               
-
-               if (mf->v4) {
-                       VECCOPY(vec, (mv+mf->v4)->co);
-                       Mat3MulVecfl(bmat, vec);
-                       VecAddf(vec, vec, ob->obmat[3]);
-                       DO_MINMAX(vec, min, max);
+               ml = me->mloop + mf->totloop;
+               for (b=0; b<mf->totloop; b++, ml++) {
+                       VECCOPY(vec, (mv+ml->v)->co);
+                       mul_m3_v3(bmat, vec);
+                       add_v3_v3v3(vec, vec, ob->obmat[3]);
+                       DO_MINMAX(vec, min, max);               
                }
+
                ok= 1;
        }
+
        return ok;
 }
 
@@ -332,35 +446,36 @@ int minmax_tface(Scene *scene, float *min, float *max)
 
 #define ME_SEAM_DONE 2         /* reuse this flag */
 
-static float edgetag_cut_cost(EditMesh *em, int e1, int e2, int vert)
+static float edgetag_cut_cost(BMEditMesh *em, int e1, int e2, int vert)
 {
-       EditVert *v = EM_get_vert_for_index(vert);
-       EditEdge *eed1 = EM_get_edge_for_index(e1), *eed2 = EM_get_edge_for_index(e2);
-       EditVert *v1 = EM_get_vert_for_index( (eed1->v1->tmp.l == vert)? eed1->v2->tmp.l: eed1->v1->tmp.l );
-       EditVert *v2 = EM_get_vert_for_index( (eed2->v1->tmp.l == vert)? eed2->v2->tmp.l: eed2->v1->tmp.l );
+       BMVert *v = EDBM_get_vert_for_index(em, vert);
+       BMEdge *eed1 = EDBM_get_edge_for_index(em, e1), *eed2 = EDBM_get_edge_for_index(em, e2);
+       BMVert *v1 = EDBM_get_vert_for_index(em, (BMINDEX_GET(eed1->v1) == vert)? BMINDEX_GET(eed1->v2): BMINDEX_GET(eed1->v1) );
+       BMVert *v2 = EDBM_get_vert_for_index(em, (BMINDEX_GET(eed2->v1) == vert)? BMINDEX_GET(eed2->v2): BMINDEX_GET(eed2->v1) );
        float cost, d1[3], d2[3];
 
-       cost = VecLenf(v1->co, v->co);
-       cost += VecLenf(v->co, v2->co);
+       cost = len_v3v3(v1->co, v->co);
+       cost += len_v3v3(v->co, v2->co);
 
-       VecSubf(d1, v->co, v1->co);
-       VecSubf(d2, v2->co, v->co);
+       sub_v3_v3v3(d1, v->co, v1->co);
+       sub_v3_v3v3(d2, v2->co, v->co);
 
-       cost = cost + 0.5f*cost*(2.0f - fabs(d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2]));
+       cost = cost + 0.5f*cost*(2.0f - fabsf(d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2]));
 
        return cost;
 }
 
-static void edgetag_add_adjacent(EditMesh *em, Heap *heap, int mednum, int vertnum, int *nedges, int *edges, int *prevedge, float *cost)
+static void edgetag_add_adjacent(BMEditMesh *em, Heap *heap, int mednum, int vertnum, 
+                                                                int *nedges, int *edges, int *prevedge, float *cost)
 {
        int startadj, endadj = nedges[vertnum+1];
 
        for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
                int adjnum = edges[startadj];
-               EditEdge *eedadj = EM_get_edge_for_index(adjnum);
+               BMEdge *eedadj = EDBM_get_edge_for_index(em, adjnum);
                float newcost;
 
-               if (eedadj->f2 & ME_SEAM_DONE)
+               if (eedadj->head.flags[0].f & ME_SEAM_DONE)
                        continue;
 
                newcost = cost[mednum] + edgetag_cut_cost(em, mednum, adjnum, vertnum);
@@ -373,72 +488,94 @@ static void edgetag_add_adjacent(EditMesh *em, Heap *heap, int mednum, int vertn
        }
 }
 
-void edgetag_context_set(Scene *scene, EditEdge *eed, int val)
+void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *eed, int val)
 {
        
        switch (scene->toolsettings->edge_mode) {
        case EDGE_MODE_SELECT:
-               EM_select_edge(eed, val);
+               BM_Select(em->bm, eed, val);
                break;
        case EDGE_MODE_TAG_SEAM:
-               if (val)                {eed->seam = 255;}
-               else                    {eed->seam = 0;}
+               if (val)                {BM_SetHFlag(eed, BM_SEAM);}
+               else                    {BM_ClearHFlag(eed, BM_SEAM);}
                break;
        case EDGE_MODE_TAG_SHARP:
-               if (val)                {eed->sharp = 1;}
-               else                    {eed->sharp = 0;}
+               if (val)                {BM_SetHFlag(eed, BM_SEAM);}
+               else                    {BM_ClearHFlag(eed, BM_SEAM);}
                break;                          
-       case EDGE_MODE_TAG_CREASE:      
-               if (val)                {eed->crease = 1.0f;}
-               else                    {eed->crease = 0.0f;}
+       case EDGE_MODE_TAG_CREASE:
+        {
+               float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE);
+               
+               if (val)                {*crease = 1.0f;}
+               else                    {*crease = 0.0f;}
                break;
+        }
        case EDGE_MODE_TAG_BEVEL:
-               if (val)                {eed->bweight = 1.0f;}
-               else                    {eed->bweight = 0.0f;}
+        {
+               float *bweight = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT);
+
+               if (val)                {*bweight = 1.0f;}
+               else                    {*bweight = 0.0f;}
                break;
+        }
        }
 }
 
-int edgetag_context_check(Scene *scene, EditEdge *eed)
+static float bm_cdata_get_single_float(BMesh *UNUSED(bm), CustomData *cdata, void *element, int type)
+{
+       BMHeader *ele = element;
+       float *f;
+       
+       if (!CustomData_has_layer(cdata, type))
+               return 0.0f;
+       
+       f = CustomData_bmesh_get(cdata, ele->data, type);
+       
+       return *f;
+}
+
+int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *eed)
 {
        switch (scene->toolsettings->edge_mode) {
        case EDGE_MODE_SELECT:
-               return (eed->f & SELECT) ? 1 : 0;
+               return BM_TestHFlag(eed, BM_SELECT) ? 1 : 0;
        case EDGE_MODE_TAG_SEAM:
-               return eed->seam ? 1 : 0;
+               return BM_TestHFlag(eed, BM_SEAM);
        case EDGE_MODE_TAG_SHARP:
-               return eed->sharp ? 1 : 0;
+               return BM_TestHFlag(eed, BM_SHARP);
        case EDGE_MODE_TAG_CREASE:      
-               return eed->crease ? 1 : 0;
+               return bm_cdata_get_single_float(em->bm, &em->bm->edata, eed, CD_CREASE) ? 1 : 0;
        case EDGE_MODE_TAG_BEVEL:
-               return eed->bweight ? 1 : 0;
+               return bm_cdata_get_single_float(em->bm, &em->bm->edata, eed, CD_BWEIGHT) ? 1 : 0;
        }
        return 0;
 }
 
 
-int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target)
+int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target)
 {
-       EditEdge *eed;
-       EditVert *ev;
-       
+       BMEdge *eed;
+       BMVert *ev;
+       BMIter iter;
        Heap *heap;
        float *cost;
        int a, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
 
 
        /* we need the vert */
-       for (ev= em->verts.first, totvert=0; ev; ev= ev->next) {
-               ev->tmp.l = totvert;
+       BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+               BMINDEX_SET(ev, totvert);
                totvert++;
        }
 
-       for (eed= em->edges.first; eed; eed = eed->next) {
-               eed->f2 = 0;
-               if (eed->h) {
-                       eed->f2 |= ME_SEAM_DONE;
+       BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+               eed->head.flags[0].f = 0;
+               if (BM_TestHFlag(eed, BM_SELECT)) {
+                       eed->head.flags[0].f |= ME_SEAM_DONE;
                }
-               eed->tmp.l = totedge;
+
+               BMINDEX_SET(eed, totedge);
                totedge++;
        }
 
@@ -449,9 +586,9 @@ int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge
        cost = MEM_mallocN(sizeof(*cost)*totedge, "SeamPathCost");
 
        /* count edges, compute adjacent edges offsets and fill adjacent edges */
-       for (eed= em->edges.first; eed; eed = eed->next) {
-               nedges[eed->v1->tmp.l+1]++;
-               nedges[eed->v2->tmp.l+1]++;
+       BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+               nedges[BMINDEX_GET(eed->v1)+1]++;
+               nedges[BMINDEX_GET(eed->v2)+1]++;
        }
 
        for (a=1; a<totvert; a++) {
@@ -461,107 +598,108 @@ int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge
        }
        nedges[0] = nedges[1] = 0;
 
-       for (a=0, eed= em->edges.first; eed; a++, eed = eed->next) {
-               edges[nedges[eed->v1->tmp.l+1]++] = a;
-               edges[nedges[eed->v2->tmp.l+1]++] = a;
+       BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+               edges[nedges[BMINDEX_GET(eed->v1)+1]++] = a;
+               edges[nedges[BMINDEX_GET(eed->v2)+1]++] = a;
 
                cost[a] = 1e20f;
                prevedge[a] = -1;
+               a++;
        }
 
        /* regular dijkstra shortest path, but over edges instead of vertices */
        heap = BLI_heap_new();
-       BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(source->tmp.l));
-       cost[source->tmp.l] = 0.0f;
-
-       EM_init_index_arrays(em, 1, 1, 0);
+       BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(BMINDEX_GET(source)));
+       cost[BMINDEX_GET(source)] = 0.0f;
 
+       EDBM_init_index_arrays(em, 1, 1, 0);
 
        while (!BLI_heap_empty(heap)) {
                mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
-               eed = EM_get_edge_for_index( mednum );
+               eed = EDBM_get_edge_for_index(em, mednum);
 
-               if (mednum == target->tmp.l)
+               if (mednum == BMINDEX_GET(target))
                        break;
 
-               if (eed->f2 & ME_SEAM_DONE)
+               if (eed->head.flags[0].f & ME_SEAM_DONE)
                        continue;
 
-               eed->f2 |= ME_SEAM_DONE;
+               eed->head.flags[0].f |= ME_SEAM_DONE;
 
-               edgetag_add_adjacent(em, heap, mednum, eed->v1->tmp.l, nedges, edges, prevedge, cost);
-               edgetag_add_adjacent(em, heap, mednum, eed->v2->tmp.l, nedges, edges, prevedge, cost);
+               edgetag_add_adjacent(em, heap, mednum, BMINDEX_GET(eed->v1), nedges, edges, prevedge, cost);
+               edgetag_add_adjacent(em, heap, mednum, BMINDEX_GET(eed->v2), nedges, edges, prevedge, cost);
        }
        
-       
        MEM_freeN(nedges);
        MEM_freeN(edges);
        MEM_freeN(cost);
        BLI_heap_free(heap, NULL);
 
-       for (eed= em->edges.first; eed; eed = eed->next) {
-               eed->f2 &= ~ME_SEAM_DONE;
+       BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+               eed->head.flags[0].f &= ~ME_SEAM_DONE;
        }
 
-       if (mednum != target->tmp.l) {
+       if (mednum != BMINDEX_GET(target)) {
                MEM_freeN(prevedge);
-               EM_free_index_arrays();
+               EDBM_free_index_arrays(em);
                return 0;
        }
 
        /* follow path back to source and mark as seam */
-       if (mednum == target->tmp.l) {
+       if (mednum == BMINDEX_GET(target)) {
                short allseams = 1;
 
-               mednum = target->tmp.l;
+               mednum = BMINDEX_GET(target);
                do {
-                       eed = EM_get_edge_for_index( mednum );
-                       if (!edgetag_context_check(scene, eed)) {
+                       eed = EDBM_get_edge_for_index(em, mednum);
+                       if (!edgetag_context_check(scene, em, eed)) {
                                allseams = 0;
                                break;
                        }
                        mednum = prevedge[mednum];
-               } while (mednum != source->tmp.l);
+               } while (mednum != BMINDEX_GET(source));
 
-               mednum = target->tmp.l;
+               mednum = BMINDEX_GET(target);
                do {
-                       eed = EM_get_edge_for_index( mednum );
+                       eed = EDBM_get_edge_for_index(em, mednum);
                        if (allseams)
-                               edgetag_context_set(scene, eed, 0);
+                               edgetag_context_set(em, scene, eed, 0);
                        else
-                               edgetag_context_set(scene, eed, 1);
+                               edgetag_context_set(em, scene, eed, 1);
                        mednum = prevedge[mednum];
                } while (mednum != -1);
        }
 
        MEM_freeN(prevedge);
-       EM_free_index_arrays();
+       EDBM_free_index_arrays(em);
        return 1;
 }
 
 /* *************************************** */
-
-static void seam_edgehash_insert_face(EdgeHash *ehash, MFace *mf)
+#if 0
+static void seam_edgehash_insert_face(EdgeHash *ehash, MPoly *mf, MLoop *loopstart)
 {
-       BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
-       BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
-       if (mf->v4) {
-               BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
-               BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
-       }
-       else
-               BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
+       MLoop *ml1, *ml2;
+       int a;
+
+       for (a=0; a<mf->totloop; a++) {
+               ml1 = loopstart + a;
+               ml2 = loopstart + (a+1) % mf->totloop;
+
+               BLI_edgehash_insert(ehash, ml1->v, ml2->v, NULL);
+       }
 }
 
 void seam_mark_clear_tface(Scene *scene, short mode)
 {
        Mesh *me;
-       MFace *mf;
+       MPoly *mf;
+       MLoop *ml1, *ml2;
        MEdge *med;
-       int a;
+       int a, b;
        
        me= get_mesh(OBACT);
-       if(me==0 ||  me->totface==0) return;
+       if(me==0 ||  me->totpoly==0) return;
 
        if (mode == 0)
                mode = pupmenu("Seams%t|Mark Border Seam %x1|Clear Seam %x2");
@@ -572,9 +710,9 @@ void seam_mark_clear_tface(Scene *scene, short mode)
        if (mode == 2) {
                EdgeHash *ehash = BLI_edgehash_new();
 
-               for (a=0, mf=me->mface; a<me->totface; a++, mf++)
+               for (a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
                        if (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))
-                               seam_edgehash_insert_face(ehash, mf);
+                               seam_edgehash_insert_face(ehash, mf, me->mloop + mf->loopstart);
 
                for (a=0, med=me->medge; a<me->totedge; a++, med++)
                        if (BLI_edgehash_haskey(ehash, med->v1, med->v2))
@@ -587,16 +725,16 @@ void seam_mark_clear_tface(Scene *scene, short mode)
                EdgeHash *ehash1 = BLI_edgehash_new();
                EdgeHash *ehash2 = BLI_edgehash_new();
 
-               for (a=0, mf=me->mface; a<me->totface; a++, mf++) {
+               for (a=0, mf=me->mpoly; a<me->totpoly; a++, mf++) {
                        if ((mf->flag & ME_HIDE) || !(mf->flag & ME_FACE_SEL))
-                               seam_edgehash_insert_face(ehash1, mf);
+                               seam_edgehash_insert_face(ehash1, mf, me->mloop + mf->loopstart);
                        else
-                               seam_edgehash_insert_face(ehash2, mf);
+                               seam_edgehash_insert_face(ehash2, mf, me->mloop + mf->loopstart);
                }
 
                for (a=0, med=me->medge; a<me->totedge; a++, med++)
                        if (BLI_edgehash_haskey(ehash1, med->v1, med->v2) &&
-                           BLI_edgehash_haskey(ehash2, med->v1, med->v2))
+                               BLI_edgehash_haskey(ehash2, med->v1, med->v2))
                                med->flag |= ME_SEAM;
 
                BLI_edgehash_free(ehash1, NULL);
@@ -607,36 +745,31 @@ void seam_mark_clear_tface(Scene *scene, short mode)
 //             unwrap_lscm(1);
 
        me->drawflag |= ME_DRAWSEAMS;
-
-// XXX notifier!               object_tface_flags_changed(OBACT, 1);
 }
+#endif
 
-void face_select(Scene *scene, View3D *v3d)
+int paintface_mouse_select(struct bContext *C, Object *ob, const short mval[2], int extend)
 {
-       Object *ob;
        Mesh *me;
-       MFace *mface, *msel;
-       short mval[2];
+       MPoly *mface, *msel;
        unsigned int a, index;
-       int shift= 0; // XXX
        
        /* Get the face under the cursor */
-       ob = OBACT;
-       if (!(ob->lay & v3d->lay)) {
-               error("The active object is not in this layer");
-       }
        me = get_mesh(ob);
-// XXX getmouseco_areawin(mval);
 
-       if (!facesel_face_pick(v3d, me, mval, &index, 1)) return;
+       if (!facesel_face_pick(C, me, ob, mval, &index, 1))
+               return 0;
        
-       msel= (((MFace*)me->mface)+index);
-       if (msel->flag & ME_HIDE) return;
+       if (index >= me->totpoly || index < 0)
+               return 0;
+
+       msel= me->mpoly + index;
+       if (msel->flag & ME_HIDE) return 0;
        
        /* clear flags */
-       mface = me->mface;
-       a = me->totface;
-       if ((shift)==0) {
+       mface = me->mpoly;
+       a = me->totpoly;
+       if (!extend) {
                while (a--) {
                        mface->flag &= ~ME_FACE_SEL;
                        mface++;
@@ -645,7 +778,7 @@ void face_select(Scene *scene, View3D *v3d)
        
        me->act_face = (int)index;
 
-       if (shift) {
+       if (extend) {
                if (msel->flag & ME_FACE_SEL)
                        msel->flag &= ~ME_FACE_SEL;
                else
@@ -655,73 +788,79 @@ void face_select(Scene *scene, View3D *v3d)
        
        /* image window redraw */
        
-
-// XXX notifier!               object_tface_flags_changed(OBACT, 1);
+       paintface_flush_flags(ob);
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
+       ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views
+       return 1;
 }
 
-void face_borderselect(Scene *scene, ARegion *ar)
+int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
 {
+       Object *ob = vc->obact;
        Mesh *me;
-       MFace *mface;
-       rcti rect;
+       MPoly *mface;
        struct ImBuf *ibuf;
        unsigned int *rt;
-       int a, sx, sy, index, val= 0;
        char *selar;
+       int a, index;
+       int sx= rect->xmax-rect->xmin+1;
+       int sy= rect->ymax-rect->ymin+1;
        
-       me= get_mesh(OBACT);
-       if(me==0) return;
-       if(me->totface==0) return;
-       
-// XXX val= get_border(&rect, 3);
-       
-       /* why readbuffer here? shouldn't be necessary (maybe a flush or so) */
-       glReadBuffer(GL_BACK);
-#ifdef __APPLE__
-       glReadBuffer(GL_AUX0); /* apple only */
-#endif
-       
-       if(val) {
-               selar= MEM_callocN(me->totface+1, "selar");
-               
-               sx= (rect.xmax-rect.xmin+1);
-               sy= (rect.ymax-rect.ymin+1);
-               if(sx*sy<=0) return;
+       me= get_mesh(ob);
+       if(me==0) return 0;
+       if(me->totpoly==0) return 0;
 
-               ibuf = IMB_allocImBuf(sx,sy,32,IB_rect,0);
-               rt = ibuf->rect;
-               glReadPixels(rect.xmin+ar->winrct.xmin,  rect.ymin+ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
-               if(ENDIAN_ORDER==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+       if(me==NULL || me->totface==0 || sx*sy <= 0)
+               return OPERATOR_CANCELLED;
 
-               a= sx*sy;
-               while(a--) {
-                       if(*rt) {
-                               index= WM_framebuffer_to_index(*rt);
-                               if(index<=me->totface) selar[index]= 1;
-                       }
-                       rt++;
+       selar= MEM_callocN(me->totpoly+1, "selar");
+
+       if (extend == 0 && select)
+               paintface_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE);
+
+       if (extend == 0 && select) {
+               mface= me->mpoly;
+               for(a=1; a<=me->totpoly; a++, mface++) {
+                       if((mface->flag & ME_HIDE) == 0)
+                               mface->flag &= ~ME_FACE_SEL;
                }
-               
-               mface= me->mface;
-               for(a=1; a<=me->totface; a++, mface++) {
-                       if(selar[a]) {
-                               if(mface->flag & ME_HIDE);
-                               else {
-                                       if(val==LEFTMOUSE) mface->flag |= ME_FACE_SEL;
-                                       else mface->flag &= ~ME_FACE_SEL;
-                               }
+       }
+
+       view3d_validate_backbuf(vc);
+
+       ibuf = IMB_allocImBuf(sx,sy,32,IB_rect);
+       rt = ibuf->rect;
+       glReadPixels(rect->xmin+vc->ar->winrct.xmin,  rect->ymin+vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
+       if(ENDIAN_ORDER==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+
+       a= sx*sy;
+       while(a--) {
+               if(*rt) {
+                       index= WM_framebuffer_to_index(*rt);
+                       if(index<=me->totface) selar[index]= 1;
+               }
+               rt++;
+       }
+
+       mface= me->mpoly;
+       for(a=1; a<=me->totpoly; a++, mface++) {
+               if(selar[a]) {
+                       if(mface->flag & ME_HIDE);
+                       else {
+                               if(select) mface->flag |= ME_FACE_SEL;
+                               else mface->flag &= ~ME_FACE_SEL;
                        }
                }
-               
-               IMB_freeImBuf(ibuf);
-               MEM_freeN(selar);
+       }
 
+       IMB_freeImBuf(ibuf);
+       MEM_freeN(selar);
 
-// XXX notifier!                       object_tface_flags_changed(OBACT, 0);
-       }
 #ifdef __APPLE__       
        glReadBuffer(GL_BACK);
 #endif
-}
 
+       paintface_flush_flags(vc->obact);
 
+       return OPERATOR_FINISHED;
+}