merge with trunk at r21785, and also fixed stupid ngon normals bug
authorJoseph Eagar <joeedh@gmail.com>
Wed, 22 Jul 2009 02:57:40 +0000 (02:57 +0000)
committerJoseph Eagar <joeedh@gmail.com>
Wed, 22 Jul 2009 02:57:40 +0000 (02:57 +0000)
42 files changed:
1  2 
projectfiles_vc9/blender/BPY_python/BPY_python.vcproj
source/blender/blenkernel/intern/editderivedbmesh.c
source/blender/blenkernel/intern/fluidsim.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/multires.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/intern/arithb.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/bmesh/intern/bmesh_opdefines.c
source/blender/bmesh/intern/bmesh_operators_private.h
source/blender/bmesh/intern/bmesh_polygon.c
source/blender/bmesh/operators/utils.c
source/blender/editors/mesh/bmesh_tools.c
source/blender/editors/mesh/editmesh_mods.c
source/blender/editors/mesh/editmesh_tools.c
source/blender/editors/mesh/mesh_intern.h
source/blender/editors/mesh/mesh_ops.c
source/blender/editors/object/object_edit.c
source/blender/editors/physics/editparticle.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_buttons/buttons_ops.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/view3d_buttons.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_manipulator.c
source/blender/editors/transform/transform_ops.c
source/blender/editors/transform/transform_orientations.c
source/blender/makesrna/SConscript
source/blender/makesrna/intern/Makefile
source/blender/makesrna/intern/SConscript
source/blender/python/generic/bpy_internal_import.c
source/blender/render/intern/source/convertblender.c
source/blender/render/intern/source/strand.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
tools/Blender.py

index f6a740ee5b08bdb46db6f6de36d0415377c925d5,f6a740ee5b08bdb46db6f6de36d0415377c925d5..7881d03f89f695213e65928837811661338faa4e
@@@ -1,7 -1,7 +1,7 @@@
  <?xml version="1.0" encoding="Windows-1252"?>\r
  <VisualStudioProject\r
        ProjectType="Visual C++"\r
--      Version="9,00"\r
++      Version="9.00"\r
        Name="BPY_python"\r
        ProjectGUID="{5A2EA6DC-1A53-4E87-9166-52870CE3B4EA}"\r
        RootNamespace="BPY_python"\r
index bfea160012149bf694e1bb28198936d991c1a224,0000000000000000000000000000000000000000..cbac230c118ad91cb12f35ac821bf2faaad111bd
mode 100644,000000..100644
--- /dev/null
@@@ -1,1526 -1,0 +1,1535 @@@
-       int i = 0, j;
 +/**
 + * $Id: editderivedbmesh.c 18571 2009-01-19 06:04:57Z joeedh $
 + *
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Tbmple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * The Original Code is Copyright (C) 2005 Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): none yet.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +#include <string.h>
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "PIL_time.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "DNA_effect_types.h"
 +#include "DNA_mesh_types.h"
 +#include "DNA_key_types.h"
 +#include "DNA_meshdata_types.h"
 +#include "DNA_modifier_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_object_force.h"
 +#include "DNA_object_fluidsim.h" // N_T
 +#include "DNA_scene_types.h" // N_T
 +#include "DNA_texture_types.h"
 +#include "DNA_view3d_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_space_types.h"
 +#include "DNA_particle_types.h"
 +
 +#include "BLI_arithb.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_editVert.h"
 +#include "BLI_edgehash.h"
 +#include "BLI_linklist.h"
 +#include "BLI_memarena.h"
 +#include "BLI_scanfill.h"
 +#include "BLI_ghash.h"
 +
 +#include "BKE_cdderivedmesh.h"
 +#include "BKE_customdata.h"
 +#include "BKE_DerivedMesh.h"
 +#include "BKE_deform.h"
 +#include "BKE_displist.h"
 +#include "BKE_effect.h"
 +#include "BKE_fluidsim.h"
 +#include "BKE_global.h"
 +#include "BKE_key.h"
 +#include "BKE_material.h"
 +#include "BKE_modifier.h"
 +#include "BKE_mesh.h"
 +#include "BKE_object.h"
 +#include "BKE_subsurf.h"
 +#include "BKE_texture.h"
 +#include "BKE_utildefines.h"
 +#include "BKE_particle.h"
 +#include "BKE_tessmesh.h"
 +
 +#include "BLO_sys_types.h" // for intptr_t support
 +
 +#include "BIF_gl.h"
 +#include "BIF_glutil.h"
 +
 +#include "GPU_draw.h"
 +#include "GPU_extensions.h"
 +#include "GPU_material.h"
 +
 +#include "bmesh.h"
 +
 +BMEditMesh *BMEdit_Create(BMesh *bm)
 +{
 +      BMEditMesh *tm = MEM_callocN(sizeof(BMEditMesh), "tm");
 +      
 +      tm->bm = bm;
 +
 +      BMEdit_RecalcTesselation(tm);
 +
 +      return tm;
 +}
 +
 +BMEditMesh *BMEdit_Copy(BMEditMesh *tm)
 +{
 +      BMEditMesh *tm2 = MEM_callocN(sizeof(BMEditMesh), "tm2");
 +      *tm2 = *tm;
 +      
 +      tm2->derivedCage = tm2->derivedFinal = NULL;
 +      
 +      tm2->looptris = NULL;
 +      tm2->bm = BM_Copy_Mesh(tm->bm);
 +      BMEdit_RecalcTesselation(tm2);
 +
 +      tm2->vert_index = NULL;
 +      tm2->edge_index = NULL;
 +      tm2->face_index = NULL;
 +
 +      return tm2;
 +}
 +
 +static void BMEdit_RecalcTesselation_intern(BMEditMesh *tm)
 +{
 +      BMesh *bm = tm->bm;
 +      BMLoop **looptris = NULL;
 +      V_DYNDECLARE(looptris);
 +      BMIter iter, liter;
 +      BMFace *f;
 +      BMLoop *l;
-                               looptris[i*3] = efa->v1->tmp.p;
-                               looptris[i*3+1] = efa->v2->tmp.p;
-                               looptris[i*3+2] = efa->v3->tmp.p;
-                               if (looptris[i*3]->head.eflag2 < looptris[i*3+1]->head.eflag2);
-                                       SWAP(BMLoop*, looptris[i*3], looptris[i*3+1]);
-                               if (looptris[i*3+1]->head.eflag2 < looptris[i*3+2]->head.eflag2);
-                                       SWAP(BMLoop*, looptris[i*3+1], looptris[i*3+2]);
-                               if (looptris[i*3]->head.eflag2 < looptris[i*3+1]->head.eflag2);
-                                       SWAP(BMLoop*, looptris[i*3], looptris[i*3+1]);
++      int i = 0, j, a, b;
 +      
 +      if (tm->looptris) MEM_freeN(tm->looptris);
 +
 +      f = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
 +      for ( ; f; f=BMIter_Step(&iter)) {
 +              /*don't consider two-edged faces*/
 +              if (f->len < 3) continue;
 +              
 +              if (f->len <= 4) {
 +                      /*triangle fan for quads.  should be recoded to
 +                        just add one tri for tris, and two for quads,
 +                        but this code works for now too.*/
 +                      l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
 +                      for (; l; l=BMIter_Step(&liter)) {
 +                              if (l == f->loopbase) continue;
 +                              if ((BMLoop*)l->head.next == f->loopbase) continue;
 +
 +                              V_GROW(looptris);
 +                              V_GROW(looptris);
 +                              V_GROW(looptris);
 +
 +                              looptris[i*3] = l;
 +                              looptris[i*3+1] = (BMLoop*)l->head.next;
 +                              looptris[i*3+2] = f->loopbase;
 +
 +                              i += 1;
 +                      }
 +              } else {
 +                      /*scanfill time*/
 +                      EditVert *v, *lastv=NULL, *firstv=NULL;
 +                      EditEdge *e;
 +                      EditFace *efa;
 +
 +                      l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
 +                      for (j=0; l; l=BMIter_Step(&liter), j++) {
 +                              /*mark order*/
 +                              l->head.eflag2 = j;
 +
 +                              v = BLI_addfillvert(l->v->co);
 +                              v->tmp.p = l;
 +                              
 +                              if (lastv) {
 +                                      e = BLI_addfilledge(lastv, v);
 +                              }
 +
 +                              lastv = v;
 +                              if (firstv==NULL) firstv = v;
 +                      }
 +
 +                      /*complete the loop*/
 +                      BLI_addfilledge(firstv, v);
 +
 +                      BLI_edgefill(0, 0);
 +                      
 +                      for (efa = fillfacebase.first; efa; efa=efa->next) {
++                              BMLoop *l1, *l2, *l3;
++
 +                              V_GROW(looptris);
 +                              V_GROW(looptris);
 +                              V_GROW(looptris);
 +                              
++                              looptris[i*3] = l1 = efa->v1->tmp.p;
++                              looptris[i*3+1] = l2 = efa->v2->tmp.p;
++                              looptris[i*3+2] = l3 = efa->v3->tmp.p;
++                              
++                              if (l1->head.eflag2 > l2->head.eflag2) {
++                                      SWAP(BMLoop*, l1, l2);
++                              }
++                              if (l2->head.eflag2 > l3->head.eflag2) {
++                                      SWAP(BMLoop*, l2, l3);
++                              }
++                              if (l1->head.eflag2 > l2->head.eflag2) {
++                                      SWAP(BMLoop*, l1, l2);
++                              }
++                              
++                              looptris[i*3] = l1;
++                              looptris[i*3+1] = l2;
++                              looptris[i*3+2] = l3;
 +
 +                              i += 1;
 +                      }
 +                      BLI_end_edgefill();
 +              }
 +      }
 +
 +      tm->tottri = i;
 +      tm->looptris = looptris;
 +}
 +
 +void BMEdit_RecalcTesselation(BMEditMesh *tm)
 +{
 +      BMEdit_RecalcTesselation_intern(tm);
 +
 +      if (tm->derivedFinal && tm->derivedFinal == tm->derivedCage) {
 +              if (tm->derivedFinal->recalcTesselation) 
 +                      tm->derivedFinal->recalcTesselation(tm->derivedFinal);
 +      } else if (tm->derivedFinal) {
 +              if (tm->derivedCage->recalcTesselation) 
 +                      tm->derivedCage->recalcTesselation(tm->derivedCage);
 +              if (tm->derivedFinal->recalcTesselation) 
 +                      tm->derivedFinal->recalcTesselation(tm->derivedFinal);
 +      }
 +}
 +
 +/*does not free the BMEditMesh struct itself*/
 +void BMEdit_Free(BMEditMesh *em)
 +{
 +      if(em->derivedFinal) {
 +              if (em->derivedFinal!=em->derivedCage) {
 +                      em->derivedFinal->needsFree= 1;
 +                      em->derivedFinal->release(em->derivedFinal);
 +              }
 +              em->derivedFinal= NULL;
 +      }
 +      if(em->derivedCage) {
 +              em->derivedCage->needsFree= 1;
 +              em->derivedCage->release(em->derivedCage);
 +              em->derivedCage= NULL;
 +      }
 +
 +      em->retopo_paint_data= NULL;
 +
 +      if (em->looptris) MEM_freeN(em->looptris);
 +
 +      if (em->vert_index) MEM_freeN(em->vert_index);
 +      if (em->edge_index) MEM_freeN(em->edge_index);
 +      if (em->face_index) MEM_freeN(em->face_index);
 +
 +      BM_Free_Mesh(em->bm);
 +}
 +
 +
 +/*
 +ok, basic design:
 +
 +the bmesh derivedmesh exposes the mesh as triangles.  it stores pointers
 +to three loops per triangle.  the derivedmesh stores a cache of tesselations
 +for each face.  this cache will smartly update as needed (though at first
 +it'll simply be more brute force).  keeping track of face/edge counts may
 +be a small problbm.
 +
 +this won't be the most efficient thing, considering that internal edges and
 +faces of tesselations are exposed.  looking up an edge by index in particular
 +is likely to be a little slow.
 +*/
 +
 +typedef struct EditDerivedBMesh {
 +      DerivedMesh dm;
 +
 +      Object *ob;
 +      BMEditMesh *tc;
 +
 +      float (*vertexCos)[3];
 +      float (*vertexNos)[3];
 +      float (*faceNos)[3];
 +
 +      /*lookup caches; these are rebuilt on dm->RecalcTesselation()
 +        (or when the derivedmesh is created, of course)*/
 +      GHash *vhash, *ehash, *fhash;
 +      BMVert **vtable;
 +      BMEdge **etable;
 +      BMFace **ftable;
 +
 +      /*private variables, for number of verts/edges/faces
 +        within the above hash/table members*/
 +      int tv, te, tf;
 +} EditDerivedBMesh;
 +
 +static void bmdm_recalc_lookups(EditDerivedBMesh *bmdm)
 +{
 +      BMIter iter;
 +      BMHeader *h;
 +      int a, i, iters[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
 +      
 +      bmdm->tv = bmdm->tc->bm->totvert;
 +      bmdm->te = bmdm->tc->bm->totedge;
 +      bmdm->tf = bmdm->tc->bm->totface;
 +
 +      if (bmdm->vhash) BLI_ghash_free(bmdm->vhash, NULL, NULL);
 +      if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL);
 +      if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL);
 +
 +      bmdm->vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
 +      bmdm->ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
 +      bmdm->fhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
 +      
 +      if (bmdm->vtable) MEM_freeN(bmdm->vtable);
 +      if (bmdm->etable) MEM_freeN(bmdm->etable);
 +      if (bmdm->ftable) MEM_freeN(bmdm->ftable);
 +      
 +      if (bmdm->tc->bm->totvert)
 +              bmdm->vtable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totvert, "bmdm->vtable");
 +      else bmdm->vtable = NULL;
 +
 +      if (bmdm->tc->bm->totedge)
 +              bmdm->etable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totedge, "bmdm->etable");
 +      else bmdm->etable = NULL;
 +      
 +      if (bmdm->tc->bm->totface)
 +              bmdm->ftable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totface, "bmdm->ftable");
 +      else bmdm->ftable = NULL;
 +      
 +      for (a=0; a<3; a++) {
 +              h = BMIter_New(&iter, bmdm->tc->bm, iters[a], NULL);
 +              for (i=0; h; h=BMIter_Step(&iter), i++) {
 +                      switch (a) {
 +                              case 0:
 +                                      bmdm->vtable[i] = (BMVert*) h;
 +                                      BLI_ghash_insert(bmdm->vhash, h, SET_INT_IN_POINTER(i));
 +                                      break;
 +                              case 1:
 +                                      bmdm->etable[i] = (BMEdge*) h;
 +                                      BLI_ghash_insert(bmdm->ehash, h, SET_INT_IN_POINTER(i));
 +                                      break;
 +                              case 2:
 +                                      bmdm->ftable[i] = (BMFace*) h;
 +                                      BLI_ghash_insert(bmdm->fhash, h, SET_INT_IN_POINTER(i));
 +                                      break;
 +
 +                      }
 +              }
 +      }
 +}
 +
 +static void bmDM_recalcTesselation(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +
 +      bmdm_recalc_lookups(bmdm);
 +}
 +
 +static void bmDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMVert *eve;
 +      BMIter iter;
 +      int i;
 +      
 +      eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; eve; i++, eve=BMIter_Step(&iter)) {
 +              if (bmdm->vertexCos) {
 +                      func(userData, i, bmdm->vertexCos[i], bmdm->vertexNos[i], NULL);
 +              } else {
 +                      func(userData, i, eve->co, eve->no, NULL);
 +              }
 +      }
 +}
 +static void bmDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int i;
 +      
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +              BMIter viter;
 +
 +              eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&viter), i++) {
 +                      BMINDEX_SET(eve, i);
 +              }
 +
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter))
 +                      func(userData, i, 
 +                           bmdm->vertexCos[BMINDEX_GET(eve)], 
 +                           bmdm->vertexCos[BMINDEX_GET(eve)]);
 +      } else {
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter))
 +                      func(userData, i, eed->v1->co, eed->v2->co);
 +      }
 +
 +}
 +
 +static void bmDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) 
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int i;
 +      
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +              BMIter viter;
 +
 +              eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&viter)) {
 +                      BMINDEX_SET(eve, i);
 +              }
 +
 +              glBegin(GL_LINES);
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
 +                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 +                              glVertex3fv(bmdm->vertexCos[BMINDEX_GET(eed->v1)]);
 +                              glVertex3fv(bmdm->vertexCos[BMINDEX_GET(eed->v2)]);
 +                      }
 +              }
 +              glEnd();
 +
 +      } else {
 +              glBegin(GL_LINES);
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
 +                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 +                              glVertex3fv(eed->v1->co);
 +                              glVertex3fv(eed->v2->co);
 +                      }
 +              }
 +              glEnd();
 +      }
 +}
 +
 +static void bmDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
 +{
 +      bmDM_drawMappedEdges(dm, NULL, NULL);
 +}
 +
 +static void bmDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) 
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int i;
 +
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++)
 +                      BMINDEX_SET(eve, i);
 +
 +              glBegin(GL_LINES);
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
 +                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 +                              setDrawInterpOptions(userData, i, 0.0);
 +                              glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(eed->v1)]);
 +                              setDrawInterpOptions(userData, i, 1.0);
 +                              glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(eed->v2)]);
 +                      }
 +              }
 +              glEnd();
 +      } else {
 +              glBegin(GL_LINES);
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
 +                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 +                              setDrawInterpOptions(userData, i, 0.0);
 +                              glVertex3fv(eed->v1->co);
 +                              setDrawInterpOptions(userData, i, 1.0);
 +                              glVertex3fv(eed->v2->co);
 +                      }
 +              }
 +              glEnd();
 +      }
 +}
 +
 +static void bmDM_drawUVEdges(DerivedMesh *dm)
 +{
 +#if 0
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMFace *efa;
 +      MTFace *tf;
 +
 +      glBegin(GL_LINES);
 +      for(efa= bmdm->tc->bm->faces.first; efa; efa= efa->next) {
 +              tf = CustomData_bm_get(&bmdm->tc->bm->pdata, efa->data, CD_MTFACE);
 +
 +              if(tf && !(efa->h)) {
 +                      glVertex2fv(tf->uv[0]);
 +                      glVertex2fv(tf->uv[1]);
 +
 +                      glVertex2fv(tf->uv[1]);
 +                      glVertex2fv(tf->uv[2]);
 +
 +                      if (!efa->v4) {
 +                              glVertex2fv(tf->uv[2]);
 +                              glVertex2fv(tf->uv[0]);
 +                      } else {
 +                              glVertex2fv(tf->uv[2]);
 +                              glVertex2fv(tf->uv[3]);
 +                              glVertex2fv(tf->uv[3]);
 +                              glVertex2fv(tf->uv[0]);
 +                      }
 +              }
 +      }
 +      glEnd();
 +#endif
 +}
 +
 +static void bmDM__calcFaceCent(BMesh *bm, BMFace *efa, float cent[3],
 +                               float (*vertexCos)[3])
 +{
 +      BMIter iter;
 +      BMLoop *l;
 +      int tot = 0;
 +      
 +      cent[0] = cent[1] = cent[2] = 0.0f;
 +      
 +      /*simple (and stupid) median (average) based method :/ */
 +
 +      l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
 +      for (; l; l=BMIter_Step(&iter)) {
 +              VECADD(cent, cent, l->v->co);
 +              tot++;
 +      }
 +
 +      if (tot==0) return;
 +      VECMUL(cent, 1.0f/(float)tot);
 +}
 +
 +static void bmDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMVert *eve;
 +      BMFace *efa;
 +      BMIter iter;
 +      float cent[3];
 +      int i;
 +
 +      if (bmdm->vertexCos) {
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter));
 +                      BMINDEX_SET(eve, i);
 +      }
 +
 +      efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
 +      for (i=0; efa; efa=BMIter_Step(&iter), i++) {
 +              bmDM__calcFaceCent(bmdm->tc->bm, efa, cent, bmdm->vertexCos);
 +              func(userData, i, cent, bmdm->vertexCos?bmdm->faceNos[i]:efa->no);
 +      }
 +}
 +
 +static void bmDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMFace *efa;
 +      BMIter iter;
 +      int i, draw;
 +
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +              
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter))
 +                      BMINDEX_SET(eve, i);
 +
 +              efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
 +              for (i=0; efa; efa=BMIter_Step(&iter), i++)
 +                      BMINDEX_SET(efa, i);
 +
 +              for (i=0; i<bmdm->tc->tottri; i++) {
 +                      BMLoop **l = bmdm->tc->looptris[i];
 +                      int drawSmooth;
 +                      
 +                      drawSmooth = (efa->head.flag & BM_SMOOTH);
 +                      efa = l[0]->f;
 +
 +                      draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BMINDEX_GET(efa), &drawSmooth);
 +                      if(draw) {
 +                              if (draw==2) { /* enabled with stipple */
 +                                      glEnable(GL_POLYGON_STIPPLE);
 +                                      glPolygonStipple(stipple_quarttone);
 +                              }
 +                              
 +                              glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 +
 +                              glBegin(GL_TRIANGLES);
 +
 +                              if (!drawSmooth) {
 +                                      glNormal3fv(efa->no);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[0]->v)]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[1]->v)]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[2]->v)]);
 +                              } else {
 +                                      glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[0]->v)]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[0]->v)]);
 +                                      glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[1]->v)]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[1]->v)]);
 +                                      glNormal3fv(bmdm->vertexNos[(int) BMINDEX_GET(l[2]->v)]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(l[2]->v)]);
 +                              }
 +                              glEnd();
 +
 +                              if (draw==2)
 +                                      glDisable(GL_POLYGON_STIPPLE);
 +                      }
 +              }
 +      } else {
 +              efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
 +              for (i=0; efa; efa=BMIter_Step(&iter), i++)
 +                      BMINDEX_SET(efa, i);
 +
 +              for (i=0; i<bmdm->tc->tottri; i++) {
 +                      BMLoop **l = bmdm->tc->looptris[i];
 +                      int drawSmooth;
 +
 +                      efa = l[0]->f;
 +
 +                      drawSmooth = (efa->head.flag & BM_SMOOTH);
 +                      
 +                      draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BMINDEX_GET(efa), &drawSmooth);
 +                      if(draw) {
 +                              if (draw==2) { /* enabled with stipple */
 +                                      glEnable(GL_POLYGON_STIPPLE);
 +                                      glPolygonStipple(stipple_quarttone);
 +                              }
 +                              glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 +                              
 +                              glBegin(GL_TRIANGLES);
 +                              if (!drawSmooth) {
 +                                      glNormal3fv(efa->no);
 +                                      glVertex3fv(l[0]->v->co);
 +                                      glVertex3fv(l[1]->v->co);
 +                                      glVertex3fv(l[2]->v->co);
 +                              } else {
 +                                      glNormal3fv(l[0]->v->no);
 +                                      glVertex3fv(l[0]->v->co);
 +                                      glNormal3fv(l[1]->v->no);
 +                                      glVertex3fv(l[1]->v->co);
 +                                      glNormal3fv(l[2]->v->no);
 +                                      glVertex3fv(l[2]->v->co);
 +                              }
 +                              glEnd();
 +                              
 +                              if (draw==2)
 +                                      glDisable(GL_POLYGON_STIPPLE);
 +                      }
 +              }
 +      }
 +}
 +
 +static void bmDM_drawFacesTex_common(DerivedMesh *dm,
 +               int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
 +               int (*drawParamsMapped)(void *userData, int index),
 +               void *userData) 
 +{
 +#if 0
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMesh *bm= bmdm->tc->bm;
 +      float (*vertexCos)[3]= bmdm->vertexCos;
 +      float (*vertexNos)[3]= bmdm->vertexNos;
 +      BMFace *efa;
 +      BMIter iter;
 +      int i;
 +
 +      /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
 +      glShadeModel(GL_SMOOTH);
 +      
 +      if (vertexCos) {
 +              BMVert *eve;
 +
 +              for (i=0,eve=bm->verts.first; eve; eve= eve->next)
 +                      BMINDEX_SET(eve, i++);
 +
 +              for (i=0,efa= bm->faces.first; efa; i++,efa= efa->next) {
 +                      MTFace *tf= CustomData_bm_get(&bm->pdata, efa->data, CD_MTFACE);
 +                      MCol *mcol= CustomData_bm_get(&bm->pdata, efa->data, CD_MCOL);
 +                      unsigned char *cp= NULL;
 +                      int drawSmooth= (efa->flag & ME_SMOOTH);
 +                      int flag;
 +
 +                      if(drawParams)
 +                              flag= drawParams(tf, mcol, efa->mat_nr);
 +                      else if(drawParamsMapped)
 +                              flag= drawParamsMapped(userData, i);
 +                      else
 +                              flag= 1;
 +
 +                      if(flag != 0) { /* flag 0 == the face is hidden or invisible */
 +                              
 +                              /* we always want smooth here since otherwise vertex colors dont interpolate */
 +                              if (mcol) {
 +                                      if (flag==1) {
 +                                              cp= (unsigned char*)mcol;
 +                                      }
 +                              } else {
 +                                      glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 +                              } 
 +                              
 +                              glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
 +                              if (!drawSmooth) {
 +                                      glNormal3fv(bmdm->faceNos[i]);
 +
 +                                      if(tf) glTexCoord2fv(tf->uv[0]);
 +                                      if(cp) glColor3ub(cp[3], cp[2], cp[1]);
 +                                      glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 +
 +                                      if(tf) glTexCoord2fv(tf->uv[1]);
 +                                      if(cp) glColor3ub(cp[7], cp[6], cp[5]);
 +                                      glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 +
 +                                      if(tf) glTexCoord2fv(tf->uv[2]);
 +                                      if(cp) glColor3ub(cp[11], cp[10], cp[9]);
 +                                      glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 +
 +                                      if(efa->v4) {
 +                                              if(tf) glTexCoord2fv(tf->uv[3]);
 +                                              if(cp) glColor3ub(cp[15], cp[14], cp[13]);
 +                                              glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 +                                      }
 +                              } else {
 +                                      if(tf) glTexCoord2fv(tf->uv[0]);
 +                                      if(cp) glColor3ub(cp[3], cp[2], cp[1]);
 +                                      glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
 +                                      glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 +
 +                                      if(tf) glTexCoord2fv(tf->uv[1]);
 +                                      if(cp) glColor3ub(cp[7], cp[6], cp[5]);
 +                                      glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
 +                                      glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 +
 +                                      if(tf) glTexCoord2fv(tf->uv[2]);
 +                                      if(cp) glColor3ub(cp[11], cp[10], cp[9]);
 +                                      glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
 +                                      glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 +
 +                                      if(efa->v4) {
 +                                              if(tf) glTexCoord2fv(tf->uv[3]);
 +                                              if(cp) glColor3ub(cp[15], cp[14], cp[13]);
 +                                              glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
 +                                              glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 +                                      }
 +                              }
 +                              glEnd();
 +                      }
 +              }
 +      } else {
 +              for (i=0,efa= bm->faces.first; efa; i++,efa= efa->next) {
 +                      MTFace *tf= CustomData_bm_get(&bm->pdata, efa->data, CD_MTFACE);
 +                      MCol *mcol= CustomData_bm_get(&bm->pdata, efa->data, CD_MCOL);
 +                      unsigned char *cp= NULL;
 +                      int drawSmooth= (efa->flag & ME_SMOOTH);
 +                      int flag;
 +
 +                      if(drawParams)
 +                              flag= drawParams(tf, mcol, efa->mat_nr);
 +                      else if(drawParamsMapped)
 +                              flag= drawParamsMapped(userData, i);
 +                      else
 +                              flag= 1;
 +
 +                      if(flag != 0) { /* flag 0 == the face is hidden or invisible */
 +                              /* we always want smooth here since otherwise vertex colors dont interpolate */
 +                              if (mcol) {
 +                                      if (flag==1) {
 +                                              cp= (unsigned char*)mcol;
 +                                      }
 +                              } else {
 +                                      glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 +                              } 
 +
 +                              glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
 +                              if (!drawSmooth) {
 +                                      glNormal3fv(efa->n);
 +
 +                                      if(tf) glTexCoord2fv(tf->uv[0]);
 +                                      if(cp) glColor3ub(cp[3], cp[2], cp[1]);
 +                                      glVertex3fv(efa->v1->co);
 +
 +                                      if(tf) glTexCoord2fv(tf->uv[1]);
 +                                      if(cp) glColor3ub(cp[7], cp[6], cp[5]);
 +                                      glVertex3fv(efa->v2->co);
 +
 +                                      if(tf) glTexCoord2fv(tf->uv[2]);
 +                                      if(cp) glColor3ub(cp[11], cp[10], cp[9]);
 +                                      glVertex3fv(efa->v3->co);
 +
 +                                      if(efa->v4) {
 +                                              if(tf) glTexCoord2fv(tf->uv[3]);
 +                                              if(cp) glColor3ub(cp[15], cp[14], cp[13]);
 +                                              glVertex3fv(efa->v4->co);
 +                                      }
 +                              } else {
 +                                      if(tf) glTexCoord2fv(tf->uv[0]);
 +                                      if(cp) glColor3ub(cp[3], cp[2], cp[1]);
 +                                      glNormal3fv(efa->v1->no);
 +                                      glVertex3fv(efa->v1->co);
 +
 +                                      if(tf) glTexCoord2fv(tf->uv[1]);
 +                                      if(cp) glColor3ub(cp[7], cp[6], cp[5]);
 +                                      glNormal3fv(efa->v2->no);
 +                                      glVertex3fv(efa->v2->co);
 +
 +                                      if(tf) glTexCoord2fv(tf->uv[2]);
 +                                      if(cp) glColor3ub(cp[11], cp[10], cp[9]);
 +                                      glNormal3fv(efa->v3->no);
 +                                      glVertex3fv(efa->v3->co);
 +
 +                                      if(efa->v4) {
 +                                              if(tf) glTexCoord2fv(tf->uv[3]);
 +                                              if(cp) glColor3ub(cp[15], cp[14], cp[13]);
 +                                              glNormal3fv(efa->v4->no);
 +                                              glVertex3fv(efa->v4->co);
 +                                      }
 +                              }
 +                              glEnd();
 +                      }
 +              }
 +      }
 +#endif
 +}
 +
 +static void bmDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
 +{
 +      bmDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
 +}
 +
 +static void bmDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
 +{
 +      bmDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
 +}
 +
 +static void bmDM_drawMappedFacesGLSL(DerivedMesh *dm,
 +               int (*setMaterial)(int, void *attribs),
 +               int (*setDrawOptions)(void *userData, int index), void *userData) 
 +{
 +#if 0
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMesh *bm= bmdm->tc->bm;
 +      float (*vertexCos)[3]= bmdm->vertexCos;
 +      float (*vertexNos)[3]= bmdm->vertexNos;
 +      BMVert *eve;
 +      BMFace *efa;
 +      DMVertexAttribs attribs;
 +      GPUVertexAttribs gattribs;
 +      MTFace *tf;
 +      int transp, new_transp, orig_transp, tfoffset;
 +      int i, b, matnr, new_matnr, dodraw, layer;
 +
 +      dodraw = 0;
 +      matnr = -1;
 +
 +      transp = GPU_get_material_blend_mode();
 +      orig_transp = transp;
 +      layer = CustomData_get_layer_index(&bm->pdata, CD_MTFACE);
 +      tfoffset = (layer == -1)? -1: bm->pdata.layers[layer].offset;
 +
 +      memset(&attribs, 0, sizeof(attribs));
 +
 +      /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
 +      glShadeModel(GL_SMOOTH);
 +
 +      for (i=0,eve=bm->verts.first; eve; eve= eve->next)
 +              BMINDEX_SET(eve, i++);
 +
 +#define PASSATTRIB(efa, eve, vert) {                                                                                  \
 +      if(attribs.totorco) {                                                                                                           \
 +              float *orco = attribs.orco.array[BMINDEX_GET(eve)];                                                     \
 +              glVertexAttrib3fvARB(attribs.orco.glIndex, orco);                                               \
 +      }                                                                                                                                                       \
 +      for(b = 0; b < attribs.tottface; b++) {                                                                         \
 +              MTFace *_tf = (MTFace*)((char*)efa->data + attribs.tface[b].bmOffset);  \
 +              glVertexAttrib2fvARB(attribs.tface[b].glIndex, _tf->uv[vert]);                  \
 +      }                                                                                                                                                       \
 +      for(b = 0; b < attribs.totmcol; b++) {                                                                          \
 +              MCol *cp = (MCol*)((char*)efa->data + attribs.mcol[b].bmOffset);                \
 +              GLubyte col[4];                                                                                                                 \
 +              col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a;                             \
 +              glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, col);                                    \
 +      }                                                                                                                                                       \
 +      if(attribs.tottang) {                                                                                                           \
 +              float *tang = attribs.tang.array[i*4 + vert];                                                   \
 +              glVertexAttrib3fvARB(attribs.tang.glIndex, tang);                                               \
 +      }                                                                                                                                                       \
 +}
 +
 +      for (i=0,efa= bm->faces.first; efa; i++,efa= efa->next) {
 +              int drawSmooth= (efa->flag & ME_SMOOTH);
 +
 +              if(setDrawOptions && !setDrawOptions(userData, i))
 +                      continue;
 +
 +              new_matnr = efa->mat_nr + 1;
 +              if(new_matnr != matnr) {
 +                      dodraw = setMaterial(matnr = new_matnr, &gattribs);
 +                      if(dodraw)
 +                              DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
 +              }
 +
 +              if(tfoffset != -1) {
 +                      tf = (MTFace*)((char*)efa->data)+tfoffset;
 +                      new_transp = tf->transp;
 +
 +                      if(new_transp != transp) {
 +                              if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
 +                                      GPU_set_material_blend_mode(orig_transp);
 +                              else
 +                                      GPU_set_material_blend_mode(new_transp);
 +                              transp = new_transp;
 +                      }
 +              }
 +
 +              if(dodraw) {
 +                      glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
 +                      if (!drawSmooth) {
 +                              if(vertexCos) glNormal3fv(bmdm->faceNos[i]);
 +                              else glNormal3fv(efa->n);
 +
 +                              PASSATTRIB(efa, efa->v1, 0);
 +                              if(vertexCos) glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 +                              else glVertex3fv(efa->v1->co);
 +
 +                              PASSATTRIB(efa, efa->v2, 1);
 +                              if(vertexCos) glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 +                              else glVertex3fv(efa->v2->co);
 +
 +                              PASSATTRIB(efa, efa->v3, 2);
 +                              if(vertexCos) glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 +                              else glVertex3fv(efa->v3->co);
 +
 +                              if(efa->v4) {
 +                                      PASSATTRIB(efa, efa->v4, 3);
 +                                      if(vertexCos) glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 +                                      else glVertex3fv(efa->v4->co);
 +                              }
 +                      } else {
 +                              PASSATTRIB(efa, efa->v1, 0);
 +                              if(vertexCos) {
 +                                      glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
 +                                      glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 +                              }
 +                              else {
 +                                      glNormal3fv(efa->v1->no);
 +                                      glVertex3fv(efa->v1->co);
 +                              }
 +
 +                              PASSATTRIB(efa, efa->v2, 1);
 +                              if(vertexCos) {
 +                                      glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
 +                                      glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 +                              }
 +                              else {
 +                                      glNormal3fv(efa->v2->no);
 +                                      glVertex3fv(efa->v2->co);
 +                              }
 +
 +                              PASSATTRIB(efa, efa->v3, 2);
 +                              if(vertexCos) {
 +                                      glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
 +                                      glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 +                              }
 +                              else {
 +                                      glNormal3fv(efa->v3->no);
 +                                      glVertex3fv(efa->v3->co);
 +                              }
 +
 +                              if(efa->v4) {
 +                                      PASSATTRIB(efa, efa->v4, 3);
 +                                      if(vertexCos) {
 +                                              glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
 +                                              glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 +                                      }
 +                                      else {
 +                                              glNormal3fv(efa->v4->no);
 +                                              glVertex3fv(efa->v4->co);
 +                                      }
 +                              }
 +                      }
 +                      glEnd();
 +              }
 +      }
 +#endif
 +}
 +
 +static void bmDM_drawFacesGLSL(DerivedMesh *dm,
 +               int (*setMaterial)(int, void *attribs))
 +{
 +      dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
 +}
 +
 +static void bmDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMVert *eve;
 +      BMIter iter;
 +      int i;
 +
 +      if (bmdm->tc->bm->verts.first) {
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++) {
 +                      if (bmdm->vertexCos) {
 +                              DO_MINMAX(bmdm->vertexCos[i], min_r, max_r);
 +                      } else {
 +                              DO_MINMAX(eve->co, min_r, max_r);
 +                      }
 +              }
 +      } else {
 +              min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
 +      }
 +}
 +static int bmDM_getNumVerts(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +
 +      return bmdm->tc->bm->totvert;
 +}
 +
 +static int bmDM_getNumEdges(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +
 +      return bmdm->tc->bm->totedge;
 +}
 +
 +static int bmDM_getNumTessFaces(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      
 +      return bmdm->tc->tottri;
 +}
 +
 +static int bmDM_getNumFaces(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      
 +      return bmdm->tc->bm->totface;
 +}
 +
 +static int bmvert_to_mvert(BMVert *ev, MVert *vert_r)
 +{
 +      VECCOPY(vert_r->co, ev->co);
 +
 +      vert_r->no[0] = (short)(ev->no[0] * 32767.0f);
 +      vert_r->no[1] = (short)(ev->no[1] * 32767.0f);
 +      vert_r->no[2] = (short)(ev->no[2] * 32767.0f);
 +
 +      /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
 +      vert_r->flag = BMFlags_To_MEFlags(ev);
 +      vert_r->mat_nr = 0;
 +      vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
 +}
 +
 +static void bmDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
 +{
 +      BMVert *ev;
 +      BMIter iter;
 +      int i;
 +
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tv) {
 +              printf("error in bmDM_getVert.\n");
 +              return;
 +      }
 +
 +      ev = ((EditDerivedBMesh *)dm)->vtable[index];
 +      bmvert_to_mvert(ev, vert_r);
 +}
 +
 +static void bmDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMEdge *e;
 +      BMVert *ev, *v1, *v2;
 +      BMIter iter;
 +      int i;
 +
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->te) {
 +              printf("error in bmDM_getEdge.\n");
 +              return;
 +      }
 +
 +      e = bmdm->etable[index];
 +
 +      edge_r->crease = (unsigned char) (e->crease*255.0f);
 +      edge_r->bweight = (unsigned char) (e->bweight*255.0f);
 +      /* TODO what to do with edge_r->flag? */
 +      edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
 +      edge_r->flag |= BMFlags_To_MEFlags(e);
 +#if 0
 +      /* this needs setup of f2 field */
 +      if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
 +#endif
 +      
 +      edge_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v1));
 +      edge_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v2));
 +}
 +
 +static void bmDM_getTessFace(DerivedMesh *dm, int index, MFace *face_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMesh *bm = bmdm->tc->bm;
 +      BMFace *ef;
 +      BMIter iter;
 +      BMLoop **l;
 +      int i;
 +      
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tf) {
 +              printf("error in bmDM_getTessFace.\n");
 +              return;
 +      }
 +
 +      l = ((EditDerivedBMesh *)dm)->tc->looptris[index];
 +
 +      ef = l[0]->f;
 +
 +      face_r->mat_nr = (unsigned char) ef->mat_nr;
 +      face_r->flag = BMFlags_To_MEFlags(ef);
 +
 +      face_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[0]->v));
 +      face_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[1]->v));
 +      face_r->v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[2]->v));
 +      face_r->v4 = 0;
 +
 +      test_index_face(face_r, NULL, 0, 3);
 +}
 +
 +static void bmDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
 +{
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMVert *ev;
 +      BMIter iter;
 +
 +      ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for( ; ev; ev = BMIter_Step(&iter), ++vert_r) {
 +              VECCOPY(vert_r->co, ev->co);
 +
 +              vert_r->no[0] = (short) (ev->no[0] * 32767.0);
 +              vert_r->no[1] = (short) (ev->no[1] * 32767.0);
 +              vert_r->no[2] = (short) (ev->no[2] * 32767.0);
 +
 +              /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
 +              vert_r->mat_nr = 0;
 +              vert_r->flag = BMFlags_To_MEFlags(ev);
 +              vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
 +      }
 +}
 +
 +static void bmDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
 +{
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMEdge *ee;
 +      BMIter iter;
 +      BMVert *ev;
 +      int i;
 +
 +      /* store vertex indices in tmp union */
 +      ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; ev; ev=BMIter_Step(&iter), i++)
 +              BMINDEX_SET(ev, i);
 +
 +      ee = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
 +      for( ; ee; ee=BMIter_Step(&iter)) {
 +              edge_r->crease = (unsigned char) (ee->crease*255.0f);
 +              edge_r->bweight = (unsigned char) (ee->bweight*255.0f);
 +              /* TODO what to do with edge_r->flag? */
 +              edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
 +              if (ee->head.flag & BM_SEAM) edge_r->flag |= ME_SEAM;
 +              if (ee->head.flag & BM_SHARP) edge_r->flag |= ME_SHARP;
 +#if 0
 +              /* this needs setup of f2 field */
 +              if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
 +#endif
 +
 +              edge_r->v1 = (int)BMINDEX_GET(ee->v1);
 +              edge_r->v2 = (int)BMINDEX_GET(ee->v2);
 +      }
 +}
 +
 +static void bmDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMFace *ef;
 +      BMVert *ev;
 +      BMIter iter;
 +      BMLoop **l;
 +      int i;
 +
 +      /* store vertexes indices in tmp union */
 +      ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; ev; ev=BMIter_Step(&iter), i++)
 +              BMINDEX_SET(ev, i);
 +
 +      for (i=0; i<bmdm->tc->tottri; i++) {
 +              l = bmdm->tc->looptris[i];
 +              ef = l[0]->f;
 +
 +              face_r->mat_nr = (unsigned char) ef->mat_nr;
 +
 +              /*HACK/TODO: need to convert this*/
 +              face_r->flag = ef->head.flag;
 +
 +              face_r->v1 = BMINDEX_GET(l[0]->v);
 +              face_r->v2 = BMINDEX_GET(l[1]->v);
 +              face_r->v3 = BMINDEX_GET(l[2]->v);
 +              face_r->v4 = 0;
 +
 +              test_index_face(face_r, NULL, 0, 3);
 +      }
 +}
 +
 +static void *bmDM_getFaceDataArray(DerivedMesh *dm, int type)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMesh *bm= bmdm->tc->bm;
 +      BMFace *efa;
 +      char *data, *bmdata;
 +      void *datalayer;
 +      int index, offset, size, i;
 +
 +      datalayer = DM_get_face_data_layer(dm, type);
 +      if(datalayer)
 +              return datalayer;
 +
 +      /* layers are store per face for editmesh, we convert to a tbmporary
 +       * data layer array in the derivedmesh when these are requested */
 +      if(type == CD_MTFACE || type == CD_MCOL) {
 +              index = CustomData_get_layer_index(&bm->pdata, type);
 +
 +              if(index != -1) {
 +                      offset = bm->pdata.layers[index].offset;
 +                      size = CustomData_sizeof(type);
 +
 +                      DM_add_face_layer(dm, type, CD_CALLOC, NULL);
 +                      index = CustomData_get_layer_index(&dm->faceData, type);
 +                      dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
 +
 +                      data = datalayer = DM_get_face_data_layer(dm, type);
 +                      for (i=0; i<bmdm->tc->tottri; i++, data+=size) {
 +                              efa = bmdm->tc->looptris[i][0]->f;
 +                              /*BMESH_TODO: need to still add tface data,
 +                                derived from the loops.*/
 +                              bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, type);
 +                              memcpy(data, bmdata, size);
 +                      }
 +              }
 +      }
 +
 +      return datalayer;
 +}
 +
 +typedef struct bmDM_loopIter {
 +      DMLoopIter head;
 +
 +      BMFace *f;
 +      BMLoop *l, *nextl;
 +      BMIter iter;
 +      BMesh *bm;
 +} bmDM_loopIter;
 +
 +typedef struct bmDM_faceIter {
 +      DMFaceIter head;
 +
 +      BMFace *f, *nextf;
 +      BMIter iter;
 +      BMesh *bm;
 +
 +      bmDM_loopIter loopiter;
 +} bmDM_faceIter;
 +
 +void bmDM_faceIterStep(void *self)
 +{
 +      bmDM_faceIter *iter = self;
 +      
 +      iter->f = iter->nextf;
 +
 +      iter->head.mat_nr = iter->f->mat_nr;
 +      iter->head.flags = BMFlags_To_MEFlags(iter->f);
 +      iter->head.index++;
 +
 +      iter->nextf = BMIter_Step(&iter->iter);
 +
 +      if (!iter->nextf) iter->head.done = 1;
 +}
 +
 +void *bmDM_getFaceCDData(void *self, int type, int layer)
 +{
 +      bmDM_faceIter *iter = self;
 +
 +      if (layer == -1) 
 +              return CustomData_bmesh_get(&iter->bm->pdata, iter->f->head.data, type);
 +      else return CustomData_bmesh_get_n(&iter->bm->pdata, iter->f->head.data, type, layer);
 +}
 +
 +void bmDM_loopIterStep(void *self)
 +{
 +      bmDM_loopIter *iter = self;
 +
 +      iter->l = iter->nextl;
 +
 +      bmvert_to_mvert(iter->l->v, &iter->head.v);
 +      iter->head.index++;
 +      iter->head.vindex = BMINDEX_GET(iter->l->v);
 +      iter->head.eindex = BMINDEX_GET(iter->l->e);
 +
 +      iter->nextl = BMIter_Step(&iter->iter);
 +
 +      if (!iter->nextl) iter->head.done = 1;
 +}
 +
 +void *bmDM_getLoopCDData(void *self, int type, int layer)
 +{
 +      bmDM_loopIter *iter = self;
 +
 +      if (layer == -1) 
 +              return CustomData_bmesh_get(&iter->bm->ldata, iter->l->head.data, type);
 +      else return CustomData_bmesh_get_n(&iter->bm->ldata, iter->l->head.data, type, layer);
 +}
 +
 +void *bmDM_getVertCDData(void *self, int type, int layer)
 +{
 +      bmDM_loopIter *iter = self;
 +
 +      if (layer == -1) 
 +              return CustomData_bmesh_get(&iter->bm->vdata, iter->l->v->head.data, type);
 +      else return CustomData_bmesh_get_n(&iter->bm->vdata, iter->l->v->head.data, type, layer);
 +}
 +
 +void bmDM_iterFree(void *self)
 +{
 +      MEM_freeN(self);
 +}
 +
 +void bmDM_nulliterFree(void *self)
 +{
 +}
 +
 +DMLoopIter *bmDM_newLoopsIter(void *faceiter)
 +{
 +      bmDM_faceIter *fiter = faceiter;
 +      bmDM_loopIter *iter = &fiter->loopiter;
 +
 +      memset(&fiter->loopiter, 0, sizeof(bmDM_loopIter));
 +
 +      iter->bm = fiter->bm;
 +      iter->f = fiter->f;
 +      iter->nextl = BMIter_New(&iter->iter, iter->bm, BM_LOOPS_OF_FACE, iter->f);
 +
 +      iter->head.step = bmDM_loopIterStep;
 +      iter->head.getLoopCDData = bmDM_getLoopCDData;
 +      iter->head.getVertCDData = bmDM_getVertCDData;
 +
 +      bmvert_to_mvert(iter->nextl->v, &iter->head.v);
 +      iter->head.vindex = BMINDEX_GET(iter->nextl->v);
 +      iter->head.eindex = BMINDEX_GET(iter->nextl->e);
 +
 +      return (DMLoopIter*) iter;
 +}
 +
 +static DMFaceIter *bmDM_getFaceIter(void *dm)
 +{
 +      EditDerivedBMesh *bmdm= dm;
 +      bmDM_faceIter *iter = MEM_callocN(sizeof(bmDM_faceIter), "bmDM_faceIter");
 +      BMIter biter;
 +      BMVert *v;
 +      BMEdge *e;
 +      int i;
 +
 +      iter->bm = bmdm->tc->bm;
 +      iter->f = iter->nextf = BMIter_New(&iter->iter, iter->bm, BM_FACES_OF_MESH, NULL);
 +      
 +      iter->head.step = bmDM_faceIterStep;
 +      iter->head.free = bmDM_iterFree;
 +      iter->head.getCDData = bmDM_getFaceCDData;
 +      iter->head.getLoopsIter = bmDM_newLoopsIter;
 +      
 +      iter->head.mat_nr = iter->f->mat_nr;
 +      iter->head.flags = BMFlags_To_MEFlags(iter->f);
 +
 +      /*set up vert/edge indices*/
 +      i = 0;
 +      BM_ITER(v, &biter, iter->bm, BM_VERTS_OF_MESH, NULL) {
 +              BMINDEX_SET(v, i);
 +              i++;
 +      }
 +
 +      i = 0;
 +      BM_ITER(e, &biter, iter->bm, BM_EDGES_OF_MESH, NULL) {
 +              BMINDEX_SET(e, i);
 +              i++;
 +      }
 +
 +      return (DMFaceIter*) iter;
 +}
 +
 +static void bmDM_release(void *dm)
 +{
 +      EditDerivedBMesh *bmdm= dm;
 +
 +      if (DM_release(dm)) {
 +              if (bmdm->vertexCos) {
 +                      MEM_freeN(bmdm->vertexCos);
 +                      MEM_freeN(bmdm->vertexNos);
 +                      MEM_freeN(bmdm->faceNos);
 +              }
 +              
 +              BLI_ghash_free(bmdm->fhash, NULL, NULL);
 +              BLI_ghash_free(bmdm->ehash, NULL, NULL);
 +              BLI_ghash_free(bmdm->vhash, NULL, NULL);
 +
 +              if (bmdm->vtable) MEM_freeN(bmdm->vtable);
 +              if (bmdm->etable) MEM_freeN(bmdm->etable);
 +              if (bmdm->ftable) MEM_freeN(bmdm->ftable);
 +              
 +              MEM_freeN(bmdm);
 +      }
 +}
 +
 +DerivedMesh *getEditDerivedBMesh(BMEditMesh *em, Object *ob,
 +                                           float (*vertexCos)[3])
 +{
 +      EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), "bmdm");
 +      BMesh *bm = em->bm;
 +
 +      bmdm->tc = em;
 +
 +      DM_init((DerivedMesh*)bmdm, em->bm->totvert, em->bm->totedge, em->tottri,
 +               em->bm->totloop, em->bm->totface);
 +
 +      bmdm->dm.getMinMax = bmDM_getMinMax;
 +
 +      bmdm->dm.getNumVerts = bmDM_getNumVerts;
 +      bmdm->dm.getNumEdges = bmDM_getNumEdges;
 +      bmdm->dm.getNumTessFaces = bmDM_getNumTessFaces;
 +      bmdm->dm.getNumFaces = bmDM_getNumFaces;
 +
 +      bmdm->dm.getVert = bmDM_getVert;
 +      bmdm->dm.getEdge = bmDM_getEdge;
 +      bmdm->dm.getTessFace = bmDM_getTessFace;
 +      bmdm->dm.copyVertArray = bmDM_copyVertArray;
 +      bmdm->dm.copyEdgeArray = bmDM_copyEdgeArray;
 +      bmdm->dm.copyTessFaceArray = bmDM_copyFaceArray;
 +      bmdm->dm.getTessFaceDataArray = bmDM_getFaceDataArray;
 +
 +      bmdm->dm.newFaceIter = bmDM_getFaceIter;
 +      bmdm->dm.recalcTesselation = bmDM_recalcTesselation;
 +
 +      bmdm->dm.foreachMappedVert = bmDM_foreachMappedVert;
 +      bmdm->dm.foreachMappedEdge = bmDM_foreachMappedEdge;
 +      bmdm->dm.foreachMappedFaceCenter = bmDM_foreachMappedFaceCenter;
 +
 +      bmdm->dm.drawEdges = bmDM_drawEdges;
 +      bmdm->dm.drawMappedEdges = bmDM_drawMappedEdges;
 +      bmdm->dm.drawMappedEdgesInterp = bmDM_drawMappedEdgesInterp;
 +      bmdm->dm.drawMappedFaces = bmDM_drawMappedFaces;
 +      bmdm->dm.drawMappedFacesTex = bmDM_drawMappedFacesTex;
 +      bmdm->dm.drawMappedFacesGLSL = bmDM_drawMappedFacesGLSL;
 +      bmdm->dm.drawFacesTex = bmDM_drawFacesTex;
 +      bmdm->dm.drawFacesGLSL = bmDM_drawFacesGLSL;
 +      bmdm->dm.drawUVEdges = bmDM_drawUVEdges;
 +
 +      bmdm->dm.release = bmDM_release;
 +      
 +      bmdm->vertexCos = vertexCos;
 +
 +      if(CustomData_has_layer(&bm->vdata, CD_MDEFORMVERT)) {
 +              BMIter iter;
 +              BMVert *eve;
 +              int i;
 +
 +              DM_add_vert_layer(&bmdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
 +              
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++)
 +                      DM_set_vert_data(&bmdm->dm, i, CD_MDEFORMVERT,
 +                                       CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_MDEFORMVERT));
 +      }
 +
 +      if(vertexCos) {
 +              BMVert *eve;
 +              BMIter iter;
 +              int totface = bm->totface;
 +              int i;
 +              
 +              eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++)
 +                      BMINDEX_SET(eve, i);
 +
 +              bmdm->vertexNos = MEM_callocN(sizeof(*bmdm->vertexNos)*i, "bmdm_vno");
 +              bmdm->faceNos = MEM_mallocN(sizeof(*bmdm->faceNos)*totface, "bmdm_vno");
 +
 +              for (i=0; i<bmdm->tc->tottri; i++) {
 +                      BMLoop **l = bmdm->tc->looptris[i];
 +                      float *v1 = vertexCos[(int) BMINDEX_GET(l[0]->v)];
 +                      float *v2 = vertexCos[(int) BMINDEX_GET(l[1]->v)];
 +                      float *v3 = vertexCos[(int) BMINDEX_GET(l[2]->v)];
 +                      float *no = bmdm->faceNos[i];
 +                      
 +                      CalcNormFloat(v1, v2, v3, no);
 +                      VecAddf(bmdm->vertexNos[BMINDEX_GET(l[0]->v)], bmdm->vertexNos[BMINDEX_GET(l[0]->v)], no);
 +                      VecAddf(bmdm->vertexNos[BMINDEX_GET(l[1]->v)], bmdm->vertexNos[BMINDEX_GET(l[1]->v)], no);
 +                      VecAddf(bmdm->vertexNos[BMINDEX_GET(l[2]->v)], bmdm->vertexNos[BMINDEX_GET(l[2]->v)], no);
 +              }
 +
 +              eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++) {
 +                      float *no = bmdm->vertexNos[i];
 +                      /* following Mesh convention; we use vertex coordinate itself
 +                       * for normal in this case */
 +                      if (Normalize(no)==0.0) {
 +                              VECCOPY(no, vertexCos[i]);
 +                              Normalize(no);
 +                      }
 +              }
 +      }
 +
 +      bmdm_recalc_lookups(bmdm);
 +
 +      return (DerivedMesh*) bmdm;
 +}
index 9004f4b9973c0c60d80eab0c3b3a2e0941cf85ad,b792564f50cd370f31ff6fffc72a6073e029486d..45b9739d3c2491cb2b6cfb4bbea7cc0359e0d7e7
@@@ -277,7 -300,7 +300,7 @@@ void psys_calc_dmcache(Object *ob, Deri
                        origindex= DM_get_vert_data_layer(dm, CD_ORIGINDEX);
                }
                else { /* FROM_FACE/FROM_VOLUME */
--                      totdmelem= dm->getNumFaces(dm);
++                      totdmelem= dm->getNumTessFaces(dm);
                        totelem= me->totface;
                        origindex= DM_get_face_data_layer(dm, CD_ORIGINDEX);
                }
@@@ -409,8 -432,8 +432,8 @@@ static void distribute_particles_in_gri
                int a, a1, a2, a0mul, a1mul, a2mul, totface;
                int amax= from==PART_FROM_FACE ? 3 : 1;
  
--              totface=dm->getNumFaces(dm);
 -              mface=dm->getFaceDataArray(dm,CD_MFACE);
++              totface=dm->getNumTessFaces(dm);
 +              mface=dm->getTessFaceDataArray(dm,CD_MFACE);
                
                for(a=0; a<amax; a++){
                        if(a==0){ a0mul=res*res; a1mul=res; a2mul=1; }
@@@ -660,7 -683,7 +683,7 @@@ void psys_thread_distribute_particle(Pa
                if(from==PART_FROM_VOLUME){
                        MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
  
--                      tot=dm->getNumFaces(dm);
++                      tot=dm->getNumTessFaces(dm);
  
                        psys_interpolate_face(mvert,mface,0,0,pa->fuv,co1,nor,0,0,0,0);
  
@@@ -1105,7 -1128,7 +1128,7 @@@ int psys_threads_init_distribution(Part
                        break;
                case PART_FROM_VOLUME:
                case PART_FROM_FACE:
--                      tot = dm->getNumFaces(dm);
++                      tot = dm->getNumTessFaces(dm);
                        break;
                case PART_FROM_PARTICLE:
                        if(psys->target_ob)
@@@ -2648,7 -2736,84 +2736,84 @@@ static void precalc_effectors(Scene *sc
        }
  }
  
 -                              MFace *mface = CDDM_get_face(surmd->dm, nearest.index);
+ int effector_find_co(Scene *scene, float *pco, SurfaceModifierData *sur, Object *ob, PartDeflect *pd, float *co, float *nor, float *vel, int *index)
+ {
+       SurfaceModifierData *surmd = NULL;
+       int ret = 0;
+       if(sur)
+               surmd = sur;
+       else if(pd && pd->flag&PFIELD_SURFACE)
+       {
+               surmd = (SurfaceModifierData *)modifiers_findByType ( ob, eModifierType_Surface );
+       }
+       if(surmd) {
+               /* closest point in the object surface is an effector */
+               BVHTreeNearest nearest;
+               nearest.index = -1;
+               nearest.dist = FLT_MAX;
+               BLI_bvhtree_find_nearest(surmd->bvhtree->tree, pco, &nearest, surmd->bvhtree->nearest_callback, surmd->bvhtree);
+               if(nearest.index != -1) {
+                       VECCOPY(co, nearest.co);
+                       if(nor) {
+                               VECCOPY(nor, nearest.no);
+                       }
+                       if(vel) {
++                              MFace *mface = CDDM_get_tessface(surmd->dm, nearest.index);
+                               
+                               VECCOPY(vel, surmd->v[mface->v1].co);
+                               VecAddf(vel, vel, surmd->v[mface->v2].co);
+                               VecAddf(vel, vel, surmd->v[mface->v3].co);
+                               if(mface->v4)
+                                       VecAddf(vel, vel, surmd->v[mface->v4].co);
+                               VecMulf(vel, mface->v4 ? 0.25f : 0.333f);
+                       }
+                       if(index)
+                               *index = nearest.index;
+                       ret = 1;
+               }
+               else {
+                       co[0] = co[1] = co[2] = 0.0f;
+                       if(nor)
+                               nor[0] = nor[1] = nor[2] = 0.0f;
+                       if(vel)
+                               vel[0] = vel[1] = vel[2] = 0.0f;
+               }
+       }
+       else {
+               /* use center of object for distance calculus */
+               VECCOPY(co, ob->obmat[3]);
+               if(nor) {
+                       VECCOPY(nor, ob->obmat[2]);
+               }
+               if(vel) {
+                       Object obcopy = *ob;
+                       
+                       VECCOPY(vel, ob->obmat[3]);
+                       where_is_object_time(scene, ob, scene->r.cfra - 1.0);
+                       VecSubf(vel, vel, ob->obmat[3]);
+                       *ob = obcopy;
+               }
+       }
  
+       return ret;
+ }
  /* calculate forces that all effectors apply to a particle*/
  void do_effectors(int pa_no, ParticleData *pa, ParticleKey *state, Scene *scene, Object *ob, ParticleSystem *psys, float *rootco, float *force_field, float *vel,float framestep, float cfra)
  {
@@@ -3030,8 -3184,8 +3184,8 @@@ int psys_intersect_dm(Scene *scene, Obj
                VECCOPY(p_max,pa_minmax+3);
        }
  
--      totface=dm->getNumFaces(dm);
 -      mface=dm->getFaceDataArray(dm,CD_MFACE);
++      totface=dm->getNumTessFaces(dm);
 +      mface=dm->getTessFaceDataArray(dm,CD_MFACE);
        mvert=dm->getVertDataArray(dm,CD_MVERT);
        
        /* lets intersect the faces */
Simple merge
index 0c849595ad1fa4540d7ed313cff82b060a24d648,0000000000000000000000000000000000000000..68231f4d2f70ef09263f793d442d090460eb8e69
mode 100644,000000..100644
--- /dev/null
@@@ -1,353 -1,0 +1,363 @@@
 +#include "bmesh.h"
 +#include "bmesh_private.h"
 +#include <stdio.h>
 +
 +/*do not rename any operator or slot names! otherwise you must go 
 +  through the code and find all references to them!*/
 +
 +
++BMOpDefine def_reversefaces = {
++      "reversefaces",
++      {{BMOP_OPSLOT_ELEMENT_BUF, "faces"},
++      {0} /*null-terminating sentinel*/,
++      },
++      bmesh_reversefaces_exec,
++      0
++};
++
 +BMOpDefine def_edgesplit = {
 +      "edgesplit",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
 +      {BMOP_OPSLOT_INT, "numcuts"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "outsplit"},
 +      {0} /*null-terminating sentinel*/,
 +      },
 +      esplit_exec,
 +      0
 +};
 +
 +BMOpDefine def_mirror = {
 +      "mirror",
 +      /*maps welded vertices to verts they should weld to.*/
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "geom"},
 +       //list of verts to keep
 +       {BMOP_OPSLOT_MAT, "mat"}, //matrix defining the mirror transformation
 +       {BMOP_OPSLOT_FLT, "mergedist"}, //does no merging if mergedist is 0
 +       {BMOP_OPSLOT_ELEMENT_BUF, "newout"},
 +       {BMOP_OPSLOT_INT,         "axis"},
 +       {BMOP_OPSLOT_INT,         "mirror_u"},
 +       {BMOP_OPSLOT_INT,         "mirror_v"},
 +       {0, /*null-terminating sentinel*/}},
 +      bmesh_mirror_exec,
 +      0,
 +};
 +
 +BMOpDefine def_finddoubles = {
 +      "finddoubles",
 +      /*maps welded vertices to verts they should weld to.*/
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
 +       //list of verts to keep
 +       {BMOP_OPSLOT_ELEMENT_BUF, "keepverts"},
 +       {BMOP_OPSLOT_FLT,         "dist"},
 +       {BMOP_OPSLOT_MAPPING, "targetmapout"},
 +       {0, /*null-terminating sentinel*/}},
 +      bmesh_finddoubles_exec,
 +      0,
 +};
 +
 +BMOpDefine def_removedoubles = {
 +      "removedoubles",
 +      /*maps welded vertices to verts they should weld to.*/
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
 +       {BMOP_OPSLOT_FLT,         "dist"},
 +       {0, /*null-terminating sentinel*/}},
 +      bmesh_removedoubles_exec,
 +      0,
 +};
 +
 +BMOpDefine def_weldverts = {
 +      "weldverts",
 +      /*maps welded vertices to verts they should weld to.*/
 +      {{BMOP_OPSLOT_MAPPING, "targetmap"},
 +       {0, /*null-terminating sentinel*/}},
 +      bmesh_weldverts_exec,
 +      0,
 +};
 +
 +BMOpDefine def_makevert = {
 +      "makevert",
 +      {{BMOP_OPSLOT_VEC, "co"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "newvertout"},
 +      {0, /*null-terminating sentinel*/}},
 +      bmesh_makevert_exec,
 +      0,
 +};
 +
 +/*contextual_create is fkey, it creates
 +  new faces, makes stuff from edge nets,
 +  makes wire edges, etc.  it also dissolves
 +  faces.*/
 +BMOpDefine def_contextual_create= {
 +      "contextual_create",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "geom"},
 +       {BMOP_OPSLOT_ELEMENT_BUF, "faceout"},
 +       {0, /*null-terminating sentinel*/}},
 +      bmesh_contextual_create_exec,
 +      0,
 +};
 +
 +BMOpDefine def_edgenet_fill= {
 +      "edgenet_fill",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
 +       {BMOP_OPSLOT_ELEMENT_BUF, "faceout"},
 +      {0, /*null-terminating sentinel*/}},
 +      bmesh_edgenet_fill_exec,
 +      0,
 +};
 +
 +BMOpDefine def_rotate = {
 +      "rotate",
 +      {{BMOP_OPSLOT_VEC, "cent"},
 +       {BMOP_OPSLOT_MAT, "mat"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "verts"},
 +      {0, /*null-terminating sentinel*/}},
 +      bmesh_rotate_exec,
 +      0,
 +};
 +
 +BMOpDefine def_translate= {
 +      "translate",
 +      {{BMOP_OPSLOT_VEC, "vec"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "verts"},
 +      {0, /*null-terminating sentinel*/}},
 +      bmesh_translate_exec,
 +      0,
 +};
 +
 +
 +/*applies a transform to vertices*/
 +BMOpDefine def_transform = {
 +      "transform",
 +      {{BMOP_OPSLOT_MAT, "mat"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "verts"},
 +      {0, /*null-terminating sentinel*/}},
 +      bmesh_transform_exec,
 +      0,
 +};
 +
 +/*loads a bmesh into an object*/
 +BMOpDefine def_object_load_bmesh = {
 +      "object_load_bmesh",
 +      {{BMOP_OPSLOT_PNT, "scene"},
 +      {BMOP_OPSLOT_PNT, "object"},
 +      {0, /*null-terminating sentinel*/}},
 +      bmesh_to_mesh_exec,
 +      0,
 +};
 +
 +
 +BMOpDefine def_mesh_to_bmesh = {
 +      "mesh_to_bmesh",
 +      {{BMOP_OPSLOT_PNT, "mesh"},
 +       {0, /*null-terminating sentinel*/}},
 +      mesh_to_bmesh_exec,
 +      0
 +};
 +
 +BMOpDefine def_extrudeverts_indiv = {
 +      "extrude_vert_indiv",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "vertout"},
 +      {0} /*null-terminating sentinel*/},
 +      extrude_vert_indiv_exec,
 +      0
 +};
 +
 +#if 0
 +BMOpDefine def_makeprim = {
 +      "makeprim",
 +      {{BMOP_OPSLOT_INT, "type"},
 +      {BMOP_OPSLOT_INT, "tot", /*rows/cols also applies to spheres*/
 +      {BMOP_OPSLOT_INT, "seg",
 +      {BMOP_OPSLOT_INT, "subdiv"},
 +      {BMOP_OPSLOT_INT, "ext"},
 +      {BMOP_OPSLOT_INT, "fill"},
 +      {BMOP_OPSLOT_FLT, "dia"},
 +      {BMOP_OPSLOT_FLT, "depth"},
 +      {BMOP_OPSLOT_PNT, "mat"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "geomout"}, //won't be implemented right away
 +      {0}}
 +      makeprim_exec,
 +      0
 +};
 +#endif
 +
 +BMOpDefine def_connectverts = {
 +      "connectverts",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"},
 +      {0} /*null-terminating sentinel*/},
 +      connectverts_exec,
 +      0
 +};
 +
 +BMOpDefine def_extrudefaceregion = {
 +      "extrudefaceregion",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "edgefacein"},
 +      {BMOP_OPSLOT_MAPPING, "exclude"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "geomout"},
 +      {0} /*null-terminating sentinel*/},
 +      extrude_edge_context_exec,
 +      0
 +};
 +
 +BMOpDefine def_makefgonsop = {
 +      "makefgon",
 +      {{BMOP_OPSLOT_INT, "trifan"}, /*use triangle fans instead of 
 +                                      real interpolation*/
 +       {0} /*null-terminating sentinel*/},
 +      bmesh_make_fgons_exec,
 +      0
 +};
 +
 +BMOpDefine def_dissolvevertsop = {
 +      "dissolveverts",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "verts"},
 +      {0} /*null-terminating sentinel*/},
 +      dissolveverts_exec,
 +      0
 +};
 +
 +BMOpDefine def_dissolveedgessop = {
 +      "dissolveedges",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "regionout"},
 +      {0} /*null-terminating sentinel*/},
 +      dissolveedges_exec,
 +      0
 +};
 +
 +BMOpDefine def_dissolveedgeloopsop = {
 +      "dissolveedgeloop",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "regionout"},
 +      {0} /*null-terminating sentinel*/},
 +      dissolve_edgeloop_exec,
 +      0
 +};
 +
 +BMOpDefine def_dissolvefacesop = {
 +      "dissolvefaces",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "faces"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "regionout"},
 +      {0} /*null-terminating sentinel*/},
 +      dissolvefaces_exec,
 +      0
 +};
 +
 +
 +BMOpDefine def_triangop = {
 +      "triangulate",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "faces"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "edgeout"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "faceout"},
 +      {BMOP_OPSLOT_MAPPING, "facemap"},
 +      {0} /*null-terminating sentinel*/},
 +      triangulate_exec,
 +      0
 +};
 +
 +BMOpDefine def_subdop = {
 +      "esubd",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "edges"},
 +      {BMOP_OPSLOT_INT, "numcuts"},
 +      {BMOP_OPSLOT_FLT, "smooth"},
 +      {BMOP_OPSLOT_FLT, "fractal"},
 +      {BMOP_OPSLOT_INT, "beauty"},
 +      {BMOP_OPSLOT_MAPPING, "custompatterns"},
 +      {BMOP_OPSLOT_MAPPING, "edgepercents"},
 +      
 +      /*these next two can have multiple types of elements in them.*/
 +      {BMOP_OPSLOT_ELEMENT_BUF, "outinner"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "outsplit"},
 +      {0} /*null-terminating sentinel*/,
 +      },
 +      esubdivide_exec,
 +      0
 +};
 +
 +BMOpDefine def_edit2bmesh = {
 +      "editmesh_to_bmesh",
 +      {{BMOP_OPSLOT_PNT, "em"}, {BMOP_OPSLOT_MAPPING, "map"},
 +      {0} /*null-terminating sentinel*/},
 +      edit2bmesh_exec,
 +      0
 +};
 +
 +BMOpDefine def_bmesh2edit = {
 +      "bmesh_to_editmesh",
 +      {{BMOP_OPSLOT_PNT, "emout"},
 +      {0} /*null-terminating sentinel*/},
 +      bmesh2edit_exec,
 +      0
 +};
 +
 +BMOpDefine def_delop = {
 +      "del",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "geom"}, {BMOP_OPSLOT_INT, "context"},
 +      {0} /*null-terminating sentinel*/},
 +      delop_exec,
 +      0
 +};
 +
 +BMOpDefine def_dupeop = {
 +      "dupe",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "geom"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "origout"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "newout"},
 +      /*facemap maps from source faces to dupe
 +        faces, and from dupe faces to source faces.*/
 +      {BMOP_OPSLOT_MAPPING, "facemap"},
 +      {BMOP_OPSLOT_MAPPING, "boundarymap"},
 +      {BMOP_OPSLOT_MAPPING, "isovertmap"},
 +      {0} /*null-terminating sentinel*/},
 +      dupeop_exec,
 +      0
 +};
 +
 +BMOpDefine def_splitop = {
 +      "split",
 +      {{BMOP_OPSLOT_ELEMENT_BUF, "geom"},
 +      {BMOP_OPSLOT_ELEMENT_BUF, "geomout"},
 +      {BMOP_OPSLOT_MAPPING, "boundarymap"},
 +      {BMOP_OPSLOT_MAPPING, "isovertmap"},
 +      {0} /*null-terminating sentinel*/},
 +      splitop_exec,
 +      0
 +};
 +
 +BMOpDefine *opdefines[] = {
 +      &def_splitop,
 +      &def_dupeop,
 +      &def_delop,
 +      &def_edit2bmesh,
 +      &def_bmesh2edit,
 +      &def_subdop,
 +      &def_triangop,
 +      &def_dissolvefacesop,
 +      &def_dissolveedgessop,
 +      &def_dissolveedgeloopsop,
 +      &def_dissolvevertsop,
 +      &def_makefgonsop,
 +      &def_extrudefaceregion,
 +      &def_connectverts,
 +      //&def_makeprim,
 +      &def_extrudeverts_indiv,
 +      &def_mesh_to_bmesh,
 +      &def_object_load_bmesh,
 +      &def_transform,
 +      &def_translate,
 +      &def_rotate,
 +      &def_edgenet_fill,
 +      &def_contextual_create,
 +      &def_makevert,
 +      &def_weldverts,
 +      &def_removedoubles,
 +      &def_finddoubles,
 +      &def_mirror,
 +      &def_edgesplit,
++      &def_reversefaces,
 +};
 +
 +int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*));
index 1eeb5e2ba2286e1cfd35201ad30a3e475d0837b7,0000000000000000000000000000000000000000..94a68ab981a5a74186833183610d6dc1ef75afe5
mode 100644,000000..100644
--- /dev/null
@@@ -1,40 -1,0 +1,41 @@@
 +#ifndef BM_OPERATORS_PRIVATE_H
 +#define BM_OPERATORS_PRIVATE_H
 +
 +struct BMesh;
 +struct BMOperator;
 +
 +void BMO_push(BMesh *bm, BMOperator *op);
 +void BMO_pop(BMesh *bm);
 +
 +void splitop_exec(BMesh *bm, BMOperator *op);
 +void dupeop_exec(BMesh *bm, BMOperator *op);
 +void delop_exec(BMesh *bm, BMOperator *op);
 +void esubdivide_exec(BMesh *bmesh, BMOperator *op);
 +void edit2bmesh_exec(BMesh *bmesh, BMOperator *op);
 +void bmesh2edit_exec(BMesh *bmesh, BMOperator *op);
 +void triangulate_exec(BMesh *bmesh, BMOperator *op);
 +void dissolvefaces_exec(BMesh *bmesh, BMOperator *op);
 +void dissolveverts_exec(BMesh *bmesh, BMOperator *op);
 +void bmesh_make_fgons_exec(BMesh *bmesh, BMOperator *op);
 +void extrude_edge_context_exec(BMesh *bm, BMOperator *op);
 +void connectverts_exec(BMesh *bm, BMOperator *op);
 +void makeprim_exec(BMesh *bm, BMOperator *op);
 +void extrude_vert_indiv_exec(BMesh *bm, BMOperator *op);
 +void mesh_to_bmesh_exec(BMesh *bm, BMOperator *op);
 +void bmesh_to_mesh_exec(BMesh *bm, BMOperator *op);
 +void bmesh_translate_exec(BMesh *bm, BMOperator *op);
 +void bmesh_transform_exec(BMesh *bm, BMOperator *op);
 +void bmesh_contextual_create_exec(BMesh *bm, BMOperator *op);
 +void bmesh_edgenet_fill_exec(BMesh *bm, BMOperator *op);
 +void bmesh_rotate_exec(BMesh *bm, BMOperator *op);
 +void bmesh_makevert_exec(BMesh *bm, BMOperator *op);
 +void dissolveedges_exec(BMesh *bm, BMOperator *op);
 +void dissolve_edgeloop_exec(BMesh *bm, BMOperator *op);
 +void bmesh_weldverts_exec(BMesh *bm, BMOperator *op);
 +void bmesh_removedoubles_exec(BMesh *bm, BMOperator *op);
 +void bmesh_finddoubles_exec(BMesh *bm, BMOperator *op);
 +void bmesh_mirror_exec(BMesh *bm, BMOperator *op);
 +void esplit_exec(BMesh *bm, BMOperator *op);
++void bmesh_reversefaces_exec(BMesh *bm, BMOperator *op);
 +
 +#endif
index 22cb62b483c02c6a35d9d907a2cd0a31d2e795df,0000000000000000000000000000000000000000..95428a12f78da5cf2e266fcd9e8bbb9bef3ca502
mode 100644,000000..100644
--- /dev/null
@@@ -1,901 -1,0 +1,902 @@@
-               if (ABS(l) < 0.1)
 +#include <string.h>
 +#include <math.h>
 +#include <stdlib.h>
 +
 +#include "BKE_utildefines.h"
 +
 +#include "BLI_arithb.h"
 +#include "BLI_blenlib.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "bmesh.h"
 +#include "bmesh_private.h"
 +
 +/*
 + *
 + * BME POLYGON.C
 + *
 + * This file contains code for dealing
 + * with polygons (normal/area calculation,
 + * tesselation, ect)
 + *
 + * TODO:
 + *   -Add in Tesselator frontend that creates
 + *     BMTriangles from copied faces
 + *  -Add in Function that checks for and flags
 + *   degenerate faces.
 + *
 +*/
 +
 +/*
 + * TEST EDGE SIDE and POINT IN TRIANGLE
 + *
 + * Point in triangle tests stolen from scanfill.c.
 + * Used for tesselator
 + *
 +*/
 +
 +static short testedgeside(double *v1, double *v2, double *v3)
 +/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
 +{
 +      double inp;
 +
 +      //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
 +      inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]);
 +
 +      if(inp<0.0) return 0;
 +      else if(inp==0) {
 +              if(v1[0]==v3[0] && v1[1]==v3[1]) return 0;
 +              if(v2[0]==v3[0] && v2[1]==v3[1]) return 0;
 +      }
 +      return 1;
 +}
 +
 +static short testedgesidef(float *v1, float *v2, float *v3)
 +/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
 +{
 +      double inp;
 +
 +      //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
 +      inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]);
 +
 +      if(inp<0.0) return 0;
 +      else if(inp==0) {
 +              if(v1[0]==v3[0] && v1[1]==v3[1]) return 0;
 +              if(v2[0]==v3[0] && v2[1]==v3[1]) return 0;
 +      }
 +      return 1;
 +}
 +
 +static int point_in_triangle(double *v1, double *v2, double *v3, double *pt)
 +{
 +      if(testedgeside(v1,v2,pt) && testedgeside(v2,v3,pt) && testedgeside(v3,v1,pt))
 +              return 1;
 +      return 0;
 +}
 +
 +/*
 + * COMPUTE POLY NORMAL
 + *
 + * Computes the normal of a planar 
 + * polygon See Graphics Gems for 
 + * computing newell normal.
 + *
 +*/
 +#define FEQ(f1, f2) (ABS((double)(f1)-(double)(f2)) < 0.1)
 +
 +static void compute_poly_normal(float normal[3], float (*verts)[3], int nverts)
 +{
 +
 +      double u[3],  v[3], w[3];/*, *w, v1[3], v2[3];*/
 +      double n[3] = {0.0, 0.0, 0.0}, l, v1[3], v2[3];
 +      int i, s=0;
 +
 +      /*this fixes some weird numerical error*/
 +      verts[0][0] += 0.0001f;
 +      verts[0][1] += 0.0001f;
 +      verts[0][2] += 0.0001f;
 +
 +      for(i = 0; i < nverts; i++){
 +              VECCOPY(u, verts[i]);
 +              VECCOPY(v, verts[(i+1) % nverts]);
 +              VECCOPY(w, verts[(i+2) % nverts]);
 +              
++#if 0
 +              VECSUB(v1, w, v);
 +              VECSUB(v2, v, u);
 +              Normalize_d(v1);
 +              Normalize_d(v2);
 +
 +              l = INPR(v1, v2);
++              if (ABS(l-1.0) < 0.1)
 +                      continue;
-       if(f->len > 4){
++#endif
 +              /* newell's method
 +              
 +              so thats?:
 +              (a[1] - b[1]) * (a[2] + b[2]);
 +              a[1]*b[2] - b[1]*a[2] - b[1]*b[2] + a[1]*a[2]
 +
 +              odd.  half of that is the cross product. . .what's the
 +              other half?
 +
 +              also could be like a[1]*(b[2] + a[2]) - b[1]*(a[2] - b[2])
 +              */
 +
 +              n[0] += (u[1] - v[1]) * (u[2] + v[2]);
 +              n[1] += (u[2] - v[2]) * (u[0] + v[0]);
 +              n[2] += (u[0] - v[0]) * (u[1] + v[1]);
 +      }
 +      
 +      l = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
 +
 +      if (l == 0.0) {
 +              normal[0] = 0.0f;
 +              normal[1] = 0.0f;
 +              normal[2] = 1.0f;
 +
 +              return;
 +      }
 +
 +      n[0] /= l;
 +      n[1] /= l;
 +      n[2] /= l;
 +      
 +      normal[0] = (float) n[0];
 +      normal[1] = (float) n[1];
 +      normal[2] = (float) n[2];
 +}
 +
 +/*
 + * COMPUTE POLY CENTER
 + *
 + * Computes the centroid and
 + * area of a polygon in the X/Y
 + * plane.
 + *
 +*/
 +
 +static int compute_poly_center(float center[3], float *area, float (*verts)[3], int nverts)
 +{
 +      int i, j;
 +      float atmp = 0.0, xtmp = 0.0, ytmp = 0.0, ai;
 +      
 +      center[0] = center[1] = center[2] = 0.0;        
 +
 +      if(nverts < 3) 
 +              return 0;
 +
 +      i = nverts-1;
 +      j = 0;
 +      
 +      while(j < nverts){
 +              ai = verts[i][0] * verts[j][1] - verts[j][0] * verts[i][1];                             
 +              atmp += ai;
 +              xtmp += (verts[j][0] + verts[i][0]) * ai;
 +              ytmp += (verts[j][1] + verts[i][1]) * ai;
 +              i = j;
 +              j += 1;
 +      }
 +
 +      if(area)
 +              *area = atmp / 2.0f;    
 +      
 +      if (atmp != 0){
 +              center[0] = xtmp /  (3.0f * atmp);
 +              center[1] = xtmp /  (3.0f * atmp);
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +float BM_face_area(BMFace *f)
 +{
 +      BMLoop *l;
 +      BMIter iter;
 +      float (*verts)[3], stackv[100][3];
 +      float area, center[3];
 +      int i;
 +
 +      if (f->len <= 100) 
 +              verts = stackv;
 +      else verts = MEM_callocN(sizeof(float)*f->len*3, "bm_face_area tmp");
 +
 +      i = 0;
 +      BM_ITER(l, &iter, NULL, BM_LOOPS_OF_FACE, f) {
 +              VECCOPY(verts[i], l->v->co);
 +              i++;
 +      }
 +
 +      compute_poly_center(center, &area, verts, f->len);
 +
 +      if (f->len > 100)
 +              MEM_freeN(verts);
 +
 +      return area;
 +}
 +/*
 +computes center of face in 3d.  uses center of bounding box.
 +*/
 +
 +int BM_Compute_Face_Center(BMesh *bm, BMFace *f, float center[3])
 +{
 +      BMIter iter;
 +      BMLoop *l;
 +      float min[3], max[3];
 +      int i;
 +
 +      INIT_MINMAX(min, max);
 +      l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
 +      for (i=0; l; l=BMIter_Step(&iter), i++) {
 +              DO_MINMAX(l->v->co, min, max);
 +      }
 +
 +      VECADD(center, min, max);
 +      VECMUL(center, 0.5f);
 +}
 +
 +/*
 + * COMPUTE POLY PLANE
 + *
 + * Projects a set polygon's vertices to 
 + * a plane defined by the average
 + * of its edges cross products
 + *
 +*/
 +
 +void compute_poly_plane(float (*verts)[3], int nverts)
 +{
 +      
 +      float avgc[3], norm[3], temp[3], mag, avgn[3];
 +      float *v1, *v2, *v3;
 +      int i;
 +      
 +      if(nverts < 3) 
 +              return;
 +
 +      avgn[0] = avgn[1] = avgn[2] = 0.0;
 +      avgc[0] = avgc[1] = avgc[2] = 0.0;
 +
 +      for(i = 0; i < nverts; i++){
 +              v1 = verts[i];
 +              v2 = verts[(i+1) % nverts];
 +              v3 = verts[(i+2) % nverts];
 +              CalcNormFloat(v1, v2, v3, norm);        
 +      
 +              avgn[0] += norm[0];
 +              avgn[1] += norm[1];
 +              avgn[2] += norm[2];
 +      }
 +
 +      /*what was this bit for?*/
 +      if(avgn[0] == 0.0 && avgn[1] == 0.0 && avgn[2] == 0.0){
 +              avgn[0] = 0.0;
 +              avgn[1] = 0.0;
 +              avgn[2] = 1.0;
 +      } else {
 +              avgn[0] /= nverts;
 +              avgn[1] /= nverts;
 +              avgn[2] /= nverts;
 +              Normalize(avgn);
 +      }
 +      
 +      for(i = 0; i < nverts; i++){
 +              v1 = verts[i];
 +              VECCOPY(temp, v1);
 +              mag = 0.0;
 +              mag += (temp[0] * avgn[0]);
 +              mag += (temp[1] * avgn[1]);
 +              mag += (temp[2] * avgn[2]);
 +              
 +              temp[0] = (avgn[0] * mag);
 +              temp[1] = (avgn[1] * mag);
 +              temp[2] = (avgn[2] * mag);
 +
 +              VecSubf(v1, v1, temp);
 +      }       
 +}
 +
 +/*
 +  BM LEGAL EDGES
 +
 +  takes in a face and a list of edges, and sets to NULL any edge in
 +  the list that bridges a concave region of the face or intersects
 +  any of the faces's edges.
 +*/
 +static void shrink_edged(double *v1, double *v2, double fac)
 +{
 +      double mid[3];
 +
 +      VECADD(mid, v1, v2);
 +      VECMUL(mid, 0.5);
 +
 +      VECSUB(v1, v1, mid);
 +      VECSUB(v2, v2, mid);
 +
 +      VECMUL(v1, fac);
 +      VECMUL(v2, fac);
 +
 +      VECADD(v1, v1, mid);
 +      VECADD(v2, v2, mid);
 +}
 +
 +static void shrink_edgef(float *v1, float *v2, float fac)
 +{
 +      float mid[3];
 +
 +      VECADD(mid, v1, v2);
 +      VECMUL(mid, 0.5);
 +
 +      VECSUB(v1, v1, mid);
 +      VECSUB(v2, v2, mid);
 +
 +      VECMUL(v1, fac);
 +      VECMUL(v2, fac);
 +
 +      VECADD(v1, v1, mid);
 +      VECADD(v2, v2, mid);
 +}
 +
 +/*
 + * POLY ROTATE PLANE
 + *
 + * Rotates a polygon so that it's
 + * normal is pointing towards the mesh Z axis
 + *
 +*/
 +
 +void poly_rotate_plane(float normal[3], float (*verts)[3], int nverts)
 +{
 +
 +      float up[3] = {0.0f,0.0f,1.0f}, axis[3], q[4];
 +      float mat[3][3];
 +      double angle;
 +      int i;
 +
 +      Crossf(axis, up, normal);
 +      axis[0] *= -1;
 +      axis[1] *= -1;
 +      axis[2] *= -1;
 +
 +      angle = saacos(normal[0]*up[0]+normal[1]*up[1] + normal[2]*up[2]);
 +
 +      if (angle == 0.0f) return;
 +
 +      AxisAngleToQuatd(q, axis, angle);
 +      QuatToMat3(q, mat);
 +
 +      for(i = 0;  i < nverts;  i++)
 +              Mat3MulVecfl(mat, verts[i]);
 +}
 +
 +/*
 + * BMESH UPDATE FACE NORMAL
 + *
 + * Updates the stored normal for the
 + * given face. Requires that a buffer
 + * of sufficient length to store projected
 + * coordinates for all of the face's vertices
 + * is passed in as well.
 + *
 +*/
 +
 +void BM_Face_UpdateNormal(BMesh *bm, BMFace *f)
 +{
 +      float projverts[12][3];
 +      float (*proj)[3] = f->len < 12 ? projverts : MEM_mallocN(sizeof(float)*f->len*3, "projvertsn");
 +      BMLoop *l = f->loopbase;
 +      int i=0;
 +
 +      if (f->len < 3) return;
 +      
 +      do {
 +              VECCOPY(proj[i], l->v->co);
 +              i += 1;
 +      } while (l != f->loopbase);
 +
 +      bmesh_update_face_normal(bm, f, proj);
 +
 +      if (projverts != proj) MEM_freeN(proj);
 +}
 +
 +void BM_Edge_UpdateNormals(BMesh *bm, BMEdge *e)
 +{
 +      BMIter iter;
 +      BMFace *f;
 +      
 +      f = BMIter_New(&iter, bm, BM_FACES_OF_EDGE, e);
 +      for (; f; f=BMIter_Step(&iter)) {
 +              BM_Face_UpdateNormal(bm, f);
 +      }
 +
 +      BM_Vert_UpdateNormal(bm, e->v1);
 +      BM_Vert_UpdateNormal(bm, e->v2);
 +}
 +
 +void BM_Vert_UpdateNormal(BMesh *bm, BMVert *v)
 +{
 +      BMIter iter;
 +      BMFace *f;
 +      int len=0;
 +
 +      v->no[0] = v->no[1] = v->no[2] = 0.0f;
 +
 +      f = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v);
 +      for (; f; f=BMIter_Step(&iter), len++) {
 +              VecAddf(v->no, f->no, v->no);
 +      }
 +
 +      if (!len) return;
 +
 +      VecMulf(v->no, 1.0f/(int)len);
 +}
 +
 +void bmesh_update_face_normal(BMesh *bm, BMFace *f, float (*projectverts)[3])
 +{
 +      BMLoop *l;
 +      int i;
 +
++      if(1) { //f->len > 4){
 +              i = 0;
 +              l = f->loopbase;
 +              do{
 +                      VECCOPY(projectverts[i], l->v->co);
 +                      l = (BMLoop*)(l->head.next);
 +                      i += 1;
 +              }while(l!=f->loopbase);
 +
 +              //compute_poly_plane(projectverts, f->len);
 +              compute_poly_normal(f->no, projectverts, f->len);       
 +      }
 +      else if(f->len == 3){
 +              BMVert *v1, *v2, *v3;
 +              v1 = f->loopbase->v;
 +              v2 = ((BMLoop*)(f->loopbase->head.next))->v;
 +              v3 = ((BMLoop*)(f->loopbase->head.next->next))->v;
 +              CalcNormFloat(v1->co, v2->co, v3->co, f->no);
 +      }
 +      else if(f->len == 4){
 +              BMVert *v1, *v2, *v3, *v4;
 +              v1 = f->loopbase->v;
 +              v2 = ((BMLoop*)(f->loopbase->head.next))->v;
 +              v3 = ((BMLoop*)(f->loopbase->head.next->next))->v;
 +              v4 = ((BMLoop*)(f->loopbase->head.prev))->v;
 +              CalcNormFloat4(v1->co, v2->co, v3->co, v4->co, f->no);
 +      }
 +      else{ /*horrible, two sided face!*/
 +              f->no[0] = 0.0;
 +              f->no[1] = 0.0;
 +              f->no[2] = 1.0;
 +      }
 +
 +}
 +
 +
 +/*
 + * BMESH FLIP NORMAL
 + * 
 + *  Reverses the winding of a  faces
 + *  Note that this does *not* update the calculated 
 + *  Normal 
 +*/
 +void BM_flip_normal(BMesh *bm, BMFace *f)
 +{     
 +      bmesh_loop_reverse(bm, f);
 +}
 +
 +/* detects if two line segments cross each other (intersects).
 +   note, there could be more winding cases then there needs to be. */
 +int linecrosses(double *v1, double *v2, double *v3, double *v4)
 +{
 +      int w1, w2, w3, w4, w5;
 +      
 +      /*w1 = winding(v1, v3, v4);
 +      w2 = winding(v2, v3, v4);
 +      w3 = winding(v3, v1, v2);
 +      w4 = winding(v4, v1, v2);
 +      
 +      return (w1 == w2) && (w3 == w4);*/
 +
 +      w1 = testedgeside(v1, v3, v2);
 +      w2 = testedgeside(v2, v4, v1);
 +      w3 = !testedgeside(v1, v2, v3);
 +      w4 = testedgeside(v3, v2, v4);
 +      w5 = !testedgeside(v3, v1, v4);
 +      return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5;
 +}
 +
 +/* detects if two line segments cross each other (intersects).
 +   note, there could be more winding cases then there needs to be. */
 +int linecrossesf(float *v1, float *v2, float *v3, float *v4)
 +{
 +      int w1, w2, w3, w4, w5, ret;
 +      
 +/*       int test1_a, test1_a, test2_a, test2_a;
 +
 +   test1_a = check_tri_clock_dir(l1p1, l1p2, l2p1);
 +   test1_b = check_tri_clock_dir(l1p1, l1p2, l2p2);
 +   if (test1_a != test1_b)
 +   {
 +      test2_a = check_tri_clock_dir(l2p1, l2p2, l1p1);
 +      test2_b = check_tri_clock_dir(l2p1, l2p2, l1p2);
 +      if (test2_a != test2_b)
 +      {
 +         return 1;
 +      }
 +   }*/
 +      /*w1 = testedgesidef(v1, v2, v3);
 +      w2 = testedgesidef(v1, v2, v4);
 +      if(w1 != w2) {
 +              w3 = testedgesidef(v3, v4, v1);
 +              w4 = testedgesidef(v3, v4, v2);
 +              if (w3 != w4) return 1;
 +      }
 +              
 +      return 0;*/
 +
 +      /*w1 = testedgesidef(v1, v3, v4);
 +      w2 = testedgesidef(v2, v3, v4);
 +      w3 = testedgesidef(v3, v1, v2);
 +      w4 = testedgesidef(v4, v1, v2);
 +      
 +      return (w1 == w2) && (w2 == w3) && (w3 == w4);*/
 +
 +      /*do an interval test on the x and y axes*/
 +      /*first do x axis*/
 +      #define T 0.01
 +      if (ABS(v1[1]-v2[1]) < T && ABS(v3[1]-v4[1]) < T &&
 +          ABS(v1[1]-v3[1]) < T) {
 +              if (v3[0] >= v1[0] && v3[0] <= v2[0])
 +                      return 1;
 +              if (v4[0] >= v1[0] && v4[0] <= v2[0])
 +                      return 1;
 +              if (v3[0] <= v1[0] && v4[0] >= v2[0])
 +                      return 1;
 +      }
 +
 +      /*now do y axis*/
 +      if (ABS(v1[0]-v2[0]) < T && ABS(v3[0]-v4[0]) < T &&
 +          ABS(v1[0]-v3[0]) < T) {
 +              if (v3[1] >= v1[1] && v3[1] <= v2[1])
 +                      return 1;
 +              if (v4[1] >= v1[1] && v4[1] <= v2[1])
 +                      return 1;
 +              if (v3[1] <= v1[1] && v4[1] >= v2[1])
 +                      return 1;
 +      }
 +
 +      /*now test winding*/
 +      w1 = testedgesidef(v1, v3, v2);
 +      w2 = testedgesidef(v2, v4, v1);
 +      w3 = !testedgesidef(v1, v2, v3);
 +      w4 = testedgesidef(v3, v2, v4);
 +      w5 = !testedgesidef(v3, v1, v4);
 +
 +      return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5; 
 +}
 +
 +int goodline(float (*projectverts)[3], BMFace *f, int v1i,
 +           int v2i, int v3i, int nvert) {
 +      BMLoop *l = f->loopbase;
 +      double v1[3], v2[3], v3[3], pv1[3], pv2[3];
 +      int i;
 +
 +      VECCOPY(v1, projectverts[v1i]);
 +      VECCOPY(v2, projectverts[v2i]);
 +      VECCOPY(v3, projectverts[v3i]);
 +      
 +      if (testedgeside(v1, v2, v3)) return 0;
 +      
 +      //for (i=0; i<nvert; i++) {
 +      do {
 +              i = l->v->head.eflag2;
 +              if (i == v1i || i == v2i || i == v3i) {
 +                      l = (BMLoop*)l->head.next;
 +                      continue;
 +              }
 +              
 +              VECCOPY(pv1, projectverts[l->v->head.eflag2]);
 +              VECCOPY(pv2, projectverts[((BMLoop*)l->head.next)->v->head.eflag2]);
 +              
 +              //if (linecrosses(pv1, pv2, v1, v3)) return 0;
 +              if (point_in_triangle(v1, v2, v3, pv1)) return 0;
 +              if (point_in_triangle(v3, v2, v1, pv1)) return 0;
 +
 +              l = (BMLoop*)l->head.next;
 +      } while (l != f->loopbase);
 +      return 1;
 +}
 +/*
 + * FIND EAR
 + *
 + * Used by tesselator to find
 + * the next triangle to 'clip off'
 + * of a polygon while tesselating.
 + *
 +*/
 +
 +static BMLoop *find_ear(BMesh *bm, BMFace *f, float (*verts)[3], 
 +                      int nvert)
 +{
 +      BMVert *v1, *v2, *v3;
 +      BMLoop *bestear = NULL, *l;
 +      float angle, bestangle = 180.0f;
 +      int isear, i=0;
 +      
 +      l = f->loopbase;
 +      do {
 +              isear = 1;
 +              
 +              v1 = ((BMLoop*)(l->head.prev))->v;
 +              v2 = l->v;
 +              v3 = ((BMLoop*)(l->head.next))->v;
 +
 +              if (BM_Edge_Exist(v1, v3)) isear = 0;
 +
 +              if (isear && !goodline(verts, f, v1->head.eflag2, v2->head.eflag2,
 +                                     v3->head.eflag2, nvert))
 +                      isear = 0;
 +              
 +              if(isear) {
 +                      /*angle = VecAngle3(verts[v1->head.eflag2], verts[v2->head.eflag2], verts[v3->head.eflag2]);
 +                      if(!bestear || ABS(angle-45.0f) < bestangle) {
 +                              bestear = l;
 +                              bestangle = ABS(45.0f-angle);
 +                      }
 +                      
 +                      if (angle > 20 && angle < 90) break;
 +                      if (angle < 100 && i > 5) break;
 +                      i += 1;*/
 +                      bestear = l;
 +                      break;
 +              }
 +              l = (BMLoop*)(l->head.next);
 +      }
 +      while(l != f->loopbase);
 +
 +      return bestear;
 +}
 +
 +/*
 + * BMESH TRIANGULATE FACE
 + *
 + * Triangulates a face using a 
 + * simple 'ear clipping' algorithm
 + * that tries to favor non-skinny
 + * triangles (angles less than 
 + * 90 degrees). If the triangulator
 + * has bits left over (or cannot
 + * triangulate at all) it uses a
 + * simple fan triangulation
 + *
 + * newfaces, if non-null, must be an array of BMFace pointers,
 + * with a length equal to f->len.  it will be filled with the new
 + * triangles, and will be NULL-terminated.
 +*/
 +void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3], 
 +                         int newedgeflag, int newfaceflag, BMFace **newfaces)
 +{
 +      int i, done, nvert, nf_i = 0;
 +      BMLoop *l, *newl, *nextloop;
 +      BMVert *v;
 +
 +      /*copy vertex coordinates to vertspace array*/
 +      i = 0;
 +      l = f->loopbase;
 +      do{
 +              VECCOPY(projectverts[i], l->v->co);
 +              l->v->head.eflag2 = i; /*warning, abuse! never duplicate in tools code! never you hear?*/ /*actually, get rid of this completely, use a new structure for this....*/
 +              i++;
 +              l = (BMLoop*)(l->head.next);
 +      }while(l != f->loopbase);
 +      
 +      ///bmesh_update_face_normal(bm, f, projectverts);
 +
 +      compute_poly_normal(f->no, projectverts, f->len);
 +      poly_rotate_plane(f->no, projectverts, i);
 +
 +      nvert = f->len;
 +
 +      //compute_poly_plane(projectverts, i);
 +      for (i=0; i<nvert; i++) {
 +              projectverts[i][2] = 0.0f;
 +      }
 +
 +      done = 0;
 +      while(!done && f->len > 3){
 +              done = 1;
 +              l = find_ear(bm, f, projectverts, nvert);
 +              if(l) {
 +                      done = 0;
 +                      v = l->v;
 +                      f = BM_Split_Face(bm, l->f, ((BMLoop*)(l->head.prev))->v, 
 +                                        ((BMLoop*)(l->head.next))->v, 
 +                                        &newl, NULL);
 +                      VECCOPY(f->no, l->f->no);
 +
 +                      if (!f) {
 +                              printf("yeek! triangulator failed to split face!\n");
 +                              break;
 +                      }
 +
 +                      BMO_SetFlag(bm, newl->e, newedgeflag);
 +                      BMO_SetFlag(bm, f, newfaceflag);
 +                      
 +                      if (newfaces) newfaces[nf_i++] = f;
 +
 +                      /*l = f->loopbase;
 +                      do {
 +                              if (l->v == v) {
 +                                      f->loopbase = l;
 +                                      break;
 +                              }
 +                              l = l->head.next;
 +                      } while (l != f->loopbase);*/
 +              }
 +      }
 +
 +      if (f->len > 3){
 +              l = f->loopbase;
 +              while (l->f->len > 3){
 +                      nextloop = ((BMLoop*)(l->head.next->next));
 +                      f = BM_Split_Face(bm, l->f, l->v, nextloop->v, 
 +                                        &newl, NULL);
 +                      if (!f) {
 +                              printf("triangle fan step of triangulator failed.\n");
 +
 +                              /*NULL-terminate*/
 +                              if (newfaces) newfaces[nf_i] = NULL;
 +                              return;
 +                      }
 +
 +                      if (newfaces) newfaces[nf_i++] = f;
 +                      
 +                      BMO_SetFlag(bm, newl->e, newedgeflag);
 +                      BMO_SetFlag(bm, f, newfaceflag);
 +                      l = nextloop;
 +              }
 +      }
 +      
 +      /*NULL-terminate*/
 +      if (newfaces) newfaces[nf_i] = NULL;
 +}
 +
 +/*each pair of loops defines a new edge, a split.  this function goes
 +  through and sets pairs that are geometrically invalid to null.  a
 +  split is invalid, if it forms a concave angle or it intersects other
 +  edges in the face, or it intersects another split.  in the case of
 +  intersecting splits, only the first of the set of intersecting
 +  splits survives.*/
 +void BM_LegalSplits(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
 +{
 +      BMIter iter;
 +      BMLoop *l;
 +      float v1[3], v2[3], v3[3], v4[3], no[3], mid[3], *p1, *p2, *p3, *p4;
 +      float out[3] = {-234324.0f, -234324.0f, 0.0f};
 +      float projectverts[100][3];
 +      float edgevertsstack[200][3];
 +      float (*projverts)[3] = projectverts;
 +      float (*edgeverts)[3] = edgevertsstack;
 +      float fac1 = 1.0000001f, fac2 = 0.9f; //9999f; //0.999f;
 +      int i, j, a=0, clen;
 +
 +      if (f->len > 100) projverts = MEM_mallocN(sizeof(float)*3*f->len, "projvertsb");
 +      if (len > 100) edgeverts = MEM_mallocN(sizeof(float)*3*2*len, "edgevertsb");
 +      
 +      i = 0;
 +      l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, f);
 +      for (; l; l=BMIter_Step(&iter)) {
 +              l->head.eflag2 = i;
 +              VECCOPY(projverts[i], l->v->co);
 +              i++;
 +      }
 +      
 +      for (i=0; i<len; i++) {
 +              VECCOPY(v1, loops[i][0]->v->co);
 +              VECCOPY(v2, loops[i][1]->v->co);
 +
 +              shrink_edgef(v1, v2, fac2);
 +              
 +              VECCOPY(edgeverts[a], v1);
 +              a++;
 +              VECCOPY(edgeverts[a], v2);
 +              a++;
 +      }
 +      
 +      compute_poly_normal(no, projverts, f->len);
 +      poly_rotate_plane(no, projverts, f->len);
 +      poly_rotate_plane(no, edgeverts, len*2);
 +      
 +      l = f->loopbase;
 +      for (i=0; i<f->len; i++) {
 +              p1 = projverts[i];
 +              out[0] = MAX2(out[0], p1[0]) + 0.01f;
 +              out[1] = MAX2(out[1], p1[1]) + 0.01f;
 +              out[2] = 0.0f;
 +              p1[2] = 0.0f;
 +
 +              //VECCOPY(l->v->co, p1);
 +
 +              l = (BMLoop*) l->head.next;
 +      }
 +      
 +      for (i=0; i<len; i++) {
 +              edgeverts[i*2][2] = 0.0f;
 +              edgeverts[i*2+1][2] = 0.0f;
 +      }
 +
 +      /*do convexity test*/
 +      for (i=0; i<len; i++) {
 +              VECCOPY(v2, edgeverts[i*2]);
 +              VECCOPY(v3, edgeverts[i*2+1]);
 +
 +              VecAddf(mid, v2, v3);
 +              VecMulf(mid, 0.5f);
 +              
 +              clen = 0;
 +              for (j=0; j<f->len; j++) {
 +                      p1 = projverts[j];
 +                      p2 = projverts[(j+1)%f->len];
 +                      
 +                      VECCOPY(v1, p1);
 +                      VECCOPY(v2, p2);
 +
 +                      shrink_edgef(v1, v2, fac1);
 +
 +                      if (linecrossesf(p1, p2, mid, out)) clen++;
 +              }
 +              
 +              if (clen%2 == 0) {
 +                      loops[i][0] = NULL;
 +              }
 +      }
 +      
 +      /*do line crossing tests*/
 +      for (i=0; i<f->len; i++) {
 +              p1 = projverts[i];
 +              p2 = projverts[(i+1)%f->len];
 +              
 +              VECCOPY(v1, p1);
 +              VECCOPY(v2, p2);
 +
 +              shrink_edgef(v1, v2, fac1);
 +
 +              for (j=0; j<len; j++) {
 +                      if (!loops[j][0]) continue;
 +
 +                      p3 = edgeverts[j*2];
 +                      p4 = edgeverts[j*2+1];
 +
 +                      if (linecrossesf(v1, v2, p3, p4))
 +                      {
 +                              loops[j][0] = NULL;
 +                      }
 +              }
 +      }
 +
 +      for (i=0; i<len; i++) {
 +              for (j=0; j<len; j++) {
 +                      if (j == i) continue;
 +                      if (!loops[i][0]) continue;
 +                      if (!loops[j][0]) continue;
 +
 +                      p1 = edgeverts[i*2];
 +                      p2 = edgeverts[i*2+1];
 +                      p3 = edgeverts[j*2];
 +                      p4 = edgeverts[j*2+1];
 +
 +                      VECCOPY(v1, p1);
 +                      VECCOPY(v2, p2);
 +
 +                      shrink_edgef(v1, v2, fac1);
 +
 +                      if (linecrossesf(v1, v2, p3, p4)) {
 +                              loops[i][0]=NULL;
 +                      }
 +              }
 +      }
 +      
 +      if (projverts != projectverts) MEM_freeN(projverts);
 +      if (edgeverts != edgevertsstack) MEM_freeN(edgeverts);
 +}
index 51f3d2411e1ffe314f4a3ddb329748cabf3ae319,0000000000000000000000000000000000000000..1d956a8b4ae2f561aecfce93719dcab582624e28
mode 100644,000000..100644
--- /dev/null
@@@ -1,90 -1,0 +1,98 @@@
 +#include "MEM_guardedalloc.h"
 +#include "BKE_customdata.h" 
 +#include "DNA_listBase.h"
 +#include "DNA_customdata_types.h"
 +#include "DNA_mesh_types.h"
 +#include "DNA_meshdata_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_scene_types.h"
 +#include <string.h>
 +#include "BKE_utildefines.h"
 +#include "BKE_mesh.h"
 +#include "BKE_global.h"
 +#include "BKE_DerivedMesh.h"
 +#include "BKE_cdderivedmesh.h"
 +
 +#include "BLI_editVert.h"
 +#include "mesh_intern.h"
 +#include "ED_mesh.h"
 +
 +#include "BLI_arithb.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_edgehash.h"
 +
 +#include "bmesh.h"
 +
 +/*
 + * UTILS.C
 + *
 + * utility bmesh operators, e.g. transform, 
 + * translate, rotate, scale, etc.
 + *
 +*/
 +
 +void bmesh_makevert_exec(BMesh *bm, BMOperator *op) {
 +      float vec[3];
 +
 +      BMO_Get_Vec(op, "co", vec);
 +
 +      BMO_SetFlag(bm, BM_Make_Vert(bm, vec, NULL), 1);        
 +      BMO_Flag_To_Slot(bm, op, "newvertout", 1, BM_VERT);
 +}
 +
 +void bmesh_transform_exec(BMesh *bm, BMOperator *op) {
 +      BMOIter iter;
 +      BMVert *v;
 +      float mat[4][4];
 +
 +      BMO_Get_Mat4(op, "mat", mat);
 +
 +      BMO_ITER(v, &iter, bm, op, "verts", BM_VERT) {
 +              Mat4MulVecfl(mat, v->co);
 +      }
 +}
 +
 +/*this operator calls the transform operator, which
 +  is a little complex, but makes it easier to make
 +  sure the transform op is working, since initially
 +  only this one will be used.*/
 +void bmesh_translate_exec(BMesh *bm, BMOperator *op) {
 +      BMOIter iter;
 +      BMVert *v;
 +      float mat[4][4], vec[3];
 +      
 +      BMO_Get_Vec(op, "vec", vec);
 +
 +      Mat4One(mat);
 +      VECCOPY(mat[3], vec);
 +
 +      BMO_CallOpf(bm, "transform mat=%m4 verts=%s", mat, op, "verts");
 +}
 +
 +void bmesh_rotate_exec(BMesh *bm, BMOperator *op) {
 +      BMOIter iter;
 +      BMVert *v;
 +      float mat[4][4], vec[3];
 +      
 +      BMO_Get_Vec(op, "cent", vec);
 +      
 +      /*there has to be a proper matrix way to do this, but
 +        this is how editmesh did it and I'm too tired to think
 +        through the math right now.*/
 +      VecMulf(vec, -1);
 +      BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec);
 +
 +      BMO_CallOpf(bm, "transform mat=%s verts=%s", op, "mat", op, "verts");
 +
 +      VecMulf(vec, -1);
 +      BMO_CallOpf(bm, "translate verts=%s vec=%v", op, "verts", vec);
 +}
 +
++void bmesh_reversefaces_exec(BMesh *bm, BMOperator *op) {
++      BMOIter iter;
++      BMFace *f;
++
++      BMO_ITER(f, &iter, bm, op, "faces", BM_FACE) {
++              BM_flip_normal(bm, f);
++      }
++}
index 11049bc12107545a134c90dba688051eb44cf647,0000000000000000000000000000000000000000..23815bcb77fac22e85e59e7fa1e91469d0aed602
mode 100644,000000..100644
--- /dev/null
@@@ -1,1453 -1,0 +1,1482 @@@
-       WM_operator_name_call(C, "TFM_OT_translation", WM_OP_INVOKE_REGION_WIN, op->ptr);
 + /* $Id: bmesh_tools.c
 + *
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * The Original Code is Copyright (C) 2004 by Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): Joseph Eagar
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +#include <stdlib.h>
 +#include <stdarg.h>
 +#include <string.h>
 +#include <math.h>
 +#include <float.h>
 +
 +#include "MEM_guardedalloc.h"
 +#include "PIL_time.h"
 +
 +#include "BLO_sys_types.h" // for intptr_t support
 +
 +#include "DNA_mesh_types.h"
 +#include "DNA_material_types.h"
 +#include "DNA_meshdata_types.h"
 +#include "DNA_modifier_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_scene_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_view3d_types.h"
 +#include "DNA_key_types.h"
 +#include "DNA_windowmanager_types.h"
 +
 +#include "RNA_types.h"
 +#include "RNA_define.h"
 +#include "RNA_access.h"
 +
 +#include "BLI_blenlib.h"
 +#include "BLI_arithb.h"
 +#include "BLI_editVert.h"
 +#include "BLI_rand.h"
 +#include "BLI_ghash.h"
 +#include "BLI_linklist.h"
 +#include "BLI_heap.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_customdata.h"
 +#include "BKE_depsgraph.h"
 +#include "BKE_global.h"
 +#include "BKE_library.h"
 +#include "BKE_mesh.h"
 +#include "BKE_object.h"
 +#include "BKE_utildefines.h"
 +#include "BKE_bmesh.h"
 +#include "BKE_report.h"
 +#include "BKE_tessmesh.h"
 +
 +#include "BIF_gl.h"
 +#include "BIF_glutil.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +
 +#include "ED_mesh.h"
 +#include "ED_view3d.h"
 +#include "ED_util.h"
 +#include "ED_screen.h"
 +#include "ED_transform.h"
 +
 +#include "UI_interface.h"
 +
 +#include "mesh_intern.h"
 +#include "bmesh.h"
 +
 +static void add_normal_aligned(float *nor, float *add)
 +{
 +      if( INPR(nor, add) < -0.9999f)
 +              VecSubf(nor, nor, add);
 +      else
 +              VecAddf(nor, nor, add);
 +}
 +
 +
 +static int subdivide_exec(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      int cuts= RNA_int_get(op->ptr,"number_cuts");
 +      float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
 +      float fractal= RNA_float_get(op->ptr, "fractal")/100;
 +      int flag= 0;
 +
 +      if(smooth != 0.0f)
 +              flag |= B_SMOOTH;
 +      if(fractal != 0.0f)
 +              flag |= B_FRACTAL;
 +
 +      BM_esubdivideflag(obedit, em->bm, BM_SELECT, smooth, fractal, scene->toolsettings->editbutflag|flag, cuts, 0);
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_subdivide(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Subdivide";
 +      ot->idname= "MESH_OT_subdivide";
 +
 +      /* api callbacks */
 +      ot->exec= subdivide_exec;
 +      ot->poll= ED_operator_editmesh;
 +
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +
 +      /* properties */
 +      RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
 +      RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
 +      RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX);
 +}
 +
 +#if 0
 +static int subdivide_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      
 +      BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, 1, 0);
 +              
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_subdivide(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Subdivide";
 +      ot->idname= "MESH_OT_subdivide";
 +      
 +      /* api callbacks */
 +      ot->exec= subdivide_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +static int subdivide_multi_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      
 +      BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, RNA_int_get(op->ptr,"number_cuts"), 0);
 +              
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_subdivide_multi(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Subdivide Multi";
 +      ot->idname= "MESH_OT_subdivide_multi";
 +      
 +      /* api callbacks */
 +      ot->exec= subdivide_multi_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* props */
 +      RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX);
 +}
 +
 +static int subdivide_multi_fractal_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +
 +      BM_esubdivideflag(obedit, em->bm, 1, -(RNA_float_get(op->ptr, "random_factor")/100), scene->toolsettings->editbutflag, RNA_int_get(op->ptr, "number_cuts"), 0);
 +              
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_subdivide_multi_fractal(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Subdivide Multi Fractal";
 +      ot->idname= "MESH_OT_subdivide_multi_fractal";
 +      
 +      /* api callbacks */
 +      ot->exec= subdivide_multi_fractal_exec;
 +      ot->poll= ED_operator_editmesh;
 +
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* properties */
 +      RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX);
 +      RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f);
 +}
 +
 +static int subdivide_smooth_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +
 +      BM_esubdivideflag(obedit, em->bm, 1, 0.292f*RNA_float_get(op->ptr, "smoothness"), scene->toolsettings->editbutflag | B_SMOOTH, 1, 0);
 +              
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_subdivide_smooth(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Subdivide Smooth";
 +      ot->idname= "MESH_OT_subdivide_smooth";
 +      
 +      /* api callbacks */
 +      ot->exec= subdivide_smooth_exec;
 +      ot->poll= ED_operator_editmesh;
 +
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* props */
 +      RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX);
 +}
 +
 +static int subdivs_invoke(bContext *C, wmOperator *op, wmEvent *event)
 +{
 +      uiPopupMenu *pup;
 +      uiLayout *layout;
 +
 +      pup= uiPupMenuBegin(C, "Subdivision Type", 0);
 +      layout= uiPupMenuLayout(pup);
 +      uiItemsEnumO(layout, "MESH_OT_subdivs", "type");
 +      uiPupMenuEnd(C, pup);
 +      
 +      return OPERATOR_CANCELLED;
 +}
 +
 +static int subdivs_exec(bContext *C, wmOperator *op)
 +{     
 +      switch(RNA_int_get(op->ptr, "type"))
 +      {
 +              case 0: // simple
 +                      subdivide_exec(C,op);
 +                      break;
 +              case 1: // multi
 +                      subdivide_multi_exec(C,op);
 +                      break;
 +              case 2: // fractal;
 +                      subdivide_multi_fractal_exec(C,op);
 +                      break;
 +              case 3: //smooth
 +                      subdivide_smooth_exec(C,op);
 +                      break;
 +      }
 +                                       
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_subdivs(wmOperatorType *ot)
 +{
 +      static EnumPropertyItem type_items[]= {
 +              {0, "SIMPLE", 0, "Simple", ""},
 +              {1, "MULTI", 0, "Multi", ""},
 +              {2, "FRACTAL", 0, "Fractal", ""},
 +              {3, "SMOOTH", 0, "Smooth", ""},
 +              {0, NULL, NULL}};
 +
 +      /* identifiers */
 +      ot->name= "subdivs";
 +      ot->idname= "MESH_OT_subdivs";
 +      
 +      /* api callbacks */
 +      ot->invoke= subdivs_invoke;
 +      ot->exec= subdivs_exec;
 +      
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /*props */
 +      RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
 +      
 +      /* this is temp, the ops are different, but they are called from subdivs, so all the possible props should be here as well*/
 +      RNA_def_int(ot->srna, "number_cuts", 4, 1, 10, "Number of Cuts", "", 1, INT_MAX);
 +      RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f);
 +      RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX);            
 +}
 +#endif
 +
 +/* individual face extrude */
 +/* will use vertex normals for extrusion directions, so *nor is unaffected */
 +short EDBM_Extrude_face_indiv(BMEditMesh *em, short flag, float *nor)
 +{
 +#if 0
 +      EditVert *eve, *v1, *v2, *v3, *v4;
 +      EditEdge *eed;
 +      EditFace *efa, *nextfa;
 +      
 +      if(em==NULL) return 0;
 +      
 +      /* selected edges with 1 or more selected face become faces */
 +      /* selected faces each makes new faces */
 +      /* always remove old faces, keeps volumes manifold */
 +      /* select the new extrusion, deselect old */
 +      
 +      /* step 1; init, count faces in edges */
 +      recalc_editnormals(em);
 +      
 +      for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;      // new select flag
 +
 +      for(eed= em->edges.first; eed; eed= eed->next) {
 +              eed->f2= 0; // amount of unselected faces
 +      }
 +      for(efa= em->faces.first; efa; efa= efa->next) {
 +              if(efa->f & SELECT);
 +              else {
 +                      efa->e1->f2++;
 +                      efa->e2->f2++;
 +                      efa->e3->f2++;
 +                      if(efa->e4) efa->e4->f2++;
 +              }
 +      }
 +
 +      /* step 2: make new faces from faces */
 +      for(efa= em->faces.last; efa; efa= efa->prev) {
 +              if(efa->f & SELECT) {
 +                      v1= addvertlist(em, efa->v1->co, efa->v1);
 +                      v2= addvertlist(em, efa->v2->co, efa->v2);
 +                      v3= addvertlist(em, efa->v3->co, efa->v3);
 +                      
 +                      v1->f1= v2->f1= v3->f1= 1;
 +                      VECCOPY(v1->no, efa->n);
 +                      VECCOPY(v2->no, efa->n);
 +                      VECCOPY(v3->no, efa->n);
 +                      if(efa->v4) {
 +                              v4= addvertlist(em, efa->v4->co, efa->v4); 
 +                              v4->f1= 1;
 +                              VECCOPY(v4->no, efa->n);
 +                      }
 +                      else v4= NULL;
 +                      
 +                      /* side faces, clockwise */
 +                      addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
 +                      addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
 +                      if(efa->v4) {
 +                              addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
 +                              addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
 +                      }
 +                      else {
 +                              addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
 +                      }
 +                      /* top face */
 +                      addfacelist(em, v1, v2, v3, v4, efa, NULL);
 +              }
 +      }
 +      
 +      /* step 3: remove old faces */
 +      efa= em->faces.first;
 +      while(efa) {
 +              nextfa= efa->next;
 +              if(efa->f & SELECT) {
 +                      BLI_remlink(&em->faces, efa);
 +                      free_editface(em, efa);
 +              }
 +              efa= nextfa;
 +      }
 +
 +      /* step 4: redo selection */
 +      EM_clear_flag_all(em, SELECT);
 +      
 +      for(eve= em->verts.first; eve; eve= eve->next) {
 +              if(eve->f1)  eve->f |= SELECT;
 +      }
 +      
 +      EM_select_flush(em);
 +      
 +      return 'n';
 +#endif
 +}
 +
 +
 +/* extrudes individual edges */
 +/* nor is filled with constraint vector */
 +short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor) 
 +{
 +#if 0
 +      EditVert *eve;
 +      EditEdge *eed;
 +      EditFace *efa;
 +      
 +      for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
 +      for(eed= em->edges.first; eed; eed= eed->next) {
 +              eed->tmp.f = NULL;
 +              eed->f2= ((eed->f & flag)!=0);
 +      }
 +      
 +      set_edge_directions_f2(em, 2);
 +
 +      /* sample for next loop */
 +      for(efa= em->faces.first; efa; efa= efa->next) {
 +              efa->e1->tmp.f = efa;
 +              efa->e2->tmp.f = efa;
 +              efa->e3->tmp.f = efa;
 +              if(efa->e4) efa->e4->tmp.f = efa;
 +      }
 +      /* make the faces */
 +      for(eed= em->edges.first; eed; eed= eed->next) {
 +              if(eed->f & flag) {
 +                      if(eed->v1->tmp.v == NULL)
 +                              eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
 +                      if(eed->v2->tmp.v == NULL)
 +                              eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
 +
 +                      if(eed->dir==1) 
 +                              addfacelist(em, eed->v1, eed->v2, 
 +                                                      eed->v2->tmp.v, eed->v1->tmp.v, 
 +                                                      eed->tmp.f, NULL);
 +                      else 
 +                              addfacelist(em, eed->v2, eed->v1, 
 +                                                      eed->v1->tmp.v, eed->v2->tmp.v, 
 +                                                      eed->tmp.f, NULL);
 +
 +                      /* for transform */
 +                      if(eed->tmp.f) {
 +                              efa = eed->tmp.f;
 +                              if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
 +                      }
 +              }
 +      }
 +      Normalize(nor);
 +      
 +      /* set correct selection */
 +      EM_clear_flag_all(em, SELECT);
 +      for(eve= em->verts.last; eve; eve= eve->prev) {
 +              if(eve->tmp.v) {
 +                      eve->tmp.v->f |= flag;
 +              }
 +      }
 +
 +      for(eed= em->edges.first; eed; eed= eed->next) {
 +              if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
 +      }
 +      
 +      if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
 +#endif
 +      return 'n';  // n is for normal constraint
 +}
 +
 +/* extrudes individual vertices */
 +short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
 +{
 +      BMOperator bmop;
 +      BMOIter siter;
 +      BMVert *v;
 +
 +      EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
 +
 +      /*deselect original verts*/
 +      v = BMO_IterNew(&siter, em->bm, &bmop, "verts", BM_VERT);
 +      for (; v; v=BMO_IterStep(&siter)) {
 +              BM_Select(em->bm, v, 0);
 +      }
 +
 +      BMO_Exec_Op(em->bm, &bmop);
 +
 +      v = BMO_IterNew(&siter, em->bm, &bmop, "vertout", BM_VERT);
 +      for (; v; v=BMO_IterStep(&siter)) {
 +              BM_Select(em->bm, v, 1);
 +      }
 +
 +      if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
 +
 +      return 'g'; // g is grab
 +}
 +
 +short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
 +{
 +      BMesh *bm = em->bm;
 +      BMIter iter;
 +      BMOIter siter;
 +      BMOperator extop;
 +      BMVert *vert;
 +      BMEdge *edge;
 +      BMFace *f;
 +      ModifierData *md;
 +      BMHeader *el;
 +      
 +      BMO_Init_Op(&extop, "extrudefaceregion");
 +      BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
 +                             flag, BM_VERT|BM_EDGE|BM_FACE);
 +
 +      BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) {
 +              BM_Select(bm, vert, 0);
 +      }
 +
 +      BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
 +              BM_Select(bm, edge, 0);
 +      }
 +
 +      BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
 +              BM_Select(bm, f, 0);
 +      }
 +
 +      /* If a mirror modifier with clipping is on, we need to adjust some 
 +       * of the cases above to handle edges on the line of symmetry.
 +       */
 +      md = obedit->modifiers.first;
 +      for (; md; md=md->next) {
 +              if (md->type==eModifierType_Mirror) {
 +                      MirrorModifierData *mmd = (MirrorModifierData*) md;     
 +              
 +                      if(mmd->flag & MOD_MIR_CLIPPING) {
 +                              float mtx[4][4];
 +                              if (mmd->mirror_ob) {
 +                                      float imtx[4][4];
 +                                      Mat4Invert(imtx, mmd->mirror_ob->obmat);
 +                                      Mat4MulMat4(mtx, obedit->obmat, imtx);
 +                              }
 +
 +                              for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
 +                                   edge; edge=BMIter_Step(&iter))
 +                              {
 +                                      if(edge->head.flag & flag) {
 +                                              float co1[3], co2[3];
 +
 +                                              VecCopyf(co1, edge->v1->co);
 +                                              VecCopyf(co2, edge->v2->co);
 +
 +                                              if (mmd->mirror_ob) {
 +                                                      VecMat4MulVecfl(co1, mtx, co1);
 +                                                      VecMat4MulVecfl(co2, mtx, co2);
 +                                              }
 +
 +                                              if (mmd->flag & MOD_MIR_AXIS_X)
 +                                                      if ( (fabs(co1[0]) < mmd->tolerance) &&
 +                                                               (fabs(co2[0]) < mmd->tolerance) )
 +                                                              BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
 +
 +                                              if (mmd->flag & MOD_MIR_AXIS_Y)
 +                                                      if ( (fabs(co1[1]) < mmd->tolerance) &&
 +                                                               (fabs(co2[1]) < mmd->tolerance) )
 +                                                              BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
 +
 +                                              if (mmd->flag & MOD_MIR_AXIS_Z)
 +                                                      if ( (fabs(co1[2]) < mmd->tolerance) &&
 +                                                               (fabs(co2[2]) < mmd->tolerance) )
 +                                                              BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      BMO_Exec_Op(bm, &extop);
 +
 +      nor[0] = nor[1] = nor[2] = 0.0f;
 +      
 +      BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
 +              BM_Select(bm, el, 1);
 +
 +              if (el->type == BM_FACE) {
 +                      f = (BMFace*)el;
 +                      add_normal_aligned(nor, f->no);
 +              };
 +      }
 +
 +      Normalize(nor);
 +
 +      BMO_Finish_Op(bm, &extop);
 +
 +      if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
 +      return 'n'; // normal constraint 
 +
 +}
 +short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
 +{
 +              BMIter iter;
 +              BMEdge *eed;
 +              
 +              /*ensure vert flags are consistent for edge selections*/
 +              eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
 +              for ( ; eed; eed=BMIter_Step(&iter)) {
 +                      if (BM_TestHFlag(eed, flag)) {
 +                              if (flag != BM_SELECT) {
 +                                      BM_SetHFlag(eed->v1, flag);
 +                                      BM_SetHFlag(eed->v2, flag);
 +                              } else {
 +                                      BM_Select(em->bm, eed->v1, 1);
 +                                      BM_Select(em->bm, eed->v2, 1);
 +                              }
 +                      } else {
 +                              if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) {
 +                                      if (flag != BM_SELECT)
 +                                              BM_SetHFlag(eed, flag);
 +                                      else BM_Select(em->bm, eed, 1);
 +                              }
 +                      }
 +              }
 +
 +              return EDBM_Extrude_edge(obedit, em, flag, nor);
 +
 +}
 +
 +static int extrude_repeat_mesh(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
 +      RegionView3D *rv3d = CTX_wm_region_view3d(C);           
 +              
 +      int steps = RNA_int_get(op->ptr,"steps");
 +      
 +      float offs = RNA_float_get(op->ptr,"offset");
 +
 +      float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
 +      short a;
 +
 +      /* dvec */
 +      dvec[0]= rv3d->persinv[2][0];
 +      dvec[1]= rv3d->persinv[2][1];
 +      dvec[2]= rv3d->persinv[2][2];
 +      Normalize(dvec);
 +      dvec[0]*= offs;
 +      dvec[1]*= offs;
 +      dvec[2]*= offs;
 +
 +      /* base correction */
 +      Mat3CpyMat4(bmat, obedit->obmat);
 +      Mat3Inv(tmat, bmat);
 +      Mat3MulVecfl(tmat, dvec);
 +
 +      for(a=0; a<steps; a++) {
 +              EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
 +              //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
 +              BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
 +              //extrudeflag(obedit, em, SELECT, nor);
 +              //translateflag(em, SELECT, dvec);
 +      }
 +      
 +      EDBM_RecalcNormals(em);
 +
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_extrude_repeat(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Extrude Repeat Mesh";
 +      ot->idname= "MESH_OT_extrude_repeat";
 +      
 +      /* api callbacks */
 +      ot->exec= extrude_repeat_mesh;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* props */
 +      RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
 +      RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
 +}
 +
 +/* generic extern called extruder */
 +int EDBM_Extrude_Mesh(Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
 +{
 +      Scene *scene= NULL;             // XXX CTX!
 +      short nr, transmode= 0;
 +      float stacknor[3] = {0.0f, 0.0f, 0.0f};
 +      float *nor = norin ? norin : stacknor;
 +
 +      nor[0] = nor[1] = nor[2] = 0.0f;
 +      if(em->selectmode & SCE_SELECT_VERTEX) {
 +              if(em->bm->totvertsel==0) nr= 0;
 +              else if(em->bm->totvertsel==1) nr= 4;
 +              else if(em->bm->totedgesel==0) nr= 4;
 +              else if(em->bm->totfacesel==0) 
 +                      nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
 +              else if(em->bm->totfacesel==1)
 +                      nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
 +              else 
 +                      nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
 +      }
 +      else if(em->selectmode & SCE_SELECT_EDGE) {
 +              if (em->bm->totedgesel==0) nr = 0;
 +              
 +              nr = 1;
 +              /*else if (em->totedgesel==1) nr = 3;
 +              else if(em->totfacesel==0) nr = 3;
 +              else if(em->totfacesel==1)
 +                      nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
 +              else
 +                      nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
 +              */
 +      }
 +      else {
 +              if (em->bm->totfacesel == 0) nr = 0;
 +              else if (em->bm->totfacesel == 1) nr = 1;
 +              else
 +                      nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
 +      }
 +              
 +      if(nr<1) return 'g';
 +
 +      if(nr==1 && em->selectmode & SCE_SELECT_VERTEX) 
 +              transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
 +      else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
 +      else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
 +      else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, SELECT, nor);
 +      else transmode= EDBM_Extrude_face_indiv(em, SELECT, nor);
 +      
 +      if(transmode==0) {
 +              BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
 +      }
 +      else {
 +              
 +                      /* We need to force immediate calculation here because 
 +                      * transform may use derived objects (which are now stale).
 +                      *
 +                      * This shouldn't be necessary, derived queries should be
 +                      * automatically building this data if invalid. Or something.
 +                      */
 +//            DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
 +              object_handle_update(scene, obedit);
 +
 +              /* individual faces? */
 +//            BIF_TransformSetUndo("Extrude");
 +              if(nr==2) {
 +//                    initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
 +//                    Transform();
 +              }
 +              else {
 +//                    initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
 +                      if(transmode=='n') {
 +                              Mat4MulVecfl(obedit->obmat, nor);
 +                              VecSubf(nor, nor, obedit->obmat[3]);
 +//                            BIF_setSingleAxisConstraint(nor, "along normal");
 +                      }
 +//                    Transform();
 +              }
 +      }
 +      
 +      return transmode;
 +}
 +
 +static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
 +{
 +      Scene *scene= CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
 +      int constraint_axis[3] = {0, 0, 1};
 +      int tmode;
 +
 +      tmode = EDBM_Extrude_Mesh(obedit, em, op, NULL);
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      RNA_enum_set(op->ptr, "proportional", 0);
 +      RNA_boolean_set(op->ptr, "mirror", 0);
 +
 +      if (tmode == 'n') {
 +              RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
 +              RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
 +      }
++      WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +/* extrude without transform */
 +static int mesh_extrude_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
 +      
 +      EDBM_Extrude_Mesh(obedit, em, op, NULL);
 +      
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      
 +      return OPERATOR_FINISHED;       
 +}
 +
 +
 +void MESH_OT_extrude(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Extrude";
 +      ot->idname= "MESH_OT_extrude";
 +      
 +      /* api callbacks */
 +      ot->invoke= mesh_extrude_invoke;
 +      ot->exec= mesh_extrude_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +
 +      /* to give to transform */
 +      Properties_Proportional(ot);
 +      Properties_Constraints(ot);
 +      RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
 +}
 +
 +/* ******************** (de)select all operator **************** */
 +
 +void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */
 +{
 +      if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
 +              EDBM_clear_flag_all(em, SELECT);
 +      else 
 +              EDBM_set_flag_all(em, SELECT);
 +}
 +
 +static int toggle_select_all_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      
 +      EDBM_toggle_select_all(em);
 +      
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_select_all_toggle(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Select/Deselect All";
 +      ot->idname= "MESH_OT_select_all_toggle";
 +      
 +      /* api callbacks */
 +      ot->exec= toggle_select_all_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +/* *************** add-click-mesh (extrude) operator ************** */
 +
 +static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
 +{
 +      ViewContext vc;
 +      BMVert *eve, *v1;
 +      BMIter iter;
 +      float min[3], max[3];
 +      int done= 0;
 +      
 +      em_setup_viewcontext(C, &vc);
 +      
 +      INIT_MINMAX(min, max);
 +      
 +      BM_ITER(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL) {
 +              if(BM_TestHFlag(v1, BM_SELECT)) {
 +                      DO_MINMAX(v1->co, min, max);
 +                      done= 1;
 +              }
 +      }
 +
 +      /* call extrude? */
 +      if(done) {
 +              BMEdge *eed;
 +              float vec[3], cent[3], mat[3][3];
 +              float nor[3]= {0.0, 0.0, 0.0};
 +              
 +              /* check for edges that are half selected, use for rotation */
 +              done= 0;
 +              BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) {
 +                      if (BM_TestHFlag(eed->v1, BM_SELECT) ^ BM_TestHFlag(eed->v2, BM_SELECT)) {
 +                              if(BM_TestHFlag(eed->v1, BM_SELECT)) 
 +                                      VecSubf(vec, eed->v1->co, eed->v2->co);
 +                              else 
 +                                      VecSubf(vec, eed->v2->co, eed->v1->co);
 +                              VecAddf(nor, nor, vec);
 +                              done= 1;
 +                      }
 +              }
 +              if(done) Normalize(nor);
 +              
 +              /* center */
 +              VecAddf(cent, min, max);
 +              VecMulf(cent, 0.5f);
 +              VECCOPY(min, cent);
 +              
 +              Mat4MulVecfl(vc.obedit->obmat, min);    // view space
 +              view3d_get_view_aligned_coordinate(&vc, min, event->mval);
 +              Mat4Invert(vc.obedit->imat, vc.obedit->obmat); 
 +              Mat4MulVecfl(vc.obedit->imat, min); // back in object space
 +              
 +              VecSubf(min, min, cent);
 +              
 +              /* calculate rotation */
 +              Mat3One(mat);
 +              if(done) {
 +                      float dot;
 +                      
 +                      VECCOPY(vec, min);
 +                      Normalize(vec);
 +                      dot= INPR(vec, nor);
 +
 +                      if( fabs(dot)<0.999) {
 +                              float cross[3], si, q1[4];
 +                              
 +                              Crossf(cross, nor, vec);
 +                              Normalize(cross);
 +                              dot= 0.5f*saacos(dot);
 +                              si= (float)sin(dot);
 +                              q1[0]= (float)cos(dot);
 +                              q1[1]= cross[0]*si;
 +                              q1[2]= cross[1]*si;
 +                              q1[3]= cross[2]*si;
 +                              
 +                              QuatToMat3(q1, mat);
 +                      }
 +              }
 +              
 +
 +              EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor);
 +              EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
 +                      BM_SELECT, cent, mat);
 +              EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
 +                      BM_SELECT, min);
 +      }
 +      else {
 +              float *curs= give_cursor(vc.scene, vc.v3d);
 +              BMOperator bmop;
 +              BMOIter oiter;
 +              
 +              VECCOPY(min, curs);
 +
 +              view3d_get_view_aligned_coordinate(&vc, min, event->mval);
 +              Mat4Invert(vc.obedit->imat, vc.obedit->obmat); 
 +              Mat4MulVecfl(vc.obedit->imat, min); // back in object space
 +              
 +              EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min);
 +              BMO_Exec_Op(vc.em->bm, &bmop);
 +
 +              BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
 +                      BM_Select(vc.em->bm, v1, 1);
 +              }
 +
 +              if (!EDBM_FinishOp(vc.em, &bmop, op, 1))
 +                      return OPERATOR_CANCELLED;
 +      }
 +
 +      //retopo_do_all();
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); 
 +      DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Duplicate or Extrude at 3D Cursor";
 +      ot->idname= "MESH_OT_dupli_extrude_cursor";
 +      
 +      /* api callbacks */
 +      ot->invoke= dupli_extrude_cursor;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +static int delete_mesh(Object *obedit, wmOperator *op, int event, Scene *scene)
 +{
 +      BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh;
 +      
 +      if(event<1) return OPERATOR_CANCELLED;
 +
 +      if(event==10 ) {
 +              //"Erase Vertices";
 +
 +              if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS))
 +                      return OPERATOR_CANCELLED;
 +      } 
 +      else if(event==11) {
 +              //"Edge Loop"
 +              if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT))
 +                      return OPERATOR_CANCELLED;
 +      }
 +      else if(event==7) {
 +              //"Dissolve"
 +              if (bem->selectmode & SCE_SELECT_FACE) {
 +                      if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT))
 +                              return OPERATOR_CANCELLED;
 +              } else if (bem->selectmode & SCE_SELECT_EDGE) {
 +                      if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT))
 +                              return OPERATOR_CANCELLED;
 +              } else if (bem->selectmode & SCE_SELECT_VERTEX) {
 +                      if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT))
 +                              return OPERATOR_CANCELLED;
 +              }
 +      }
 +      else if(event==4) {
 +              //Edges and Faces
 +              if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES))
 +                      return OPERATOR_CANCELLED;
 +      } 
 +      else if(event==1) {
 +              //"Erase Edges"
 +              if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES))
 +                      return OPERATOR_CANCELLED;
 +      }
 +      else if(event==2) {
 +              //"Erase Faces";
 +              if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES))
 +                      return OPERATOR_CANCELLED;
 +      }
 +      else if(event==5) {
 +              //"Erase Only Faces";
 +              if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
 +                                BM_SELECT, DEL_ONLYFACES))
 +                      return OPERATOR_CANCELLED;
 +      }
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +/* Note, these values must match delete_mesh() event values */
 +static EnumPropertyItem prop_mesh_delete_types[] = {
 +      {7, "DISSOLVE",         0, "Dissolve", ""},
 +      {10,"VERT",             0, "Vertices", ""},
 +      {1, "EDGE",             0, "Edges", ""},
 +      {2, "FACE",             0, "Faces", ""},
 +      {11, "EDGE_LOOP", 0, "Edge Loop", ""},
 +      {4, "EDGE_FACE", 0, "Edges & Faces", ""},
 +      {5, "ONLY_FACE", 0, "Only Faces", ""},
 +      {0, NULL, 0, NULL, NULL}
 +};
 +
 +static int delete_mesh_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +
 +      delete_mesh(obedit, op, RNA_enum_get(op->ptr, "type"), scene);
 +      
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA|ND_GEOM_SELECT, obedit);
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_delete(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Delete";
 +      ot->idname= "MESH_OT_delete";
 +      
 +      /* api callbacks */
 +      ot->invoke= WM_menu_invoke;
 +      ot->exec= delete_mesh_exec;
 +      
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /*props */
 +      RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
 +}
 +
 +
 +static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
 +{
 +      BMOperator bmop;
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      
 +      if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT))
 +              return OPERATOR_CANCELLED;
 +      
 +      BMO_Exec_Op(em->bm, &bmop);
 +      BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT);
 +
 +      if (!EDBM_FinishOp(em, &bmop, op, 1))
 +              return OPERATOR_CANCELLED;
 +
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);     
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_edge_face_add(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Make Edge/Face";
 +      ot->idname= "MESH_OT_edge_face_add";
 +      
 +      /* api callbacks */
 +      ot->exec= addedgeface_mesh_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +}
 +
 +static EnumPropertyItem prop_mesh_edit_types[] = {
 +      {1, "VERT", 0, "Vertices", ""},
 +      {2, "EDGE", 0, "Edges", ""},
 +      {3, "FACE", 0, "Faces", ""},
 +      {0, NULL, 0, NULL, NULL}
 +};
 +
 +static int mesh_selection_type_exec(bContext *C, wmOperator *op)
 +{             
 +      
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      int type = RNA_enum_get(op->ptr,"type");
 +
 +      switch (type) {
 +              case 1:
 +                      em->selectmode = SCE_SELECT_VERTEX;
 +                      break;
 +              case 2:
 +                      em->selectmode = SCE_SELECT_EDGE;
 +                      break;
 +              case 3:
 +                      em->selectmode = SCE_SELECT_FACE;
 +                      break;
 +      }
 +
 +      EDBM_selectmode_set(em);
 +      CTX_data_scene(C)->toolsettings->selectmode = em->selectmode;
 +
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_selection_type(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Selection Mode";
 +      ot->idname= "MESH_OT_selection_type";
 +      
 +      /* api callbacks */
 +      ot->invoke= WM_menu_invoke;
 +      ot->exec= mesh_selection_type_exec;
 +      
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* props */
 +      RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
 +      RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode");       
 +}
 +
 +/* ************************* SEAMS AND EDGES **************** */
 +
 +static int editbmesh_mark_seam(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      Mesh *me= ((Mesh *)obedit->data);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      BMesh *bm = em->bm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int clear = RNA_boolean_get(op->ptr, "clear");
 +      
 +      /* auto-enable seams drawing */
 +      if(clear==0) {
 +              me->drawflag |= ME_DRAWSEAMS;
 +      }
 +
 +      if(clear) {
 +              BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
 +                      if (BM_TestHFlag(eed, BM_HIDDEN) == 0 &&
 +                          BM_TestHFlag(eed, BM_SELECT) != 0)
 +                      {
 +                              BM_ClearHFlag(eed, BM_SEAM);
 +                      }
 +              }
 +      }
 +      else {
 +              BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
 +                      if (BM_TestHFlag(eed, BM_HIDDEN) == 0 &&
 +                          BM_TestHFlag(eed, BM_SELECT) != 0)
 +                      {
 +                              BM_SetHFlag(eed, BM_SEAM);
 +                      }
 +              }
 +      }
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_mark_seam(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Mark Seam";
 +      ot->idname= "MESH_OT_mark_seam";
 +      
 +      /* api callbacks */
 +      ot->exec= editbmesh_mark_seam;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
 +}
 +
 +static int editbmesh_mark_sharp(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      Mesh *me= ((Mesh *)obedit->data);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      BMesh *bm = em->bm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int clear = RNA_boolean_get(op->ptr, "clear");
 +
 +      /* auto-enable sharp edge drawing */
 +      if(clear == 0) {
 +              me->drawflag |= ME_DRAWSHARP;
 +      }
 +
 +      if(!clear) {
 +              BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
 +                      if (BM_TestHFlag(eed, BM_HIDDEN) == 0 &&
 +                          BM_TestHFlag(eed, BM_SELECT) != 0)
 +                      {
 +                              BM_SetHFlag(eed, BM_SHARP);
 +                      }
 +              }
 +      } else {
 +              BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) {
 +                      if (BM_TestHFlag(eed, BM_HIDDEN) == 0 &&
 +                          BM_TestHFlag(eed, BM_SELECT) != 0)
 +                      {
 +                              BM_ClearHFlag(eed, BM_SHARP);
 +                      }
 +              }
 +      }
 +
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_mark_sharp(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Mark Sharp";
 +      ot->idname= "MESH_OT_mark_sharp";
 +      
 +      /* api callbacks */
 +      ot->exec= editbmesh_mark_sharp;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
 +}
 +
 +
 +static int editbmesh_vert_connect(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      Mesh *me= ((Mesh *)obedit->data);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      BMesh *bm = em->bm;
 +      BMOperator bmop;
 +      int len = 0;
 +      
 +      BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT);
 +      BMO_Exec_Op(bm, &bmop);
 +      len = BMO_GetSlot(&bmop, "edgeout")->len;
 +      BMO_Finish_Op(bm, &bmop);
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 +}
 +
 +void MESH_OT_vert_connect(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Vertex Connect";
 +      ot->idname= "MESH_OT_vert_connect";
 +      
 +      /* api callbacks */
 +      ot->exec= editbmesh_vert_connect;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +static int editbmesh_edge_split(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      Mesh *me= ((Mesh *)obedit->data);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      BMesh *bm = em->bm;
 +      BMOperator bmop;
 +      int len = 0;
 +      
 +      BMO_InitOpf(bm, &bmop, "edgesplit edges=%he numcuts=%d", BM_SELECT, RNA_int_get(op->ptr,"number_cuts"));
 +      BMO_Exec_Op(bm, &bmop);
 +      len = BMO_GetSlot(&bmop, "outsplit")->len;
 +      BMO_Finish_Op(bm, &bmop);
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 +}
 +
 +void MESH_OT_edge_split(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Edge Split";
 +      ot->idname= "MESH_OT_edge_split";
 +      
 +      /* api callbacks */
 +      ot->exec= editbmesh_edge_split;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +
 +      RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
 +}
 +
 +/****************** add duplicate operator ***************/
 +
 +static int mesh_duplicate_exec(bContext *C, wmOperator *op)
 +{
 +      Scene *scene= CTX_data_scene(C);
 +      Object *ob= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
 +      BMOperator bmop;
 +
 +      EDBM_InitOpf(em, &bmop, op, "dupe geom=%hvef", BM_SELECT);
 +      
 +      BMO_Exec_Op(em->bm, &bmop);
 +      EDBM_clear_flag_all(em, BM_SELECT);
 +
 +      BMO_HeaderFlag_Buffer(em->bm, &bmop, "newout", BM_SELECT);
 +
 +      if (!EDBM_FinishOp(em, &bmop, op, 1))
 +              return OPERATOR_CANCELLED;
 +
 +      DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
 +{
 +      int ret;
 +
 +      WM_cursor_wait(1);
 +      ret = mesh_duplicate_exec(C, op);
 +      WM_cursor_wait(0);
 +
 +      if (ret == OPERATOR_CANCELLED)
 +              return OPERATOR_CANCELLED;
 +      
 +      RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
 +      WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_duplicate(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Duplicate";
 +      ot->idname= "MESH_OT_duplicate";
 +      
 +      /* api callbacks */
 +      ot->invoke= mesh_duplicate_invoke;
 +      ot->exec= mesh_duplicate_exec;
 +      
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* to give to transform */
 +      RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
 +}
 +
++static int flip_normals(bContext *C, wmOperator *op)
++{
++      Scene *scene = CTX_data_scene(C);
++      Object *obedit= CTX_data_edit_object(C);
++      BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
++      
++      if (!EDBM_CallOpf(em, op, "reversefaces facaes=%hf", BM_SELECT))
++              return OPERATOR_CANCELLED;
++      
++      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
++      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
++
++      return OPERATOR_FINISHED;
++}
++
++void MESH_OT_flip_normals(wmOperatorType *ot)
++{
++      /* identifiers */
++      ot->name= "Flip Normals";
++      ot->idname= "MESH_OT_flip_normals";
++      
++      /* api callbacks */
++      ot->exec= flip_normals;
++      ot->poll= ED_operator_editmesh;
++      
++      /* flags */
++      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
++}
++
index 1d92d93442d75706144491973695f2b68de86ec5,5fc2ce467921a9299bd222d5bc5df9ff57996a77..17eff214a126878e3ab848037831b7810dee3e14
@@@ -3725,45 -4467,45 +3725,3 @@@ void flipface(EditMesh *em, EditFace *e
        if(efa->v4) CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
        else CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
  }
--
--
--static int flip_normals(bContext *C, wmOperator *op)
--{
--      Scene *scene = CTX_data_scene(C);
--      Object *obedit= CTX_data_edit_object(C);
--      EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
--      EditFace *efa;
--      
--      efa= em->faces.first;
--      while(efa) {
--              if( efa->f & SELECT ){
--                      flipface(em, efa);
--              }
--              efa= efa->next;
--      }
--      
--      /* update vertex normals too */
--      recalc_editnormals(em);
--
--      BKE_mesh_end_editmesh(obedit->data, em);
--
--      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
--      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
--
--      return OPERATOR_FINISHED;
--}
--
--void MESH_OT_flip_normals(wmOperatorType *ot)
--{
--      /* identifiers */
--      ot->name= "Flip Normals";
--      ot->idname= "MESH_OT_flip_normals";
--      
--      /* api callbacks */
--      ot->exec= flip_normals;
--      ot->poll= ED_operator_editmesh;
--      
--      /* flags */
--      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
--}
--
index 50ac789412013ebb05c321da39bd4948858265ca,76f355ab7f9bebf399ee729c44d5beb7345ecd4b..46753d49c2ba3babbcbb487dbbe9b3f7b1f9eaba
@@@ -759,9 -759,9 +768,10 @@@ void MESH_OT_extrude(wmOperatorType *ot
  
        /* to give to transform */
        Properties_Proportional(ot);
+       Properties_Constraints(ot);
        RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
  }
 +#endif
  
  static int split_mesh(bContext *C, wmOperator *op)
  {
@@@ -4812,8 -4993,7 +4822,8 @@@ static int mesh_rip_invoke(bContext *C
  
        RNA_enum_set(op->ptr, "proportional", 0);
        RNA_boolean_set(op->ptr, "mirror", 0);
-       WM_operator_name_call(C, "TFM_OT_translation", WM_OP_INVOKE_REGION_WIN, op->ptr);
+       WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
 +#endif
  
        return OPERATOR_FINISHED;
  }
index 2a1ae7be543306e3854d68f4ed3f42338a98f494,3b47eeca59d47647d518be239acef8c1159a4ce2..c0234d4b3e97f065d2c7198c4ff7c922a7030531
@@@ -7,7 -7,8 +7,8 @@@ o = SConscript('intern/SConscript'
  objs += o
  
  incs = '#/intern/guardedalloc ../blenkernel ../blenlib ../makesdna intern .'
 -incs += ' ../windowmanager ../editors/include ../imbuf'
 +incs += ' ../windowmanager ../editors/include ../imbuf ../bmesh'
+ incs += ' ../render/extern/include'
  
  defs = []
  
index 4a3715fb9a97e15c91b6597b475802b6c54a80d8,c7cc6e7a4bfe335b250ddf7140cb4a79e630a5f4..a2268e11aa288a927c114416d27619502855412c
@@@ -52,7 -52,7 +52,8 @@@ CPPFLAGS += -I../../imbu
  CPPFLAGS += -I../../makesdna
  CPPFLAGS += -I../../windowmanager
  CPPFLAGS += -I../../editors/include
 +CPPFLAGS += -I../../bmesh
+ CPPFLAGS += -I../../render/extern/include
  CPPFLAGS += -I..
  CPPFLAGS += -I.
  
index 53243fd97a0daef0645f7a7ce0764d239de7b68f,a4f184a3f67bc0ea7ec55999ea8786e8c088fc22..7f6870f617c099ffac2ecc6be32c00b801fbe538
@@@ -29,9 -29,10 +29,10 @@@ makesrna_tool.Append(CCFLAGS = '-DBASE_
  
  defs = []
  
 -incs = '#/intern/guardedalloc ../../blenlib ../../blenkernel'
 +incs = '#/intern/guardedalloc ../../bmesh ../../blenlib ../../blenkernel'
  incs += ' ../../imbuf ../../makesdna ../../makesrna'
  incs += ' ../../windowmanager ../../editors/include'
+ incs += ' ../../render/extern/include'
  
  if env['WITH_BF_OPENEXR']:
        defs.append('WITH_OPENEXR')
index 306bce91bc8db64b3fe32a7a4c653ede2e37936b,749fa55a83332b1174be67f0881f55752ef94993..a32086912f0165e4a06fda69cd139bfc7c1477eb
@@@ -477,8 -480,9 +483,9 @@@ class BlenderEnvironment(SConsEnvironme
                global vcp
                print bc.HEADER+'Configuring program '+bc.ENDC+bc.OKGREEN+progname+bc.ENDC
                lenv = self.Clone()
 -              if lenv['OURPLATFORM'] in ('win32-vc', 'cygwin', 'win64-vc'):
 +              if lenv['OURPLATFORM'] in ['win32-vc', 'cygwin']:
                        lenv.Append(LINKFLAGS = lenv['PLATFORM_LINKFLAGS'])
+                       lenv.Append(LINKFLAGS = ['/FORCE:MULTIPLE'])
                        if lenv['BF_DEBUG']:
                                lenv.Prepend(LINKFLAGS = ['/DEBUG','/PDB:'+progname+'.pdb'])
                if  lenv['OURPLATFORM']=='linux2':