=bmesh= merge from trunk at r36153
authorJoseph Eagar <joeedh@gmail.com>
Fri, 15 Apr 2011 01:19:13 +0000 (01:19 +0000)
committerJoseph Eagar <joeedh@gmail.com>
Fri, 15 Apr 2011 01:19:13 +0000 (01:19 +0000)
249 files changed:
1  2 
build_files/cmake/example_scripts/make_quicky.py
intern/ghost/GHOST_C-api.h
intern/ghost/GHOST_IEvent.h
intern/ghost/GHOST_ISystem.h
intern/ghost/intern/GHOST_C-api.cpp
intern/ghost/intern/GHOST_System.cpp
intern/ghost/intern/GHOST_System.h
intern/ghost/intern/GHOST_SystemX11.cpp
intern/guardedalloc/MEM_guardedalloc.h
intern/guardedalloc/intern/mallocn.c
release/scripts/startup/bl_ui/space_view3d.py
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/BKE_blender.h
source/blender/blenkernel/BKE_idcode.h
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/BKE_paint.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/BME_Customdata.c
source/blender/blenkernel/intern/BME_conversions.c
source/blender/blenkernel/intern/BME_eulers.c
source/blender/blenkernel/intern/BME_mesh.c
source/blender/blenkernel/intern/BME_structure.c
source/blender/blenkernel/intern/BME_tools.c
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/anim.c
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/blender.c
source/blender/blenkernel/intern/bvhutils.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/cloth.c
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/context.c
source/blender/blenkernel/intern/curve.c
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/deform.c
source/blender/blenkernel/intern/displist.c
source/blender/blenkernel/intern/editderivedbmesh.c
source/blender/blenkernel/intern/effect.c
source/blender/blenkernel/intern/exotic.c
source/blender/blenkernel/intern/fluidsim.c
source/blender/blenkernel/intern/fmodifier.c
source/blender/blenkernel/intern/font.c
source/blender/blenkernel/intern/idcode.c
source/blender/blenkernel/intern/key.c
source/blender/blenkernel/intern/lattice.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/mesh_validate.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/multires.c
source/blender/blenkernel/intern/node.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/sca.c
source/blender/blenkernel/intern/seqcache.c
source/blender/blenkernel/intern/shrinkwrap.c
source/blender/blenkernel/intern/smoke.c
source/blender/blenkernel/intern/softbody.c
source/blender/blenkernel/intern/sound.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/blenkernel/nla_private.h
source/blender/blenlib/BLI_array.h
source/blender/blenlib/BLI_editVert.h
source/blender/blenlib/BLI_utildefines.h
source/blender/blenlib/intern/BLI_ghash.c
source/blender/blenlib/intern/BLI_mempool.c
source/blender/blenlib/intern/edgehash.c
source/blender/blenlib/intern/math_geom.c
source/blender/blenlib/intern/math_vector_inline.c
source/blender/blenlib/intern/pbvh.c
source/blender/blenlib/intern/rct.c
source/blender/blenlib/intern/scanfill.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/bmesh/operators/bevel.c
source/blender/collada/CMakeLists.txt
source/blender/collada/DocumentExporter.cpp
source/blender/editors/armature/editarmature.c
source/blender/editors/armature/meshlaplacian.c
source/blender/editors/armature/poseobject.c
source/blender/editors/armature/reeb.c
source/blender/editors/curve/editcurve.c
source/blender/editors/curve/editfont.c
source/blender/editors/gpencil/gpencil_paint.c
source/blender/editors/include/ED_mesh.h
source/blender/editors/include/ED_util.h
source/blender/editors/include/ED_uvedit.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/include/UI_resources.h
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/resources.c
source/blender/editors/mesh/CMakeLists.txt
source/blender/editors/mesh/editface.c
source/blender/editors/mesh/knifetool.c
source/blender/editors/mesh/loopcut.c
source/blender/editors/mesh/mesh_data.c
source/blender/editors/mesh/mesh_intern.h
source/blender/editors/mesh/mesh_ops.c
source/blender/editors/mesh/meshtools.c
source/blender/editors/metaball/mball_edit.c
source/blender/editors/object/object_add.c
source/blender/editors/object/object_constraint.c
source/blender/editors/object/object_edit.c
source/blender/editors/object/object_hook.c
source/blender/editors/object/object_intern.h
source/blender/editors/object/object_lattice.c
source/blender/editors/object/object_modifier.c
source/blender/editors/object/object_ops.c
source/blender/editors/object/object_relations.c
source/blender/editors/object/object_shapekey.c
source/blender/editors/object/object_transform.c
source/blender/editors/object/object_vgroup.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/physics/particle_object.c
source/blender/editors/render/CMakeLists.txt
source/blender/editors/render/render_shading.c
source/blender/editors/screen/CMakeLists.txt
source/blender/editors/screen/screen_edit.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_utils.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/sculpt_paint/sculpt_undo.c
source/blender/editors/space_api/spacetypes.c
source/blender/editors/space_image/CMakeLists.txt
source/blender/editors/space_image/image_buttons.c
source/blender/editors/space_image/image_draw.c
source/blender/editors/space_image/image_header.c
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_info/CMakeLists.txt
source/blender/editors/space_info/info_stats.c
source/blender/editors/space_logic/logic_buttons.c
source/blender/editors/space_outliner/outliner.c
source/blender/editors/space_view3d/CMakeLists.txt
source/blender/editors/space_view3d/drawarmature.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_buttons.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_intern.h
source/blender/editors/space_view3d/view3d_ops.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/space_view3d/view3d_snap.c
source/blender/editors/space_view3d/view3d_toolbar.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/CMakeLists.txt
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_constraints.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_manipulator.c
source/blender/editors/transform/transform_orientations.c
source/blender/editors/transform/transform_snap.c
source/blender/editors/util/crazyspace.c
source/blender/editors/util/ed_util.c
source/blender/editors/util/editmode_undo.c
source/blender/editors/uvedit/CMakeLists.txt
source/blender/editors/uvedit/uvedit_draw.c
source/blender/editors/uvedit/uvedit_intern.h
source/blender/editors/uvedit/uvedit_ops.c
source/blender/editors/uvedit/uvedit_parametrizer.c
source/blender/editors/uvedit/uvedit_parametrizer.h
source/blender/editors/uvedit/uvedit_unwrap_ops.c
source/blender/gpu/intern/gpu_buffers.c
source/blender/gpu/intern/gpu_draw.c
source/blender/ikplugin/intern/itasc_plugin.cpp
source/blender/makesdna/DNA_mesh_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesdna/DNA_object_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/makesdna/intern/makesdna.c
source/blender/makesrna/SConscript
source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/SConscript
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_animviz.c
source/blender/makesrna/intern/rna_constraint.c
source/blender/makesrna/intern/rna_fcurve.c
source/blender/makesrna/intern/rna_image_api.c
source/blender/makesrna/intern/rna_main_api.c
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_mesh_api.c
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_nla.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_pose_api.c
source/blender/makesrna/intern/rna_scene.c
source/blender/makesrna/intern/rna_userdef.c
source/blender/makesrna/intern/rna_wm_api.c
source/blender/modifiers/intern/MOD_armature.c
source/blender/modifiers/intern/MOD_array.c
source/blender/modifiers/intern/MOD_bevel.c
source/blender/modifiers/intern/MOD_build.c
source/blender/modifiers/intern/MOD_collision.c
source/blender/modifiers/intern/MOD_curve.c
source/blender/modifiers/intern/MOD_decimate.c
source/blender/modifiers/intern/MOD_displace.c
source/blender/modifiers/intern/MOD_edgesplit.c
source/blender/modifiers/intern/MOD_explode.c
source/blender/modifiers/intern/MOD_hook.c
source/blender/modifiers/intern/MOD_lattice.c
source/blender/modifiers/intern/MOD_mask.c
source/blender/modifiers/intern/MOD_meshdeform.c
source/blender/modifiers/intern/MOD_mirror.c
source/blender/modifiers/intern/MOD_multires.c
source/blender/modifiers/intern/MOD_particleinstance.c
source/blender/modifiers/intern/MOD_particlesystem.c
source/blender/modifiers/intern/MOD_screw.c
source/blender/modifiers/intern/MOD_solidify.c
source/blender/modifiers/intern/MOD_subsurf.c
source/blender/modifiers/intern/MOD_surface.c
source/blender/modifiers/intern/MOD_uvproject.c
source/blender/modifiers/intern/MOD_wave.c
source/blender/nodes/intern/SHD_nodes/SHD_output.c
source/blender/python/generic/bpy_internal_import.h
source/blender/python/intern/bpy.c
source/blender/python/intern/bpy_operator_wrap.c
source/blender/python/intern/bpy_rna.h
source/blender/readblenfile/intern/BLO_readblenfile.c
source/blender/render/intern/include/raycounter.h
source/blender/render/intern/include/rayobject.h
source/blender/render/intern/raytrace/reorganize.h
source/blender/render/intern/source/convertblender.c
source/blender/render/intern/source/pipeline.c
source/blender/render/intern/source/pointdensity.c
source/blender/render/intern/source/shadeoutput.c
source/blender/render/intern/source/strand.c
source/blender/windowmanager/CMakeLists.txt
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_init_exit.c
source/blender/windowmanager/intern/wm_operators.c
source/blender/windowmanager/intern/wm_window.c
source/blenderplayer/CMakeLists.txt
source/blenderplayer/bad_level_call_stubs/CMakeLists.txt
source/blenderplayer/bad_level_call_stubs/SConscript
source/blenderplayer/bad_level_call_stubs/stubs.c
source/creator/CMakeLists.txt
source/creator/creator.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp

@@@ -40,10 -41,10 +40,10 @@@ def print_help(targets)
  
  def main():
      targets = set()
 -
 +    
      # collect targets
-     file = open("Makefile", "r")
-     for line in file:
+     makefile = open("Makefile", "r")
+     for line in makefile:
          line = line.rstrip()
          if not line or line[0] in ". \t@$#":
              continue
@@@ -58,9 -59,8 +58,9 @@@
              continue
  
          targets.add(line)
-     file.close()
+     makefile.close()
  
 +
      # remove cmake targets
      bad = set([
          "help",
Simple merge
  #ifndef _GHOST_IEVENT_H_
  #define _GHOST_IEVENT_H_
  
+ #include <stddef.h>
  #include "GHOST_Types.h"
 -
 -class GHOST_IWindow;
 +#include "GHOST_IWindow.h"
 +#include "intern/GHOST_ModifierKeys.h"
  
  /**
   * Interface class for events received from GHOST.
Simple merge
Simple merge
@@@ -226,34 -219,18 +219,45 @@@ GHOST_TSuccess GHOST_System::addEventCo
        return success;
  }
  
+ GHOST_TSuccess GHOST_System::removeEventConsumer(GHOST_IEventConsumer* consumer)
+ {
+       GHOST_TSuccess success;
+       if (m_eventManager) {
+               success = m_eventManager->removeConsumer(consumer);
+       }
+       else {
+               success = GHOST_kFailure;
+       }
+       return success;
+ }
  
 + GHOST_TSuccess GHOST_System::beginRecord(FILE *file)
 + {
 +      return this->m_eventManager->beginRecord(file);
 + }
 +
 + GHOST_TSuccess GHOST_System::endRecord()
 + {
 +      return this->m_eventManager->endRecord();
 + }
 +
 + GHOST_TSuccess GHOST_System::playbackEvents(FILE *file)
 + {
 +      return this->m_eventManager->playbackEvents(file);
 + }
 +
 +
 + bool GHOST_System::playingEvents(bool *hasevent) const
 + {
 +      return this->m_eventManager->playingEvents(hasevent);
 + }
 +
 + bool GHOST_System::recordingEvents()
 + {
 +      return this->m_eventManager->recordingEvents();
 + }
 +
 +
  GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent* event)
  {
        GHOST_TSuccess success;
Simple merge
@@@ -619,20 -643,16 +619,21 @@@ short _MEM_freeN(void *vmemh, const cha
                error = 2;
                MemorY_ErroR(memh->name,"end corrupt");
                name = check_memlist(memh);
-               if (name != 0){
+               if (name != NULL){
 -                      if (name != memh->name) MemorY_ErroR(name,"is also corrupt");
 +                      sprintf(str1, "Error in %s on line %d: %s is also corrupt", file, line, name);
 +                      if (name != memh->name) MemorY_ErroR(name, str1);
                }
        } else{
                error = -1;
                name = check_memlist(memh);
 -              if (name == NULL)
 -                      MemorY_ErroR("free","pointer not in memlist");
 -              else
 -                      MemorY_ErroR(name,"error in header");
++
 +              if (name == 0) {
 +                      sprintf(str1, "Error in %s on line %d: pointer not in memlist", file, line);
 +                      MemorY_ErroR("free", str1);
 +              } else {
 +                      sprintf(str1, "Error in %s on line %d: error in header", file, line);
 +                      MemorY_ErroR(name, str1);
 +              }
        }
  
        totblock--;
@@@ -1373,7 -1421,7 +1420,7 @@@ class VIEW3D_MT_edit_mesh_specials(bpy.
          layout.operator("mesh.select_inverse")
          layout.operator("mesh.flip_normals")
          layout.operator("mesh.vertices_smooth", text="Smooth")
--        layout.operator("mesh.bevel", text="Bevel")
++        layout.operator("mesh.bevel", text="Bevel")
          layout.operator("mesh.faces_shade_smooth")
          layout.operator("mesh.faces_shade_flat")
          layout.operator("mesh.blend_from_shape")
@@@ -61,33 -58,11 +61,31 @@@ struct Scene
  extern "C" {
  #endif
  
--struct EditMesh *BKE_mesh_get_editmesh(struct Mesh *me);
--void BKE_mesh_end_editmesh(struct Mesh *me, struct EditMesh *em);
 +struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob);
 +
 +/*
 +  this function recreates a tesselation.
 +  returns number of tesselation faces.
 +
 +  use_poly_origindex sets whether or not the tesselation faces' origindex
 +  layer should point to original poly indices or real poly indices.
 +
 +  use_face_origindex sets the tesselation faces' origindex layer
 +  to point to the tesselation faces themselves, not the polys.
 +
 +  if both of the above are 0, it'll use the indices of the mpolys of the MPoly
 +  data in pdata, and ignore the origindex layer altogether.
 + */
 +int mesh_recalcTesselation(struct CustomData *fdata, struct CustomData *ldata, 
 +      struct CustomData *pdata, struct MVert *mvert, int totface, 
 +      int totloop, int totpoly, int use_poly_origindex, int use_face_origindex);
 +
 +/*calculates a face normal.*/
 +void mesh_calc_poly_normal(struct MPoly *mpoly, struct MLoop *loopstart, 
 +                           struct MVert *mvarray, float *no);
  
  void unlink_mesh(struct Mesh *me);
 -void free_mesh(struct Mesh *me);
 +void free_mesh(struct Mesh *me, int unlink);
  struct Mesh *add_mesh(const char *name);
  struct Mesh *copy_mesh(struct Mesh *me);
  void mesh_update_customdata_pointers(struct Mesh *me);
@@@ -106,23 -76,17 +104,26 @@@ int test_index_face(struct MFace *mface
  struct Mesh *get_mesh(struct Object *ob);
  void set_mesh(struct Object *ob, struct Mesh *me);
  void mball_to_mesh(struct ListBase *lb, struct Mesh *me);
--int nurbs_to_mdata(struct Object *ob, struct MVert **allvert, int *_totvert,
--      struct MEdge **alledge, int *_totedge, struct MFace **allface, int *_totface);
--int nurbs_to_mdata_customdb(struct Object *ob, struct ListBase *dispbase,
--      struct MVert **allvert, int *_totvert, struct MEdge **alledge, int *_totedge,
--      struct MFace **allface, int *_totface);
++int nurbs_to_mdata(struct Object *ob, struct MVert **allvert, int *totvert,
++      struct MEdge **alledge, int *totedge, struct MFace **allface, struct MLoop **allloop, struct MPoly **allpoly, 
++      int *totface, int *totloop, int *totpoly);
++int nurbs_to_mdata_customdb(struct Object *ob, struct ListBase *dispbase, struct MVert **allvert, int *_totvert,
++      struct MEdge **alledge, int *_totedge, struct MFace **allface, struct MLoop **allloop, struct MPoly **allpoly, 
++      int *_totface, int *_totloop, int *_totpoly);
  void nurbs_to_mesh(struct Object *ob);
  void mesh_to_curve(struct Scene *scene, struct Object *ob);
  void free_dverts(struct MDeformVert *dvert, int totvert);
  void copy_dverts(struct MDeformVert *dst, struct MDeformVert *src, int totvert); /* __NLA */
  void mesh_delete_material_index(struct Mesh *me, int index);
  void mesh_set_smooth_flag(struct Object *meshOb, int enableSmooth);
++void convert_mfaces_to_mpolys(struct Mesh *mesh);
++void mesh_calc_tessface_normals(struct MVert *mverts, int numVerts,struct  MFace *mfaces, int numFaces, float (*faceNors_r)[3]);
 +
 +/*used for unit testing; compares two meshes, checking only
 +  differences we care about.  should be usable with leaf's
 +  testing framework I get RNA work done, will use hackish
 +  testing code for now.*/
 +char *mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
  
  struct BoundBox *mesh_get_bb(struct Object *ob);
  void mesh_get_texspace(struct Mesh *me, float *loc_r, float *rot_r, float *size_r);
@@@ -136,7 -100,7 +137,9 @@@ void mesh_strip_loose_edges(struct Mes
        /* Calculate vertex and face normals, face normals are returned in *faceNors_r if non-NULL
         * and vertex normals are stored in actual mverts.
         */
- void mesh_calc_normals(struct MVert *mverts, int numVerts, struct MFace *mfaces, int numFaces, float **faceNors_r);
 -void mesh_calc_normals(struct MVert *mverts, int numVerts, struct MFace *mfaces, int numFaces, float (*faceNors_r)[3]);
++void mesh_calc_normals(struct MVert *mverts, int numVerts, struct MLoop *mloop, 
++      struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3], 
++      struct MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3]);
  
        /* Return a newly MEM_malloc'd array of all the mesh vertex locations
         * (_numVerts_r_ may be NULL) */
Simple merge
   *
   * ***** END GPL LICENSE BLOCK *****
   */
 -
 +#if 0
+ /** \file blender/blenkernel/intern/BME_structure.c
+  *  \ingroup bke
+  */
  #include <limits.h>
  
  #include "MEM_guardedalloc.h"
@@@ -1749,15 -1667,15 +1752,17 @@@ DerivedMesh *CDDM_from_curve_customDB(O
        MVert *allvert;
        MEdge *alledge;
        MFace *allface;
--      int totvert, totedge, totface;
++      MLoop *allloop;
++      MPoly *allpoly;
++      int totvert, totedge, totface, totloop, totpoly;
  
        if (nurbs_to_mdata_customdb(ob, dispbase, &allvert, &totvert, &alledge,
--              &totedge, &allface, &totface) != 0) {
++              &totedge, &allface, &allloop, &allpoly, &totface, &totloop, &totpoly) != 0) {
                /* Error initializing mdata. This often happens when curve is empty */
 -              return CDDM_new(0, 0, 0);
 +              return CDDM_new(0, 0, 0, 0, 0);
        }
  
-       dm = CDDM_new(totvert, totedge, totface, totface*4, totface);
 -      dm = CDDM_new(totvert, totedge, totface);
++      dm = CDDM_new(totvert, totedge, totface, totloop, totpoly);
        dm->deformedOnly = 1;
  
        cddm = (CDDerivedMesh*)dm;
        memcpy(cddm->mvert, allvert, totvert*sizeof(MVert));
        memcpy(cddm->medge, alledge, totedge*sizeof(MEdge));
        memcpy(cddm->mface, allface, totface*sizeof(MFace));
++      memcpy(cddm->mloop, allloop, totloop*sizeof(MLoop));
++      memcpy(cddm->mpoly, allpoly, totpoly*sizeof(MPoly));
  
        MEM_freeN(allvert);
        MEM_freeN(alledge);
        MEM_freeN(allface);
++      MEM_freeN(allloop);
++      MEM_freeN(allpoly);
  
        return dm;
  }
@@@ -2227,281 -1790,22 +2236,235 @@@ void CDDM_apply_vert_normals(DerivedMes
  void CDDM_calc_normals(DerivedMesh *dm)
  {
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
-       float (*temp_nors)[3];
--      float (*face_nors)[3];
-       float (*vert_nors)[3];
-       int i, j, *origIndex;
-       int numVerts = dm->numVertData;
-       int numFaces = dm->numFaceData;
-       MFace *mf;
-       MPoly *mp;
-       MVert *mv;
-       MLoop *ml;
-       if(numVerts == 0) return;
--
-       if (CustomData_has_layer(&dm->faceData, CD_NORMAL))
-               CustomData_free_layer(&dm->faceData, CD_NORMAL, dm->numFaceData, 0);
++      float (*face_nors)[3] = NULL;
++      
+       if(dm->numVertData == 0) return;
  
-       /*recalc tesselation to ensure we have valid origindex values
-         for mface->mpoly lookups.*/
+       /* we don't want to overwrite any referenced layers */
+       cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
++      
++      /*set tesselation origindex values to map to poly indices, rather then poly
++        poly origindex values*/
 +      cdDM_recalcTesselation2(dm);
-       numFaces = dm->numFaceData;
-       /*first go through and calculate normals for all the polys*/
-       temp_nors = MEM_callocN(sizeof(float)*3*dm->numPolyData, "temp_nors cdderivedmesh.c");
-       vert_nors = MEM_callocN(sizeof(float)*3*dm->numVertData, "vert_nors cdderivedmesh.c");
 +      
-       mp = cddm->mpoly;
-       for (i=0; i<dm->numPolyData; i++, mp++) {
-               mesh_calc_poly_normal(mp, cddm->mloop+mp->loopstart, cddm->mvert, temp_nors[i]);
-               ml = cddm->mloop + mp->loopstart;
-               for (j=0; j<mp->totloop; j++, ml++) {
-                       VECADD(vert_nors[ml->v], vert_nors[ml->v], temp_nors[i]);
-               }
-       }
-       face_nors = MEM_callocN(sizeof(float)*3*dm->numFaceData, "face_nors cdderivedmesh.c");
-       origIndex = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX);
-       mf = cddm->mface;
-       for (i=0; i<dm->numFaceData; i++, mf++, origIndex++) {
-               VECCOPY(face_nors[i], temp_nors[*origIndex]);
-       }
-       mv = cddm->mvert;
-       for (i=0; i<dm->numVertData; i++, mv++) {
-               float *no = vert_nors[i];
-               
-               if (normalize_v3(no) == 0.0) {
-                       VECCOPY(no, mv->co);
-                       if (normalize_v3(no) == 0.0) {
-                               no[0] = 0.0f;
-                               no[1] = 0.0f;
-                               no[2] = 1.0f;
-                       }
-               }
-               normal_float_to_short_v3(mv->no, no);
-       }
-       MEM_freeN(temp_nors);
-       MEM_freeN(vert_nors);
-       /*this restores original poly origindex -> tessface origindex mapping,
-         instead of the poly index -> tessface origindex one we generated
-         with cdDM_recalcTesselation2*/
++      face_nors = MEM_mallocN(sizeof(float)*3*dm->numFaceData, "face_nors");
++      
++      /* calculate face normals */
++      mesh_calc_normals(cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm), 
++                                        dm->numLoopData, dm->numPolyData, NULL, cddm->mface, dm->numFaceData, 
++                                        CustomData_get_layer(&dm->faceData, CD_ORIGINDEX), face_nors);
++      
++      /*restore tesselation origindex indices to poly origindex indices*/
 +      cdDM_recalcTesselation(dm);
 -      /* make a face normal layer if not present */
 -      face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
 -      if(!face_nors)
 -              face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC,
 -                                                                               NULL, dm->numFaceData);
 +      CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_ASSIGN, 
 +              face_nors, dm->numFaceData);
 +}
  
 -      /* calculate face normals */
 -      mesh_calc_normals(cddm->mvert, dm->numVertData, CDDM_get_faces(dm), dm->numFaceData, face_nors);
 +#if 1
 +/*merge verts
 + 
 +  vtargetmap is a table that maps vertices to target vertices.  a value of -1
 +  indicates a vertex is a target, and is to be kept.
 +  
 +  this frees dm, and returns a new one.
 +  
 +  this is a really horribly written function.  ger. - joeedh
 +
 + */
 +DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap)
 +{
 +      CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 +      CDDerivedMesh *cddm2 = NULL;
 +      MVert *mv, *mvert = NULL;
 +      BLI_array_declare(mvert);
 +      MEdge *me, *medge = NULL;
 +      BLI_array_declare(medge);
 +      MPoly *mp, *mpoly = NULL;
 +      BLI_array_declare(mpoly);
 +      MLoop *ml, *mloop = NULL;
 +      BLI_array_declare(mloop);
 +      EdgeHash *ehash = BLI_edgehash_new();
 +      int *newv = NULL, *newe = NULL, *newl = NULL;
 +      int *oldv = NULL, *olde = NULL, *oldl = NULL, *oldp = NULL;
 +      BLI_array_declare(oldv); BLI_array_declare(olde); BLI_array_declare(oldl); BLI_array_declare(oldp);
 +      int i, j, c, totloop, totpoly;
 +      
 +      totloop = dm->numLoopData;
 +      totpoly = dm->numPolyData;
 +      
 +      newv = MEM_callocN(sizeof(int)*dm->numVertData, "newv vtable CDDM_merge_verts");
 +      newe = MEM_callocN(sizeof(int)*dm->numEdgeData, "newv etable CDDM_merge_verts");
 +      newl = MEM_callocN(sizeof(int)*totloop, "newv ltable CDDM_merge_verts");
 +      
 +      /*fill newl with destination vertex indices*/
 +      mv = cddm->mvert;
 +      c = 0;
 +      for (i=0; i<dm->numVertData; i++, mv++) {
 +              if (vtargetmap[i] == -1) {
 +                      BLI_array_append(oldv, i);
 +                      newv[i] = c++;
 +                      BLI_array_append(mvert, *mv);
 +              }
 +      }
 +      
 +      /*now link target vertices to destination indices*/
 +      for (i=0; i<dm->numVertData; i++) {
 +              if (vtargetmap[i] != -1) {
 +                      newv[i] = newv[vtargetmap[i]];
 +              }
 +      }
 +      
 +      /*find-replace merged vertices with target vertices*/   
 +      ml = cddm->mloop;
 +      c = 0;
 +      for (i=0; i<totloop; i++, ml++) {
 +              if (ml->v == -1)
 +                      continue;
 +              
 +              if (vtargetmap[ml->v] != -1) {
 +                      me = &cddm->medge[ml->e];
 +                      if (me->v1 == ml->v)
 +                              me->v1 = vtargetmap[ml->v];
 +                      else
 +                              me->v2 = vtargetmap[ml->v];
 +                      
 +                      ml->v = vtargetmap[ml->v];
 +              }
 +      }
 +      
 +      /*now go through and fix edges and faces*/
 +      me = cddm->medge;
 +      c = 0;
 +      for (i=0; i<dm->numEdgeData; i++, me++) {
 +              int v1, v2;
 +              
 +              if (me->v1 == me->v2) {
 +                      newe[i] = -1;
 +                      continue;
 +              }
 +              
 +              if (vtargetmap[me->v1] != -1)
 +                      v1 = vtargetmap[me->v1];
 +              else
 +                      v1 = me->v1;
 +              
 +              if (vtargetmap[me->v2] != -1)
 +                      v2 = vtargetmap[me->v2];
 +              else
 +                      v2 = me->v2;
 +              
 +              if (BLI_edgehash_haskey(ehash, v1, v2)) {
 +                      newe[i] = GET_INT_FROM_POINTER(BLI_edgehash_lookup(ehash, v1, v2));
 +              } else {
 +                      BLI_array_append(olde, i);
 +                      newe[i] = c;
 +                      BLI_array_append(medge, *me);
 +                      BLI_edgehash_insert(ehash, v1, v2, SET_INT_IN_POINTER(c));
 +                      c++;
 +              }
 +      }
 +      
 +      mp = cddm->mpoly;
 +      for (i=0; i<totpoly; i++, mp++) {
 +              MPoly *mp2;
 +              
 +              ml = cddm->mloop + mp->loopstart;
 +              
 +              c = 0;
 +              for (j=0; j<mp->totloop; j++, ml++) {
 +                      if (ml->v == -1)
 +                              continue;
 +                      
 +                      me = cddm->medge + ml->e;
 +                      if (me->v1 != me->v2) {
 +                              BLI_array_append(oldl, j+mp->loopstart);
 +                              BLI_array_append(mloop, *ml);
 +                              newl[j+mp->loopstart] = BLI_array_count(mloop)-1;
 +                              c++;
 +                      }
 +              }
 +              
 +              if (!c)
 +                      continue;
 +              
 +              mp2 = BLI_array_append(mpoly, *mp);
 +              mp2->totloop = c;
 +              mp2->loopstart = BLI_array_count(mloop) - c;
 +              
 +              BLI_array_append(oldp, i);
 +      }
 +      
 +      /*create new cddm*/     
-       cddm2 = (CDDerivedMesh*) CDDM_from_template(cddm, BLI_array_count(mvert), BLI_array_count(medge), 0, BLI_array_count(mloop), BLI_array_count(mpoly));
++      cddm2 = (CDDerivedMesh*) CDDM_from_template((DerivedMesh*)cddm, BLI_array_count(mvert), BLI_array_count(medge), 0, BLI_array_count(mloop), BLI_array_count(mpoly));
 +      
 +      /*update edge indices and copy customdata*/
 +      me = medge;
 +      for (i=0; i<cddm2->dm.numEdgeData; i++, me++) {
 +              if (newv[me->v1] != -1)
 +                      me->v1 = newv[me->v1];
 +              if (newv[me->v2] != -1)
 +                      me->v2 = newv[me->v2];
 +              
 +              CustomData_copy_data(&dm->edgeData, &cddm2->dm.edgeData, olde[i], i, 1);
 +      }
 +      
 +      /*update loop indices and copy customdata*/
 +      ml = mloop;
 +      for (i=0; i<cddm2->dm.numLoopData; i++, ml++) {
 +              if (newe[ml->e] != -1)
 +                      ml->e = newe[ml->e];
 +              if (newv[ml->v] != -1)
 +                      ml->v = newv[ml->v];
 +                      
 +              CustomData_copy_data(&dm->loopData, &cddm2->dm.loopData, oldl[i], i, 1);
 +      }
 +      
 +      /*copy vertex customdata*/      
 +      mv = mvert;
 +      for (i=0; i<cddm2->dm.numVertData; i++, mv++) {
 +              CustomData_copy_data(&dm->vertData, &cddm2->dm.vertData, oldv[i], i, 1);
 +      }
 +      
 +      /*copy poly customdata*/
 +      mp = mpoly;
 +      for (i=0; i<cddm2->dm.numPolyData; i++, mp++) {
 +              CustomData_copy_data(&dm->polyData, &cddm2->dm.polyData, oldp[i], i, 1);
 +      }
 +      
 +      /*copy over data.  CustomData_add_layer can do this, need to look it up.*/
 +      memcpy(cddm2->mvert, mvert, sizeof(MVert)*BLI_array_count(mvert));
 +      memcpy(cddm2->medge, medge, sizeof(MEdge)*BLI_array_count(medge));
 +      memcpy(cddm2->mloop, mloop, sizeof(MLoop)*BLI_array_count(mloop));
 +      memcpy(cddm2->mpoly, mpoly, sizeof(MPoly)*BLI_array_count(mpoly));
 +      BLI_array_free(mvert); BLI_array_free(medge); BLI_array_free(mloop); BLI_array_free(mpoly);
 +
-       CDDM_recalc_tesselation(cddm2, 1);
++      CDDM_recalc_tesselation((DerivedMesh*)cddm2, 1);
 +      
 +      if (newv) 
 +              MEM_freeN(newv); 
 +      if (newe)
 +              MEM_freeN(newe); 
 +      if (newl)
 +              MEM_freeN(newl);
 +      if (oldv) 
 +              MEM_freeN(oldv); 
 +      if (olde) 
 +              MEM_freeN(olde); 
 +      if (oldl) 
 +              MEM_freeN(oldl); 
 +      if (oldp) 
 +              MEM_freeN(oldp);
 +      if (ehash)
 +              BLI_edgehash_free(ehash, NULL);
 +
 +      /*free old derivedmesh*/
 +      dm->needsFree = 1;
 +      dm->release(dm);
 +      
 +      return (DerivedMesh*)cddm2;
  }
 +#endif
  
  void CDDM_calc_edges(DerivedMesh *dm)
  {
@@@ -114,62 -106,6 +119,62 @@@ bContext *CTX_copy(const bContext *C
        return newC;
  }
  
- #ifdef EVENT_RECORDER
++#if defined(EVENT_RECORDER) && !defined(BUILDING_GAMEPLAYER)
 +extern GHOST_SystemHandle g_system;
 +
 +int CTX_rec_events(bContext *C)
 +{
 +      return GHOST_RecordingEvents(g_system);
 +}
 +
 +int CTX_rec_events_set(bContext *C, int state)
 +{
 +      FILE *f = CTX_rec_file(C);
 +      
 +      if (GHOST_RecordingEvents(g_system) && !state)
 +              GHOST_StopRecording(g_system);
 +      else if (!GHOST_RecordingEvents(g_system) && state) 
 +              GHOST_RecordEvents(g_system, f);
 +      
 +      return 1;
 +}
 +
 +FILE *CTX_rec_file(bContext *C)
 +{
 +      static FILE *f = NULL;
 +      if (!f)
 +              f = fopen("eventlog.txt", "wb");
 +      return f;
 +}
 +
 +int CTX_set_events_path(bContext *C, char *path)
 +{
 +      if (!path) {
 +              C->evtplaypath[0] = 0;
 +      } else {
 +              FILE *file = fopen(path, "rb");
 +              
 +              if (!file)
 +                      return 0;
 +              
 +              strcpy(C->evtplaypath, path);
 +              if (g_system)
 +                      GHOST_PlaybackEvents(g_system, file);
 +      }
 +      
 +      return 1;
 +}
 +
 +extern int erec_playing;
 +int CTX_play_events(bContext *C, char **playpath)
 +{
 +      if (playpath)
 +              *playpath = C->evtplaypath[0] ? C->evtplaypath : NULL;
 +
 +      return GHOST_PlayingEvents(g_system);
 +}
 +#endif
 +
  void CTX_free(bContext *C)
  {
        MEM_freeN(C);
@@@ -453,119 -442,114 +458,14 @@@ static void layerInterp_mdisps(void **s
                                float *sub_weights, int count, void *dest)
  {
        MDisps *d = dest;
--      MDisps *s = NULL;
--      int st, stl;
--      int i, x, y;
--      int side, S, dst_corners, src_corners;
--      float crn_weight[4][2];
--      float (*sw)[4] = (void*)sub_weights;
--      float (*disps)[3], (*out)[3];
  
        /* happens when flipping normals of newly created mesh */
 -      if(!d->totdisp)
 -              return;
 -
 -      s = sources[0];
 -      dst_corners = multires_mdisp_corners(d);
 -      src_corners = multires_mdisp_corners(s);
 -
 -      if(sub_weights && count == 2 && src_corners == 3) {
 -              src_corners = multires_mdisp_corners(sources[1]);
 -
 -              /* special case -- converting two triangles to quad */
 -              if(src_corners == 3 && dst_corners == 4) {
 -                      MDisps tris[2];
 -                      int vindex[4] = {0};
 -
 -                      S = 0;
 -                      for(i = 0; i < 2; i++)
 -                              for(y = 0; y < 4; y++)
 -                                      for(x = 0; x < 4; x++)
 -                                              if(sw[x+i*4][y])
 -                                                      vindex[x] = y;
 -
 -                      for(i = 0; i < 2; i++) {
 -                              float sw_m4[4][4] = {{0}};
 -                              int a = 7 & ~(1 << vindex[i*2] | 1 << vindex[i*2+1]);
 -
 -                              sw_m4[0][vindex[i*2+1]] = 1;
 -                              sw_m4[1][vindex[i*2]] = 1;
 -
 -                              for(x = 0; x < 3; x++)
 -                                      if(a & (1 << x))
 -                                              sw_m4[2][x] = 1;
 -
 -                              tris[i] = *((MDisps*)sources[i]);
 -                              tris[i].disps = MEM_dupallocN(tris[i].disps);
 -                              layerInterp_mdisps(&sources[i], NULL, (float*)sw_m4, 1, &tris[i]);
 -                      }
 -
 -                      mdisp_join_tris(d, &tris[0], &tris[1]);
 -
 -                      for(i = 0; i < 2; i++)
 -                              MEM_freeN(tris[i].disps);
 -
 -                      return;
 -              }
 +      if(!d->totdisp) {
 +              d->totdisp = ((MDisps*)sources[0])->totdisp;
        }
 -
 -      /* For now, some restrictions on the input */
 -      if(count != 1 || !sub_weights) {
 -              for(i = 0; i < d->totdisp; ++i)
 -                      zero_v3(d->disps[i]);
 -
 -              return;
 -      }
 -
 -      /* Initialize the destination */
 -      disps = MEM_callocN(3*d->totdisp*sizeof(float), "iterp disps");
 -
 -      side = sqrt(d->totdisp / dst_corners);
 -      st = (side<<1)-1;
 -      stl = st - 1;
 -
 -      sw= (void*)sub_weights;
 -      for(i = 0; i < 4; ++i) {
 -              crn_weight[i][0] = 0 * sw[i][0] + stl * sw[i][1] + stl * sw[i][2] + 0 * sw[i][3];
 -              crn_weight[i][1] = 0 * sw[i][0] + 0 * sw[i][1] + stl * sw[i][2] + stl * sw[i][3];
 -      }
 -
 -      multires_mdisp_smooth_bounds(s);
 -
 -      out = disps;
 -      for(S = 0; S < dst_corners; S++) {
 -              float base[2], axis_x[2], axis_y[2];
 -
 -              mdisp_apply_weight(S, dst_corners, 0, 0, st, crn_weight, &base[0], &base[1]);
 -              mdisp_apply_weight(S, dst_corners, side-1, 0, st, crn_weight, &axis_x[0], &axis_x[1]);
 -              mdisp_apply_weight(S, dst_corners, 0, side-1, st, crn_weight, &axis_y[0], &axis_y[1]);
 -
 -              sub_v2_v2(axis_x, base);
 -              sub_v2_v2(axis_y, base);
 -              normalize_v2(axis_x);
 -              normalize_v2(axis_y);
 -
 -              for(y = 0; y < side; ++y) {
 -                      for(x = 0; x < side; ++x, ++out) {
 -                              int crn;
 -                              float face_u, face_v, crn_u, crn_v;
 -
 -                              mdisp_apply_weight(S, dst_corners, x, y, st, crn_weight, &face_u, &face_v);
 -                              crn = mdisp_rot_face_to_crn(src_corners, st, face_u, face_v, &crn_u, &crn_v);
 -
 -                              old_mdisps_bilinear((*out), &s->disps[crn*side*side], side, crn_u, crn_v);
 -                              mdisp_flip_disp(crn, dst_corners, axis_x, axis_y, *out);
 -                      }
 -              }
 -      }
 -
 -      MEM_freeN(d->disps);
 -      d->disps = disps;
 +      
 +      if (!d->disps && d->totdisp)
 +              d->disps = BLI_cellalloc_calloc(sizeof(float)*3*d->totdisp, "blank mdisps in layerInterp_mdisps");
- #if 0 
-       s = sources[0];
-       dst_corners = multires_mdisp_corners(d);
-       src_corners = multires_mdisp_corners(s);
-       if(sub_weights && count == 2 && src_corners == 3) {
-               src_corners = multires_mdisp_corners(sources[1]);
-               /* special case -- converting two triangles to quad */
-               if(src_corners == 3 && dst_corners == 4) {
-                       MDisps tris[2];
-                       int vindex[4] = {0};
-                       S = 0;
-                       for(i = 0; i < 2; i++)
-                               for(y = 0; y < 4; y++)
-                                       for(x = 0; x < 4; x++)
-                                               if(sw[x+i*4][y])
-                                                       vindex[x] = y;
-                       for(i = 0; i < 2; i++) {
-                               float sw_m4[4][4] = {{0}};
-                               int a = 7 & ~(1 << vindex[i*2] | 1 << vindex[i*2+1]);
-                               sw_m4[0][vindex[i*2+1]] = 1;
-                               sw_m4[1][vindex[i*2]] = 1;
-                               for(x = 0; x < 3; x++)
-                                       if(a & (1 << x))
-                                               sw_m4[2][x] = 1;
-                               tris[i] = *((MDisps*)sources[i]);
-                               tris[i].disps = BLI_cellalloc_dupalloc(tris[i].disps);
-                               layerInterp_mdisps(&sources[i], NULL, (float*)sw_m4, 1, &tris[i]);
-                       }
-                       mdisp_join_tris(d, &tris[0], &tris[1]);
-                       for(i = 0; i < 2; i++)
-                               BLI_cellalloc_free(tris[i].disps);
-                       return;
-               }
-       }
-       /* For now, some restrictions on the input */
-       if(count != 1 || !sub_weights) {
-               for(i = 0; i < d->totdisp; ++i)
-                       zero_v3(d->disps[i]);
-               return;
-       }
-       /* Initialize the destination */
-       out = disps = BLI_cellalloc_calloc(3*d->totdisp*sizeof(float), "iterp disps");
-       side = sqrt(d->totdisp / dst_corners);
-       st = (side<<1)-1;
-       stl = st - 1;
-       sw= (void*)sub_weights;
-       for(i = 0; i < 4; ++i) {
-               crn_weight[i][0] = 0 * sw[i][0] + stl * sw[i][1] + stl * sw[i][2] + 0 * sw[i][3];
-               crn_weight[i][1] = 0 * sw[i][0] + 0 * sw[i][1] + stl * sw[i][2] + stl * sw[i][3];
-       }
-       multires_mdisp_smooth_bounds(s);
-       out = disps;
-       for(S = 0; S < dst_corners; S++) {
-               float base[2], axis_x[2], axis_y[2];
-               mdisp_apply_weight(S, dst_corners, 0, 0, st, crn_weight, &base[0], &base[1]);
-               mdisp_apply_weight(S, dst_corners, side-1, 0, st, crn_weight, &axis_x[0], &axis_x[1]);
-               mdisp_apply_weight(S, dst_corners, 0, side-1, st, crn_weight, &axis_y[0], &axis_y[1]);
-               sub_v2_v2(axis_x, base);
-               sub_v2_v2(axis_y, base);
-               normalize_v2(axis_x);
-               normalize_v2(axis_y);
-               for(y = 0; y < side; ++y) {
-                       for(x = 0; x < side; ++x, ++out) {
-                               int crn;
-                               float face_u, face_v, crn_u, crn_v;
-                               mdisp_apply_weight(S, dst_corners, x, y, st, crn_weight, &face_u, &face_v);
-                               crn = mdisp_rot_face_to_crn(src_corners, st, face_u, face_v, &crn_u, &crn_v);
-                               old_mdisps_bilinear((*out), &s->disps[crn*side*side], side, crn_u, crn_v);
-                               mdisp_flip_disp(crn, dst_corners, axis_x, axis_y, *out);
-                       }
-               }
-       }
-       BLI_cellalloc_free(d->disps);
-       d->disps = disps;
- #endif
  }
  
  static void layerCopy_mdisps(const void *source, void *dest, int count)
index 1479cb2,0000000..e601791
mode 100644,000000..100644
--- /dev/null
@@@ -1,1712 -1,0 +1,1715 @@@
- static void bmDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
 +/**
 + * $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_math.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 "BLI_array.h"
 +#include "BLI_utildefines.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;
 +      BLI_array_declare(looptris);
 +      BMIter iter, liter;
 +      BMFace *f;
 +      BMLoop *l;
 +      int i = 0, j;
 +      
 +      if (tm->looptris) MEM_freeN(tm->looptris);
 +
 +#if 0 //simple quad/triangle code for performance testing purposes
 +      looptris = MEM_callocN(sizeof(void*)*bm->totface*8, "looptris");
 +
 +      f = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
 +      for ( ; f; f=BMIter_Step(&iter)) {
 +              EditVert *v, *lastv=NULL, *firstv=NULL;
 +              EditEdge *e;
 +              EditFace *efa;
 +
 +              /*don't consider two-edged faces*/
 +              if (f->len < 3) continue;
 +              
 +              //BLI_array_growone(looptris);
 +              //BLI_array_growone(looptris);
 +              //BLI_array_growone(looptris);
 +
 +              looptris[i*3] = f->loopbase;
 +              looptris[i*3+1] = f->loopbase->head.next;
 +              looptris[i*3+2] = f->loopbase->head.next->next;
 +              i++;
 +
 +              if (f->len > 3) {
 +                      //BLI_array_growone(looptris);
 +                      //BLI_array_growone(looptris);
 +                      //BLI_array_growone(looptris);
 +
 +                      looptris[i*3] = f->loopbase;
 +                      looptris[i*3+1] = f->loopbase->head.next->next;
 +                      looptris[i*3+2] = f->loopbase->head.next->next->next;
 +                      i++;
 +              }
 +
 +      }
 +
 +      tm->tottri = i;
 +      tm->looptris = looptris;
 +      return;
 +#endif
 +
 +      f = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
 +      for ( ; f; f=BMIter_Step(&iter)) {
 +              EditVert *v, *lastv=NULL, *firstv=NULL;
 +              EditEdge *e;
 +              EditFace *efa;
 +
 +              /*don't consider two-edged faces*/
 +              if (f->len < 3) continue;
 +              
 +              /*scanfill time*/
 +              l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
 +              for (j=0; l; l=BMIter_Step(&liter), j++) {
 +                      /*mark order*/
 +                      l->_index = 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(2);
 +              
 +              for (efa = fillfacebase.first; efa; efa=efa->next) {
 +                      BMLoop *l1, *l2, *l3;
 +
 +                      BLI_array_growone(looptris);
 +                      BLI_array_growone(looptris);
 +                      BLI_array_growone(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->_index > l2->_index) {
 +                              SWAP(BMLoop*, l1, l2);
 +                      }
 +                      if (l2->_index > l3->_index) {
 +                              SWAP(BMLoop*, l2, l3);
 +                      }
 +                      if (l1->_index > l2->_index) {
 +                              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);
 +      }
 +}
 +
 +void BMEdit_UpdateLinkedCustomData(BMEditMesh *em)
 +{
 +      BMesh *bm = em->bm;
 +      int act;
 +
 +      if (CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)) {
 +              act = CustomData_get_active_layer(&bm->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_active(&bm->ldata, CD_MLOOPUV, act);
 +
 +              act = CustomData_get_render_layer(&bm->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_render(&bm->ldata, CD_MLOOPUV, act);
 +
 +              act = CustomData_get_clone_layer(&bm->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_clone(&bm->ldata, CD_MLOOPUV, act);
 +
 +              act = CustomData_get_stencil_layer(&bm->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_stencil(&bm->ldata, CD_MLOOPUV, act);
 +      }
 +}
 +
 +/*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);
 +
 +      if (em->bm)
 +              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;
 +
 +      /*customdata layout of the tesselated faces*/
 +      CustomData tessface_layout;
 +} 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, "bmesh derived");
 +      bmdm->ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
 +      bmdm->fhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
 +      
 +      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(eed->v1)], 
 +                           bmdm->vertexCos[BMINDEX_GET(eed->v2)]);
 +      } 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), 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)) {
 +                              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_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
++static void bmDM_drawEdges(DerivedMesh *dm, int drawLooseEdges, int drawAllEdges)
 +{
 +      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)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEditMesh *em = bmdm->tc;
 +      BMFace *efa;
 +      BMIter iter;
 +
 +      glBegin(GL_LINES);
 +      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +              BMIter liter;
 +              BMLoop *l;
 +              MLoopUV *lastluv = NULL, *firstluv = NULL;
 +              
 +              if (BM_TestHFlag(efa, BM_HIDDEN))
 +                      continue;
 +              
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                      MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                      
 +                      if (luv) {
 +                              if (lastluv) 
 +                                      glVertex2fv(luv->uv);
 +                              glVertex2fv(luv->uv);
 +                              
 +                              lastluv = luv;
 +                              if (!firstluv) 
 +                                      firstluv = luv;
 +                      }
 +              }
 +              
 +              if (lastluv) {
 +                      glVertex2fv(lastluv->uv);
 +                      glVertex2fv(firstluv->uv);
 +              }
 +      }
 +      glEnd();
 +}
 +
 +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 :/ */
 +      
 +      if (vertexCos) {
 +              l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
 +              for (; l; l=BMIter_Step(&iter)) {
 +                      VECADD(cent, cent, vertexCos[BMINDEX_GET(l->v)]);
 +                      tot++;
 +              }
 +      } else {
 +              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;
 +      mul_v3_fl(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), i++)
 +                      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 DMFaceIter *bmDM_getFaceIter(void *dm)
++static void bmDM_drawMappedFaces(DerivedMesh *dm, 
++      int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), 
++      void *userData, int useColors, 
++      int (*setMaterial)(int, void *attribs))
 +{
 +      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), i++)
 +                      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;
 +                      
 +                      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(bmdm->faceNos[i]);
 +                                      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_get_tri_tex(BMesh *bm, BMLoop **ls, MLoopUV *luv[3], MLoopCol *lcol[3], 
 +                           int has_uv, int has_col)
 +{
 +      if (has_uv) { 
 +              luv[0] = CustomData_bmesh_get(&bm->ldata, ls[0]->head.data, CD_MLOOPUV);
 +              luv[1] = CustomData_bmesh_get(&bm->ldata, ls[1]->head.data, CD_MLOOPUV);
 +              luv[2] = CustomData_bmesh_get(&bm->ldata, ls[2]->head.data, CD_MLOOPUV);
 +      }
 +
 +      if (has_col) {
 +              lcol[0] = CustomData_bmesh_get(&bm->ldata, ls[0]->head.data, CD_MLOOPCOL);
 +              lcol[1] = CustomData_bmesh_get(&bm->ldata, ls[1]->head.data, CD_MLOOPCOL);
 +              lcol[2] = CustomData_bmesh_get(&bm->ldata, ls[2]->head.data, CD_MLOOPCOL);
 +      }
 +
 +
 +}
 +
 +static void bmDM_drawFacesTex_common(DerivedMesh *dm,
 +               int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
 +               int (*drawParamsMapped)(void *userData, int index),
 +               void *userData) 
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEditMesh *em = bmdm->tc;
 +      BMesh *bm= bmdm->tc->bm;
 +      float (*vertexCos)[3]= bmdm->vertexCos;
 +      float (*vertexNos)[3]= bmdm->vertexNos;
 +      BMFace *efa;
 +      BMVert *eve;
 +      BMIter iter;
 +      MLoopUV *luv[3], dummyluv = {0};
 +      MLoopCol *lcol[3], dummylcol = {0};
 +      int i, has_vcol = CustomData_has_layer(&bm->ldata, CD_MLOOPCOL);
 +      int has_uv = CustomData_has_layer(&bm->pdata, CD_MTEXPOLY);
 +      
 +      luv[0] = luv[1] = luv[2] = &dummyluv;
 +      lcol[0] = lcol[1] = lcol[2] = &dummylcol;
 +
 +      dummylcol.a = dummylcol.r = dummylcol.g = dummylcol.b = 255;
 +
 +      /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
 +      glShadeModel(GL_SMOOTH);
 +      
 +      i = 0;
 +      BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL)
 +              BMINDEX_SET(efa, i++);
 +
 +      if (vertexCos) {
 +              i = 0;
 +              BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
 +                      BMINDEX_SET(eve, i++);
 +                              
 +              glBegin(GL_TRIANGLES);
 +              for (i=0; i<em->tottri; i++) {
 +                      BMLoop **ls = em->looptris[i];
 +                      MTexPoly *tp= CustomData_bmesh_get(&bm->pdata, ls[0]->f->head.data, CD_MTEXPOLY);
 +                      MTFace mtf = {0};
 +                      unsigned char *cp= NULL;
 +                      int drawSmooth= BM_TestHFlag(ls[0]->f, BM_SMOOTH);
 +                      int flag;
 +
 +                      efa = ls[0]->f;
 +                      
 +                      if (has_uv) {
 +                              mtf.flag = tp->flag;
 +                              mtf.tpage = tp->tpage;
 +                              mtf.transp = tp->transp;
 +                              mtf.mode = tp->mode;
 +                              mtf.tile = tp->tile;
 +                              mtf.unwrap = tp->unwrap;
 +                      }
 +
 +                      if(drawParams)
 +                              flag= drawParams(&mtf, has_vcol, efa->mat_nr);
 +                      else if(drawParamsMapped)
 +                              flag= drawParamsMapped(userData, BMINDEX_GET(efa));
 +                      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 (!has_vcol) {
 +                                      glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 +                              } 
 +                              
 +                              if (!drawSmooth) {
 +                                      glNormal3fv(bmdm->faceNos[i]);
 +                                      
 +                                      bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
 +                                      
 +                                      glTexCoord2fv(luv[0]->uv);
 +                                      glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
 +                                      glVertex3fv(vertexCos[BMINDEX_GET(ls[0]->v)]);
 +
 +                                      glTexCoord2fv(luv[1]->uv);
 +                                      glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
 +                                      glVertex3fv(vertexCos[BMINDEX_GET(ls[1]->v)]);
 +
 +                                      glTexCoord2fv(luv[2]->uv);
 +                                      glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
 +                                      glVertex3fv(vertexCos[BMINDEX_GET(ls[2]->v)]);
 +                              } else {
 +                                      bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
 +                                      
 +                                      glTexCoord2fv(luv[0]->uv);
 +                                      glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
 +                                      glNormal3fv(vertexNos[BMINDEX_GET(ls[0]->v)]);
 +                                      glVertex3fv(vertexCos[BMINDEX_GET(ls[0]->v)]);
 +
 +                                      glTexCoord2fv(luv[1]->uv);
 +                                      glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
 +                                      glNormal3fv(vertexNos[BMINDEX_GET(ls[1]->v)]);
 +                                      glVertex3fv(vertexCos[BMINDEX_GET(ls[1]->v)]);
 +
 +                                      glTexCoord2fv(luv[2]->uv);
 +                                      glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
 +                                      glNormal3fv(vertexNos[BMINDEX_GET(ls[2]->v)]);
 +                                      glVertex3fv(vertexCos[BMINDEX_GET(ls[2]->v)]);
 +                              }
 +                      }
 +              }
 +              glEnd();
 +      } else {
 +              i = 0;
 +              BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
 +                      BMINDEX_SET(eve, i++);
 +                              
 +              for (i=0; i<em->tottri; i++) {
 +                      BMLoop **ls = em->looptris[i];
 +                      MTexPoly *tp= CustomData_bmesh_get(&bm->pdata, ls[0]->f->head.data, CD_MTEXPOLY);
 +                      MTFace mtf = {0};
 +                      unsigned char *cp= NULL;
 +                      int drawSmooth= BM_TestHFlag(ls[0]->f, BM_SMOOTH);
 +                      int flag;
 +
 +                      efa = ls[0]->f;
 +                      
 +                      if (has_uv) {
 +                              mtf.flag = tp->flag;
 +                              mtf.tpage = tp->tpage;
 +                              mtf.transp = tp->transp;
 +                              mtf.mode = tp->mode;
 +                              mtf.tile = tp->tile;
 +                              mtf.unwrap = tp->unwrap;
 +                      }
 +
 +                      if(drawParams)
 +                              flag= drawParams(&mtf, has_vcol, efa->mat_nr);
 +                      else if(drawParamsMapped)
 +                              flag= drawParamsMapped(userData, BMINDEX_GET(efa));
 +                      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 (!has_vcol) {
 +                                      glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 +                              } 
 +                              
 +                              glBegin(GL_TRIANGLES);
 +                              if (!drawSmooth) {
 +                                      glNormal3fv(efa->no);
 +                                      
 +                                      bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
 +                                      
 +                                      if (luv[0])
 +                                              glTexCoord2fv(luv[0]->uv);
 +                                      if (lcol[0])
 +                                              glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glVertex3fv(ls[0]->v->co);
 +
 +                                      if (luv[1])
 +                                              glTexCoord2fv(luv[1]->uv);
 +                                      if (lcol[1])
 +                                              glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glVertex3fv(ls[1]->v->co);
 +
 +                                      if (luv[2])
 +                                              glTexCoord2fv(luv[2]->uv);
 +                                      if (lcol[2])
 +                                              glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glVertex3fv(ls[2]->v->co);
 +                              } else {
 +                                      bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
 +                                      
 +                                      if (luv[0])
 +                                              glTexCoord2fv(luv[0]->uv);
 +                                      if (lcol[0])
 +                                              glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glNormal3fv(ls[0]->v->no);
 +                                      glVertex3fv(ls[0]->v->co);
 +
 +                                      if (luv[1])
 +                                              glTexCoord2fv(luv[1]->uv);
 +                                      if (lcol[1])
 +                                              glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glNormal3fv(ls[1]->v->no);
 +                                      glVertex3fv(ls[1]->v->co);
 +
 +                                      if (luv[2])
 +                                              glTexCoord2fv(luv[2]->uv);
 +                                      if (lcol[2])
 +                                              glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glNormal3fv(ls[2]->v->no);
 +                                      glVertex3fv(ls[2]->v->co);
 +                              }
 +                              glEnd();
 +                      }
 +              }
 +      }
 +}
 +
 +static void bmDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, 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->totvert) {
 +              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(BMesh *bm, 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);
 +
 +      vert_r->flag = BMFlags_To_MEFlags(ev);
 +
 +      if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
 +              vert_r->bweight = (unsigned char) (BM_GetCDf(&bm->vdata, ev, CD_BWEIGHT)*255.0f);
 +      }
 +
 +      return 1;
 +}
 +
 +static void bmDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
 +{
 +      BMVert *ev;
 +
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tv) {
 +              printf("error in bmDM_getVert.\n");
 +              return;
 +      }
 +
 +      ev = ((EditDerivedBMesh *)dm)->vtable[index];
 +      bmvert_to_mvert(((EditDerivedBMesh *)dm)->tc->bm, 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;
 +
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->te) {
 +              printf("error in bmDM_getEdge.\n");
 +              return;
 +      }
 +
 +      e = bmdm->etable[index];
 +
 +      if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
 +              edge_r->bweight = (unsigned char) (BM_GetCDf(&bm->edata, e, CD_BWEIGHT)*255.0f);
 +      }
 +
 +      if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
 +              edge_r->crease = (unsigned char) (BM_GetCDf(&bm->edata, e, CD_CREASE)*255.0f);
 +      }
 +
 +      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;
 +      BMFace *ef;
 +      BMLoop **l;
 +      
 +      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);
 +
 +              vert_r->flag = BMFlags_To_MEFlags(ev);
 +
 +              if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
 +                      vert_r->bweight = (unsigned char) (BM_GetCDf(&bm->vdata, ev, CD_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 has_bweight = CustomData_has_layer(&bm->edata, CD_BWEIGHT);
 +      int i, has_crease = CustomData_has_layer(&bm->edata, CD_CREASE);
 +
 +      /* 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)) {
 +              if (has_bweight) {
 +                      edge_r->bweight = (unsigned char) (BM_GetCDf(&bm->edata, ee, CD_BWEIGHT)*255.0f);
 +              }
 +
 +              if (has_crease) {
 +                      edge_r->crease = (unsigned char) (BM_GetCDf(&bm->edata, ee, CD_CREASE)*255.0f);
 +              }
 +
 +              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 (edge draw flags, if I remember right) 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_tessface_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_tessface_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_tessface_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;
 +      
 +      if (iter->f) {
 +              iter->f->mat_nr = iter->head.mat_nr;
 +              iter->f->head.flag = MEFlags_To_BMFlags(iter->head.flags, BM_FACE);
 +      }
 +
 +      iter->f = iter->nextf;
 +
 +      iter->head.mat_nr = iter->f->mat_nr;
 +      iter->head.flags = BMFlags_To_MEFlags(iter->f);
 +      iter->head.index++;
 +
 +      iter->head.len = iter->f->len;
 +
 +      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 = BMIter_Step(&iter->iter);
 +      if (!iter->l) {
 +              iter->head.done = 1;
 +              return;
 +      }
 +
 +      bmvert_to_mvert(iter->bm, 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);
 +}
 +
 +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->l = 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->bm, iter->l->v, &iter->head.v);
 +      iter->head.vindex = BMINDEX_GET(iter->l->v);
 +      iter->head.eindex = BMINDEX_GET(iter->l->e);
 +
 +      return (DMLoopIter*) iter;
 +}
 +
-       EditDerivedBMesh *bmdm= dm;
++static DMFaceIter *bmDM_getFaceIter(DerivedMesh *dm)
 +{
- static void bmDM_release(void *dm)
++      EditDerivedBMesh *bmdm= (EditDerivedBMesh*)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;
 +}
 +
-       EditDerivedBMesh *bmdm= dm;
++static void bmDM_release(DerivedMesh *dm)
 +{
++      EditDerivedBMesh *bmdm= (EditDerivedBMesh *)dm;
 +
 +      if (DM_release(dm)) {
 +              if (bmdm->vertexCos) {
 +                      MEM_freeN(bmdm->vertexCos);
 +                      MEM_freeN(bmdm->vertexNos);
 +                      MEM_freeN(bmdm->faceNos);
 +              }
 +              
 +              if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL);
 +              if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL);
 +              if (bmdm->vhash) 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);
 +      }
 +}
 +
 +CustomData *bmDm_getVertDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->vdata;
 +}
 +
 +CustomData *bmDm_getEdgeDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->edata;
 +}
 +
 +CustomData *bmDm_getTessFaceDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tessface_layout;
 +}
 +
 +CustomData *bmDm_getLoopDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->ldata;
 +}
 +
 +CustomData *bmDm_getFaceDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->pdata;
 +}
 +
 +
 +DerivedMesh *getEditDerivedBMesh(BMEditMesh *em, Object *ob,
 +                                           float (*vertexCos)[3])
 +{
 +      EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), "bmdm");
 +      BMesh *bm = em->bm;
 +      int i;
 +      
 +      bmdm->tc = em;
 +
 +      DM_init((DerivedMesh*)bmdm, DM_TYPE_EDITBMESH, em->bm->totvert, 
 +               em->bm->totedge, em->tottri, em->bm->totloop, em->bm->totface);
 +      
 +      for (i=0; i<bm->ldata.totlayer; i++) {
 +              if (bm->ldata.layers[i].type == CD_MLOOPCOL) {
 +                      CustomData_add_layer(&bmdm->tessface_layout, CD_MCOL, CD_ASSIGN, NULL, 0);
 +              } else if (bm->ldata.layers[i].type == CD_MLOOPUV) {
 +                      CustomData_add_layer(&bmdm->tessface_layout, CD_MTFACE, CD_ASSIGN, NULL, 0);
 +              }
 +      }
 +
 +      bmdm->dm.numVertData = bm->totvert;
 +      bmdm->dm.numEdgeData = bm->totedge;
 +      bmdm->dm.numFaceData = em->tottri;
 +      bmdm->dm.numLoopData = bm->totloop;
 +      bmdm->dm.numPolyData = bm->totface;
 +
 +      bmdm->dm.getMinMax = bmDM_getMinMax;
 +
 +      bmdm->dm.getVertDataLayout = bmDm_getVertDataLayout;
 +      bmdm->dm.getEdgeDataLayout = bmDm_getEdgeDataLayout;
 +      bmdm->dm.getTessFaceDataLayout = bmDm_getTessFaceDataLayout;
 +      bmdm->dm.getLoopDataLayout = bmDm_getLoopDataLayout;
 +      bmdm->dm.getFaceDataLayout = bmDm_getFaceDataLayout;
 +
 +      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 = bmdm->tc->tottri;
 +              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];
 +                      
 +                      normal_tri_v3( no,v1, v2, v3);
 +                      add_v3_v3v3(bmdm->vertexNos[BMINDEX_GET(l[0]->v)], bmdm->vertexNos[BMINDEX_GET(l[0]->v)], no);
 +                      add_v3_v3v3(bmdm->vertexNos[BMINDEX_GET(l[1]->v)], bmdm->vertexNos[BMINDEX_GET(l[1]->v)], no);
 +                      add_v3_v3v3(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_v3(no)==0.0) {
 +                              VECCOPY(no, vertexCos[i]);
 +                              normalize_v3(no);
 +                      }
 +              }
 +      }
 +
 +      //bmdm_recalc_lookups(bmdm);
 +
 +      return (DerivedMesh*) bmdm;
 +}
@@@ -941,13 -592,13 +946,17 @@@ static void mfaces_strip_loose(MFace *m
  }
  
  /* Create edges based on known verts and faces */
--static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, int UNUSED(totvert), int totface,
++static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *allloop,
++      MPoly *allpoly, int UNUSED(totvert), int totface, int totloop, int totpoly, 
        int old, MEdge **alledge, int *_totedge)
  {
++      MPoly *mpoly;
++      MLoop *mloop;
        MFace *mface;
        MEdge *medge;
++      EdgeHash *hash = BLI_edgehash_new();
        struct edgesort *edsort, *ed;
--      int a, totedge=0, final=0;
++      int a, b, totedge=0, final=0;
  
        /* we put all edges in array, sort them, and detect doubles that way */
  
        medge->flag |= ME_EDGERENDER;
  
        MEM_freeN(edsort);
++      
++      /*set edge members of mloops*/
++      medge= *alledge;
++      for (a=0; a<*_totedge; a++, medge++) {
++              BLI_edgehash_insert(hash, medge->v1, medge->v2, SET_INT_IN_POINTER(a));
++      }
++      
++      mpoly = allpoly;
++      for (a=0; a<totpoly; a++, mpoly++) {
++              mloop = allloop + mpoly->loopstart;
++              for (b=0; b<mpoly->totloop; b++) {
++                      int v1, v2;
++                      
++                      v1 = mloop[b].v;
++                      v2 = mloop[(b+1)%mpoly->loopstart].v;
++                      mloop[b].e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(hash, v1, v2));
++              }
++      }
++      
++      BLI_edgehash_free(hash, NULL);
  }
  
  void make_edges(Mesh *me, int old)
        MEdge *medge;
        int totedge=0;
  
--      make_edges_mdata(me->mvert, me->mface, me->totvert, me->totface, old, &medge, &totedge);
++      make_edges_mdata(me->mvert, me->mface, me->mloop, me->mpoly, me->totvert, me->totface, me->totloop, me->totpoly, old, &medge, &totedge);
        if(totedge==0) {
                /* flag that mesh has edges */
                me->medge = medge;
@@@ -1124,31 -773,31 +1151,37 @@@ void mball_to_mesh(ListBase *lb, Mesh *
                }
  
                make_edges(me, 0);      // all edges
--      }       
++              convert_mfaces_to_mpolys(me);
++      }
  }
  
  /* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
  /* return non-zero on error */
  int nurbs_to_mdata(Object *ob, MVert **allvert, int *totvert,
--      MEdge **alledge, int *totedge, MFace **allface, int *totface)
++      MEdge **alledge, int *totedge, MFace **allface, MLoop **allloop, MPoly **allpoly, 
++      int *totface, int *totloop, int *totpoly)
  {
        return nurbs_to_mdata_customdb(ob, &ob->disp,
--              allvert, totvert, alledge, totedge, allface, totface);
++              allvert, totvert, alledge, totedge, allface, allloop, allpoly, totface, totloop, totpoly);
  }
  
  /* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
  /* use specified dispbase  */
  int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int *_totvert,
--      MEdge **alledge, int *_totedge, MFace **allface, int *_totface)
++      MEdge **alledge, int *_totedge, MFace **allface, MLoop **allloop, MPoly **allpoly, 
++      int *_totface, int *_totloop, int *_totpoly)
  {
        DispList *dl;
        Curve *cu;
        MVert *mvert;
        MFace *mface;
++      MPoly *mpoly;
++      MLoop *mloop;
        float *data;
        int a, b, ofs, vertcount, startvert, totvert=0, totvlak=0;
        int p1, p2, p3, p4, *index;
        int conv_polys= 0;
++      int i, j;
  
        cu= ob->data;
  
        }
  
        *allvert= mvert= MEM_callocN(sizeof (MVert) * totvert, "nurbs_init mvert");
--      *allface= mface= MEM_callocN(sizeof (MVert) * totvlak, "nurbs_init mface");
--
++      *allface= mface= MEM_callocN(sizeof (MFace) * totvlak, "nurbs_init mface");
++      *allloop = mloop = MEM_callocN(sizeof(MLoop) * totvlak * 4, "nurbs_init mloop");
++      *allpoly = mpoly = MEM_callocN(sizeof(MPoly) * totvlak * 4, "nurbs_init mloop");
++      
        /* verts and faces */
        vertcount= 0;
  
  
                dl= dl->next;
        }
--
++      
++      mface= *allface;
++      j = 0;
++      for (i=0; i<totvert; i++, mpoly++, mface++) {
++              int k;
++              
++              if (!mface->v3) {
++                      mpoly--;
++                      i--;
++                      continue;
++              }
++              
++              if (mface >= *allface + totvlak)
++                      break;
++              
++              mpoly->loopstart= j;
++              mpoly->totloop= mface->v4 ? 4 : 3;
++              for (k=0; k<mpoly->totloop; k++, mloop++) {
++                      mloop->v = (&mface->v1)[k];
++              }
++      }
++      
++      *_totpoly= i;
++      *_totloop= j;
        *_totvert= totvert;
        *_totface= totvlak;
  
--      make_edges_mdata(*allvert, *allface, totvert, totvlak, 0, alledge, _totedge);
++      make_edges_mdata(*allvert, *allface, *allloop, *allpoly, totvert, totvlak, *_totloop, *_totpoly, 0, alledge, _totedge);
        mfaces_strip_loose(*allface, _totface);
  
        return 0;
@@@ -1346,12 -995,12 +1404,14 @@@ void nurbs_to_mesh(Object *ob
        MVert *allvert= NULL;
        MEdge *alledge= NULL;
        MFace *allface= NULL;
--      int totvert, totedge, totface;
++      MLoop *allloop = NULL;
++      MPoly *allpoly = NULL;
++      int totvert, totedge, totface, totloop, totpoly;
  
        cu= ob->data;
  
        if (dm == NULL) {
--              if (nurbs_to_mdata (ob, &allvert, &totvert, &alledge, &totedge, &allface, &totface) != 0) {
++              if (nurbs_to_mdata (ob, &allvert, &totvert, &alledge, &totedge, &allface, &allloop, &allpoly, &totface, &totloop, &totpoly) != 0) {
                        /* Error initializing */
                        return;
                }
                me->totvert= totvert;
                me->totface= totface;
                me->totedge= totedge;
++              me->totloop = totloop;
++              me->totpoly = totpoly;
  
                me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert);
--              me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, allface, me->totface);
                me->medge= CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge);
++              me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, allface, me->totface);
++              me->mloop= CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop);
++              me->mpoly= CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
  
--              mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
++              mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
        } else {
                me= add_mesh("Mesh");
                DM_to_mesh(dm, me);
@@@ -1619,30 -1268,33 +1683,108 @@@ void mesh_set_smooth_flag(Object *meshO
                        mf->flag &= ~ME_SMOOTH;
                }
        }
 -      mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
 -void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3]) 
++      mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, 
++                                        me->totpoly, NULL, NULL, 0, NULL, NULL);
+ }
- void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float **faceNors_r) 
++void mesh_calc_normals(MVert *mverts, int numVerts, MLoop *mloop, MPoly *mpolys, 
++      int UNUSED(numLoops), int numPolys, float (*polyNors_r)[3], MFace *mfaces, int numFaces, 
++      int *origIndexFace, float (*faceNors_r)[3])
++{
++      float (*pnors)[3] = polyNors_r, (*fnors)[3] = faceNors_r;
++      float (*tnorms)[3] = NULL;
++      int i, j, *origIndex;
++      MFace *mf;
++      MPoly *mp;
++      MLoop *ml;
++      
++      if(numPolys == 0) return;
++      
++      /*first go through and calculate normals for all the polys*/
++      tnorms = MEM_callocN(sizeof(float)*3*numVerts, "tnorms cdderivedmesh.c");
++      if (!pnors) 
++              pnors = MEM_callocN(sizeof(float)*3*numPolys, "poly_nors cdderivedmesh.c");
++      if (!fnors)
++              fnors = MEM_callocN(sizeof(float)*3*numFaces, "face nors cdderivedmesh.c");
++      
++      mp = mpolys;
++      for (i=0; i<numPolys; i++, mp++) {
++              mesh_calc_poly_normal(mp, mloop+mp->loopstart, mverts, pnors[i]);
++              
++              ml = mloop + mp->loopstart;
++              /*this is kindof hackish, probably need to calculate quads around face center for
++                ngons, not this weird quad-fitting thing I've got going here*/
++              for (j=0; j<mp->totloop; j += 4, ml++) {
++                      int v1, v2, v3, v4;
++                      
++                      v1 = ml->v; 
++                      v2 = mloop[mp->loopstart+(j+1)%mp->totloop].v;
++                      v3 = mloop[mp->loopstart+(j+2)%mp->totloop].v;
++                      v4 = mloop[mp->loopstart+(j+3)%mp->totloop].v;
++                                      
++                      accumulate_vertex_normals(tnorms[v1], tnorms[v2], tnorms[v3], v4 != v1 ? tnorms[v4] : NULL,
++                                                                        pnors[i], mverts[v1].co, mverts[v2].co, mverts[v3].co, v4!=v1 ? mverts[v4].co : NULL);
++                      
++              }
++      }
++      
++      /* following Mesh convention; we use vertex coordinate itself for normal in this case */
++      for(i=0; i<numVerts; i++) {
++              MVert *mv= &mverts[i];
++              float *no= tnorms[i];
++              
++              if(normalize_v3(no) == 0.0f)
++                      normalize_v3_v3(no, mv->co);
++
++              normal_float_to_short_v3(mv->no, no);
++      }
++      
++      if (origIndexFace && fnors==faceNors_r && numFaces) {
++              mf = mfaces;
++              for (i=0; i<numFaces; i++, mf++, origIndexFace++) {
++                      if (origIndex < numPolys) {
++                              VECCOPY(fnors[i], tnorms[*origIndexFace]);
++                      } else {
++                              /*eek, we're not corrusponding to polys*/
++                              printf("error in mesh_calc_normals; tesselation face indices are incorrect.  normals may look bad.\n");
++                      }
++              }
++      }
++      
++      MEM_freeN(tnorms);
++      if (fnors != faceNors_r)
++              MEM_freeN(fnors);
++      if (pnors != polyNors_r)
++              MEM_freeN(pnors);
++      
++      fnors = pnors = NULL;
++      
 +}
 +
++void mesh_calc_tessface_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3]) 
  {
        float (*tnorms)[3]= MEM_callocN(numVerts*sizeof(*tnorms), "tnorms");
-       float *fnors= MEM_callocN(sizeof(*fnors)*3*numFaces, "meshnormals");
+       float (*fnors)[3]= (faceNors_r)? faceNors_r: MEM_callocN(sizeof(*fnors)*numFaces, "meshnormals");
        int i;
  
-       for (i=0; i<numFaces; i++) {
+       for(i=0; i<numFaces; i++) {
                MFace *mf= &mfaces[i];
-               float *f_no= &fnors[i*3];
+               float *f_no= fnors[i];
+               float *n4 = (mf->v4)? tnorms[mf->v4]: NULL;
+               float *c4 = (mf->v4)? mverts[mf->v4].co: NULL;
  
-               if (mf->v4)
-                       normal_quad_v3( f_no,mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co);
+               if(mf->v4)
+                       normal_quad_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co);
                else
-                       normal_tri_v3( f_no,mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co);
-               
-               add_v3_v3(tnorms[mf->v1], f_no);
-               add_v3_v3(tnorms[mf->v2], f_no);
-               add_v3_v3(tnorms[mf->v3], f_no);
-               if (mf->v4)
-                       add_v3_v3(tnorms[mf->v4], f_no);
+                       normal_tri_v3(f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co);
+               accumulate_vertex_normals(tnorms[mf->v1], tnorms[mf->v2], tnorms[mf->v3], n4,
+                       f_no, mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, c4);
        }
-       for (i=0; i<numVerts; i++) {
+       /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+       for(i=0; i<numVerts; i++) {
                MVert *mv= &mverts[i];
                float *no= tnorms[i];
                
        
        MEM_freeN(tnorms);
  
-       if (faceNors_r) {
-               *faceNors_r = fnors;
-       } else {
+       if(fnors != faceNors_r)
                MEM_freeN(fnors);
+ }
++
++void bmesh_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, int numCol) 
++{
++      MTFace *texface;
++      MTexPoly *texpoly;
++      MCol *mcol;
++      MLoopCol *mloopcol;
++      MLoopUV *mloopuv;
++      MFace *mf;
++      int i;
++
++      for(i=0; i < numTex; i++){
++              texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
++              texpoly = CustomData_get_n(&me->pdata, CD_MTEXPOLY, findex, i); 
++              mf = me->mface + findex;
++              
++              texpoly->tpage = texface->tpage;
++              texpoly->flag = texface->flag;
++              texpoly->transp = texface->transp;
++              texpoly->mode = texface->mode;
++              texpoly->tile = texface->tile;
++              texpoly->unwrap = texface->unwrap;
++      
++              mloopuv = CustomData_get_n(&me->ldata, CD_MLOOPUV, loopstart, i);
++              mloopuv->uv[0] = texface->uv[0][0]; mloopuv->uv[1] = texface->uv[0][1]; mloopuv++;
++              mloopuv->uv[0] = texface->uv[1][0]; mloopuv->uv[1] = texface->uv[1][1]; mloopuv++;
++              mloopuv->uv[0] = texface->uv[2][0]; mloopuv->uv[1] = texface->uv[2][1]; mloopuv++;
++
++              if (mf->v4) {
++                      mloopuv->uv[0] = texface->uv[3][0]; mloopuv->uv[1] = texface->uv[3][1]; mloopuv++;
++              }
++      }
++
++      for(i=0; i < numCol; i++){
++              mf = me->mface + findex;
++              mloopcol = CustomData_get_n(&me->ldata, CD_MLOOPCOL, loopstart, i);
++              mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
++
++              mloopcol->r = mcol[0].r; mloopcol->g = mcol[0].g; mloopcol->b = mcol[0].b; mloopcol->a = mcol[0].a; mloopcol++;
++              mloopcol->r = mcol[1].r; mloopcol->g = mcol[1].g; mloopcol->b = mcol[1].b; mloopcol->a = mcol[1].a; mloopcol++;
++              mloopcol->r = mcol[2].r; mloopcol->g = mcol[2].g; mloopcol->b = mcol[2].b; mloopcol->a = mcol[2].a; mloopcol++;
++              if (mf->v4) {
++                      mloopcol->r = mcol[3].r; mloopcol->g = mcol[3].g; mloopcol->b = mcol[3].b; mloopcol->a = mcol[3].a; mloopcol++;
++              }
 +      }
++      
++      if (CustomData_has_layer(&me->fdata, CD_MDISPS)) {
++              MDisps *ld = CustomData_get(&me->ldata, loopstart, CD_MDISPS);
++              MDisps *fd = CustomData_get(&me->fdata, findex, CD_MDISPS);
++              float (*disps)[3] = fd->disps;
++              int i, tot = mf->v4 ? 4 : 3;
++              int side, corners;
++              
++              corners = multires_mdisp_corners(fd);
++              side = sqrt(fd->totdisp / corners);
++              
++              for (i=0; i<tot; i++, disps += side*side, ld++) {
++                      ld->totdisp = side*side;
++                      
++                      if (ld->disps)
++                              BLI_cellalloc_free(ld->disps);
++                      
++                      ld->disps = BLI_cellalloc_malloc(sizeof(float)*3*side*side, "converted loop mdisps");
++                      memcpy(ld->disps, disps, sizeof(float)*3*side*side);
++              }
++      }
++}
++
++void convert_mfaces_to_mpolys(Mesh *mesh)
++{
++      MFace *mf;
++      MLoop *ml;
++      MPoly *mp;
++      MEdge *me;
++      EdgeHash *eh;
++      int numTex, numCol;
++      int i, j, totloop;
++
++      mesh->totpoly = mesh->totface;
++      mesh->mpoly = MEM_callocN(sizeof(MPoly)*mesh->totpoly, "mpoly converted");
++      CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_ASSIGN, mesh->mpoly, mesh->totpoly);
++
++      numTex = CustomData_number_of_layers(&mesh->fdata, CD_MTFACE);
++      numCol = CustomData_number_of_layers(&mesh->fdata, CD_MCOL);
++      
++      totloop = 0;
++      mf = mesh->mface;
++      for (i=0; i<mesh->totface; i++, mf++) {
++              totloop += mf->v4 ? 4 : 3;
++      }
++      
++      mesh->totloop = totloop;
++      mesh->mloop = MEM_callocN(sizeof(MLoop)*mesh->totloop, "mloop converted");
++
++      CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_ASSIGN, mesh->mloop, totloop);
++      CustomData_to_bmeshpoly(&mesh->fdata, &mesh->pdata, &mesh->ldata,
++              mesh->totloop, mesh->totpoly);
++
++      eh = BLI_edgehash_new();
++
++      /*build edge hash*/
++      me = mesh->medge;
++      for (i=0; i<mesh->totedge; i++, me++) {
++              BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i));
++      }
++
++      j = 0; /*current loop index*/
++      ml = mesh->mloop;
++      mf = mesh->mface;
++      mp = mesh->mpoly;
++      for (i=0; i<mesh->totface; i++, mf++, mp++) {
++              mp->loopstart = j;
++              
++              mp->totloop = mf->v4 ? 4 : 3;
++
++              mp->mat_nr = mf->mat_nr;
++              mp->flag = mf->flag;
++              
++              #define ML(v1, v2) {ml->v = mf->v1; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); ml++; j++;}
++              
++              ML(v1, v2);
++              ML(v2, v3);
++              if (mf->v4) {
++                      ML(v3, v4);
++                      ML(v4, v1);
++              } else {
++                      ML(v3, v1);
++              }
++              
++              #undef ML
++
++              bmesh_corners_to_loops(mesh, i, mp->loopstart, numTex, numCol);
++      }
++
++      /*BMESH_TODO now to deal with fgons*/
++
++      BLI_edgehash_free(eh, NULL);
 +}
 +
  float (*mesh_getVertexCos(Mesh *me, int *numVerts_r))[3]
  {
        int i, numVerts = me->totvert;
@@@ -913,127 -894,6 +918,127 @@@ static void multiresModifier_update(Der
        }
  }
  
-       CCGDerivedMesh *ccgdm, *subsurf=NULL;
 +
 +void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to)
 +{
-       ccgdm = (CCGDerivedMesh*)multires_dm_create_local(ob, dm, totlvl, totlvl, mmd->simple);
++      DerivedMesh *ccgdm, *subsurf=NULL;
 +      DMGridData **gridData, **subGridData=NULL;
 +      MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
 +      MDisps *mdisps;
 +      MultiresModifierData *mmd = get_multires_modifier(NULL, ob, 1);
 +      int *gridOffset, totlvl;
 +      int i, k, numGrids, gridSize, dGridSize, dSkip;
 +      
 +      if (!mmd)
 +              return;
 +      
 +      mdisps = CustomData_get_layer(&dm->loopData, CD_MDISPS);
 +
 +      if(!mdisps) {
 +              goto cleanup;
 +      }
 +
 +      totlvl = mmd->totlvl;
-       numGrids = subsurf->dm.getNumGrids(subsurf);
-       gridSize = subsurf->dm.getGridSize(subsurf);
-       gridData = subsurf->dm.getGridData(subsurf);
++      ccgdm = multires_dm_create_local(ob, dm, totlvl, totlvl, mmd->simple);
 +      
 +      subsurf = subsurf_dm_create_local(ob, dm, totlvl,
 +              mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges);
 +
-       gridSize = ccgdm->dm.getGridSize((DerivedMesh*)ccgdm);
-       gridData = ccgdm->dm.getGridData((DerivedMesh*)ccgdm);
-       gridOffset = ccgdm->dm.getGridOffset((DerivedMesh*)ccgdm);
++      numGrids = subsurf->getNumGrids(subsurf);
++      gridSize = subsurf->getGridSize(subsurf);
++      gridData = subsurf->getGridData(subsurf);
 +
 +      subGridData = MEM_callocN(sizeof(DMGridData*)*numGrids, "subGridData*");
 +
 +      for(i = 0; i < numGrids; i++) {
 +              subGridData[i] = MEM_callocN(sizeof(DMGridData)*gridSize*gridSize, "subGridData");
 +              memcpy(subGridData[i], gridData[i], sizeof(DMGridData)*gridSize*gridSize);
 +      }
 +      
 +      /*numGrids = ccgdm->dm->getNumGrids((DerivedMesh*)ccgdm);*/ /*UNUSED*/
-               subsurf->dm.needsFree = 1;
-               subsurf->dm.release(subsurf);
++      gridSize = ccgdm->getGridSize((DerivedMesh*)ccgdm);
++      gridData = ccgdm->getGridData((DerivedMesh*)ccgdm);
++      gridOffset = ccgdm->getGridOffset((DerivedMesh*)ccgdm);
 +
 +      dGridSize = multires_side_tot[totlvl];
 +      dSkip = (dGridSize-1)/(gridSize-1);
 +
 +      k = 0; /*current loop/mdisp index within the mloop array*/
 +
 +      //#pragma omp parallel for private(i) if(dm->numLoopData*gridSize*gridSize >= CCG_OMP_LIMIT)
 +
 +      for(i = 0; i < dm->numPolyData; ++i) {
 +              const int numVerts = mpoly[i].totloop;
 +              int S, x, y, gIndex = gridOffset[i];
 +                                              
 +              for(S = 0; S < numVerts; ++S, ++gIndex, ++k) {
 +                      MDisps *mdisp = &mdisps[mpoly[i].loopstart+S];
 +                      DMGridData *grid = gridData[gIndex];
 +                      DMGridData *subgrid = subGridData[gIndex];
 +                      float (*dispgrid)[3] = NULL;
 +
 +                      /* when adding new faces in edit mode, need to allocate disps */
 +                      if(!mdisp->disps) {
 +                              mdisp->totdisp = gridSize*gridSize;
 +                              mdisp->disps = BLI_cellalloc_calloc(sizeof(float)*3*mdisp->totdisp, "disp in multires_set_space");
 +                      }
 +
 +                      dispgrid = mdisp->disps;
 +
 +                      for(y = 0; y < gridSize; y++) {
 +                              for(x = 0; x < gridSize; x++) {
 +                                      float *data = dispgrid[dGridSize*y*dSkip + x*dSkip];
 +                                      float *no = subgrid[x + y*gridSize].no;
 +                                      float *co = subgrid[x + y*gridSize].co;
 +                                      float mat[3][3], tx[3], ty[3], dco[3];
 +                                      
 +                                      /* construct tangent space matrix */
 +                                      grid_tangent(gridSize, gIndex, x, y, 0, subGridData, tx);
 +                                      normalize_v3(tx);
 +
 +                                      grid_tangent(gridSize, gIndex, x, y, 1, subGridData, ty);
 +                                      normalize_v3(ty);
 +                                      column_vectors_to_mat3(mat, tx, ty, no);
 +
 +                                      /* convert to absolute coordinates in space */
 +                                      if (from == MULTIRES_SPACE_TANGENT) {
 +                                              mul_v3_m3v3(dco, mat, data);
 +                                              add_v3_v3(dco, co);
 +                                      } else if (from == MULTIRES_SPACE_OBJECT) {
 +                                              add_v3_v3v3(dco, co, data);
 +                                      } else if (from == MULTIRES_SPACE_ABSOLUTE) {
 +                                              copy_v3_v3(dco, data);
 +                                      }
 +                                      
 +                                      column_vectors_to_mat3(mat, tx, ty, no);
 +
 +                                      /*now, convert to desired displacement type*/
 +                                      if (to == MULTIRES_SPACE_TANGENT) {
 +                                              invert_m3(mat);
 +
 +                                              sub_v3_v3(dco, co);
 +                                              mul_v3_m3v3(data, mat, dco);
 +                                      } else if (to == MULTIRES_SPACE_OBJECT) {
 +                                              sub_v3_v3(dco, co);
 +                                              mul_v3_m3v3(data, mat, dco);
 +                                      } else if (to == MULTIRES_SPACE_ABSOLUTE) {
 +                                              copy_v3_v3(data, dco);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +cleanup:
 +      if (subsurf) {
-       ccgdm->dm.needsFree = 1;
-       ccgdm->dm.release((DerivedMesh*)ccgdm);
++              subsurf->needsFree = 1;
++              subsurf->release(subsurf);
 +      }
 +      
++      ccgdm->needsFree = 1;
++      ccgdm->release(ccgdm);
 +}
 +
  void multires_stitch_grids(Object *ob)
  {
        /* utility for smooth brush */
@@@ -4324,43 -4331,36 +4333,36 @@@ void psys_get_dupli_texture(ParticleSys
                                mtface += cpa->num;
                                psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, uv);
                        }
-                       else
-                               uv[0]= uv[1]= 0.0f;
+               
+                       psys_particle_on_emitter(psmd,PART_FROM_FACE,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,loc,0,0,0,orco,0);
+                       return;
+               }
+               else {
+                       pa = psys->particles + cpa->pa[0];
                }
-               else
-                       uv[0]= uv[1]= 0.0f;
-               psys_particle_on_emitter(psmd,
-                       (part->childtype == PART_CHILD_FACES)? PART_FROM_FACE: PART_FROM_PARTICLE,
-                       cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,loc,0,0,0,orco,0);
        }
-       else {
-               if(part->from == PART_FROM_FACE) {
-                       mtface= CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE);
-                       num= pa->num_dmcache;
  
-                       if(num == DMCACHE_NOTFOUND)
-                               num= pa->num;
+       if(part->from == PART_FROM_FACE) {
+               mtface= CustomData_get_layer(&psmd->dm->faceData, CD_MTFACE);
+               num= pa->num_dmcache;
  
-                       if (num >= psmd->dm->getNumTessFaces(psmd->dm)) {
-                               /* happens when simplify is enabled
-                                * gives invalid coords but would crash otherwise */
-                               num= DMCACHE_NOTFOUND;
-                       }
+               if(num == DMCACHE_NOTFOUND)
+                       num= pa->num;
  
-                       if(mtface && num != DMCACHE_NOTFOUND) {
-                               mface= psmd->dm->getTessFaceData(psmd->dm, num, CD_MFACE);
-                               mtface += num;
-                               psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
-                       }
-                       else
-                               uv[0]= uv[1]= 0.0f;
 -              if (num >= psmd->dm->getNumFaces(psmd->dm)) {
++              if (num >= psmd->dm->getNumTessFaces(psmd->dm)) {
+                       /* happens when simplify is enabled
+                               * gives invalid coords but would crash otherwise */
+                       num= DMCACHE_NOTFOUND;
                }
-               else
-                       uv[0]= uv[1]= 0.0f;
  
-               psys_particle_on_emitter(psmd,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,0,0,0,orco,0);
+               if(mtface && num != DMCACHE_NOTFOUND) {
 -                      mface= psmd->dm->getFaceData(psmd->dm, num, CD_MFACE);
++                      mface= psmd->dm->getTessFaceData(psmd->dm, num, CD_MFACE);
+                       mtface += num;
+                       psys_interpolate_uvs(mtface, mface->v4, pa->fuv, uv);
+               }
        }
+       psys_particle_on_emitter(psmd,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,loc,0,0,0,orco,0);
  }
  
  void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa, ChildParticle *cpa, ParticleCacheKey *cache, float mat[][4], float *scale)
@@@ -1095,52 -1120,14 +1120,14 @@@ static int distribute_threads_init_data
                }
        }
  
-       /* 1. */
-       switch(from){
-               case PART_FROM_VERT:
-                       tot = dm->getNumVerts(dm);
-                       break;
-               case PART_FROM_VOLUME:
-               case PART_FROM_FACE:
-                       tot = dm->getNumTessFaces(dm);
-                       break;
-               case PART_FROM_PARTICLE:
-                       if(psys->target_ob)
-                               tob=psys->target_ob;
-                       else
-                               tob=ob;
+       /* Get total number of emission elements and allocate needed arrays */
 -      totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumFaces(dm);
++      totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumTessFaces(dm);
  
-                       if((tpsys=BLI_findlink(&tob->particlesystem,psys->target_psys-1))){
-                               tpars=tpsys->particles;
-                               tot=tpsys->totpart;
-                       }
-                       break;
-       }
+       if(totelem == 0){
+               distribute_invalid(scene, psys, children ? PART_FROM_CHILD : 0);
  
-       if(tot==0){
-               /*no_distr=1;*/ /*UNUSED*/
-               if(children){
-                       if(G.f & G_DEBUG)
-                               fprintf(stderr,"Particle child distribution error: Nothing to emit from!\n");
-                       if(psys->child) {
-                               for(p=0,cpa=psys->child; p<totpart; p++,cpa++){
-                                       cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3]= 0.0;
-                                       cpa->foffset= 0.0f;
-                                       cpa->parent=0;
-                                       cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
-                                       cpa->num= -1;
-                               }
-                       }
-               }
-               else {
-                       if(G.f & G_DEBUG)
-                               fprintf(stderr,"Particle distribution error: Nothing to emit from!\n");
-                       for(p=0,pa=psys->particles; p<totpart; p++,pa++){
-                               pa->fuv[0]=pa->fuv[1]=pa->fuv[2]= pa->fuv[3]= 0.0;
-                               pa->foffset= 0.0f;
-                               pa->num= -1;
-                       }
-               }
+               if(G.f & G_DEBUG)
+                       fprintf(stderr,"Particle distribution error: Nothing to emit from!\n");
  
                if(dm != finaldm) dm->release(dm);
                return 0;
                
                orcodata= dm->getVertDataArray(dm, CD_ORCO);
  
-               for(i=0; i<tot; i++){
+               for(i=0; i<totelem; i++){
 -                      MFace *mf=dm->getFaceData(dm,i,CD_MFACE);
 +                      MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
  
                        if(orcodata) {
                                VECCOPY(co1, orcodata[mf->v1]);
                maxweight=min;
        }
  
-       /* 2.2 */
-       if(ELEM3(from,PART_FROM_VERT,PART_FROM_FACE,PART_FROM_VOLUME)){
-               float *vweight= psys_cache_vgroup(dm,psys,PSYS_VG_DENSITY);
+       /* Calculate weights from vgroup */
+       vweight = psys_cache_vgroup(dm,psys,PSYS_VG_DENSITY);
  
-               if(vweight){
-                       if(from==PART_FROM_VERT) {
-                               for(i=0;i<tot; i++)
-                                       weight[i]*=vweight[i];
-                       }
-                       else { /* PART_FROM_FACE / PART_FROM_VOLUME */
-                               for(i=0;i<tot; i++){
-                                       MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
-                                       tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
+       if(vweight){
+               if(from==PART_FROM_VERT) {
+                       for(i=0;i<totelem; i++)
+                               element_weight[i]*=vweight[i];
+               }
+               else { /* PART_FROM_FACE / PART_FROM_VOLUME */
+                       for(i=0;i<totelem; i++){
 -                              MFace *mf=dm->getFaceData(dm,i,CD_MFACE);
++                              MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
+                               tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
                                
-                                       if(mf->v4) {
-                                               tweight += vweight[mf->v4];
-                                               tweight /= 4.0;
-                                       }
-                                       else {
-                                               tweight /= 3.0;
-                                       }
-                                       weight[i]*=tweight;
+                               if(mf->v4) {
+                                       tweight += vweight[mf->v4];
+                                       tweight /= 4.0f;
+                               }
+                               else {
+                                       tweight /= 3.0f;
                                }
+                               element_weight[i]*=tweight;
                        }
-                       MEM_freeN(vweight);
                }
+               MEM_freeN(vweight);
        }
  
-       /* 3. */
+       /* Calculate total weight of all elements */
        totweight= 0.0f;
-       for(i=0;i<tot; i++)
-               totweight += weight[i];
+       for(i=0;i<totelem; i++)
+               totweight += element_weight[i];
  
-       if(totweight > 0.0f)
-               totweight= 1.0f/totweight;
+       inv_totweight = (totweight > 0.f ? 1.f/totweight : 0.f);
  
-       sum[0]= 0.0f;
-       for(i=0;i<tot; i++)
-               sum[i+1]= sum[i]+weight[i]*totweight;
+       /* Calculate cumulative weights */
+       element_sum[0]= 0.0f;
+       for(i=0; i<totelem; i++)
+               element_sum[i+1]= element_sum[i] + element_weight[i] * inv_totweight;
        
+       /* Finally assign elements to particles */
        if((part->flag&PART_TRAND) || (part->simplify_flag&PART_SIMPLIFY_ENABLE)) {
                float pos;
  
                }
        }
  
-       MEM_freeN(sum);
-       /* for hair, sort by origindex, allows optimizations in rendering */
-       /* however with virtual parents the children need to be in random order */
-       if(part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents!=0.0)) {
-               if(from != PART_FROM_PARTICLE) {
-                       COMPARE_ORIG_INDEX = NULL;
+       MEM_freeN(element_sum);
  
-                       if(from == PART_FROM_VERT) {
-                               if(dm->numVertData)
-                                       COMPARE_ORIG_INDEX= dm->getVertDataArray(dm, CD_ORIGINDEX);
-                       }
-                       else {
-                               if(dm->numFaceData)
-                                       COMPARE_ORIG_INDEX= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
-                       }
+       /* For hair, sort by origindex (allows optimizations in rendering), */
+       /* however with virtual parents the children need to be in random order. */
+       if(part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents!=0.0f)) {
+               COMPARE_ORIG_INDEX = NULL;
  
-                       if(COMPARE_ORIG_INDEX) {
-                               qsort(index, totpart, sizeof(int), compare_orig_index);
-                               COMPARE_ORIG_INDEX = NULL;
-                       }
+               if(from == PART_FROM_VERT) {
+                       if(dm->numVertData)
+                               COMPARE_ORIG_INDEX= dm->getVertDataArray(dm, CD_ORIGINDEX);
+               }
+               else {
+                       if(dm->numFaceData)
 -                              COMPARE_ORIG_INDEX= dm->getFaceDataArray(dm, CD_ORIGINDEX);
++                              COMPARE_ORIG_INDEX= dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
                }
-       }
  
-       /* weights are no longer used except for FROM_PARTICLE, which needs them zeroed for indexing */
-       if(from==PART_FROM_PARTICLE){
-               for(i=0; i<tot; i++)
-                       weight[i]=0.0f;
+               if(COMPARE_ORIG_INDEX) {
+                       qsort(particle_element, totpart, sizeof(int), distribute_compare_orig_index);
+                       COMPARE_ORIG_INDEX = NULL;
+               }
        }
  
-       /* 4. */
+       /* Create jittering if needed */
        if(distr==PART_DISTR_JIT && ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
                jitlevel= part->userjit;
                
@@@ -1622,40 -1575,16 +1575,16 @@@ void reset_particle(ParticleSimulationD
        float q_phase[4];
        int p = pa - psys->particles;
        part=psys->part;
 -      
 +
- #if 0 /* deprecated code */
-       if(part->from==PART_FROM_PARTICLE){
-               float speed;
-               ParticleSimulationData tsim= {0};
-               tsim.scene= sim->scene;
-               tsim.ob= psys->target_ob ? psys->target_ob : ob;
-               tsim.psys = BLI_findlink(&tsim.ob->particlesystem, sim->psys->target_psys-1);
-               state.time = pa->time;
-               if(pa->num == -1)
-                       memset(&state, 0, sizeof(state));
-               else
-                       psys_get_particle_state(&tsim, pa->num, &state, 1);
-               psys_get_from_key(&state, loc, nor, rot, 0);
-               mul_qt_v3(rot, vtan);
-               mul_qt_v3(rot, utan);
-               speed= normalize_v3_v3(p_vel, state.vel);
-               mul_v3_fl(p_vel, dot_v3v3(r_vel, p_vel));
-               VECSUB(p_vel, r_vel, p_vel);
-               normalize_v3(p_vel);
-               mul_v3_fl(p_vel, speed);
-               VECCOPY(pa->fuv, loc); /* abusing pa->fuv (not used for "from particle") for storing emit location */
-       }
-       else{
- #endif
        /* get precise emitter matrix if particle is born */
-       if(part->type!=PART_HAIR && pa->time < cfra && pa->time >= sim->psys->cfra) {
+       if(part->type!=PART_HAIR && dtime > 0.f && pa->time < cfra && pa->time >= sim->psys->cfra) {
                /* we have to force RECALC_ANIM here since where_is_objec_time only does drivers */
-               BKE_animsys_evaluate_animdata(&sim->ob->id, sim->ob->adt, pa->time, ADT_RECALC_ANIM);
-               where_is_object_time(sim->scene, sim->ob, pa->time);
+               while(ob) {
+                       BKE_animsys_evaluate_animdata(&ob->id, ob->adt, pa->time, ADT_RECALC_ANIM);
+                       ob = ob->parent;
+               }
+               ob = sim->ob;
+               where_is_object_time(sim->scene, ob, pa->time);
        }
  
        /* get birth location from object               */
@@@ -383,146 -380,51 +388,105 @@@ static void set_subsurf_uv(CCGSubSurf *
        MEM_freeN(faceMap);
  }
  
- static void calc_ss_weights(int gridFaces,
-                                                       FaceVertWeight **qweight, FaceVertWeight **tweight)
- {
-       FaceVertWeight *qw, *tw;
-       int x, y, j;
-       int numWeights = gridFaces * gridFaces;
-       *tweight = MEM_mallocN(sizeof(**tweight) * numWeights, "ssTriWeight");
-       *qweight = MEM_mallocN(sizeof(**qweight) * numWeights, "ssQuadWeight");
-       qw = *qweight;
-       tw = *tweight;
-       for (y = 0; y < gridFaces; y++) {
-               for (x = 0; x < gridFaces; x++) {
-                       for (j = 0; j < 4; j++) {
-                               int fx = x + (j == 2 || j == 3);
-                               int fy = y + (j == 1 || j == 2);
-                               float x_v = (float) fx / gridFaces;
-                               float y_v = (float) fy / gridFaces;
-                               float tx_v = (1.0f - x_v), ty_v = (1.0f - y_v);
-                               float center = (1.0f / 3.0f) * tx_v * ty_v;
-                               (*tw)[j][0] = center + 0.5f * tx_v * y_v;
-                               (*tw)[j][2] = center + 0.5f * x_v * ty_v;
-                               (*tw)[j][1] = 1.0f - (*tw)[j][0] - (*tw)[j][2];
-                               (*tw)[j][3] = 0.0f;
-                               tx_v *= 0.5f;
-                               ty_v *= 0.5f;
-                               (*qw)[j][3] = tx_v * ty_v;
-                               (*qw)[j][0] = (*qw)[j][3] + tx_v * y_v;
-                               (*qw)[j][2] = (*qw)[j][3] + x_v * ty_v;
-                               (*qw)[j][1] = 1.0f - (*qw)[j][0] - (*qw)[j][2] - (*qw)[j][3];
-                       }
-                       tw++;
-                       qw++;
-               }
-       }
- }
  /* face weighting */
 -static void calc_ss_weights(int gridFaces,
 -                                                      FaceVertWeight **qweight, FaceVertWeight **tweight)
 +typedef struct FaceVertWeightEntry {
 +      FaceVertWeight *weight;
 +      float *w;
 +      int valid;
 +} FaceVertWeightEntry;
 +
 +typedef struct WeightTable {
 +      FaceVertWeightEntry *weight_table;
 +      int len;
 +} WeightTable;
 +
 +static float *get_ss_weights(WeightTable *wtable, int gridCuts, int faceLen)
  {
 -      FaceVertWeight *qw, *tw;
 -      int x, y, j;
 -      int numWeights = gridFaces * gridFaces;
 -
 -      *tweight = MEM_mallocN(sizeof(**tweight) * numWeights, "ssTriWeight");
 -      *qweight = MEM_mallocN(sizeof(**qweight) * numWeights, "ssQuadWeight");
 -
 -      qw = *qweight;
 -      tw = *tweight;
 -
 -      for (y = 0; y < gridFaces; y++) {
 -              for (x = 0; x < gridFaces; x++) {
 -                      for (j = 0; j < 4; j++) {
 -                              int fx = x + (j == 2 || j == 3);
 -                              int fy = y + (j == 1 || j == 2);
 -                              float x_v = (float) fx / gridFaces;
 -                              float y_v = (float) fy / gridFaces;
 -                              float tx_v = (1.0f - x_v), ty_v = (1.0f - y_v);
 -                              float center = (1.0f / 3.0f) * tx_v * ty_v;
 -
 -                              (*tw)[j][0] = center + 0.5f * tx_v * y_v;
 -                              (*tw)[j][2] = center + 0.5f * x_v * ty_v;
 -                              (*tw)[j][1] = 1.0f - (*tw)[j][0] - (*tw)[j][2];
 -                              (*tw)[j][3] = 0.0f;
 -
 -                              tx_v *= 0.5f;
 -                              ty_v *= 0.5f;
 -
 -                              (*qw)[j][3] = tx_v * ty_v;
 -                              (*qw)[j][0] = (*qw)[j][3] + tx_v * y_v;
 -                              (*qw)[j][2] = (*qw)[j][3] + x_v * ty_v;
 -                              (*qw)[j][1] = 1.0f - (*qw)[j][0] - (*qw)[j][2] - (*qw)[j][3];
 +      int x, y, i, j;
 +      float *w, w1, w2, w4, fac, fac2, fx, fy;
 +
 +      if (wtable->len <= faceLen) {
 +              void *tmp = MEM_callocN(sizeof(FaceVertWeightEntry)*(faceLen+1), "weight table alloc 2");
 +              
 +              if (wtable->len) {
 +                      memcpy(tmp, wtable->weight_table, sizeof(FaceVertWeightEntry)*wtable->len);
 +                      MEM_freeN(wtable->weight_table);
 +              }
 +              
 +              wtable->weight_table = tmp;
 +              wtable->len = faceLen+1;
 +      }
 +
 +      if (!wtable->weight_table[faceLen].valid) {
 +              wtable->weight_table[faceLen].valid = 1;
 +              wtable->weight_table[faceLen].w = w = MEM_callocN(sizeof(float)*faceLen*faceLen*(gridCuts+2)*(gridCuts+2), "weight table alloc");
 +              fac = 1.0 / (float)faceLen;
  
 +              for (i=0; i<faceLen; i++) {
 +                      for (x=0; x<gridCuts+2; x++) {
 +                              for (y=0; y<gridCuts+2; y++) {
 +                                      fx = 0.5f - (float)x / (float)(gridCuts+1) / 2.0f;
 +                                      fy = 0.5f - (float)y / (float)(gridCuts+1) / 2.0f;
 +                              
 +                                      fac2 = faceLen - 4;
 +                                      w1 = (1.0f - fx) * (1.0f - fy) + (-fac2*fx*fy*fac);
 +                                      w2 = (1.0f - fx + fac2*fx*-fac) * (fy);
 +                                      w4 = (fx) * (1.0 - fy + -fac2*fy*fac);
 +                                      
 +                                      fac2 = 1.0 - (w1+w2+w4);
 +                                      fac2 = fac2 / (float)(faceLen-3);
 +                                      for (j=0; j<faceLen; j++)
 +                                              w[j] = fac2;
 +                                      
 +                                      w[i] = w1;
 +                                      w[(i-1+faceLen)%faceLen] = w2;
 +                                      w[(i+1)%faceLen] = w4;
 +
 +                                      w += faceLen;
 +                              }
                        }
 -                      tw++;
 -                      qw++;
                }
        }
 +
 +      return wtable->weight_table[faceLen].w;
  }
  
 -static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
 +void free_ss_weights(WeightTable *wtable)
 +{
 +      int i;
 +
 +      for (i=0; i<wtable->len; i++) {
 +              if (wtable->weight_table[i].valid)
 +                      MEM_freeN(wtable->weight_table[i].w);
 +      }
 +      
 +      if (wtable->weight_table)
 +              MEM_freeN(wtable->weight_table);
 +}
 +
++#if 0
 +static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
 +                                 int drawInteriorEdges, int useSubsurfUv,
 +                                 DerivedMesh *dm, struct MultiresSubsurf *ms)
 +{
 +      DerivedMesh *cgdm, *result;
 +      double curt = PIL_check_seconds_timer();
 +
 +      cgdm = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);
 +      result = CDDM_copy(cgdm, 1);
 +
 +      printf("subsurf conversion time: %.6lf\n", PIL_check_seconds_timer() - curt);
 +      
 +      cgdm->needsFree = 1;
 +      cgdm->release(cgdm);
 +
 +      CDDM_calc_normals(result);
 +
 +      return result;
 +}
++#endif
 +
 +static int ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
                                                                         float (*vertexCos)[3], int useFlatSubdiv)
  {
        float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss);
@@@ -1631,13 -1363,13 +1599,13 @@@ static void ccgDM_drawFacesSolid(Derive
  }
  
        /* Only used by non-editmesh types */
 -static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +static void cgdm_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
        GPUVertexAttribs gattribs;
-       DMVertexAttribs attribs= {{{0}}};
+       DMVertexAttribs attribs= {{{NULL}}};
 -      MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE);
 +      MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE);
        int gridSize = ccgSubSurf_getGridSize(ss);
        int gridFaces = gridSize - 1;
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
index b1db253,0000000..bc8a122
mode 100644,000000..100644
--- /dev/null
@@@ -1,99 -1,0 +1,99 @@@
- #define BLI_array_pop(arr) ((arr&&_##arr##_count) ? arr[--_##arr##_count] : NULL)
 +/**
 + * Array Library
 + *
 + * ***** 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) 2008 Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): Joseph Eagar.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +/*
 +this library needs to be changed to not use macros quite so heavily,
 +and to be more of a complete array API.  The way arrays are
 +exposed to client code as normal C arrays is very useful though, imho.
 +it does require some use of macros, however.  
 +
 +anyway, it's used a bit too heavily to simply rewrite as a 
 +more "correct" solution without macros entirely.  I originally wrote this
 +to be very easy to use, without the normal pain of most array libraries.
 +This was especially helpful when it came to the massive refactors necessary for
 +bmesh, and really helped to speed the process up. - joeedh
 +  
 +little array macro library.  example of usage:
 +
 +int *arr = NULL;
 +BLI_array_declare(arr);
 +int i;
 +
 +for (i=0; i<10; i++) {
 +      BLI_array_growone(arr);
 +      arr[i] = something;
 +}
 +BLI_array_free(arr);
 +
 +arrays are buffered, using double-buffering (so on each reallocation,
 +the array size is doubled).  supposedly this should give good Big Oh
 +behaviour, though it may not be the best in practice.
 +*/
 +
 +#define BLI_array_declare(arr) int _##arr##_count=0; void *_##arr##_tmp; void *_##arr##_static = NULL
 +
 +/*this will use stack space, up to maxstatic array elements, befoe
 +  switching to dynamic heap allocation*/
 +#define BLI_array_staticdeclare(arr, maxstatic) int _##arr##_count=0; void *_##arr##_tmp; char _##arr##_static[maxstatic*sizeof(arr)]
 +
 +/*this returns the entire size of the array, including any buffering.*/
 +#define BLI_array_totalsize_dyn(arr) ((arr)==NULL ? 0 : MEM_allocN_len(arr) / sizeof(*arr))
 +#define BLI_array_totalsize(arr) ((signed int)((arr == _##arr##_static && arr != NULL) ? (sizeof(_##arr##_static) / sizeof(*arr)) : BLI_array_totalsize_dyn(arr)))
 +
 +/*this returns the logical size of the array, not including buffering.*/
 +#define BLI_array_count(arr) _##arr##_count
 +
 +/*grow the array by one.  zeroes the new elements.*/
 +#define _BLI_array_growone(arr) \
 +      BLI_array_totalsize(arr) > _##arr##_count ? ++_##arr##_count : \
 +      ((_##arr##_tmp = MEM_callocN(sizeof(*arr)*(_##arr##_count*2+2), #arr " " __FILE__ " ")),\
 +      (arr && memcpy(_##arr##_tmp, arr, sizeof(*arr) * _##arr##_count)),\
 +      (arr && (arr != (void*)_##arr##_static ? (MEM_freeN(arr), arr) : arr)),\
 +      (arr = _##arr##_tmp),\
 +      _##arr##_count++)
 +
 +/*returns length of array*/
 +#define BLI_array_growone(arr) (arr==NULL && _##arr##_static != NULL  ?  ((arr=(void*)_##arr##_static), ++_##arr##_count) : _BLI_array_growone(arr))
 +
 +      /*appends an item to the array and returns a pointer to the item in the array.
 +  item is not a pointer, but actual data value.*/
 +#define BLI_array_append(arr, item) (BLI_array_growone(arr), (arr[_##arr##_count-1] = item), (arr+(_##arr##_count-1)))
 +
 +/*grow an array by a specified number of items.*/
 +#define BLI_array_growitems(arr, num) {int _i; for (_i=0; _i<(num); _i++) {BLI_array_growone(arr);}}
 +#define BLI_array_free(arr) if (arr && arr != _##arr##_static) MEM_freeN(arr)
 +
++#define BLI_array_pop(arr) ((arr&&_##arr##_count) ? arr[--_##arr##_count] : 0)
 +/*resets the logical size of an array to zero, but doesn't
 +  free the memory.*/
 +#define BLI_array_empty(arr) _##arr##_count=0
 +
 +/*set the count of the array, doesn't actually increase the allocated array
 +  size.  don't use this unless you know what you're doing.*/
 +#define BLI_array_set_length(arr, count) _##arr##_count = (count)
Simple merge
@@@ -1531,7 -1535,7 +1536,7 @@@ void BLI_pbvh_apply_vertCos(PBVH *pbvh
                }
  
                /* coordinates are new -- normals should also be updated */
--              mesh_calc_normals(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL);
++              mesh_calc_tessface_normals(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL);
  
                for (a= 0; a < pbvh->totnode; ++a)
                        BLI_pbvh_node_mark_update(&pbvh->nodes[a]);
Simple merge
   * ***** END GPL LICENSE BLOCK *****
   * (uit traces) maart 95
   */
 -
+ /** \file blender/blenlib/intern/scanfill.c
+  *  \ingroup bli
+  */
  
 +#include <stdio.h>
 +#include <math.h>
 +#include <stdlib.h>
 +#include <string.h>
  
  #include "MEM_guardedalloc.h"
  
@@@ -3503,149 -3456,8 +3519,10 @@@ static void direct_link_customdata(File
                        i++;
                }
        }
 +
 +      customData_update_typemap(data);
  }
  
- void bmesh_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, int numCol) 
- {
-       MTFace *texface;
-       MTexPoly *texpoly;
-       MCol *mcol;
-       MLoopCol *mloopcol;
-       MLoopUV *mloopuv;
-       MFace *mf;
-       int i;
-       for(i=0; i < numTex; i++){
-               texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
-               texpoly = CustomData_get_n(&me->pdata, CD_MTEXPOLY, findex, i); 
-               mf = me->mface + findex;
-               
-               texpoly->tpage = texface->tpage;
-               texpoly->flag = texface->flag;
-               texpoly->transp = texface->transp;
-               texpoly->mode = texface->mode;
-               texpoly->tile = texface->tile;
-               texpoly->unwrap = texface->unwrap;
-       
-               mloopuv = CustomData_get_n(&me->ldata, CD_MLOOPUV, loopstart, i);
-               mloopuv->uv[0] = texface->uv[0][0]; mloopuv->uv[1] = texface->uv[0][1]; mloopuv++;
-               mloopuv->uv[0] = texface->uv[1][0]; mloopuv->uv[1] = texface->uv[1][1]; mloopuv++;
-               mloopuv->uv[0] = texface->uv[2][0]; mloopuv->uv[1] = texface->uv[2][1]; mloopuv++;
-               if (mf->v4) {
-                       mloopuv->uv[0] = texface->uv[3][0]; mloopuv->uv[1] = texface->uv[3][1]; mloopuv++;
-               }
-       }
-       for(i=0; i < numCol; i++){
-               mf = me->mface + findex;
-               mloopcol = CustomData_get_n(&me->ldata, CD_MLOOPCOL, loopstart, i);
-               mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
-               mloopcol->r = mcol[0].r; mloopcol->g = mcol[0].g; mloopcol->b = mcol[0].b; mloopcol->a = mcol[0].a; mloopcol++;
-               mloopcol->r = mcol[1].r; mloopcol->g = mcol[1].g; mloopcol->b = mcol[1].b; mloopcol->a = mcol[1].a; mloopcol++;
-               mloopcol->r = mcol[2].r; mloopcol->g = mcol[2].g; mloopcol->b = mcol[2].b; mloopcol->a = mcol[2].a; mloopcol++;
-               if (mf->v4) {
-                       mloopcol->r = mcol[3].r; mloopcol->g = mcol[3].g; mloopcol->b = mcol[3].b; mloopcol->a = mcol[3].a; mloopcol++;
-               }
-       }
-       
-       if (CustomData_has_layer(&me->fdata, CD_MDISPS)) {
-               MDisps *ld = CustomData_get(&me->ldata, loopstart, CD_MDISPS);
-               MDisps *fd = CustomData_get(&me->fdata, findex, CD_MDISPS);
-               float (*disps)[3] = fd->disps;
-               int i, tot = mf->v4 ? 4 : 3;
-               int side, corners;
-               
-               corners = multires_mdisp_corners(fd);
-               side = sqrt(fd->totdisp / corners);
-               
-               for (i=0; i<tot; i++, disps += side*side, ld++) {
-                       ld->totdisp = side*side;
-                       
-                       if (ld->disps)
-                               BLI_cellalloc_free(ld->disps);
-                       
-                       ld->disps = BLI_cellalloc_malloc(sizeof(float)*3*side*side, "converted loop mdisps");
-                       memcpy(ld->disps, disps, sizeof(float)*3*side*side);
-               }
-       }
- }
- static void convert_mfaces_to_mpolys(Mesh *mesh)
- {
-       MFace *mf;
-       MLoop *ml;
-       MPoly *mp;
-       MEdge *me;
-       EdgeHash *eh;
-       int numTex, numCol;
-       int i, j, totloop;
-       mesh->totpoly = mesh->totface;
-       mesh->mpoly = MEM_callocN(sizeof(MPoly)*mesh->totpoly, "mpoly converted");
-       CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_ASSIGN, mesh->mpoly, mesh->totpoly);
-       numTex = CustomData_number_of_layers(&mesh->fdata, CD_MTFACE);
-       numCol = CustomData_number_of_layers(&mesh->fdata, CD_MCOL);
-       
-       totloop = 0;
-       mf = mesh->mface;
-       for (i=0; i<mesh->totface; i++, mf++) {
-               totloop += mf->v4 ? 4 : 3;
-       }
-       
-       mesh->totloop = totloop;
-       mesh->mloop = MEM_callocN(sizeof(MLoop)*mesh->totloop, "mloop converted");
-       CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_ASSIGN, mesh->mloop, totloop);
-       CustomData_to_bmeshpoly(&mesh->fdata, &mesh->pdata, &mesh->ldata,
-               mesh->totloop, mesh->totpoly);
-       eh = BLI_edgehash_new();
-       /*build edge hash*/
-       me = mesh->medge;
-       for (i=0; i<mesh->totedge; i++, me++) {
-               BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i));
-       }
-       j = 0; /*current loop index*/
-       ml = mesh->mloop;
-       mf = mesh->mface;
-       mp = mesh->mpoly;
-       for (i=0; i<mesh->totface; i++, mf++, mp++) {
-               mp->loopstart = j;
-               
-               mp->totloop = mf->v4 ? 4 : 3;
-               mp->mat_nr = mf->mat_nr;
-               mp->flag = mf->flag;
-               
-               #define ML(v1, v2) {ml->v = mf->v1; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); ml++; j++;}
-               
-               ML(v1, v2);
-               ML(v2, v3);
-               if (mf->v4) {
-                       ML(v3, v4);
-                       ML(v4, v1);
-               } else {
-                       ML(v3, v1);
-               }
-               
-               #undef ML
-               bmesh_corners_to_loops(mesh, i, mp->loopstart, numTex, numCol);
-       }
-       /*BMESH_TODO now to deal with fgons*/
-       BLI_edgehash_free(eh, NULL);
- }
  static void direct_link_mesh(FileData *fd, Mesh *mesh)
  {
        mesh->mat= newdataadr(fd, mesh->mat);
@@@ -11702,8 -11527,55 +11599,55 @@@ static void do_versions(FileData *fd, L
  
                for (brush= main->brush.first; brush; brush= brush->id.next) {
                        if(brush->height == 0)
-                               brush->height= 0.4;
+                               brush->height= 0.4f;
                }
 -                      mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+               /* replace 'rim material' option for in offset*/
+               for(ob = main->object.first; ob; ob = ob->id.next) {
+                       ModifierData *md;
+                       for(md= ob->modifiers.first; md; md= md->next) {
+                               if (md->type == eModifierType_Solidify) {
+                                       SolidifyModifierData *smd = (SolidifyModifierData *)md;
+                                       if(smd->flag & MOD_SOLIDIFY_RIM_MATERIAL) {
+                                               smd->mat_ofs_rim= 1;
+                                               smd->flag &= ~MOD_SOLIDIFY_RIM_MATERIAL;
+                                       }
+                               }
+                       }
+               }
+               /* particle draw color from material */
+               for(part = main->particle.first; part; part = part->id.next) {
+                       if(part->draw & PART_DRAW_MAT_COL)
+                               part->draw_col = PART_DRAW_COL_MAT;
+               }
+       }
+       if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 6)){
+               Mesh *me;
+               for(me= main->mesh.first; me; me= me->id.next)
++                      mesh_calc_tessface_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+       }
+       if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 2)){
+               /* update blur area sizes from 0..1 range to 0..100 percentage */
+               Scene *scene;
+               bNode *node;
+               for (scene=main->scene.first; scene; scene=scene->id.next)
+                       if (scene->nodetree)
+                               for (node=scene->nodetree->nodes.first; node; node=node->next)
+                                       if (node->type==CMP_NODE_BLUR) {
+                                               NodeBlurData *nbd= node->storage;
+                                               nbd->percentx *= 100.0f;
+                                               nbd->percenty *= 100.0f;
+                                       }
+       }
+       /* put compatibility code here until next subversion bump */
+       {
        }
        
        /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
index a48faa1,0000000..d74ffc7
mode 100644,000000..100644
--- /dev/null
@@@ -1,716 -1,0 +1,681 @@@
- /* "Projects" a vector perpendicular to vec2 against vec1, such that
-  * the projected vec1 + vec2 has a min distance of 1 from the "edge" defined by vec2.
-  * note: the direction, is_forward, is used in conjunction with up_vec to determine
-  * whether this is a convex or concave corner. If it is a concave corner, it will
-  * be projected "backwards." If vec1 is before vec2, is_forward should be 0 (we are projecting backwards).
-  * vec1 is the vector to project onto (expected to be normalized)
-  * vec2 is the direction of projection (pointing away from vec1)
-  * up_vec is used for orientation (expected to be normalized)
-  * returns the length of the projected vector that lies along vec1 */
- static float BM_bevel_project_vec(float *vec1, float *vec2, float *up_vec, int is_forward) {
-       float factor, vec3[3], tmp[3],c1,c2;
-       cross_v3_v3v3(tmp,vec1,vec2);
-       normalize_v3(tmp);
-       factor = dot_v3v3(up_vec,tmp);
-       if ((factor > 0 && is_forward) || (factor < 0 && !is_forward)) {
-               cross_v3_v3v3(vec3,vec2,tmp); /* hmm, maybe up_vec should be used instead of tmp */
-       }
-       else {
-               cross_v3_v3v3(vec3,tmp,vec2); /* hmm, maybe up_vec should be used instead of tmp */
-       }
-       normalize_v3(vec3);
-       c1 = dot_v3v3(vec3,vec1);
-       c2 = dot_v3v3(vec1,vec1);
-       if (fabs(c1) < 0.000001f || fabs(c2) < 0.000001f) {
-               factor = 0.0f;
-       }
-       else {
-               factor = c2/c1;
-       }
-       return factor;
- }
 +#include "MEM_guardedalloc.h"
 +
 +#include "BKE_utildefines.h"
 +
 +#include "BLI_ghash.h"
 +#include "BLI_memarena.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_array.h"
 +#include "BLI_math.h"
 +#include "BLI_array.h"
 +#include "BLI_utildefines.h"
 +#include "BLI_smallhash.h"
 +
 +#include "bmesh.h"
 +#include "bmesh_operators_private.h"
 +
 +#define BEVEL_FLAG    1
 +#define BEVEL_DEL     2
 +#define FACE_NEW      4
 +#define EDGE_OLD      8
 +#define FACE_OLD      16
 +#define FACE_DONE     32
 +#define VERT_OLD      64
 +#define FACE_SPAN     128
 +#define FACE_HOLE     256
 +
 +typedef struct LoopTag {
 +      BMVert *newv;
 +} LoopTag;
 +
 +typedef struct EdgeTag {
 +      BMVert *newv1, *newv2;
 +} EdgeTag;
 +
 +void calc_corner_co(BMesh *UNUSED(bm), BMLoop *l, float *co, float fac)
 +{
 +      float /* no[3], tan[3], */ vec1[3], vec2[3], v1[3], v2[3], v3[3], v4[3];
 +      // float p1[3], p2[3], w[3];
 +      // float l1, l2;
 +      // int ret;
 +
 +      copy_v3_v3(v1, l->prev->v->co);
 +      copy_v3_v3(v2, l->v->co);
 +      copy_v3_v3(v3, l->v->co);
 +      copy_v3_v3(v4, l->next->v->co);
 +      
 +      /*calculate normal*/
 +      sub_v3_v3v3(vec1, v1, v2);
 +      sub_v3_v3v3(vec2, v4, v3);
 +#if 0
 +      cross_v3_v3v3(no, vec2, vec1);
 +      normalize_v3(no);
 +      
 +      if (dot_v3v3(no, no) < DBL_EPSILON*10) {
 +              copy_v3_v3(no, l->f->no);
 +      }
 +      
 +      /*compute offsets*/
 +      l1 = len_v3(vec1)*fac;
 +      l2 = len_v3(vec2)*fac;
 +      if (dot_v3v3(no, l->f->no) < 0.0) {
 +              l1 = -l1;
 +              l2 = -l2;
 +      }       
 +      
 +      /*compute tangent and offset first edge*/
 +      cross_v3_v3v3(tan, vec1, no);
 +      normalize_v3(tan);
 +
 +      mul_v3_fl(tan, l1);
 +      
 +      add_v3_v3(v1, tan);
 +      add_v3_v3(v2, tan);
 +      
 +      /*compute tangent and offset second edge*/
 +      cross_v3_v3v3(tan, no, vec2);
 +      normalize_v3(tan);
 +      
 +      mul_v3_fl(tan, l2);
 +
 +      add_v3_v3(v3, tan);
 +      add_v3_v3(v4, tan);
 +      
 +      /*compute intersection*/
 +      ret = isect_line_line_v3(v1, v2, v3, v4, p1, p2);
 +      if (ret==1) {
 +              copy_v3_v3(co, p1);
 +      } else if (ret==2) {
 +              add_v3_v3v3(co, p1, p2);
 +              mul_v3_fl(co, 0.5);
 +      } else { /*colinear case*/
 +              add_v3_v3v3(co, v2, v3);
 +              mul_v3_fl(co, 0.5);
 +      }
 +#endif
 +      /*oddly, this simplistic method seems to work the best*/
 +      mul_v3_fl(vec1, fac);
 +      mul_v3_fl(vec2, fac);
 +      add_v3_v3(vec1, vec2);
 +      mul_v3_fl(vec1, 0.5);
 +      
 +      add_v3_v3v3(co, vec1, l->v->co);
 +}
 +
 +#define ETAG_SET(e, v, nv) (v) == (e)->v1 ? (etags[BMINDEX_GET((e))].newv1 = (nv)) : (etags[BMINDEX_GET((e))].newv2 = (nv))
 +#define ETAG_GET(e, v) ((v) == (e)->v1 ? (etags[BMINDEX_GET((e))].newv1) : (etags[BMINDEX_GET((e))].newv2))
 +
 +void bmesh_bevel_exec(BMesh *bm, BMOperator *op)
 +{
 +      BMOIter siter;
 +      BMIter iter;
 +      BMEdge *e;
 +      BMVert *v;
 +      BMFace **faces = NULL;
 +      LoopTag *tags=NULL, *tag;
 +      EdgeTag *etags = NULL, *etag;
 +      BMVert **verts = NULL;
 +      BMEdge **edges = NULL;
 +      BLI_array_declare(faces);
 +      BLI_array_declare(tags);
 +      BLI_array_declare(etags);
 +      BLI_array_declare(verts);
 +      BLI_array_declare(edges);
 +      SmallHash hash;
 +      float fac = BMO_Get_Float(op, "percent");
 +      int i, HasMDisps = CustomData_has_layer(&bm->ldata, CD_MDISPS);
 +      
 +      BLI_smallhash_init(&hash);
 +      
 +      BMO_ITER(e, &siter, bm, op, "geom", BM_EDGE) {
 +              BMO_SetFlag(bm, e, BEVEL_FLAG|BEVEL_DEL);
 +              BMO_SetFlag(bm, e->v1, BEVEL_FLAG|BEVEL_DEL);
 +              BMO_SetFlag(bm, e->v2, BEVEL_FLAG|BEVEL_DEL);
 +              
 +              if (BM_Edge_FaceCount(e) < 2) {
 +                      BMO_ClearFlag(bm, e, BEVEL_DEL);
 +                      BMO_ClearFlag(bm, e->v1, BEVEL_DEL);
 +                      BMO_ClearFlag(bm, e->v2, BEVEL_DEL);
 +              }
 +      }
 +      
 +      BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
 +              BMO_SetFlag(bm, v, VERT_OLD);
 +      }
 +
 +#if 0
 +      //a bit of cleaner code that, alas, doens't work.
 +      /*build edge tags*/
 +      BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
 +              if (BMO_TestFlag(bm, e->v1, BEVEL_FLAG) || BMO_TestFlag(bm, e->v2, BEVEL_FLAG)) {
 +                      BMIter liter;
 +                      BMLoop *l;
 +                      
 +                      if (!BMO_TestFlag(bm, e, EDGE_OLD)) {
 +                              BMINDEX_SET(e, BLI_array_count(etags));
 +                              BLI_array_growone(etags);
 +                              
 +                              BMO_SetFlag(bm, e, EDGE_OLD);
 +                      }
 +                      
 +                      BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
 +                              BMLoop *l2;
 +                              BMIter liter2;
 +                              
 +                              if (BMO_TestFlag(bm, l->f, BEVEL_FLAG))
 +                                      continue;
 +                      
 +                              BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_FACE, l->f) {
 +                                      BMINDEX_SET(l2, BLI_array_count(tags));
 +                                      BLI_array_growone(tags);
 +
 +                                      if (!BMO_TestFlag(bm, l2->e, EDGE_OLD)) {
 +                                              BMINDEX_SET(l2->e, BLI_array_count(etags));
 +                                              BLI_array_growone(etags);
 +                                              
 +                                              BMO_SetFlag(bm, l2->e, EDGE_OLD);
 +                                      }
 +                              }
 +
 +                              BMO_SetFlag(bm, l->f, BEVEL_FLAG);
 +                              BLI_array_append(faces, l->f);
 +                      }
 +              } else {
 +                      BMINDEX_SET(e, -1);
 +              }
 +      }
 +#endif
 +      
 +      /*create and assign looptag structures*/
 +      BMO_ITER(e, &siter, bm, op, "geom", BM_EDGE) {
 +              BMLoop *l;
 +              BMIter liter;
 +
 +              BMO_SetFlag(bm, e->v1, BEVEL_FLAG|BEVEL_DEL);
 +              BMO_SetFlag(bm, e->v2, BEVEL_FLAG|BEVEL_DEL);
 +              
 +              if (BM_Edge_FaceCount(e) < 2) {
 +                      BMO_ClearFlag(bm, e, BEVEL_DEL);
 +                      BMO_ClearFlag(bm, e->v1, BEVEL_DEL);
 +                      BMO_ClearFlag(bm, e->v2, BEVEL_DEL);
 +                      //continue;     
 +              }
 +              
 +              if (!BLI_smallhash_haskey(&hash, (intptr_t)e)) {
 +                      BLI_array_growone(etags);
 +                      BMINDEX_SET(e, BLI_array_count(etags)-1);
 +                      BLI_smallhash_insert(&hash, (intptr_t)e, NULL);
 +                      BMO_SetFlag(bm, e, EDGE_OLD);
 +              }
 +              
 +              /*find all faces surrounding e->v1 and, e->v2*/
 +              for (i=0; i<2; i++) {
 +                      BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, i?e->v2:e->v1) {
 +                              BMLoop *l2;
 +                              BMIter liter2;
 +                              
 +                              /*see if we've already processed this loop's face*/
 +                              if (BLI_smallhash_haskey(&hash, (intptr_t)l->f))
 +                                      continue;
 +                              
 +                              /*create tags for all loops in l->f*/
 +                              BM_ITER(l2, &liter2, bm, BM_LOOPS_OF_FACE, l->f) {
 +                                      BLI_array_growone(tags);
 +                                      BMINDEX_SET(l2, BLI_array_count(tags)-1);
 +                                      
 +                                      if (!BLI_smallhash_haskey(&hash, (intptr_t)l2->e)) {
 +                                              BLI_array_growone(etags);
 +                                              BMINDEX_SET(l2->e, BLI_array_count(etags)-1);
 +                                              BLI_smallhash_insert(&hash, (intptr_t)l2->e, NULL);                                             
 +                                              BMO_SetFlag(bm, l2->e, EDGE_OLD);
 +                                      }
 +                              }
 +      
 +                              BLI_smallhash_insert(&hash, (intptr_t)l->f, NULL);
 +                              BMO_SetFlag(bm, l->f, BEVEL_FLAG);
 +                              BLI_array_append(faces, l->f);
 +                      }
 +              }
 +      }
 +
 +      BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
 +              BMIter eiter;
 +              
 +              if (!BMO_TestFlag(bm, v, BEVEL_FLAG))
 +                      continue;
 +              
 +              BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
 +                      if (!BMO_TestFlag(bm, e, BEVEL_FLAG) && !ETAG_GET(e, v)) {
 +                              BMVert *v2;
 +                              float co[3];
 +                              
 +                              v2 = BM_OtherEdgeVert(e, v);
 +                              sub_v3_v3v3(co, v2->co, v->co);
 +                              mul_v3_fl(co, fac);
 +                              add_v3_v3(co, v->co);
 +                              
 +                              v2 = BM_Make_Vert(bm, co, v);
 +                              ETAG_SET(e, v, v2);
 +                      }
 +              }
 +      }
 +      
 +      for (i=0; i<BLI_array_count(faces); i++) {
 +              BMLoop *l;
 +              BMIter liter;
 +              
 +              BMO_SetFlag(bm, faces[i], FACE_OLD);
 +              
 +              BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, faces[i]) {
 +                      float co[3];
 +
 +                      if (BMO_TestFlag(bm, l->e, BEVEL_FLAG)) {
 +                              if (BMO_TestFlag(bm, l->prev->e, BEVEL_FLAG))
 +                              {
 +                                      tag = tags + BMINDEX_GET(l);
 +                                      calc_corner_co(bm, l, co, fac);
 +                                      tag->newv = BM_Make_Vert(bm, co, l->v);
 +                              } else {
 +                                      tag = tags + BMINDEX_GET(l);
 +                                      tag->newv = ETAG_GET(l->prev->e, l->v);
 +                                      
 +                                      if (!tag->newv) {
 +                                              sub_v3_v3v3(co, l->prev->v->co, l->v->co);
 +                                              mul_v3_fl(co, fac);
 +                                              add_v3_v3(co, l->v->co);
 +                                      
 +                                              tag->newv = BM_Make_Vert(bm, co, l->v);
 +                                              
 +                                              ETAG_SET(l->prev->e, l->v, tag->newv);
 +                                      }
 +                              }
 +                      } else if (BMO_TestFlag(bm, l->v, BEVEL_FLAG)) {
 +                              tag = tags + BMINDEX_GET(l);
 +                              tag->newv = ETAG_GET(l->e, l->v);                               
 +              
 +                              if (!tag->newv) {
 +                                      sub_v3_v3v3(co, l->next->v->co, l->v->co);
 +                                      mul_v3_fl(co, fac);
 +                                      add_v3_v3(co, l->v->co);
 +                      
 +                                      tag = tags + BMINDEX_GET(l);
 +                                      tag->newv = BM_Make_Vert(bm, co, l->v);
 +                                      
 +                                      ETAG_SET(l->e, l->v, tag->newv);
 +                              }                                       
 +                      } else {
 +                              tag = tags + BMINDEX_GET(l);
 +                              tag->newv = l->v;
 +                              BMO_ClearFlag(bm, l->v, BEVEL_DEL);
 +                      }
 +              }
 +      }
 +      
 +      /*create new faces*/
 +      for (i=0; i<BLI_array_count(faces); i++) {
 +              BMLoop *l;
 +              BMIter liter;
 +              BMFace *f;
 +              int j;
 +              
 +              BMO_SetFlag(bm, faces[i], BEVEL_DEL);
 +              
 +              BLI_array_empty(verts);
 +              BLI_array_empty(edges);
 +              
 +              BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, faces[i]) {
 +                      BMVert *v2;
 +                      
 +                      tag = tags + BMINDEX_GET(l);
 +                      BLI_array_append(verts, tag->newv);
 +                      
 +                      etag = etags + BMINDEX_GET(l->e);
 +                      v2 = l->next->v == l->e->v1 ? etag->newv1 : etag->newv2;
 +                      
 +                      tag = tags + BMINDEX_GET(l->next);
 +                      if (!BMO_TestFlag(bm, l->e, BEVEL_FLAG) && v2 && v2 != tag->newv) {
 +                              BLI_array_append(verts, v2);
 +                      }
 +              }
 +              
 +              for (j=0; j<BLI_array_count(verts); j++) {
 +                      BMVert *next = verts[(j+1)%BLI_array_count(verts)];
 +
 +                      e = BM_Make_Edge(bm, next, verts[j], NULL, 1);
 +                      BLI_array_append(edges, e);
 +              }
 +              
 +              f = BM_Make_Face(bm, verts, edges, BLI_array_count(verts));
 +              if (!f) {
 +                      printf("eck!!\n");
 +                      continue;
 +              }
 +                      
 +              BMO_SetFlag(bm, f, FACE_NEW);
 +              
 +              /*create quad spans between split edges*/
 +              BMO_SetFlag(bm, f, FACE_NEW);
 +              BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, faces[i]) {
 +                      BMVert *v1=NULL, *v2=NULL, *v3=NULL, *v4=NULL;
 +                      
 +                      if (!BMO_TestFlag(bm, l->e, BEVEL_FLAG))
 +                              continue;
 +                      
 +                      v1 = tags[BMINDEX_GET(l)].newv;
 +                      v2 = tags[BMINDEX_GET(l->next)].newv;
 +                      if (l->radial_next != l) {
 +                              v3 = tags[BMINDEX_GET(l->radial_next)].newv;
 +                              if (l->radial_next->next->v == l->next->v) {
 +                                      v4 = v3;
 +                                      v3 = tags[BMINDEX_GET(l->radial_next->next)].newv;
 +