did math lib conversion, equivilent to merge with trunk/2.5 at r24464
authorJoseph Eagar <joeedh@gmail.com>
Mon, 23 Nov 2009 14:41:22 +0000 (14:41 +0000)
committerJoseph Eagar <joeedh@gmail.com>
Mon, 23 Nov 2009 14:41:22 +0000 (14:41 +0000)
138 files changed:
1  2 
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/booleanops.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/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/lattice.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/modifiers_bmesh.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/shrinkwrap.c
source/blender/blenkernel/intern/smoke.c
source/blender/blenkernel/intern/softbody.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/blenkernel/intern/verse_geometry_node.c
source/blender/blenkernel/intern/verse_method.c
source/blender/blenkernel/intern/verse_object_node.c
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/intern/math_vector_inline.c
source/blender/blenlib/intern/scanfill.c
source/blender/blenloader/intern/readfile.c
source/blender/bmesh/editmesh_tools.c
source/blender/bmesh/intern/bmesh_marking.c
source/blender/bmesh/intern/bmesh_mesh.c
source/blender/bmesh/intern/bmesh_mods.c
source/blender/bmesh/intern/bmesh_operators.c
source/blender/bmesh/intern/bmesh_polygon.c
source/blender/bmesh/intern/bmesh_queries.c
source/blender/bmesh/operators/bmesh_dupeops.c
source/blender/bmesh/operators/connectops.c
source/blender/bmesh/operators/createops.c
source/blender/bmesh/operators/dissolveops.c
source/blender/bmesh/operators/edgesplitop.c
source/blender/bmesh/operators/extrudeops.c
source/blender/bmesh/operators/mirror.c
source/blender/bmesh/operators/removedoubles.c
source/blender/bmesh/operators/subdivideop.c
source/blender/bmesh/operators/triangulateop.c
source/blender/bmesh/operators/utils.c
source/blender/bmesh/tools/BME_bevel.c
source/blender/editors/animation/drivers.c
source/blender/editors/animation/keyframing.c
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/interface/interface_handlers.c
source/blender/editors/mesh/bmesh_select.c
source/blender/editors/mesh/bmesh_selecthistory.c
source/blender/editors/mesh/bmesh_tools.c
source/blender/editors/mesh/bmeshutils.c
source/blender/editors/mesh/editbmesh_bvh.c
source/blender/editors/mesh/editface.c
source/blender/editors/mesh/editmesh.c
source/blender/editors/mesh/editmesh_add.c
source/blender/editors/mesh/editmesh_lib.c
source/blender/editors/mesh/editmesh_loop.c
source/blender/editors/mesh/editmesh_mods.c
source/blender/editors/mesh/editmesh_tools.c
source/blender/editors/mesh/mesh_data.c
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_relations.c
source/blender/editors/object/object_shapekey.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/physics/particle_object.c
source/blender/editors/render/render_shading.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/space_image/space_image.c
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/view3d_buttons.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/space_view3d/view3d_snap.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/transform.c
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_ops.c
source/blender/editors/transform/transform_orientations.c
source/blender/editors/transform/transform_snap.c
source/blender/editors/uvedit/uvedit_draw.c
source/blender/editors/uvedit/uvedit_ops.c
source/blender/editors/uvedit/uvedit_parametrizer.c
source/blender/editors/uvedit/uvedit_unwrap_ops.c
source/blender/gpu/intern/gpu_buffers.c
source/blender/ikplugin/intern/itasc_plugin.cpp
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_object.c
source/blender/python/generic/Geometry.c
source/blender/python/generic/Mathutils.c
source/blender/python/generic/euler.c
source/blender/python/generic/matrix.c
source/blender/python/generic/quat.c
source/blender/python/generic/vector.c
source/blender/render/intern/source/convertblender.c
source/blender/render/intern/source/pointdensity.c
source/blender/render/intern/source/rayobject_blibvh.c
source/blender/render/intern/source/rayobject_instance.c
source/blender/render/intern/source/rayobject_octree.c
source/blender/render/intern/source/shadeoutput.c
source/blender/render/intern/source/strand.c
source/gameengine/Converter/BL_ArmatureActuator.cpp
source/gameengine/Converter/BL_ArmatureChannel.cpp
source/gameengine/Converter/BL_ArmatureConstraint.cpp
source/gameengine/Converter/BL_BlenderDataConversion.cpp

index 15ef809158be30cc4cbea8731a240a6397e6c442,d92e8fe422717c231334df295e502b13feeb1685..fd41624d27c9ad6038ec8d3f545063c654fe4cd4
@@@ -42,9 -42,8 +42,9 @@@
  
  #include "BKE_utildefines.h"
  #include "BKE_bmesh.h"
- #include "BLI_arithb.h"
+ #include "BLI_math.h"
  #include "BLI_blenlib.h"
 +#include "BLI_cellalloc.h"
  
  /*split this all into a seperate bevel.c file in src*/
  
index ec927dd30de2f8aaf6d33d77f51271789b85e9e2,f9abaa9da0244108919d9c4e01e799e8b7b783b1..cf4b9e8e0b7e008c40ebec077cbbed1c08170f86
@@@ -844,14 -630,14 +844,14 @@@ static void emDM__calcFaceCent(EditFac
        }
  
        if (efa->v4) {
-               VecMulf(cent, 0.25f);
+               mul_v3_fl(cent, 0.25f);
        } else {
-               VecMulf(cent, 0.33333333333f);
+               mul_v3_fl(cent, 0.33333333333f);
        }
  }
 -static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
 +static void emDM_foreachMappedFaceCenter(void *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 +      EditMeshDerivedMesh *emdm= dm;
        EditVert *eve;
        EditFace *efa;
        float cent[3];
index e6599c2a5b9f0d26b5473ddab0f3ee1c939abe8c,e0a19da52efac9806fd83ef12edd31ab78646878..a3946946e6c43d9d1c7c3f10eb481be9aded15f4
@@@ -596,16 -596,17 +596,16 @@@ static void face_duplilist(ListBase *lb
        /* simple preventing of too deep nested groups */
        if(level>MAX_DUPLI_RECUR) return;
        
-       Mat4CpyMat4(pmat, par->obmat);
+       copy_m4_m4(pmat, par->obmat);
 -      
 -      em = BKE_mesh_get_editmesh(me);
 +      em = me->edit_btmesh;
 +
        if(em) {
                int totvert;
 +              dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
                
 -              dm= editmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
 -              
 -              totface= dm->getNumFaces(dm);
 +              totface= dm->getNumTessFaces(dm);
                mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp");
 -              dm->copyFaceArray(dm, mface);
 +              dm->copyTessFaceArray(dm, mface);
                totvert= dm->getNumVerts(dm);
                mvert= MEM_mallocN(sizeof(MVert)*totvert, "mvert temp");
                dm->copyVertArray(dm, mvert);
index edf784f2a6eb1ec7da3f11420710ff7bbff75fc0,ab1f60ea6a6f9cf1a435ab59cc020d0b4db324ea..a53ab49317122ff36f56c84a0412deb6c45eeba7
@@@ -34,9 -34,8 +34,9 @@@
  
  #include "MEM_guardedalloc.h"
  
- #include "BLI_arithb.h"
+ #include "BLI_math.h"
  #include "BLI_blenlib.h"
 +#include "BLI_cellalloc.h"
  
  #include "DNA_armature_types.h"
  #include "DNA_action_types.h"
index dbe19847306ba55b02e1dbe7962ce3c22c992a80,30d1b65cc8b00bf3cd95ebe0bc4fd8687e2596b5..c76d40fc0b1a4497a609d9c52e8cfb6c473259ed
  #include "BKE_mesh.h"
  #include "BKE_multires.h"
  #include "BKE_utildefines.h"
 +#include "BKE_tessmesh.h"
  
- #include "BLI_arithb.h"
 +#include "BLI_editVert.h"
 +#include "BLI_scanfill.h"
+ #include "BLI_math.h"
  #include "BLI_blenlib.h"
  #include "BLI_edgehash.h"
  #include "BLI_editVert.h"
@@@ -1269,23 -1254,21 +1269,23 @@@ static void cdDM_foreachMappedFaceCente
                if (index) {
                        orig = *index++;
                        if(orig == ORIGINDEX_NONE) continue;
 -              }
 -              else
 +              } else
                        orig = i;
-                       VecAddf(cent, cent, mv[ml->v].co);
 +              
 +              ml = &cddm->mloop[mf->loopstart];
 +              cent[0] = cent[1] = cent[2] = 0.0f;
 +              for (j=0; j<mf->totloop; j++, ml++) {
-               VecMulf(cent, 1.0f / (float)j);
++                      add_v3_v3v3(cent, cent, mv[ml->v].co);
 +              }
++              mul_v3_fl(cent, 1.0f / (float)j);
  
 -              VECCOPY(cent, mv[mf->v1].co);
 -              add_v3_v3v3(cent, cent, mv[mf->v2].co);
 -              add_v3_v3v3(cent, cent, mv[mf->v3].co);
 -
 -              if (mf->v4) {
 -                      normal_quad_v3( no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
 -                      add_v3_v3v3(cent, cent, mv[mf->v4].co);
 -                      mul_v3_fl(cent, 0.25f);
 +              ml = &cddm->mloop[mf->loopstart];
 +              if (j > 3) {
-                       CalcNormFloat4(mv[ml->v].co, mv[(ml+1)->v].co,
-                                      mv[(ml+2)->v].co, mv[(ml+3)->v].co, no);
++                      normal_quad_v3(no, mv[ml->v].co, mv[(ml+1)->v].co,
++                                     mv[(ml+2)->v].co, mv[(ml+3)->v].co);
                } else {
-                       CalcNormFloat(mv[ml->v].co, mv[(ml+1)->v].co,
-                                      mv[(ml+2)->v].co, no);
 -                      normal_tri_v3( no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
 -                      mul_v3_fl(cent, 0.33333333333f);
++                      normal_tri_v3(no, mv[ml->v].co, mv[(ml+1)->v].co,
++                                     mv[(ml+2)->v].co);
                }
  
                func(userData, orig, cent, no);
@@@ -2006,64 -1597,51 +2006,64 @@@ void CDDM_calc_normals(DerivedMesh *dm
  
        if(numVerts == 0) return;
  
 -      temp_nors = MEM_callocN(numVerts * sizeof(*temp_nors),
 -                              "CDDM_calc_normals temp_nors");
 +      if (CustomData_has_layer(&dm->faceData, CD_NORMAL))
 +              CustomData_free_layer(&dm->faceData, CD_NORMAL, dm->numFaceData, 0);
  
 -      /* we don't want to overwrite any referenced layers */
 -      mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
 -      cddm->mvert = mv;
 +      /*recalc tesselation to ensure we have valid origindex values
 +        for mface->mpoly lookups.*/
 +      cdDM_recalcTesselation2(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);
 +      numFaces = dm->numFaceData;
  
 -      /* calculate face normals and add to vertex normals */
 -      mf = CDDM_get_faces(dm);
 -      for(i = 0; i < numFaces; i++, mf++) {
 -              float *f_no = face_nors[i];
 +      /*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]);
  
 -              if(mf->v4)
 -                      normal_quad_v3( f_no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
 -              else
 -                      normal_tri_v3( f_no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
 -              
 -              add_v3_v3v3(temp_nors[mf->v1], temp_nors[mf->v1], f_no);
 -              add_v3_v3v3(temp_nors[mf->v2], temp_nors[mf->v2], f_no);
 -              add_v3_v3v3(temp_nors[mf->v3], temp_nors[mf->v3], f_no);
 -              if(mf->v4)
 -                      add_v3_v3v3(temp_nors[mf->v4], temp_nors[mf->v4], f_no);
 +              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]);
 +              }
        }
  
 -      /* normalize vertex normals and assign */
 -      for(i = 0; i < numVerts; i++, mv++) {
 -              float *no = 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(no) == 0.0) {
+               if (normalize_v3(no) == 0.0) {
                        VECCOPY(no, mv->co);
-                       if (Normalize(no) == 0.0) {
 -                      normalize_v3(no);
++                      if (normalize_v3(no) == 0.0) {
 +                              no[0] = 0.0f;
 +                              no[1] = 0.0f;
 +                              no[2] = 1.0f;
 +                      }
                }
  
 -              mv->no[0] = (short)(no[0] * 32767.0);
 -              mv->no[1] = (short)(no[1] * 32767.0);
 -              mv->no[2] = (short)(no[2] * 32767.0);
 +              mv->no[0] = (short)(no[0] * 32767.0f);
 +              mv->no[1] = (short)(no[1] * 32767.0f);
 +              mv->no[2] = (short)(no[2] * 32767.0f);
        }
 -      
 +
        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*/
 +      cdDM_recalcTesselation(dm);
 +      CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_ASSIGN, 
 +              face_nors, dm->numFaceData);
  }
  
  void CDDM_calc_edges(DerivedMesh *dm)
@@@ -2460,10 -1844,10 +2460,10 @@@ DerivedMesh *MultiresDM_new(MultiresSub
                mvert = CustomData_get_layer(&orig->vertData, CD_MVERT);
                mrdm->orco = MEM_callocN(sizeof(float) * 3 * orig->getNumVerts(orig), "multires orco");
                for(i = 0; i < orig->getNumVerts(orig); ++i)
-                       VecCopyf(mrdm->orco[i], mvert[i].co);
+                       copy_v3_v3(mrdm->orco[i], mvert[i].co);
        }
        else
 -              DM_init(dm, numVerts, numEdges, numFaces);
 +              DM_init(dm, numVerts, numEdges, numFaces, numLoops, numPolys);
  
        CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
index 771f7d6ecbc9d6d4141c2e2ae00d8eaab1fff5e2,55001f58d2f6c4e5485b954e552d8e42ee2826c5..c15d0dc59c11d856f1400bae683e440fdb387dd5
@@@ -36,9 -36,8 +36,9 @@@
  #include "MEM_guardedalloc.h"
  
  #include "BLI_blenlib.h"
- #include "BLI_arithb.h"
+ #include "BLI_math.h"
  #include "BLI_editVert.h"
 +#include "BLI_cellalloc.h"
  
  #include "DNA_armature_types.h"
  #include "DNA_constraint_types.h"
index 8c3176ee362b559af1ae3329c69f220e3ae677e1,c1e45243bb505961330c58e73999b3050620406a..0d3f8b3491852fbfe5978cdca4332e4f4b610e2b
@@@ -59,8 -59,7 +59,8 @@@
  #include "BKE_mesh.h"
  
  #include "BLI_blenlib.h"
- #include "BLI_arithb.h"
+ #include "BLI_math.h"
 +#include "BLI_cellalloc.h"
  
  #ifdef HAVE_CONFIG_H
  #include <config.h>
index 6e8bfb9040f77b18f8f5c9c9224c16a8b995db5e,0000000000000000000000000000000000000000..6c9957e3ab322092b81ee1457150f03f1c07da0f
mode 100644,000000..100644
--- /dev/null
@@@ -1,1694 -1,0 +1,1694 @@@
- #include "BLI_arithb.h"
 +/**
 + * $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"
 +
-                       CalcNormFloat(v1, v2, v3, no);
-                       VecAddf(bmdm->vertexNos[BMINDEX_GET(l[0]->v)], bmdm->vertexNos[BMINDEX_GET(l[0]->v)], no);
-                       VecAddf(bmdm->vertexNos[BMINDEX_GET(l[1]->v)], bmdm->vertexNos[BMINDEX_GET(l[1]->v)], no);
-                       VecAddf(bmdm->vertexNos[BMINDEX_GET(l[2]->v)], bmdm->vertexNos[BMINDEX_GET(l[2]->v)], no);
++#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 "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, a, b;
 +      
 +      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->head.eflag2 = j;
 +
 +                      v = BLI_addfillvert(l->v->co);
 +                      v->tmp.p = l;
 +                      
 +                      if (lastv) {
 +                              e = BLI_addfilledge(lastv, v);
 +                      }
 +
 +                      lastv = v;
 +                      if (firstv==NULL) firstv = v;
 +              }
 +
 +              /*complete the loop*/
 +              BLI_addfilledge(firstv, v);
 +
 +              BLI_edgefill(0, 0);
 +              
 +              for (efa = fillfacebase.first; efa; efa=efa->next) {
 +                      BMLoop *l1, *l2, *l3;
 +
 +                      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->head.eflag2 > l2->head.eflag2) {
 +                              SWAP(BMLoop*, l1, l2);
 +                      }
 +                      if (l2->head.eflag2 > l3->head.eflag2) {
 +                              SWAP(BMLoop*, l2, l3);
 +                      }
 +                      if (l1->head.eflag2 > l2->head.eflag2) {
 +                              SWAP(BMLoop*, l1, l2);
 +                      }
 +                      
 +                      looptris[i*3] = l1;
 +                      looptris[i*3+1] = l2;
 +                      looptris[i*3+2] = l3;
 +
 +                      i += 1;
 +              }
 +
 +              BLI_end_edgefill();
 +      }
 +
 +      tm->tottri = i;
 +      tm->looptris = looptris;
 +}
 +
 +void BMEdit_RecalcTesselation(BMEditMesh *tm)
 +{
 +      BMEdit_RecalcTesselation_intern(tm);
 +
 +      if (tm->derivedFinal && tm->derivedFinal == tm->derivedCage) {
 +              if (tm->derivedFinal->recalcTesselation) 
 +                      tm->derivedFinal->recalcTesselation(tm->derivedFinal);
 +      } else if (tm->derivedFinal) {
 +              if (tm->derivedCage->recalcTesselation) 
 +                      tm->derivedCage->recalcTesselation(tm->derivedCage);
 +              if (tm->derivedFinal->recalcTesselation) 
 +                      tm->derivedFinal->recalcTesselation(tm->derivedFinal);
 +      }
 +}
 +
 +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_mask_layer(&bm->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_mask(&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);
 +
 +      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);
 +      bmdm->ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
 +      bmdm->fhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
 +      
 +      if (bmdm->vtable) MEM_freeN(bmdm->vtable);
 +      if (bmdm->etable) MEM_freeN(bmdm->etable);
 +      if (bmdm->ftable) MEM_freeN(bmdm->ftable);
 +      
 +      if (bmdm->tc->bm->totvert)
 +              bmdm->vtable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totvert, "bmdm->vtable");
 +      else bmdm->vtable = NULL;
 +
 +      if (bmdm->tc->bm->totedge)
 +              bmdm->etable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totedge, "bmdm->etable");
 +      else bmdm->etable = NULL;
 +      
 +      if (bmdm->tc->bm->totface)
 +              bmdm->ftable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totface, "bmdm->ftable");
 +      else bmdm->ftable = NULL;
 +      
 +      for (a=0; a<3; a++) {
 +              h = BMIter_New(&iter, bmdm->tc->bm, iters[a], NULL);
 +              for (i=0; h; h=BMIter_Step(&iter), i++) {
 +                      switch (a) {
 +                              case 0:
 +                                      bmdm->vtable[i] = (BMVert*) h;
 +                                      BLI_ghash_insert(bmdm->vhash, h, SET_INT_IN_POINTER(i));
 +                                      break;
 +                              case 1:
 +                                      bmdm->etable[i] = (BMEdge*) h;
 +                                      BLI_ghash_insert(bmdm->ehash, h, SET_INT_IN_POINTER(i));
 +                                      break;
 +                              case 2:
 +                                      bmdm->ftable[i] = (BMFace*) h;
 +                                      BLI_ghash_insert(bmdm->fhash, h, SET_INT_IN_POINTER(i));
 +                                      break;
 +
 +                      }
 +              }
 +      }
 +}
 +
 +static void bmDM_recalcTesselation(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +
 +      //bmdm_recalc_lookups(bmdm);
 +}
 +
 +static void bmDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMVert *eve;
 +      BMIter iter;
 +      int i;
 +      
 +      eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; eve; i++, eve=BMIter_Step(&iter)) {
 +              if (bmdm->vertexCos) {
 +                      func(userData, i, bmdm->vertexCos[i], bmdm->vertexNos[i], NULL);
 +              } else {
 +                      func(userData, i, eve->co, eve->no, NULL);
 +              }
 +      }
 +}
 +static void bmDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int i;
 +      
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +              BMIter viter;
 +
 +              eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&viter), i++) {
 +                      BMINDEX_SET(eve, i);
 +              }
 +
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter))
 +                      func(userData, i, 
 +                           bmdm->vertexCos[BMINDEX_GET(eve)], 
 +                           bmdm->vertexCos[BMINDEX_GET(eve)]);
 +      } else {
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter))
 +                      func(userData, i, eed->v1->co, eed->v2->co);
 +      }
 +
 +}
 +
 +static void bmDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) 
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int i;
 +      
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +              BMIter viter;
 +
 +              eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&viter), 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_drawEdges(DerivedMesh *dm, int drawLooseEdges)
 +{
 +      bmDM_drawMappedEdges(dm, NULL, NULL);
 +}
 +
 +static void bmDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) 
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int i;
 +
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++)
 +                      BMINDEX_SET(eve, i);
 +
 +              glBegin(GL_LINES);
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
 +                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 +                              setDrawInterpOptions(userData, i, 0.0);
 +                              glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(eed->v1)]);
 +                              setDrawInterpOptions(userData, i, 1.0);
 +                              glVertex3fv(bmdm->vertexCos[(int) BMINDEX_GET(eed->v2)]);
 +                      }
 +              }
 +              glEnd();
 +      } else {
 +              glBegin(GL_LINES);
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
 +                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 +                              setDrawInterpOptions(userData, i, 0.0);
 +                              glVertex3fv(eed->v1->co);
 +                              setDrawInterpOptions(userData, i, 1.0);
 +                              glVertex3fv(eed->v2->co);
 +                      }
 +              }
 +              glEnd();
 +      }
 +}
 +
 +static void bmDM_drawUVEdges(DerivedMesh *dm)
 +{
 +#if 0
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMFace *efa;
 +      MTFace *tf;
 +
 +      glBegin(GL_LINES);
 +      for(efa= bmdm->tc->bm->faces.first; efa; efa= efa->next) {
 +              tf = CustomData_bm_get(&bmdm->tc->bm->pdata, efa->data, CD_MTFACE);
 +
 +              if(tf && !(efa->h)) {
 +                      glVertex2fv(tf->uv[0]);
 +                      glVertex2fv(tf->uv[1]);
 +
 +                      glVertex2fv(tf->uv[1]);
 +                      glVertex2fv(tf->uv[2]);
 +
 +                      if (!efa->v4) {
 +                              glVertex2fv(tf->uv[2]);
 +                              glVertex2fv(tf->uv[0]);
 +                      } else {
 +                              glVertex2fv(tf->uv[2]);
 +                              glVertex2fv(tf->uv[3]);
 +                              glVertex2fv(tf->uv[3]);
 +                              glVertex2fv(tf->uv[0]);
 +                      }
 +              }
 +      }
 +      glEnd();
 +#endif
 +}
 +
 +static void bmDM__calcFaceCent(BMesh *bm, BMFace *efa, float cent[3],
 +                               float (*vertexCos)[3])
 +{
 +      BMIter iter;
 +      BMLoop *l;
 +      int tot = 0;
 +      
 +      cent[0] = cent[1] = cent[2] = 0.0f;
 +      
 +      /*simple (and stupid) median (average) based method :/ */
 +      
 +      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;
 +      VECMUL(cent, 1.0f/(float)tot);
 +}
 +
 +static void bmDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMVert *eve;
 +      BMFace *efa;
 +      BMIter iter;
 +      float cent[3];
 +      int i;
 +
 +      if (bmdm->vertexCos) {
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), 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 void bmDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMFace *efa;
 +      BMIter iter;
 +      int i, draw;
 +
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +              
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), 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->verts.first) {
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++) {
 +                      if (bmdm->vertexCos) {
 +                              DO_MINMAX(bmdm->vertexCos[i], min_r, max_r);
 +                      } else {
 +                              DO_MINMAX(eve->co, min_r, max_r);
 +                      }
 +              }
 +      } else {
 +              min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
 +      }
 +}
 +static int bmDM_getNumVerts(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +
 +      return bmdm->tc->bm->totvert;
 +}
 +
 +static int bmDM_getNumEdges(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +
 +      return bmdm->tc->bm->totedge;
 +}
 +
 +static int bmDM_getNumTessFaces(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      
 +      return bmdm->tc->tottri;
 +}
 +
 +static int bmDM_getNumFaces(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      
 +      return bmdm->tc->bm->totface;
 +}
 +
 +static int bmvert_to_mvert(BMVert *ev, MVert *vert_r)
 +{
 +      VECCOPY(vert_r->co, ev->co);
 +
 +      vert_r->no[0] = (short)(ev->no[0] * 32767.0f);
 +      vert_r->no[1] = (short)(ev->no[1] * 32767.0f);
 +      vert_r->no[2] = (short)(ev->no[2] * 32767.0f);
 +
 +      /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
 +      vert_r->flag = BMFlags_To_MEFlags(ev);
 +      vert_r->mat_nr = 0;
 +      vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
 +}
 +
 +static void bmDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
 +{
 +      BMVert *ev;
 +      BMIter iter;
 +      int i;
 +
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tv) {
 +              printf("error in bmDM_getVert.\n");
 +              return;
 +      }
 +
 +      ev = ((EditDerivedBMesh *)dm)->vtable[index];
 +      bmvert_to_mvert(ev, vert_r);
 +}
 +
 +static void bmDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMEdge *e;
 +      BMVert *ev, *v1, *v2;
 +      BMIter iter;
 +      int i;
 +
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->te) {
 +              printf("error in bmDM_getEdge.\n");
 +              return;
 +      }
 +
 +      e = bmdm->etable[index];
 +
 +      edge_r->crease = (unsigned char) (e->crease*255.0f);
 +      edge_r->bweight = (unsigned char) (e->bweight*255.0f);
 +      /* TODO what to do with edge_r->flag? */
 +      edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
 +      edge_r->flag |= BMFlags_To_MEFlags(e);
 +#if 0
 +      /* this needs setup of f2 field */
 +      if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
 +#endif
 +      
 +      edge_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v1));
 +      edge_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v2));
 +}
 +
 +static void bmDM_getTessFace(DerivedMesh *dm, int index, MFace *face_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMesh *bm = bmdm->tc->bm;
 +      BMFace *ef;
 +      BMIter iter;
 +      BMLoop **l;
 +      int i;
 +      
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tf) {
 +              printf("error in bmDM_getTessFace.\n");
 +              return;
 +      }
 +
 +      l = ((EditDerivedBMesh *)dm)->tc->looptris[index];
 +
 +      ef = l[0]->f;
 +
 +      face_r->mat_nr = (unsigned char) ef->mat_nr;
 +      face_r->flag = BMFlags_To_MEFlags(ef);
 +
 +      face_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[0]->v));
 +      face_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[1]->v));
 +      face_r->v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[2]->v));
 +      face_r->v4 = 0;
 +
 +      test_index_face(face_r, NULL, 0, 3);
 +}
 +
 +static void bmDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
 +{
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMVert *ev;
 +      BMIter iter;
 +
 +      ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for( ; ev; ev = BMIter_Step(&iter), ++vert_r) {
 +              VECCOPY(vert_r->co, ev->co);
 +
 +              vert_r->no[0] = (short) (ev->no[0] * 32767.0);
 +              vert_r->no[1] = (short) (ev->no[1] * 32767.0);
 +              vert_r->no[2] = (short) (ev->no[2] * 32767.0);
 +
 +              /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
 +              vert_r->mat_nr = 0;
 +              vert_r->flag = BMFlags_To_MEFlags(ev);
 +              vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
 +      }
 +}
 +
 +static void bmDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
 +{
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMEdge *ee;
 +      BMIter iter;
 +      BMVert *ev;
 +      int i;
 +
 +      /* store vertex indices in tmp union */
 +      ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; ev; ev=BMIter_Step(&iter), i++)
 +              BMINDEX_SET(ev, i);
 +
 +      ee = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
 +      for( ; ee; ee=BMIter_Step(&iter)) {
 +              edge_r->crease = (unsigned char) (ee->crease*255.0f);
 +              edge_r->bweight = (unsigned char) (ee->bweight*255.0f);
 +              /* TODO what to do with edge_r->flag? */
 +              edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
 +              if (ee->head.flag & BM_SEAM) edge_r->flag |= ME_SEAM;
 +              if (ee->head.flag & BM_SHARP) edge_r->flag |= ME_SHARP;
 +#if 0
 +              /* this needs setup of f2 field */
 +              if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
 +#endif
 +
 +              edge_r->v1 = (int)BMINDEX_GET(ee->v1);
 +              edge_r->v2 = (int)BMINDEX_GET(ee->v2);
 +      }
 +}
 +
 +static void bmDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMFace *ef;
 +      BMVert *ev;
 +      BMIter iter;
 +      BMLoop **l;
 +      int i;
 +
 +      /* store vertexes indices in tmp union */
 +      ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; ev; ev=BMIter_Step(&iter), i++)
 +              BMINDEX_SET(ev, i);
 +
 +      for (i=0; i<bmdm->tc->tottri; i++) {
 +              l = bmdm->tc->looptris[i];
 +              ef = l[0]->f;
 +
 +              face_r->mat_nr = (unsigned char) ef->mat_nr;
 +
 +              /*HACK/TODO: need to convert this*/
 +              face_r->flag = ef->head.flag;
 +
 +              face_r->v1 = BMINDEX_GET(l[0]->v);
 +              face_r->v2 = BMINDEX_GET(l[1]->v);
 +              face_r->v3 = BMINDEX_GET(l[2]->v);
 +              face_r->v4 = 0;
 +
 +              test_index_face(face_r, NULL, 0, 3);
 +      }
 +}
 +
 +static void *bmDM_getFaceDataArray(DerivedMesh *dm, int type)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMesh *bm= bmdm->tc->bm;
 +      BMFace *efa;
 +      char *data, *bmdata;
 +      void *datalayer;
 +      int index, offset, size, i;
 +
 +      datalayer = DM_get_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;
 +      
 +      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->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->l->v, &iter->head.v);
 +      iter->head.vindex = BMINDEX_GET(iter->l->v);
 +      iter->head.eindex = BMINDEX_GET(iter->l->e);
 +
 +      return (DMLoopIter*) iter;
 +}
 +
 +static DMFaceIter *bmDM_getFaceIter(void *dm)
 +{
 +      EditDerivedBMesh *bmdm= dm;
 +      bmDM_faceIter *iter = MEM_callocN(sizeof(bmDM_faceIter), "bmDM_faceIter");
 +      BMIter biter;
 +      BMVert *v;
 +      BMEdge *e;
 +      int i;
 +
 +      iter->bm = bmdm->tc->bm;
 +      iter->f = iter->nextf = BMIter_New(&iter->iter, iter->bm, BM_FACES_OF_MESH, NULL);
 +      
 +      iter->head.step = bmDM_faceIterStep;
 +      iter->head.free = bmDM_iterFree;
 +      iter->head.getCDData = bmDM_getFaceCDData;
 +      iter->head.getLoopsIter = bmDM_newLoopsIter;
 +      
 +      iter->head.mat_nr = iter->f->mat_nr;
 +      iter->head.flags = BMFlags_To_MEFlags(iter->f);
 +
 +      /*set up vert/edge indices*/
 +      i = 0;
 +      BM_ITER(v, &biter, iter->bm, BM_VERTS_OF_MESH, NULL) {
 +              BMINDEX_SET(v, i);
 +              i++;
 +      }
 +
 +      i = 0;
 +      BM_ITER(e, &biter, iter->bm, BM_EDGES_OF_MESH, NULL) {
 +              BMINDEX_SET(e, i);
 +              i++;
 +      }
 +
 +      return (DMFaceIter*) iter;
 +}
 +
 +static void bmDM_release(void *dm)
 +{
 +      EditDerivedBMesh *bmdm= dm;
 +
 +      if (DM_release(dm)) {
 +              if (bmdm->vertexCos) {
 +                      MEM_freeN(bmdm->vertexCos);
 +                      MEM_freeN(bmdm->vertexNos);
 +                      MEM_freeN(bmdm->faceNos);
 +              }
 +              
 +              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, 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];
 +                      
-                       if (Normalize(no)==0.0) {
++                      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 */
-                               Normalize(no);
++                      if (normalize_v3(no)==0.0) {
 +                              VECCOPY(no, vertexCos[i]);
++                              normalize_v3(no);
 +                      }
 +              }
 +      }
 +
 +      //bmdm_recalc_lookups(bmdm);
 +
 +      return (DerivedMesh*) bmdm;
 +}
index a6a99de462de33f5350be061bb45e240552d5ef3,6d63553396d90b91a920c0b25d9cc96fc8b24d79..d8d0e49dcb4bf8e5862a1f0804aa2e8736df1001
@@@ -571,15 -571,15 +571,15 @@@ int closest_point_on_surface(SurfaceMod
                }
  
                if(surface_vel) {
 -                      MFace *mface = CDDM_get_face(surmd->dm, nearest.index);
 +                      MFace *mface = CDDM_get_tessface(surmd->dm, nearest.index);
                        
                        VECCOPY(surface_vel, surmd->v[mface->v1].co);
-                       VecAddf(surface_vel, surface_vel, surmd->v[mface->v2].co);
-                       VecAddf(surface_vel, surface_vel, surmd->v[mface->v3].co);
+                       add_v3_v3v3(surface_vel, surface_vel, surmd->v[mface->v2].co);
+                       add_v3_v3v3(surface_vel, surface_vel, surmd->v[mface->v3].co);
                        if(mface->v4)
-                               VecAddf(surface_vel, surface_vel, surmd->v[mface->v4].co);
+                               add_v3_v3v3(surface_vel, surface_vel, surmd->v[mface->v4].co);
  
-                       VecMulf(surface_vel, mface->v4 ? 0.25f : 0.333f);
+                       mul_v3_fl(surface_vel, mface->v4 ? 0.25f : 0.333f);
                }
                return 1;
        }
index 4ebd36f36c727bae2b167fe42da77afff98d0a97,dc548edbb2594ce11814579afb54ee4eccac6eff..af3642f1b0646ae96bfa63025c62df96dfa4c765
@@@ -39,8 -39,7 +39,8 @@@
  #include "MEM_guardedalloc.h"
  
  #include "BLI_blenlib.h"
- #include "BLI_arithb.h"
+ #include "BLI_math.h"
 +#include "BLI_cellalloc.h"
  
  #include "DNA_armature_types.h"
  #include "DNA_mesh_types.h"
index 8a74f560f02505eb629ecde4dbab1d080f2cf138,d5c597b802c9085a5ba4880c636adde4340ba048..0867afc0fb28cb6ca4e976ca87a5d1fd570d1167
  
  #include "BLI_blenlib.h"
  #include "BLI_editVert.h"
- #include "BLI_arithb.h"
+ #include "BLI_math.h"
 +#include "BLI_cellalloc.h"
 +#include "BLI_array.h"
  #include "BLI_edgehash.h"
  
 +#include "bmesh.h"
  
  EditMesh *BKE_mesh_get_editmesh(Mesh *me)
  {
@@@ -1543,264 -1409,3 +1543,264 @@@ void mesh_pmv_off(Object *ob, Mesh *me
                me->pv= NULL;
        }
  }
-               CalcNormFloat(v1->co, v2->co, v3->co, no);
 +
 +static void mesh_loops_to_corners(CustomData *fdata, CustomData *ldata, 
 +                         CustomData *pdata, int lindex[3], int findex, 
 +                         int polyindex, int numTex, int numCol) 
 +{
 +      MTFace *texface;
 +      MTexPoly *texpoly;
 +      MCol *mcol;
 +      MLoopCol *mloopcol;
 +      MLoopUV *mloopuv;
 +      int i, j, hasWCol = CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL);
 +
 +      for(i=0; i < numTex; i++){
 +              texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
 +              texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, i);
 +              
 +              texface->tpage = texpoly->tpage;
 +              texface->flag = texpoly->flag;
 +              texface->transp = texpoly->transp;
 +              texface->mode = texpoly->mode;
 +              texface->tile = texpoly->tile;
 +              texface->unwrap = texpoly->unwrap;
 +
 +              for (j=0; j<3; j++) {
 +                      mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, lindex[j], i);
 +                      texface->uv[j][0] = mloopuv->uv[0];
 +                      texface->uv[j][1] = mloopuv->uv[1];
 +              }
 +      }
 +
 +      for(i=0; i < numCol; i++){
 +              mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
 +
 +              for (j=0; j<3; j++) {
 +                      mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, lindex[j], i);
 +                      mcol[j].r = mloopcol->r;
 +                      mcol[j].g = mloopcol->g;
 +                      mcol[j].b = mloopcol->b;
 +                      mcol[j].a = mloopcol->a;
 +              }
 +      }
 +
 +      if (hasWCol) {
 +              mcol = CustomData_get(fdata,  findex, CD_WEIGHT_MCOL);
 +
 +              for (j=0; j<3; j++) {
 +                      mloopcol = CustomData_get(ldata, lindex[j], CD_WEIGHT_MLOOPCOL);
 +                      mcol[j].r = mloopcol->r;
 +                      mcol[j].g = mloopcol->g;
 +                      mcol[j].b = mloopcol->b;
 +                      mcol[j].a = mloopcol->a;
 +              }
 +      }
 +}
 +
 +/*this function recreates a tesselation.
 +
 +  returns number of tesselation faces.*/
 +int mesh_recalcTesselation(CustomData *fdata, 
 +                           CustomData *ldata, CustomData *pdata,
 +                           MVert *mvert, int totface, int totloop, 
 +                           int totpoly, int use_poly_origindex)
 +{
 +      MPoly *mp, *mpoly;
 +      MLoop *ml, *mloop;
 +      MFace *mf = NULL, *mface;
 +      BLI_array_declare(mf);
 +      EditVert *v, *lastv, *firstv;
 +      EditFace *f;
 +      BLI_array_declare(origIndex);
 +      int i, j, k, lindex[3], *origIndex = NULL, *polyorigIndex;
 +      int numTex, numCol;
 +
 +      mpoly = CustomData_get_layer(pdata, CD_MPOLY);
 +      mloop = CustomData_get_layer(ldata, CD_MLOOP);
 +
 +      numTex = CustomData_number_of_layers(ldata, CD_MLOOPUV);
 +      numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
 +      
 +      k = 0;
 +      mp = mpoly;
 +      polyorigIndex = use_poly_origindex? CustomData_get_layer(pdata, CD_ORIGINDEX) : NULL;
 +      for (i=0; i<totpoly; i++, mp++) {
 +              ml = mloop + mp->loopstart;
 +              firstv = NULL;
 +              lastv = NULL;
 +              for (j=0; j<mp->totloop; j++, ml++) {
 +                      v = BLI_addfillvert(mvert[ml->v].co);
 +                      if (polyorigIndex)
 +                              v->tmp.l = polyorigIndex[i];
 +                      else
 +                              v->tmp.l = i;
 +
 +                      v->keyindex = mp->loopstart + j;
 +
 +                      if (lastv)
 +                              BLI_addfilledge(lastv, v);
 +
 +                      if (!firstv)
 +                              firstv = v;
 +                      lastv = v;
 +              }
 +              BLI_addfilledge(lastv, firstv);
 +              
 +              BLI_edgefill(0, 0);
 +              for (f=fillfacebase.first; f; f=f->next) {
 +                      BLI_array_growone(mf);
 +                      BLI_array_growone(origIndex);
 +
 +                      /*these are loop indices, they'll be transformed
 +                        into vert indices later.*/
 +                      mf[k].v1 = f->v1->keyindex;
 +                      mf[k].v2 = f->v2->keyindex;
 +                      mf[k].v3 = f->v3->keyindex;
 +                      mf[k].mat_nr = mp->mat_nr;
 +                      mf[k].flag = mp->flag;
 +                      origIndex[k] = f->v1->tmp.l;
 +
 +                      k++;
 +              }
 +
 +              BLI_end_edgefill();
 +      }
 +
 +      CustomData_free(fdata, totface);
 +      memset(fdata, 0, sizeof(CustomData));
 +      totface = k;
 +      
 +      CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mf, totface);
 +      CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, origIndex, totface);
 +      CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
 +
 +      mface = mf;
 +      for (i=0; i<totface; i++, mf++) {
 +              /*ensure winding is correct*/
 +              if (mf->v1 > mf->v2) {
 +                      SWAP(int, mf->v1, mf->v2);
 +              }
 +              if (mf->v2 > mf->v3) {
 +                      SWAP(int, mf->v2, mf->v3);
 +              }
 +              if (mf->v1 > mf->v2) {
 +                      SWAP(int, mf->v1, mf->v2);
 +              }
 +
 +              lindex[0] = mf->v1;
 +              lindex[1] = mf->v2;
 +              lindex[2] = mf->v3;
 +
 +              /*transform loop indices to vert indices*/
 +              mf->v1 = mloop[mf->v1].v;
 +              mf->v2 = mloop[mf->v2].v;
 +              mf->v3 = mloop[mf->v3].v;
 +
 +              mesh_loops_to_corners(fdata, ldata, pdata,
 +                      lindex, i, origIndex[i], numTex, numCol);
 +      }
 +
 +      return totface;
 +}
 +
 +/*
 + * COMPUTE POLY NORMAL
 + *
 + * Computes the normal of a planar 
 + * polygon See Graphics Gems for 
 + * computing newell normal.
 + *
 +*/
 +static void mesh_calc_ngon_normal(MPoly *mpoly, MLoop *loopstart, 
 +                                MVert *mvert, float *normal)
 +{
 +
 +      MVert *v1, *v2, *v3;
 +      double u[3],  v[3], w[3];
 +      double n[3] = {0.0, 0.0, 0.0}, l;
 +      int i, s=0;
 +
 +      for(i = 0; i < mpoly->totloop; i++){
 +              v1 = mvert + loopstart[i].v;
 +              v2 = mvert + loopstart[(i+1)%mpoly->totloop].v;
 +              v3 = mvert + loopstart[(i+2)%mpoly->totloop].v;
 +              
 +              VECCOPY(u, v1->co);
 +              VECCOPY(v, v2->co);
 +              VECCOPY(w, v3->co);
 +
 +              /*this fixes some weird numerical error*/
 +              if (i==0) {
 +                      u[0] += 0.0001f;
 +                      u[1] += 0.0001f;
 +                      u[2] += 0.0001f;
 +              }
 +              
 +              /* newell's method
 +              
 +              so thats?:
 +              (a[1] - b[1]) * (a[2] + b[2]);
 +              a[1]*b[2] - b[1]*a[2] - b[1]*b[2] + a[1]*a[2]
 +
 +              odd.  half of that is the cross product. . .what's the
 +              other half?
 +
 +              also could be like a[1]*(b[2] + a[2]) - b[1]*(a[2] - b[2])
 +              */
 +
 +              n[0] += (u[1] - v[1]) * (u[2] + v[2]);
 +              n[1] += (u[2] - v[2]) * (u[0] + v[0]);
 +              n[2] += (u[0] - v[0]) * (u[1] + v[1]);
 +      }
 +      
 +      l = n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
 +      l = sqrt(l);
 +
 +      if (l == 0.0) {
 +              normal[0] = 0.0f;
 +              normal[1] = 0.0f;
 +              normal[2] = 1.0f;
 +
 +              return;
 +      } else l = 1.0f / l;
 +
 +      n[0] *= l;
 +      n[1] *= l;
 +      n[2] *= l;
 +      
 +      normal[0] = (float) n[0];
 +      normal[1] = (float) n[1];
 +      normal[2] = (float) n[2];
 +
 +}
 +
 +void mesh_calc_poly_normal(MPoly *mpoly, MLoop *loopstart, 
 +                           MVert *mvarray, float *no)
 +{
 +      if(mpoly->totloop > 4) {
 +              mesh_calc_ngon_normal(mpoly, loopstart, mvarray, no);
 +      }
 +      else if(mpoly->totloop == 3){
 +              MVert *v1, *v2, *v3;
 +
 +              v1 = mvarray + (loopstart++)->v;
 +              v2 = mvarray + (loopstart++)->v;
 +              v3 = mvarray + loopstart->v;
-               CalcNormFloat4(v1->co, v2->co, v3->co, v4->co, no);
++              normal_tri_v3( no,v1->co, v2->co, v3->co);
 +      }
 +      else if(mpoly->totloop == 4){
 +              MVert *v1, *v2, *v3, *v4;
 +
 +              v1 = mvarray + (loopstart++)->v;
 +              v2 = mvarray + (loopstart++)->v;
 +              v3 = mvarray + (loopstart++)->v;
 +              v4 = mvarray + loopstart->v;
++              normal_quad_v3( no,v1->co, v2->co, v3->co, v4->co);
 +      }
 +      else{ /*horrible, two sided face!*/
 +              no[0] = 0.0;
 +              no[1] = 0.0;
 +              no[2] = 1.0;
 +      }
 +}
index 3730ebb89b3afb454142d1777b4a319d49efb637,744c9712248ee7ce35d537ddbb707a4089caa640..c34abd3ef8ba3507c1a58820d43204d108be3f03
@@@ -1278,16 -1269,16 +1278,16 @@@ static DerivedMesh *arrayModifier_doArr
                  if(end_cap) {
                          finalVerts += end_cap->getNumVerts(end_cap);
                          finalEdges += end_cap->getNumEdges(end_cap);
 -                        finalFaces += end_cap->getNumFaces(end_cap);
 +                        finalFaces += end_cap->getNumTessFaces(end_cap);
                  }
 -                result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces);
 +                result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces, 0, 0);
  
                  /* calculate the offset matrix of the final copy (for merging) */ 
-                 Mat4One(final_offset);
+                 unit_m4(final_offset);
  
                  for(j=0; j < count - 1; j++) {
-                         Mat4MulMat4(tmp_mat, final_offset, offset);
-                         Mat4CpyMat4(final_offset, tmp_mat);
+                         mul_m4_m4m4(tmp_mat, final_offset, offset);
+                         copy_m4_m4(final_offset, tmp_mat);
                  }
  
                  numVerts = numEdges = numFaces = 0;
  
                          capVerts = start_cap->getNumVerts(start_cap);
                          capEdges = start_cap->getNumEdges(start_cap);
 -                        capFaces = start_cap->getNumFaces(start_cap);
 +                        capFaces = start_cap->getNumTessFaces(start_cap);
                          cap_mvert = start_cap->getVertArray(start_cap);
                          cap_medge = start_cap->getEdgeArray(start_cap);
 -                        cap_mface = start_cap->getFaceArray(start_cap);
 +                        cap_mface = start_cap->getTessFaceArray(start_cap);
  
-                         Mat4Invert(startoffset, offset);
+                         invert_m4_m4(startoffset, offset);
  
                          vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
                                          "arrayModifier_doArray vert_map");
  
                          capVerts = end_cap->getNumVerts(end_cap);
                          capEdges = end_cap->getNumEdges(end_cap);
 -                        capFaces = end_cap->getNumFaces(end_cap);
 +                        capFaces = end_cap->getNumTessFaces(end_cap);
                          cap_mvert = end_cap->getVertArray(end_cap);
                          cap_medge = end_cap->getEdgeArray(end_cap);
 -                        cap_mface = end_cap->getFaceArray(end_cap);
 +                        cap_mface = end_cap->getTessFaceArray(end_cap);
  
-                         Mat4MulMat4(endoffset, final_offset, offset);
+                         mul_m4_m4m4(endoffset, final_offset, offset);
  
                          vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
                                          "arrayModifier_doArray vert_map");
@@@ -3195,10 -4002,10 +3195,10 @@@ static DerivedMesh *uvprojectModifier_d
        /* if only one projector, project coords to UVs */
        if(num_projectors == 1)
                for(i = 0, co = coords; i < numVerts; ++i, ++co)
-                       Mat4MulVec3Project(projectors[0].projmat, *co);
+                       mul_project_m4_v4(projectors[0].projmat, *co);
  
 -      mface = dm->getFaceArray(dm);
 -      numFaces = dm->getNumFaces(dm);
 +      mface = dm->getTessFaceArray(dm);
 +      numFaces = dm->getNumTessFaces(dm);
  
        /* apply coords as UVs, and apply image if tfaces are new */
        for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {
@@@ -6491,11 -7296,11 +6491,11 @@@ static DerivedMesh * explodeModifier_sp
                                        VECADD(dupve->co,dupve->co,mv->co);
                                        mv=CDDM_get_vert(splitdm,mf->v4);
                                        VECADD(dupve->co,dupve->co,mv->co);
-                                       VecMulf(dupve->co,0.25);
+                                       mul_v3_fl(dupve->co,0.25);
  
  
 -                                      df1=CDDM_get_face(splitdm,curdupface);
 -                                      DM_copy_face_data(splitdm,splitdm,i,curdupface,1);
 +                                      df1=CDDM_get_tessface(splitdm,curdupface);
 +                                      DM_copy_tessface_data(splitdm,splitdm,i,curdupface,1);
                                        *df1=*mf;
                                        curdupface++;
  
index 84bbb1fb5d7987a91604f65a8e86686d91a748f0,0000000000000000000000000000000000000000..4fde1d45dcbcb3fdefb71a6c4e8b29f0818e64e5
mode 100644,000000..100644
--- /dev/null
@@@ -1,728 -1,0 +1,728 @@@
- #include "BLI_arithb.h"
 +/*
 +* $Id: modifier_bmesh.c 20831 2009-06-12 14:02:37Z 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 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 +*
 +* The Original Code is Copyright (C) 2005 by the Blender Foundation.
 +* All rights reserved.
 +*
 +* Contributor(s): Joseph Eagar
 +*
 +* ***** END GPL LICENSE BLOCK *****
 +*
 +* Modifier stack implementation.
 +*
 +* BKE_modifier.h contains the function prototypes for this file.
 +*
 +*/
 +
 +#include "string.h"
 +#include "stdarg.h"
 +#include "math.h"
 +#include "float.h"
 +#include "ctype.h"
 +
-       Mat4One(offset);
++#include "BLI_math.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_kdopbvh.h"
 +#include "BLI_kdtree.h"
 +#include "BLI_linklist.h"
 +#include "BLI_rand.h"
 +#include "BLI_edgehash.h"
 +#include "BLI_ghash.h"
 +#include "BLI_memarena.h"
 +#include "BLI_cellalloc.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "DNA_action_types.h"
 +#include "DNA_armature_types.h"
 +#include "DNA_camera_types.h"
 +#include "DNA_cloth_types.h"
 +#include "DNA_curve_types.h"
 +#include "DNA_effect_types.h"
 +#include "DNA_material_types.h"
 +#include "DNA_mesh_types.h"
 +#include "DNA_meshdata_types.h"
 +#include "DNA_modifier_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_object_force.h"
 +#include "DNA_particle_types.h"
 +#include "DNA_scene_types.h"
 +#include "DNA_texture_types.h"
 +
 +#include "BLI_editVert.h"
 +#include "BLI_array.h"
 +
 +#include "BKE_main.h"
 +#include "BKE_anim.h"
 +#include "BKE_bmesh.h"
 +// XXX #include "BKE_booleanops.h"
 +#include "BKE_cloth.h"
 +#include "BKE_collision.h"
 +#include "BKE_cdderivedmesh.h"
 +#include "BKE_curve.h"
 +#include "BKE_customdata.h"
 +#include "BKE_DerivedMesh.h"
 +#include "BKE_displist.h"
 +#include "BKE_fluidsim.h"
 +#include "BKE_global.h"
 +#include "BKE_multires.h"
 +#include "BKE_lattice.h"
 +#include "BKE_library.h"
 +#include "BKE_material.h"
 +#include "BKE_mesh.h"
 +#include "BKE_modifier.h"
 +#include "BKE_object.h"
 +#include "BKE_particle.h"
 +#include "BKE_pointcache.h"
 +#include "BKE_softbody.h"
 +#include "BKE_subsurf.h"
 +#include "BKE_texture.h"
 +#include "BKE_utildefines.h"
 +#include "BKE_tessmesh.h"
 +
 +#include "depsgraph_private.h"
 +#include "BKE_deform.h"
 +#include "BKE_shrinkwrap.h"
 +#include "BKE_simple_deform.h"
 +
 +#include "CCGSubSurf.h"
 +#include "RE_shader_ext.h"
 +#include "LOD_decimation.h"
 +
 +/*converts a cddm to a BMEditMesh.  if existing is non-NULL, the
 +  new geometry will be put in there.*/
 +BMEditMesh *CDDM_To_BMesh(DerivedMesh *dm, BMEditMesh *existing)
 +{
 +      int allocsize[4] = {512, 512, 2048, 512};
 +      BMesh *bm, bmold; /*bmold is for storing old customdata layout*/
 +      BMEditMesh *em = existing;
 +      MVert *mv, *mvert;
 +      MEdge *me, *medge;
 +      DMFaceIter *dfiter;
 +      DMLoopIter *dliter;
 +      BMVert *v, **vtable, **verts=NULL;
 +      BMEdge *e, **etable, **edges=NULL;
 +      BMFace *f;
 +      BMIter liter;
 +      BLI_array_declare(verts);
 +      BLI_array_declare(edges);
 +      int numTex, numCol;
 +      int i, j, k, totvert, totedge, totface;
 +      
 +      if (em) bm = em->bm;
 +      else bm = BM_Make_Mesh(allocsize);
 +
 +      bmold = *bm;
 +
 +      /*merge custom data layout*/
 +      CustomData_bmesh_merge(&dm->vertData, &bm->vdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_VERT);
 +      CustomData_bmesh_merge(&dm->edgeData, &bm->edata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_EDGE);
 +      CustomData_bmesh_merge(&dm->loopData, &bm->ldata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_LOOP);
 +      CustomData_bmesh_merge(&dm->polyData, &bm->pdata, CD_MASK_DERIVEDMESH, CD_CALLOC, bm, BM_FACE);
 +
 +      /*needed later*/
 +      numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
 +      numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);
 +
 +      totvert = dm->getNumVerts(dm);
 +      totedge = dm->getNumEdges(dm);
 +      totface = dm->getNumFaces(dm);
 +
 +      vtable = MEM_callocN(sizeof(void**)*totvert, "vert table in BMDM_Copy");
 +      etable = MEM_callocN(sizeof(void**)*totedge, "edge table in BMDM_Copy");
 +
 +      /*do verts*/
 +      mv = mvert = dm->dupVertArray(dm);
 +      for (i=0; i<totvert; i++, mv++) {
 +              v = BM_Make_Vert(bm, mv->co, NULL);
 +              
 +              v->bweight = mv->bweight;
 +              VECCOPY(v->no, mv->no);
 +              v->head.flag = MEFlags_To_BMFlags(mv->flag, BM_VERT);
 +
 +              CustomData_to_bmesh_block(&dm->vertData, &bm->vdata, i, &v->head.data);
 +              vtable[i] = v;
 +      }
 +      MEM_freeN(mvert);
 +
 +      /*do edges*/
 +      me = medge = dm->dupEdgeArray(dm);
 +      for (i=0; i<totedge; i++, me++) {
 +              e = BM_Make_Edge(bm, vtable[me->v1], vtable[me->v2], NULL, 0);
 +
 +              e->bweight = me->bweight;
 +              e->crease = me->crease;
 +              e->head.flag = MEFlags_To_BMFlags(me->flag, BM_EDGE);
 +
 +              CustomData_to_bmesh_block(&dm->edgeData, &bm->edata, i, &e->head.data);
 +              etable[i] = e;
 +      }
 +      MEM_freeN(medge);
 +      
 +      /*do faces*/
 +      k = 0;
 +      dfiter = dm->newFaceIter(dm);
 +      for (; !dfiter->done; dfiter->step(dfiter)) {
 +              BMLoop *l;
 +
 +              BLI_array_empty(verts);
 +              BLI_array_empty(edges);
 +
 +              dliter = dfiter->getLoopsIter(dfiter);
 +              for (j=0; !dliter->done; dliter->step(dliter), j++) {
 +                      BLI_array_growone(verts);
 +                      BLI_array_growone(edges);
 +
 +                      verts[j] = vtable[dliter->vindex];
 +                      edges[j] = etable[dliter->eindex];
 +              }
 +
 +              if (j < 2)
 +                      break;
 +              
 +              f = BM_Make_Ngon(bm, verts[0], verts[1], edges, dfiter->len, 0);
 +
 +              if (!f) 
 +                      continue;
 +
 +              f->head.flag = MEFlags_To_BMFlags(dfiter->flags, BM_FACE);
 +              f->mat_nr = dfiter->mat_nr;
 +
 +              dliter = dfiter->getLoopsIter(dfiter);
 +              l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
 +              for (j=0; l; l=BMIter_Step(&liter)) {
 +                      CustomData_to_bmesh_block(&dm->loopData, &bm->ldata, k, &l->head.data);
 +                      k += 1;
 +              }
 +
 +              CustomData_to_bmesh_block(&dm->polyData, &bm->pdata, 
 +                      dfiter->index, &f->head.data);
 +      }
 +      dfiter->free(dfiter);
 +
 +      MEM_freeN(vtable);
 +      MEM_freeN(etable);
 +      
 +      BLI_array_free(verts);
 +      BLI_array_free(edges);
 +
 +      if (!em) em = BMEdit_Create(bm);
 +      else BMEdit_RecalcTesselation(em);
 +
 +      return em;
 +}
 +
 +static float vertarray_size(MVert *mvert, int numVerts, int axis)
 +{
 +      int i;
 +      float min_co, max_co;
 +
 +      /* if there are no vertices, width is 0 */
 +      if(numVerts == 0) return 0;
 +
 +      /* find the minimum and maximum coordinates on the desired axis */
 +      min_co = max_co = mvert->co[axis];
 +      ++mvert;
 +      for(i = 1; i < numVerts; ++i, ++mvert) {
 +              if(mvert->co[axis] < min_co) min_co = mvert->co[axis];
 +              if(mvert->co[axis] > max_co) max_co = mvert->co[axis];
 +      }
 +
 +      return max_co - min_co;
 +}
 +
 +/* finds the best possible flipped name. For renaming; check for unique names afterwards */
 +/* if strip_number: removes number extensions */
 +static void vertgroup_flip_name (char *name, int strip_number)
 +{
 +      int     len;
 +      char    prefix[128]={""};   /* The part before the facing */
 +      char    suffix[128]={""};   /* The part after the facing */
 +      char    replace[128]={""};  /* The replacement string */
 +      char    number[128]={""};   /* The number extension string */
 +      char    *index=NULL;
 +
 +      len= strlen(name);
 +      if(len<3) return; // we don't do names like .R or .L
 +
 +      /* We first check the case with a .### extension, let's find the last period */
 +      if(isdigit(name[len-1])) {
 +              index= strrchr(name, '.'); // last occurrance
 +              if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever!
 +                      if(strip_number==0) 
 +                              strcpy(number, index);
 +                      *index= 0;
 +                      len= strlen(name);
 +              }
 +      }
 +
 +      strcpy (prefix, name);
 +
 +#define IS_SEPARATOR(a) ((a)=='.' || (a)==' ' || (a)=='-' || (a)=='_')
 +
 +      /* first case; separator . - _ with extensions r R l L  */
 +      if( IS_SEPARATOR(name[len-2]) ) {
 +              switch(name[len-1]) {
 +                      case 'l':
 +                              prefix[len-1]= 0;
 +                              strcpy(replace, "r");
 +                              break;
 +                      case 'r':
 +                              prefix[len-1]= 0;
 +                              strcpy(replace, "l");
 +                              break;
 +                      case 'L':
 +                              prefix[len-1]= 0;
 +                              strcpy(replace, "R");
 +                              break;
 +                      case 'R':
 +                              prefix[len-1]= 0;
 +                              strcpy(replace, "L");
 +                              break;
 +              }
 +      }
 +      /* case; beginning with r R l L , with separator after it */
 +      else if( IS_SEPARATOR(name[1]) ) {
 +              switch(name[0]) {
 +                      case 'l':
 +                              strcpy(replace, "r");
 +                              strcpy(suffix, name+1);
 +                              prefix[0]= 0;
 +                              break;
 +                      case 'r':
 +                              strcpy(replace, "l");
 +                              strcpy(suffix, name+1);
 +                              prefix[0]= 0;
 +                              break;
 +                      case 'L':
 +                              strcpy(replace, "R");
 +                              strcpy(suffix, name+1);
 +                              prefix[0]= 0;
 +                              break;
 +                      case 'R':
 +                              strcpy(replace, "L");
 +                              strcpy(suffix, name+1);
 +                              prefix[0]= 0;
 +                              break;
 +              }
 +      }
 +      else if(len > 5) {
 +              /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
 +              index = BLI_strcasestr(prefix, "right");
 +              if (index==prefix || index==prefix+len-5) {
 +                      if(index[0]=='r') 
 +                              strcpy (replace, "left");
 +                      else {
 +                              if(index[1]=='I') 
 +                                      strcpy (replace, "LEFT");
 +                              else
 +                                      strcpy (replace, "Left");
 +                      }
 +                      *index= 0;
 +                      strcpy (suffix, index+5);
 +              }
 +              else {
 +                      index = BLI_strcasestr(prefix, "left");
 +                      if (index==prefix || index==prefix+len-4) {
 +                              if(index[0]=='l') 
 +                                      strcpy (replace, "right");
 +                              else {
 +                                      if(index[1]=='E') 
 +                                              strcpy (replace, "RIGHT");
 +                                      else
 +                                              strcpy (replace, "Right");
 +                              }
 +                              *index= 0;
 +                              strcpy (suffix, index+4);
 +                      }
 +              }
 +      }
 +
 +#undef IS_SEPARATOR
 +
 +      sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
 +}
 +
 +typedef struct IndexMapEntry {
 +      /* the new vert index that this old vert index maps to */
 +      int new;
 +      /* -1 if this vert isn't merged, otherwise the old vert index it
 +      * should be replaced with
 +      */
 +      int merge;
 +      /* 1 if this vert's first copy is merged with the last copy of its
 +      * merge target, otherwise 0
 +      */
 +      short merge_final;
 +} IndexMapEntry;
 +
 +/* indexMap - an array of IndexMap entries
 + * oldIndex - the old index to map
 + * copyNum - the copy number to map to (original = 0, first copy = 1, etc.)
 + */
 +static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum)
 +{
 +      if(indexMap[oldIndex].merge < 0) {
 +              /* vert wasn't merged, so use copy of this vert */
 +              return indexMap[oldIndex].new + copyNum;
 +      } else if(indexMap[oldIndex].merge == oldIndex) {
 +              /* vert was merged with itself */
 +              return indexMap[oldIndex].new;
 +      } else {
 +              /* vert was merged with another vert */
 +              /* follow the chain of merges to the end, or until we've passed
 +              * a number of vertices equal to the copy number
 +              */
 +              if(copyNum <= 0)
 +                      return indexMap[oldIndex].new;
 +              else
 +                      return calc_mapping(indexMap, indexMap[oldIndex].merge,
 +                                          copyNum - 1);
 +      }
 +}
 +
 +static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
 +                                        Scene *scene, Object *ob, DerivedMesh *dm,
 +                                          int initFlags)
 +{
 +      DerivedMesh *cddm = dm; //copying shouldn't be necassary here, as all modifiers return CDDM's
 +      BMEditMesh *em = CDDM_To_BMesh(cddm, NULL);
 +      BMOperator op, oldop, weldop;
 +      int i, j, indexLen;
 +      /* offset matrix */
 +      float offset[4][4];
 +      float final_offset[4][4];
 +      float tmp_mat[4][4];
 +      float length = amd->length;
 +      int count = amd->count, maxVerts;
 +      int finalVerts, finalEdges, finalFaces;
 +      int *indexMap = NULL;
 +      DerivedMesh *start_cap = NULL, *end_cap = NULL;
 +      MVert *src_mvert;
 +
 +      /* need to avoid infinite recursion here */
 +      if(amd->start_cap && amd->start_cap != ob)
 +              start_cap = mesh_get_derived_final(scene, amd->start_cap, CD_MASK_MESH);
 +      if(amd->end_cap && amd->end_cap != ob)
 +              end_cap = mesh_get_derived_final(scene, amd->end_cap, CD_MASK_MESH);
 +
-               VecAddf(offset[3], offset[3], amd->offset);
++      unit_m4(offset);
 +
 +      src_mvert = cddm->getVertArray(dm);
 +      maxVerts = cddm->getNumVerts(dm);
 +
 +      if(amd->offset_type & MOD_ARR_OFF_CONST)
-                       Mat4Invert(obinv, ob->obmat);
++              add_v3_v3v3(offset[3], offset[3], amd->offset);
 +      if(amd->offset_type & MOD_ARR_OFF_RELATIVE) {
 +              for(j = 0; j < 3; j++)
 +                      offset[3][j] += amd->scale[j] * vertarray_size(src_mvert,
 +                                      maxVerts, j);
 +      }
 +
 +      if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
 +              float obinv[4][4];
 +              float result_mat[4][4];
 +
 +              if(ob)
-                       Mat4One(obinv);
++                      invert_m4_m4(obinv, ob->obmat);
 +              else
-               Mat4MulSerie(result_mat, offset,
++                      unit_m4(obinv);
 +
-               Mat4CpyMat4(offset, result_mat);
++              mul_serie_m4(result_mat, offset,
 +                               obinv, amd->offset_ob->obmat,
 +                                 NULL, NULL, NULL, NULL, NULL);
-                       scale = Mat3ToScalef(tmp_mat);
++              copy_m4_m4(offset, result_mat);
 +      }
 +
 +      if(amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
 +              Curve *cu = amd->curve_ob->data;
 +              if(cu) {
 +                      float tmp_mat[3][3];
 +                      float scale;
 +                      
 +                      object_to_mat3(amd->curve_ob, tmp_mat);
-       Mat4One(final_offset);
++                      scale = mat3_to_scale(tmp_mat);
 +                              
 +                      if(!cu->path) {
 +                              cu->flag |= CU_PATH; // needed for path & bevlist
 +                              makeDispListCurveTypes(scene, amd->curve_ob, 0);
 +                      }
 +                      if(cu->path)
 +                              length = scale*cu->path->totdist;
 +              }
 +      }
 +
 +      /* calculate the maximum number of copies which will fit within the
 +      prescribed length */
 +      if(amd->fit_type == MOD_ARR_FITLENGTH
 +                || amd->fit_type == MOD_ARR_FITCURVE)
 +      {
 +              float dist = sqrt(INPR(offset[3], offset[3]));
 +
 +              if(dist > 1e-6f)
 +                      /* this gives length = first copy start to last copy end
 +                      add a tiny offset for floating point rounding errors */
 +                      count = (length + 1e-6f) / dist;
 +              else
 +                      /* if the offset has no translation, just make one copy */
 +                      count = 1;
 +      }
 +
 +      if(count < 1)
 +              count = 1;
 +
 +      /* allocate memory for count duplicates (including original) plus
 +                * start and end caps
 +      */
 +      finalVerts = dm->getNumVerts(dm) * count;
 +      finalEdges = dm->getNumEdges(dm) * count;
 +      finalFaces = dm->getNumFaces(dm) * count;
 +      if(start_cap) {
 +              finalVerts += start_cap->getNumVerts(start_cap);
 +              finalEdges += start_cap->getNumEdges(start_cap);
 +              finalFaces += start_cap->getNumFaces(start_cap);
 +      }
 +      if(end_cap) {
 +              finalVerts += end_cap->getNumVerts(end_cap);
 +              finalEdges += end_cap->getNumEdges(end_cap);
 +              finalFaces += end_cap->getNumFaces(end_cap);
 +      }
 +
 +      /* calculate the offset matrix of the final copy (for merging) */ 
-               Mat4MulMat4(tmp_mat, final_offset, offset);
-               Mat4CpyMat4(final_offset, tmp_mat);
++      unit_m4(final_offset);
 +
 +      for(j=0; j < count - 1; j++) {
-               Mat4Invert(mtx2, mmd->mirror_ob->obmat);
-               Mat4MulMat4(mtx, ob->obmat, mtx2);
++              mul_m4_m4m4(tmp_mat, final_offset, offset);
++              copy_m4_m4(final_offset, tmp_mat);
 +      }
 +
 +      BMO_Init_Op(&weldop, "weldverts");
 +      BMO_InitOpf(em->bm, &op, "dupe geom=%avef");
 +      oldop = op;
 +      for (j=0; j < count; j++) {
 +              BMVert *v, *v2;
 +              BMOpSlot *s1;
 +              BMOpSlot *s2;
 +
 +              BMO_InitOpf(em->bm, &op, "dupe geom=%s", &oldop, j==0 ? "geom" : "newout");
 +              BMO_Exec_Op(em->bm, &op);
 +
 +              s1 = BMO_GetSlot(&op, "geom");
 +              s2 = BMO_GetSlot(&op, "newout");
 +
 +              BMO_CallOpf(em->bm, "transform mat=%m4 verts=%s", offset, &op, "newout");
 +
 +              #define _E(s, i) ((BMVert**)(s)->data.buf)[i]
 +
 +              /*calculate merge mapping*/
 +              if (j == 0) {
 +                      BMOperator findop;
 +                      BMOIter oiter;
 +                      BMVert *v, *v2;
 +                      BMHeader *h;
 +
 +                      BMO_InitOpf(em->bm, &findop, 
 +                              "finddoubles verts=%av dist=%f keepverts=%s", 
 +                              amd->merge_dist, &op, "geom");
 +
 +                      i = 0;
 +                      BMO_ITER(h, &oiter, em->bm, &op, "geom", BM_ALL) {
 +                              BMINDEX_SET(h, i);
 +                              i++;
 +                      }
 +
 +                      BMO_ITER(h, &oiter, em->bm, &op, "newout", BM_ALL) {
 +                              BMINDEX_SET(h, i);
 +                              i++;
 +                      }
 +
 +                      BMO_Exec_Op(em->bm, &findop);
 +
 +                      indexLen = i;
 +                      indexMap = MEM_callocN(sizeof(int)*indexLen, "indexMap");
 +
 +                      /*element type argument doesn't do anything here*/
 +                      BMO_ITER(v, &oiter, em->bm, &findop, "targetmapout", 0) {
 +                              v2 = BMO_IterMapValp(&oiter);
 +
 +                              indexMap[BMINDEX_GET(v)] = BMINDEX_GET(v2)+1;
 +                      }
 +
 +                      BMO_Finish_Op(em->bm, &findop);
 +              } 
 +
 +              /*generate merge mappping using index map.  we do this by using the
 +                operator slots as lookup arrays.*/
 +              #define E(i) (i) < s1->len ? _E(s1, i) : _E(s2, (i)-s1->len)
 +
 +              for (i=0; i<indexLen; i++) {
 +                      if (!indexMap[i]) continue;
 +
 +                      v = E(i);
 +                      v2 = E(indexMap[i]-1);
 +
 +                      BMO_Insert_MapPointer(em->bm, &weldop, "targetmap", v, v2);
 +              }
 +
 +              #undef E
 +              #undef _E
 +
 +              BMO_Finish_Op(em->bm, &oldop);
 +              oldop = op;
 +      }
 +
 +      if (j > 0) BMO_Finish_Op(em->bm, &op);
 +
 +      if (amd->flags & MOD_ARR_MERGE)
 +              BMO_Exec_Op(em->bm, &weldop);
 +
 +      BMO_Finish_Op(em->bm, &weldop);
 +
 +      BMEdit_RecalcTesselation(em);
 +      cddm = CDDM_from_BMEditMesh(em, NULL);
 +
 +      BMEdit_Free(em);
 +      MEM_freeN(indexMap);
 +
 +      return cddm;
 +}
 +
 +DerivedMesh *arrayModifier_applyModifier(ModifierData *md, Object *ob, 
 +                                       DerivedMesh *derivedData,
 +                                         int useRenderParams, int isFinalCalc)
 +{
 +      DerivedMesh *result;
 +      ArrayModifierData *amd = (ArrayModifierData*) md;
 +
 +      result = arrayModifier_doArray(amd, md->scene, ob, derivedData, 0);
 +
 +      //if(result != derivedData)
 +      //      CDDM_calc_normals(result);
 +
 +      return result;
 +}
 +
 +DerivedMesh *arrayModifier_applyModifierEM(ModifierData *md, Object *ob,
 +                                           BMEditMesh *editData, 
 +                                           DerivedMesh *derivedData)
 +{
 +      return arrayModifier_applyModifier(md, ob, derivedData, 0, 1);
 +}
 +
 +/* Mirror */
 +#define VERT_NEW      1
 +
 +DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
 +              Object *ob,
 +              DerivedMesh *dm,
 +              int initFlags,
 +              int axis)
 +{
 +      float tolerance = mmd->tolerance;
 +      DerivedMesh *result, *cddm;
 +      BMEditMesh *em;
 +      BMesh *bm;
 +      BMOIter siter1;
 +      BMOperator op;
 +      BMVert *v1;
 +      int vector_size=0, a, b;
 +      bDeformGroup *def, *defb;
 +      bDeformGroup **vector_def = NULL;
 +      float mtx[4][4], imtx[4][4];
 +      int j;
 +
 +      cddm = dm; //copying shouldn't be necassary here, as all modifiers return CDDM's
 +      em = CDDM_To_BMesh(dm, NULL);
 +
 +      /*convienence variable*/
 +      bm = em->bm;
 +
 +      if (mmd->flag & MOD_MIR_VGROUP) {
 +              /* calculate the number of deformedGroups */
 +              for(vector_size = 0, def = ob->defbase.first; def;
 +                  def = def->next, vector_size++);
 +
 +              /* load the deformedGroups for fast access */
 +              vector_def =
 +                  (bDeformGroup **)MEM_mallocN(sizeof(bDeformGroup*) * vector_size,
 +                                               "group_index");
 +              for(a = 0, def = ob->defbase.first; def; def = def->next, a++) {
 +                      vector_def[a] = def;
 +              }
 +      }
 +
 +      if (mmd->mirror_ob) {
 +              float mtx2[4][4], vec[3];
 +              
-               Mat4One(mtx);
++              invert_m4_m4(mtx2, mmd->mirror_ob->obmat);
++              mul_m4_m4m4(mtx, ob->obmat, mtx2);
 +      } else {
++              unit_m4(mtx);
 +      }
 +
 +      BMO_InitOpf(bm, &op, "mirror geom=%avef mat=%m4 mergedist=%f axis=%d", 
 +                  mtx, mmd->tolerance, axis);
 +      
 +      BMO_Exec_Op(bm, &op);
 +
 +      BMO_CallOpf(bm, "reversefaces faces=%s", &op, "newout");
 +      
 +      /*handle vgroup stuff*/
 +      if (mmd->flag & MOD_MIR_VGROUP) {
 +              BMO_ITER(v1, &siter1, bm, &op, "newout", BM_VERT) {
 +                      MDeformVert *dvert = CustomData_bmesh_get(&bm->vdata, v1->head.data, CD_MDEFORMVERT);
 +                      
 +                      if (dvert) {
 +                              for(j = 0; j < dvert[0].totweight; ++j) {
 +                                      char tmpname[32];
 +                                      
 +                                      if(dvert->dw[j].def_nr < 0 ||
 +                                         dvert->dw[j].def_nr >= vector_size)
 +                                              continue;
 +                                      
 +                                      def = vector_def[dvert->dw[j].def_nr];
 +                                      strcpy(tmpname, def->name);
 +                                      vertgroup_flip_name(tmpname,0);
 +                                      
 +                                      for(b = 0, defb = ob->defbase.first; defb;
 +                                          defb = defb->next, b++)
 +                                      {
 +                                              if(!strcmp(defb->name, tmpname))
 +                                              {
 +                                                      dvert->dw[j].def_nr = b;
 +                                                      break;
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +      
 +      BMO_Finish_Op(bm, &op);
 +
 +      BMEdit_RecalcTesselation(em);
 +      result = CDDM_from_BMEditMesh(em, NULL); //CDDM_copy(getEditDerivedBMesh(em, ob, NULL), 0);
 +
 +      BMEdit_Free(em);
 +      MEM_freeN(em);
 +
 +      if (vector_def) MEM_freeN(vector_def);
 +
 +      return result;
 +}
index b9eb6d6d6d2a799c6f5b0bd4be92a8043f631bae,e241d5808cda125d386a19ec85d39cb140f075f9..68846966cb38fb4644219e97da1a4cd32563f440
@@@ -3204,10 -3203,10 +3204,10 @@@ static void psys_face_mat(Object *ob, D
  
        int i = pa->num_dmcache==DMCACHE_NOTFOUND ? pa->num : pa->num_dmcache;
        
-       if (i==-1 || i >= dm->getNumTessFaces(dm)) { Mat4One(mat); return; }
 -      if (i==-1 || i >= dm->getNumFaces(dm)) { unit_m4(mat); return; }
++      if (i==-1 || i >= dm->getNumTessFaces(dm)) { unit_m4(mat); return; }
  
 -      mface=dm->getFaceData(dm,i,CD_MFACE);
 -      osface=dm->getFaceData(dm,i,CD_ORIGSPACE);
 +      mface=dm->getTessFaceData(dm,i,CD_MFACE);
 +      osface=dm->getTessFaceData(dm,i,CD_ORIGSPACE);
        
        if(orco && (orcodata=dm->getVertDataArray(dm, CD_ORCO))) {
                VECCOPY(v[0], orcodata[mface->v1]);
index 92c586f0001b6407010f24fb071b535022e7c92c,c9bf29ed29c6dada581b252fe739df7cc7c2f4ef..1c9e65eae73d8f0dbb25d996499f82c3c8543601
  #include "BKE_global.h"
  #include "BKE_mesh.h"
  #include "BKE_subsurf.h"
 +#include "BKE_mesh.h"
 +#include "BKE_tessmesh.h"
  
- #include "BLI_arithb.h"
+ #include "BLI_math.h"
  #include "BLI_kdtree.h"
  #include "BLI_kdopbvh.h"
  #include "BLI_editVert.h"
index da2cb8c5504fdbffbd99c107d371b8a42d158779,0a106b1920d6a70fa317089eee803f3f007857db..e53707bd6eb993822ab261d21a167ca42a072e2e
@@@ -1128,11 -1128,11 +1128,11 @@@ void smokeModifier_do(SmokeModifierDat
                        if(smd->coll->dm)
                                smd->coll->dm->release(smd->coll->dm);
  
 -                      smd->coll->dm = CDDM_copy(dm);
 +                      smd->coll->dm = CDDM_copy(dm, 1);
  
                        // rigid movement support
-                       Mat4CpyMat4(smd->coll->mat_old, smd->coll->mat);
-                       Mat4CpyMat4(smd->coll->mat, ob->obmat);
+                       copy_m4_m4(smd->coll->mat_old, smd->coll->mat);
+                       copy_m4_m4(smd->coll->mat, ob->obmat);
                }
                else if(scene->r.cfra < smd->time)
                {
index 94b9cfcdf537e5efeb3ef477b5e66b472d023346,0a68ad6e80390a870a11a48ea09699cc48c9e777..2e4bef26df40a86fe26d7031467b0ba269bf94a6
@@@ -66,10 -66,9 +66,10 @@@ variables on the UI for no
  #include "DNA_scene_types.h"
  
  #include "BLI_blenlib.h"
- #include "BLI_arithb.h"
+ #include "BLI_math.h"
  #include "BLI_ghash.h"
  #include "BLI_threads.h"
 +#include "BLI_cellalloc.h"
  
  #include "BKE_curve.h"
  #include "BKE_effect.h"
index 97b82e31b81f4e0684f28aedf51cee8a02668320,cb2e2c437bf95f2c3cafd10befdb55a3b9c5f26e..af5cefbe1618f4aefbe1e51c4e7e800c1d8e428c
@@@ -655,23 -549,19 +655,23 @@@ static DerivedMesh *ss_to_cdderivedmesh
        origIndex = result->getVertData(result, 0, CD_ORIGINDEX);
  
        for(index = 0; index < totface; index++) {
 -              CCGFace *f = faceMap2[index];
 -              int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
 -              FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
 -              int vertIdx[4];
 +              CCFace *f = faceMap2[index];
 +              int x, y, S, numVerts = CCS_getFaceNumVerts(f);
 +              FaceVertWeight *weight = 0;//get_ss_weights(&wtable, gridFaces-1, numVerts);
 +
 +              BLI_array_empty(vertIdx);
  
                for(S = 0; S < numVerts; S++) {
 -                      CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
 +                      CCVert *v = CCS_getFaceVert(ss, f, S);
 +                      BLI_array_growone(vertIdx);
  
 -                      vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
 +                      vertIdx[S] = GET_INT_FROM_POINTER(CCS_getVertVertHandle(v));
                }
  
 +#if 0
                DM_interp_vert_data(dm, result, vertIdx, weight[0][0], numVerts, i);
 -              copy_v3_v3(mvert->co, ccgSubSurf_getFaceCenterData(f));
 +#endif
-               VecCopyf(mvert->co, CCS_getFaceCenterData(f));
++              copy_v3_v3(mvert->co, CCS_getFaceCenterData(f));
                *origIndex = ORIGINDEX_NONE;
                ++mvert;
                ++origIndex;
                                w[S]      = weight[x][0][1];
                                w[nextS]  = weight[x][0][2];
                                w[otherS] = weight[x][0][3];
 +
                                DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
-                               VecCopyf(mvert->co,
 +#endif
 -                                       ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
+                               copy_v3_v3(mvert->co,
 +                                       CCS_getFaceGridEdgeData(ss, f, S, x));
  
                                *origIndex = ORIGINDEX_NONE;
                                ++mvert;
                                        w[nextS]  = weight[y * gridFaces + x][0][2];
                                        w[otherS] = weight[y * gridFaces + x][0][3];
                                        DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
-                                       VecCopyf(mvert->co,
 +#endif
 +
 -                                               ccgSubSurf_getFaceGridData(ss, f, S, x, y));
+                                       copy_v3_v3(mvert->co,
 +                                               CCS_getFaceGridData(ss, f, S, x, y));
                                        *origIndex = ORIGINDEX_NONE;
                                        ++mvert;
                                        ++origIndex;
                int x;
                int vertIdx[2];
  
 -              CCGVert *v;
 -              v = ccgSubSurf_getEdgeVert0(e);
 -              vertIdx[0] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
 -              v = ccgSubSurf_getEdgeVert1(e);
 -              vertIdx[1] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
 -
 +              CCVert *v;
 +              v = CCS_getEdgeVert0(e);
 +              vertIdx[0] = GET_INT_FROM_POINTER(CCS_getVertVertHandle(v));
 +              v = CCS_getEdgeVert1(e);
 +              vertIdx[1] = GET_INT_FROM_POINTER(CCS_getVertVertHandle(v));
 +              
                for(x = 1; x < edgeSize - 1; x++) {
 -                      float w[2];
 -                      w[1] = (float) x / (edgeSize - 1);
 -                      w[0] = 1 - w[1];
 -                      DM_interp_vert_data(dm, result, vertIdx, w, 2, i);
 -                      copy_v3_v3(mvert->co, ccgSubSurf_getEdgeData(ss, e, x));
 +                      float w2[2];
 +
 +                      w2[1] = (float) x / (edgeSize - 1);
 +                      w2[0] = 1 - w2[1];
 +                      DM_interp_vert_data(dm, result, vertIdx, w2, 2, i);
 +
-                       VecCopyf(mvert->co, CCS_getEdgeData(ss, e, x));
++                      copy_v3_v3(mvert->co, CCS_getEdgeData(ss, e, x));
                        *origIndex = ORIGINDEX_NONE;
                        ++mvert;
                        ++origIndex;
        }
  
        for(index = 0; index < totvert; index++) {
 -              CCGVert *v = vertMap2[index];
 +              CCVert *v = vertMap2[index];
                int vertIdx;
  
 -              vertIdx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
 +              vertIdx = GET_INT_FROM_POINTER(CCS_getVertVertHandle(v));
  
                DM_copy_vert_data(dm, result, vertIdx, i, 1);
-               VecCopyf(mvert->co, CCS_getVertData(ss, v));
 -              copy_v3_v3(mvert->co, ccgSubSurf_getVertData(ss, v));
++              copy_v3_v3(mvert->co, CCS_getVertData(ss, v));
  
 -              *((int*)ccgSubSurf_getVertUserData(ss, v)) = i;
 -              *origIndex = ccgDM_getVertMapIndex(ss, v);
 +              *((int*)CCS_getVertUserData(ss, v)) = i;
 +              *origIndex = cgdm_getVertMapIndex(ss, v);
                ++mvert;
                ++origIndex;
                i++;
@@@ -1154,43 -1014,43 +1154,43 @@@ static void cgdm_getFinalVert(DerivedMe
                gridSideEnd = 1 + numVerts * gridSideVerts;
                gridInternalEnd = gridSideEnd + numVerts * gridInternalVerts;
  
 -              offset = vertNum - ccgdm->faceMap[i].startVert;
 +              offset = vertNum - cgdm->faceMap[i].startVert;
                if(offset < 1) {
-                       VecCopyf(mv->co, CCS_getFaceCenterData(f));
 -                      copy_v3_v3(mv->co, ccgSubSurf_getFaceCenterData(f));
++                      copy_v3_v3(mv->co, CCS_getFaceCenterData(f));
                } else if(offset < gridSideEnd) {
                        offset -= 1;
                        grid = offset / gridSideVerts;
                        x = offset % gridSideVerts + 1;
-                       VecCopyf(mv->co, CCS_getFaceGridEdgeData(ss, f, grid, x));
 -                      copy_v3_v3(mv->co, ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x));
++                      copy_v3_v3(mv->co, CCS_getFaceGridEdgeData(ss, f, grid, x));
                } else if(offset < gridInternalEnd) {
                        offset -= gridSideEnd;
                        grid = offset / gridInternalVerts;
                        offset %= gridInternalVerts;
                        y = offset / gridSideVerts + 1;
                        x = offset % gridSideVerts + 1;
-                       VecCopyf(mv->co, CCS_getFaceGridData(ss, f, grid, x, y));
 -                      copy_v3_v3(mv->co, ccgSubSurf_getFaceGridData(ss, f, grid, x, y));
++                      copy_v3_v3(mv->co, CCS_getFaceGridData(ss, f, grid, x, y));
                }
 -      } else if((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
 +      } else if((vertNum < cgdm->vertMap[0].startVert) && (CCS_getNumEdges(ss) > 0)) {
                /* this vert comes from edge data */
 -              CCGEdge *e;
 -              int lastedge = ccgSubSurf_getNumEdges(ss) - 1;
 +              CCEdge *e;
 +              int lastedge = CCS_getNumEdges(ss) - 1;
                int x;
  
                i = 0;
 -              while(i < lastedge && vertNum >= ccgdm->edgeMap[i + 1].startVert)
 +              while(i < lastedge && vertNum >= cgdm->edgeMap[i + 1].startVert)
                        ++i;
  
 -              e = ccgdm->edgeMap[i].edge;
 +              e = cgdm->edgeMap[i].edge;
  
 -              x = vertNum - ccgdm->edgeMap[i].startVert + 1;
 -              copy_v3_v3(mv->co, ccgSubSurf_getEdgeData(ss, e, x));
 +              x = vertNum - cgdm->edgeMap[i].startVert + 1;
-               VecCopyf(mv->co, CCS_getEdgeData(ss, e, x));
++              copy_v3_v3(mv->co, CCS_getEdgeData(ss, e, x));
        } else {
                /* this vert comes from vert data */
 -              CCGVert *v;
 -              i = vertNum - ccgdm->vertMap[0].startVert;
 +              CCVert *v;
 +              i = vertNum - cgdm->vertMap[0].startVert;
  
 -              v = ccgdm->vertMap[i].vert;
 -              copy_v3_v3(mv->co, ccgSubSurf_getVertData(ss, v));
 +              v = cgdm->vertMap[i].vert;
-               VecCopyf(mv->co, CCS_getVertData(ss, v));
++              copy_v3_v3(mv->co, CCS_getVertData(ss, v));
        }
  }
  
@@@ -1309,42 -1169,39 +1309,42 @@@ static void cgdm_getFinalFace(DerivedMe
        mf->v3 = getFaceIndex(ss, f, grid, x+1, y+1, edgeSize, gridSize);
        mf->v4 = getFaceIndex(ss, f, grid, x+1, y+0, edgeSize, gridSize);
  
 -      if(faceFlags) mf->flag = faceFlags[i*4];
 -      else mf->flag = ME_SMOOTH;
 +      if(faceFlags) {
 +              mf->flag = faceFlags[i*4];
 +              mf->mat_nr = faceFlags[i*4+1];
 +      } else 
 +              mf->flag = ME_SMOOTH;
  }
  
 -static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
 +static void cgdm_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
  {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CSubSurf *ss = cgdm->ss;
        int index;
        int totvert, totedge, totface;
 -      int gridSize = ccgSubSurf_getGridSize(ss);
 -      int edgeSize = ccgSubSurf_getEdgeSize(ss);
 +      int gridSize = CCS_getGridSize(ss);
 +      int edgeSize = CCS_getEdgeSize(ss);
        int i = 0;
  
 -      totface = ccgSubSurf_getNumFaces(ss);
 +      totface = CCS_getNumFaces(ss);
        for(index = 0; index < totface; index++) {
 -              CCGFace *f = ccgdm->faceMap[index].face;
 -              int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
 +              CCFace *f = cgdm->faceMap[index].face;
 +              int x, y, S, numVerts = CCS_getFaceNumVerts(f);
  
-               VecCopyf(mvert[i++].co, CCS_getFaceCenterData(f));
 -              copy_v3_v3(mvert[i++].co, ccgSubSurf_getFaceCenterData(f));
++              copy_v3_v3(mvert[i++].co, CCS_getFaceCenterData(f));
                
                for(S = 0; S < numVerts; S++) {
                        for(x = 1; x < gridSize - 1; x++) {
-                               VecCopyf(mvert[i++].co,
+                               copy_v3_v3(mvert[i++].co,
 -                                       ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
 +                                       CCS_getFaceGridEdgeData(ss, f, S, x));
                        }
                }
  
                for(S = 0; S < numVerts; S++) {
                        for(y = 1; y < gridSize - 1; y++) {
                                for(x = 1; x < gridSize - 1; x++) {
-                                       VecCopyf(mvert[i++].co,
+                                       copy_v3_v3(mvert[i++].co,
 -                                               ccgSubSurf_getFaceGridData(ss, f, S, x, y));
 +                                               CCS_getFaceGridData(ss, f, S, x, y));
                                }
                        }
                }
                int x;
  
                for(x = 1; x < edgeSize - 1; x++) {
-                       VecCopyf(mvert[i++].co, CCS_getEdgeData(ss, e, x));
 -                      copy_v3_v3(mvert[i++].co, ccgSubSurf_getEdgeData(ss, e, x));
++                      copy_v3_v3(mvert[i++].co, CCS_getEdgeData(ss, e, x));
                }
        }
  
 -      totvert = ccgSubSurf_getNumVerts(ss);
 +      totvert = CCS_getNumVerts(ss);
        for(index = 0; index < totvert; index++) {
 -              CCGVert *v = ccgdm->vertMap[index].vert;
 +              CCVert *v = cgdm->vertMap[index].vert;
  
-               VecCopyf(mvert[i].co, CCS_getVertData(ss, v));
 -              copy_v3_v3(mvert[i].co, ccgSubSurf_getVertData(ss, v));
++              copy_v3_v3(mvert[i].co, CCS_getVertData(ss, v));
  
                i++;
        }
@@@ -1696,21 -1394,21 +1696,21 @@@ static void cgdm_getVertCos(DerivedMes
  
        i = 0;
        for (index=0; index<totface; index++) {
 -              CCGFace *f = faceMap2[index];
 -              int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
 +              CCFace *f = faceMap2[index];
 +              int x, y, S, numVerts = CCS_getFaceNumVerts(f);
  
-               VecCopyf(cos[i++], CCS_getFaceCenterData(f));
 -              copy_v3_v3(cos[i++], ccgSubSurf_getFaceCenterData(f));
++              copy_v3_v3(cos[i++], CCS_getFaceCenterData(f));
                
                for (S=0; S<numVerts; S++) {
                        for (x=1; x<gridSize-1; x++) {
-                               VecCopyf(cos[i++], CCS_getFaceGridEdgeData(ss, f, S, x));
 -                              copy_v3_v3(cos[i++], ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
++                              copy_v3_v3(cos[i++], CCS_getFaceGridEdgeData(ss, f, S, x));
                        }
                }
  
                for (S=0; S<numVerts; S++) {
                        for (y=1; y<gridSize-1; y++) {
                                for (x=1; x<gridSize-1; x++) {
-                                       VecCopyf(cos[i++], CCS_getFaceGridData(ss, f, S, x, y));
 -                                      copy_v3_v3(cos[i++], ccgSubSurf_getFaceGridData(ss, f, S, x, y));
++                                      copy_v3_v3(cos[i++], CCS_getFaceGridData(ss, f, S, x, y));
                                }
                        }
                }
                int x;
  
                for (x=1; x<edgeSize-1; x++) {
-                       VecCopyf(cos[i++], CCS_getEdgeData(ss, e, x));
 -                      copy_v3_v3(cos[i++], ccgSubSurf_getEdgeData(ss, e, x));
++                      copy_v3_v3(cos[i++], CCS_getEdgeData(ss, e, x));
                }
        }
  
        for (index=0; index<totvert; index++) {
 -              CCGVert *v = vertMap2[index];
 -              copy_v3_v3(cos[i++], ccgSubSurf_getVertData(ss, v));
 +              CCVert *v = vertMap2[index];
-               VecCopyf(cos[i++], CCS_getVertData(ss, v));
++              copy_v3_v3(cos[i++], CCS_getVertData(ss, v));
        }
  
        MEM_freeN(vertMap2);
@@@ -3332,20 -2708,20 +3332,20 @@@ void subsurf_calculate_limit_positions(
                face_sum[0]= face_sum[1]= face_sum[2]= 0.0;
  
                for (i=0; i<N; i++) {
 -                      CCGEdge *e = ccgSubSurf_getVertEdge(v, i);
 -                      add_v3_v3v3(edge_sum, edge_sum, ccgSubSurf_getEdgeData(ss, e, 1));
 +                      CCEdge *e = CCS_getVertEdge(v, i);
-                       VecAddf(edge_sum, edge_sum, CCS_getEdgeData(ss, e, 1));
++                      add_v3_v3v3(edge_sum, edge_sum, CCS_getEdgeData(ss, e, 1));
                }
                for (i=0; i<numFaces; i++) {
 -                      CCGFace *f = ccgSubSurf_getVertFace(v, i);
 -                      add_v3_v3v3(face_sum, face_sum, ccgSubSurf_getFaceCenterData(f));
 +                      CCFace *f = CCS_getVertFace(v, i);
-                       VecAddf(face_sum, face_sum, CCS_getFaceCenterData(f));
++                      add_v3_v3v3(face_sum, face_sum, CCS_getFaceCenterData(f));
                }
  
                /* ad-hoc correction for boundary vertices, to at least avoid them
                   moving completely out of place (brecht) */
                if(numFaces && numFaces != N)
-                       VecMulf(face_sum, (float)N/(float)numFaces);
+                       mul_v3_fl(face_sum, (float)N/(float)numFaces);
  
 -              co = ccgSubSurf_getVertData(ss, v);
 +              co = CCS_getVertData(ss, v);
                positions_r[idx][0] = (co[0]*N*N + edge_sum[0]*4 + face_sum[0])/(N*(N+5));
                positions_r[idx][1] = (co[1]*N*N + edge_sum[1]*4 + face_sum[1])/(N*(N+5));
                positions_r[idx][2] = (co[2]*N*N + edge_sum[2]*4 + face_sum[2])/(N*(N+5));
index a53ad2cb6274d3ff42d501d29f8a172e4881530c,0000000000000000000000000000000000000000..0b3f26007a6794353ed76bc974e304c4291eb8cd
mode 100644,000000..100644
--- /dev/null
@@@ -1,2101 -1,0 +1,2101 @@@
- #include "BLI_arithb.h"
 +/**
 + * $Id: verse_geometry_node.c 12931 2007-12-17 18:20:48Z theeth $
 + *
 + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version. The Blender
 + * Foundation also sells licenses for use in proprietary software under
 + * the Blender License.  See http://www.blender.org/BL/ for information
 + * about this.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * Contributor(s): Jiri Hnidek.
 + *
 + * ***** END GPL/BL DUAL LICENSE BLOCK *****
 + */
 +
 +#ifdef WITH_VERSE
 +
 +#include <string.h>
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "DNA_listBase.h"
 +
 +#include "BLI_dynamiclist.h"
 +#include "BLI_blenlib.h"
-                       VecAddf(vface->vvert3->no, vface->vvert3->no, vface->no);
++#include "BLI_math.h"
 +
 +#include "BKE_verse.h"
 +#include "BKE_utildefines.h"
 +
 +#include "BIF_verse.h"
 +
 +#include "verse.h"
 +
 +/* function prototypes of static functions */
 +
 +/* test functions for callback functions */
 +static char test_polygon_set_corner_uint32(uint32 v0, uint32 v1, uint32 v2, uint32 v3);
 +
 +/* callback functions */
 +static void cb_g_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real);
 +static void cb_g_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id);
 +static void cb_g_vertex_set_xyz_real32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x,       real32 y, real32 z);
 +static void cb_g_polygon_set_corner_uint32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
 +static void cb_g_vertex_delete_real32(void *user_data, VNodeID node_id, uint32 vertex_id);
 +static void cb_g_polygon_delete(void *user_data, VNodeID node_id, uint32 polygon_id);
 +static void cb_g_crease_set_edge(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease);
 +static void cb_g_crease_set_vertex(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease);
 +
 +/* other static functions */
 +
 +static void free_unneeded_verseverts_of_verseface(struct VNode *vnode, struct VerseFace *vface);
 +static void free_verse_vertex(struct VLayer *vlayer, struct VerseVert *vvert);
 +static void free_verse_face(struct VLayer *vlayer, struct VerseFace *vface);
 +static void free_verse_layer_data(struct VNode *vnode, struct VLayer *vlayer);
 +
 +static void send_verse_face(struct VerseFace *vface);
 +
 +static VerseVert* find_verse_vert_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 vertex_id, real32 x, real32 y, real32 z);
 +static VerseFace* find_verse_face_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
 +
 +static unsigned short test_incoming_verseface(struct VGeomData *geom, struct VerseFace *vface);
 +static void find_unsent_faces(struct VNode *vnode, struct VerseVert *vvert);
 +static void find_vlayer_orphans(struct VNode *vnode, struct VerseVert *vvert);
 +static void move_face_orphan_to_dlist(struct VNode *vnode, struct VLayer *vlayer, struct VerseFace *vface);
 +static void increase_verse_verts_references(struct VerseFace *vface);
 +static void recalculate_verseface_normals(struct VNode *vnode);
 +
 +/* verse edge functions */
 +static VerseEdge* find_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
 +static void insert_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge);
 +static void remove_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge);
 +static void remove_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
 +static void add_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
 +static void update_edgehash_of_deleted_verseface(struct VNode *vnode, struct VerseFace *vface);
 +static void update_edgehash_of_changed_verseface(struct VNode *vnode, struct VerseFace *vface, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
 +static void update_edgehash_of_new_verseface(struct VNode *vnode, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
 +
 +/*
 + * recalcute normals of all VerseFaces
 + */
 +static void recalculate_verseface_normals(VNode *vnode)
 +{
 +      struct VLayer *vert_layer, *face_layer;
 +      struct VerseFace *vface;
 +      struct VerseVert *vvert;
 +
 +      if(vnode->type != V_NT_GEOMETRY) return;
 +
 +      vert_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
 +      face_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
 +
 +      vvert = vert_layer->dl.lb.first;
 +      while(vvert) {
 +              vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0;
 +              vvert = vvert->next;
 +      }
 +
 +      vface = face_layer->dl.lb.first;
 +      while(vface) {
 +              /* calculate face normals */
 +              if(vface->vvert3) {
 +                      CalcNormFloat4(vface->vvert0->co, vface->vvert1->co,
 +                                      vface->vvert2->co, vface->vvert3->co, vface->no);
-               VecAddf(vface->vvert0->no, vface->vvert0->no, vface->no);
-               VecAddf(vface->vvert1->no, vface->vvert1->no, vface->no);
-               VecAddf(vface->vvert2->no, vface->vvert2->no, vface->no);
++                      add_v3_v3v3(vface->vvert3->no, vface->vvert3->no, vface->no);
 +              }
 +              else
 +                      CalcNormFloat(vface->vvert0->co, vface->vvert1->co,
 +                                      vface->vvert2->co, vface->no);
 +
 +              /* calculate vertex normals ... it is averadge of all face normals using the vertex */
-               Normalize(vvert->no);
++              add_v3_v3v3(vface->vvert0->no, vface->vvert0->no, vface->no);
++              add_v3_v3v3(vface->vvert1->no, vface->vvert1->no, vface->no);
++              add_v3_v3v3(vface->vvert2->no, vface->vvert2->no, vface->no);
 +
 +              vface = vface->next;
 +      }
 +
 +      /* we have to normalize all vertex normals */
 +      vvert = vert_layer->dl.lb.first;
 +      while(vvert) {
++              normalize_v3(vvert->no);
 +              vvert = vvert->next;
 +      }
 +}
 +
 +/*
 + * add created item to the queue and send it if possible
 + */
 +void add_item_to_send_queue(ListBase *lb, void *item, short type)
 +{
 +      struct VNode *vnode;
 +      struct VLayer *vlayer;
 +      struct VerseVert *vvert;
 +      struct VerseFace *vface;
 +
 +      /* this prevent from adding duplicated faces */
 +      if(type==VERSE_FACE) {
 +              struct Link *link = (Link*)lb->first;
 +              while(link) {
 +                      if(link==item) {
 +                              if(((VerseFace*)item)->flag & FACE_SENT) {
 +/*                                    printf("\tverse face %d marked as OBSOLETE\n", ((VerseFace*)item)->id);*/
 +                                      ((VerseFace*)item)->flag |= FACE_OBSOLETE;
 +                              }
 +                              return;
 +                      }
 +                      link = link->next;
 +              }
 +      }
 +
 +      /* add item to sending queue (two way dynamic list) */
 +      BLI_addtail(lb, item);
 +
 +      /* send item, when it is possible */
 +      switch (type) {
 +              case VERSE_NODE:        /* only first node in queue can be sent */
 +                      if(lb->first==lb->last) 
 +                              send_verse_node((VNode*)item);
 +                      break;
 +              case VERSE_LINK:        /* both object between have to exist */
 +                      if(((VLink*)item)->flag & LINK_SEND_READY)
 +                              send_verse_link((VLink*)item);
 +                      break;
 +              case VERSE_LAYER:
 +                      if(((VLayer*)item)->vnode->flag & NODE_RECEIVED)
 +                              send_verse_layer((VLayer*)item);
 +                      break;
 +              case VERSE_VERT:
 +                      if(((VerseVert*)item)->vlayer->flag & LAYER_RECEIVED)
 +                              send_verse_vertex((VerseVert*)item);
 +                      break;
 +              case VERSE_FACE:        /* all vertexes of face have to be received */
 +                      if(((VerseFace*)item)->flag & FACE_SEND_READY)
 +                              send_verse_face((VerseFace*)item);
 +                      break;
 +              case VERSE_TAG:
 +                      send_verse_tag((VTag*)item);
 +                      break;
 +              case VERSE_TAG_GROUP:
 +                      send_verse_taggroup((VTagGroup*)item);
 +                      break;
 +              case VERSE_VERT_UINT32: /* parent item has to exist */
 +                      vnode = (((uint32_item*)item)->vlayer)->vnode;
 +                      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
 +                      vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id );
 +                      if(vvert != NULL)
 +                              send_verse_vert_uint32((uint32_item*)item, type);
 +                      break;
 +              case VERSE_VERT_REAL32: /* parent item has to exist */
 +                      vnode = (((real32_item*)item)->vlayer)->vnode;
 +                      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
 +                      vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id );
 +                      if( vvert != NULL)
 +                              send_verse_vert_real32((real32_item*)item, type);
 +                      break;
 +              case VERSE_VERT_VEC_REAL32:     /* parent item has to exist */
 +                      vnode = (((vec_real32_item*)item)->vlayer)->vnode;
 +                      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
 +                      vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((vec_real32_item*)item)->id );
 +                      if(vvert != NULL)
 +                              send_verse_vert_vec_real32((vec_real32_item*)item, type);
 +                      break;
 +              case VERSE_FACE_UINT8:  /* parent item has to exist */
 +                      vnode = (((uint8_item*)item)->vlayer)->vnode;
 +                      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
 +                      vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint8_item*)item)->id );
 +                      if(vface != NULL)
 +                              send_verse_face_uint8((uint8_item*)item, type);
 +                      break;
 +              case VERSE_FACE_UINT32: /* parent item has to exist */
 +                      vnode = (((uint32_item*)item)->vlayer)->vnode;
 +                      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
 +                      vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id );
 +                      if(vface != NULL)
 +                              send_verse_face_uint32((uint32_item*)item, type);
 +                      break;
 +              case VERSE_FACE_REAL32: /* parent item has to exist */
 +                      vnode = (((real32_item*)item)->vlayer)->vnode;
 +                      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
 +                      vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id );
 +                      if(vface != NULL)
 +                              send_verse_face_real32((real32_item*)item, type);
 +                      break;
 +              case VERSE_FACE_QUAT_UINT32:    /* parent item has to exist */
 +                      vnode = (((quat_uint32_item*)item)->vlayer)->vnode;
 +                      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
 +                      vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_uint32_item*)item)->id );
 +                      if(vface != NULL)
 +                              send_verse_face_corner_quat_uint32((quat_uint32_item*)item, type);
 +                      break;
 +              case VERSE_FACE_QUAT_REAL32:    /* parent item has to exist */
 +                      vnode = (((quat_real32_item*)item)->vlayer)->vnode;
 +                      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
 +                      vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_real32_item*)item)->id );
 +                      if(vface != NULL)
 +                              send_verse_face_corner_quat_real32((quat_real32_item*)item, type);
 +                      break;
 +      }
 +}
 +
 +/*
 + * return VerseLayer with certain content (vertexes, polygons, in the
 + * future: weight, red color, etc.)
 + */
 +VLayer* find_verse_layer_type(VGeomData *geom, short content)
 +{
 +      struct VLayer *vlayer = NULL;
 +      
 +      switch(content) {
 +              case VERTEX_LAYER:
 +                      /* VERTEX_LAYER equals 0 and vertex layer is
 +                       * always in 1st layer */
 +                      vlayer = geom->layers.da.items[VERTEX_LAYER];
 +                      break;
 +              case POLYGON_LAYER:
 +                      /* POLYGON_LAYER equals 1 and vertex layer is
 +                       * always in 2nd layer */
 +                      vlayer = geom->layers.da.items[POLYGON_LAYER];
 +                      break;
 +      }
 +
 +      return vlayer;
 +}
 +
 +/*
 + * increase references of VerseVerts of new VerseFace
 + */
 +static void increase_verse_verts_references(VerseFace *vface)
 +{
 +      if(vface->vvert0) vface->vvert0->counter++;
 +      if(vface->vvert1) vface->vvert1->counter++;
 +      if(vface->vvert2) vface->vvert2->counter++;
 +      if(vface->vvert3) vface->vvert3->counter++;
 +}
 +
 +/*
 + * move VerseFace from list of orphans to dlist of VerseFaces (if VerseFace was only changed
 + * then this VerseFace is only removed from list of orphans)
 + */
 +static void move_face_orphan_to_dlist(VNode *vnode, VLayer *vlayer, VerseFace *vface)
 +{
 +      /* remove vface from list of orphans */
 +      BLI_remlink(&(vlayer->orphans), vface);
 +      /* increase references of all vertexes beying part of this face*/
 +      increase_verse_verts_references(vface);
 +
 +      if(vface->flag & FACE_RECEIVED) {
 +              /* set up vface flag */
 +              vface->flag &= ~FACE_RECEIVED;
 +              /* move vface to dynamic list of faces */
 +              BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id);
 +              /* recalculate all vertex and faces normals */
 +              recalculate_verseface_normals(vnode);
 +              /* post create action (change local data) */
 +              ((VGeomData*)vnode->data)->post_polygon_create(vface);
 +      }
 +      else if(vface->flag & FACE_CHANGED) {
 +              /* set up vface flag */
 +              vface->flag &= ~FACE_CHANGED;
 +              /* move vface to dynamic list of faces */
 +              BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id);
 +              /* recalculate all vertex and faces normals */
 +              recalculate_verseface_normals(vnode);
 +              /* post create action (change local data) */
 +              ((VGeomData*)vnode->data)->post_polygon_set_corner(vface);
 +      }
 +}
 +
 +/*
 + * find all VerseFaces waiting in queue, which needs id of new VerseVert
 + */
 +static void find_unsent_faces(VNode *vnode, VerseVert *vvert)
 +{
 +      VLayer *vlayer;
 +      VerseFace *vface, *next_vface;
 +
 +      vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
 +
 +      if(vlayer) {
 +              vface = vlayer->queue.first;
 +              while(vface) {
 +                      next_vface = vface->next;
 +                      if(vface->vvert0==vvert) {
 +                              vface->v0 = vvert->id;
 +                              vface->counter--;
 +                      }
 +                      else if(vface->vvert1==vvert) {
 +                              vface->v1 = vvert->id;
 +                              vface->counter--;
 +                      }
 +                      else if(vface->vvert2==vvert) {
 +                              vface->v2 = vvert->id;
 +                              vface->counter--;
 +                      }
 +                      else if(vface->vvert3==vvert){
 +                              vface->v3 = vvert->id;
 +                              vface->counter--;
 +                      }
 +
 +                      if(vface->counter<1 && !(vface->flag & FACE_SENT))
 +                              send_verse_face(vface);
 +
 +                      vface = next_vface;
 +              }
 +      }
 +}
 +
 +/*
 + * find all VerseFace orphans, which needs incoming VerseVert
 + */
 +static void find_vlayer_orphans(VNode *vnode, VerseVert *vvert)
 +{
 +      VLayer *vlayer;
 +      VerseFace *vface, *next_vface;
 +      unsigned int vertex_id = vvert->id;
 +
 +      vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
 +
 +      if(vlayer) {
 +              vface = vlayer->orphans.first;
 +              while(vface){
 +                      next_vface = vface->next;
 +                      if(vface->v0 == vertex_id) {
 +                              vface->vvert0 = vvert;
 +                              vface->counter--;
 +                      }
 +                      else if(vface->v1 == vertex_id) {
 +                              vface->vvert1 = vvert;
 +                              vface->counter--;
 +                      }
 +                      else if(vface->v2 == vertex_id) {
 +                              vface->vvert2 = vvert;
 +                              vface->counter--;
 +                      }
 +                      else if(vface->v3 == vertex_id) {
 +                              vface->vvert3 = vvert;
 +                              vface->counter--;
 +                      }
 +                      if(vface->counter<1) {
 +                              /* moving VerseFace orphan to dlist */
 +                              move_face_orphan_to_dlist(vnode, vlayer, vface);
 +                      }
 +                      vface = next_vface;
 +              }
 +      }
 +}
 +
 +/*
 + * return number of VerseVerts missing to incoming VerseFace, set up pointers
 + * at VerseVerts
 + */
 +static unsigned short test_incoming_verseface(VGeomData *geom, VerseFace *vface)
 +{
 +      struct VLayer *vert_layer;
 +      struct VerseVert *vvert; 
 +      int counter=0;
 +
 +      vert_layer = find_verse_layer_type(geom, VERTEX_LAYER);
 +
 +      if(vface->v0 != -1){
 +              vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v0);
 +              if(vvert==NULL) counter++;
 +              else vface->vvert0 = vvert;
 +      }
 +      if(vface->v1 != -1){
 +              vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v1);
 +              if(vvert==NULL) counter++;
 +              else vface->vvert1 = vvert;
 +      }
 +      if(vface->v2 != -1){
 +              vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v2);
 +              if(vvert==NULL) counter++;
 +              else vface->vvert2 = vvert;
 +      }
 +      if(vface->v3 != -1){
 +              vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v3);
 +              if(vvert==NULL) counter++;
 +              else vface->vvert3 = vvert;
 +      }
 +      
 +      return counter;
 +}
 +
 +/*
 + * try to find changed VerseFace in sending queue
 + */
 +static VerseFace* find_changed_verse_face_in_queue(VLayer *vlayer, uint32 polygon_id)
 +{
 +      struct VerseFace *vface = vlayer->queue.first;
 +
 +      while(vface){
 +              if(vface->id == polygon_id && vface->flag & FACE_CHANGED) {
 +                      return vface;
 +              }
 +              vface = vface->next;
 +      }
 +      return NULL;
 +}
 +
 +/*
 + * try to find VerseFace in queue
 + */
 +static VerseFace* find_verse_face_in_queue(
 +              VLayer *vlayer,
 +              VNodeID node_id,
 +              uint32 polygon_id,
 +              uint32 v0,
 +              uint32 v1,
 +              uint32 v2,
 +              uint32 v3)
 +{
 +      struct VerseFace *vface = vlayer->queue.first;
 +
 +      while(vface){
 +              if((vface->v0==v0) && (vface->v1==v1) && (vface->v2==v2) && (vface->v3==v3)){
 +                      vface->id = polygon_id;
 +                      vface->vlayer = vlayer;
 +                      return vface;
 +              }
 +              vface = vface->next;
 +      }
 +      return NULL;
 +}
 +
 +/*
 + * try to find VerseVert in queue
 + */
 +static VerseVert* find_verse_vert_in_queue(
 +              VLayer *vlayer,
 +              VNodeID node_id,
 +              uint32 vertex_id,
 +              real32 x,
 +              real32 y,
 +              real32 z)
 +{
 +      struct VerseVert *vvert = vlayer->queue.first;
 +
 +      while(vvert){
 +              if((vvert->vlayer->vnode->id == node_id) && (vvert->co[0] == x) && (vvert->co[1] == y) && (vvert->co[2] == z))
 +              {
 +                      vvert->id = vertex_id;
 +                      vvert->vlayer = vlayer;
 +
 +                      return vvert;
 +              }
 +              vvert = vvert->next;
 +      }
 +
 +      return NULL;
 +}
 +
 +
 +/*
 + * send quat of float values to verse server (4x32 bits)
 + */
 +void send_verse_face_corner_quat_real32(quat_real32_item *item, short type)
 +{
 +      verse_send_g_polygon_set_corner_real32(
 +                      item->vlayer->vnode->id,
 +                      item->vlayer->id,
 +                      item->id,
 +                      item->value[0],
 +                      item->value[1],
 +                      item->value[2],
 +                      item->value[3]);
 +}
 +
 +/*
 + * send quat of unsigned int values to verse server (4x32 bits)
 + */
 +void send_verse_face_corner_quat_uint32(quat_uint32_item *item, short type)
 +{
 +      verse_send_g_polygon_set_corner_uint32(
 +                      item->vlayer->vnode->id,
 +                      item->vlayer->id,
 +                      item->id,
 +                      item->value[0],
 +                      item->value[1],
 +                      item->value[2],
 +                      item->value[3]);
 +}
 +
 +/*
 + * send float value (32 bits) to verse server
 + */
 +void send_verse_face_real32(real32_item *item, short type)
 +{
 +      verse_send_g_polygon_set_face_real32(
 +                      item->vlayer->vnode->id,
 +                      item->vlayer->id,
 +                      item->id,
 +                      item->value);
 +}
 +
 +/*
 + * send unsigned integer (32 bits) to verse server
 + */
 +void send_verse_face_uint32(uint32_item *item, short type)
 +{
 +      verse_send_g_polygon_set_face_uint32(
 +                      item->vlayer->vnode->id,
 +                      item->vlayer->id,
 +                      item->id,
 +                      item->value);
 +}
 +
 +/*
 + * send unsigned char (8 bits) to verse server
 + */
 +void send_verse_face_uint8(uint8_item *item, short type)
 +{
 +      verse_send_g_polygon_set_face_uint8(
 +                      item->vlayer->vnode->id,
 +                      item->vlayer->id,
 +                      item->id,
 +                      item->value);
 +}
 +
 +/*
 + * send vector of float values to verse server (3x32 bits)
 + */
 +void send_verse_vert_vec_real32(vec_real32_item *item, short type)
 +{
 +      verse_send_g_vertex_set_xyz_real32(
 +                      item->vlayer->vnode->id,
 +                      item->vlayer->id,
 +                      item->id,
 +                      item->value[0],
 +                      item->value[1],
 +                      item->value[2]);
 +}
 +
 +/*
 + * send float value (32 bits) to verse server
 + */
 +void send_verse_vert_real32(real32_item *item, short type)
 +{
 +      verse_send_g_vertex_set_real32(
 +                      item->vlayer->vnode->id,
 +                      item->vlayer->id,
 +                      item->id,
 +                      item->value);
 +}
 +
 +/*
 + * send unsigned integer (32 bits) to verse server
 + */
 +void send_verse_vert_uint32(uint32_item *item, short type)
 +{
 +      verse_send_g_vertex_set_uint32(
 +                      item->vlayer->vnode->id,
 +                      item->vlayer->id,
 +                      item->id,
 +                      item->value);
 +}
 +
 +/*
 + * send delete command to verse server
 + */
 +void send_verse_vertex_delete(VerseVert *vvert)
 +{
 +      verse_session_set(vvert->vlayer->vnode->session->vsession);
 +
 +      vvert->flag |= VERT_OBSOLETE;
 +      
 +      verse_send_g_vertex_delete_real32(vvert->vlayer->vnode->id, vvert->id);
 +}
 +
 +/*
 + * send VerseLayer to verse server
 + */
 +void send_verse_layer(VLayer *vlayer)
 +{
 +      verse_session_set(vlayer->vnode->session->vsession);
 +
 +      verse_send_g_layer_create(
 +                      vlayer->vnode->id,
 +                      vlayer->id,
 +                      vlayer->name,
 +                      vlayer->type,
 +                      vlayer->def_int,
 +                      vlayer->def_real);
 +}
 +
 +/* 
 + * send VerseVert to verse server
 + */
 +void send_verse_vertex(VerseVert *vvert)
 +{
 +      /* new vertex position will not be sent, when vertex was deleted */
 +      if(vvert->flag & VERT_OBSOLETE) return;
 +      
 +      verse_session_set(vvert->vlayer->vnode->session->vsession);
 +
 +      verse_send_g_vertex_set_xyz_real32(
 +                      vvert->vlayer->vnode->id,
 +                      vvert->vlayer->id,
 +                      vvert->id,
 +                      vvert->co[0],
 +                      vvert->co[2],
 +                      -vvert->co[1]);
 +}
 +
 +/*
 + * send delete command to verse server
 + */
 +void send_verse_face_delete(VerseFace *vface)
 +{
 +      verse_session_set(vface->vlayer->vnode->session->vsession);
 +
 +      vface->flag |= FACE_DELETED;
 +
 +      verse_send_g_polygon_delete(vface->vlayer->vnode->id, vface->id);
 +}
 +
 +/*
 + * send VerseFace to verse server
 + */
 +static void send_verse_face(VerseFace *vface)
 +{
 +      verse_session_set(vface->vlayer->vnode->session->vsession);
 +
 +      vface->flag |= FACE_SENT;
 +
 +      if(vface->v3 != -1) {
 +              verse_send_g_polygon_set_corner_uint32(
 +                              vface->vlayer->vnode->id,
 +                              vface->vlayer->id,
 +                              vface->id,
 +                              vface->v0,
 +                              vface->v3,      /* verse use clock-wise winding */
 +                              vface->v2,
 +                              vface->v1);     /* verse use clock-wise winding */
 +      }
 +      else {
 +              verse_send_g_polygon_set_corner_uint32(
 +                              vface->vlayer->vnode->id,
 +                              vface->vlayer->id,
 +                              vface->id,
 +                              vface->v0,
 +                              vface->v2,      /* verse use clock-wise winding */
 +                              vface->v1,      /* verse use clock-wise winding */
 +                              vface->v3);
 +      }
 +}
 +
 +/*
 + * free VerseVert
 + */
 +static void free_verse_vertex(VLayer *vlayer, VerseVert *vvert)
 +{
 +      /* free VerseVert */
 +      BLI_freelinkN(&(vlayer->orphans), vvert);
 +}
 +
 +/*
 + * free VerseFace (and blender face)
 + */
 +static void free_verse_face(VLayer *vlayer, VerseFace *vface)
 +{
 +      /* free VerseFace */
 +      BLI_dlist_free_item(&(vlayer->dl), (unsigned int)vface->id);
 +}
 +
 +/*
 + * free VerseLayer data
 + */
 +static void free_verse_layer_data(VNode *vnode, VLayer *vlayer)
 +{
 +      struct VerseFace *vface;
 +      struct VerseVert *vvert;
 +
 +      /* set up EditVert->vvert and EditFace->vface pointers to NULL */
 +      switch(vlayer->content) {
 +              case VERTEX_LAYER:
 +                      vvert = (VerseVert*)vlayer->dl.lb.first;
 +                      while(vvert) {
 +                              ((VGeomData*)vnode->data)->post_vertex_free_constraint(vvert);
 +                              vvert = vvert->next;
 +                      }
 +                      break;
 +              case POLYGON_LAYER:
 +                      vface = (VerseFace*)vlayer->dl.lb.first;
 +                      while(vface) {
 +                              ((VGeomData*)vnode->data)->post_polygon_free_constraint(vface);
 +                              vface = vface->next;
 +                      }
 +                      break;
 +              default:
 +                      break;
 +      }
 +      /* free Verse Layer name */
 +      MEM_freeN(vlayer->name);
 +      /* destroy VerseLayer data (vertexes, polygons, etc.) */
 +      BLI_dlist_destroy(&(vlayer->dl));
 +      /* free unsent data */
 +      BLI_freelistN(&(vlayer->queue));
 +      /* free orphans */
 +      BLI_freelistN(&(vlayer->orphans));
 +}
 +
 +/*
 + * free all unneeded VerseVerts waiting for deleting
 + */
 +static void free_unneeded_verseverts_of_verseface(VNode *vnode, VerseFace *vface)
 +{
 +      struct VLayer *vert_vlayer;
 +
 +      /* find layer containing vertexes */
 +      vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
 +
 +      /* free all "deleted" VerseVert waiting for deleting this VerseFace */
 +      
 +      if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) {
 +              ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0);
 +              free_verse_vertex(vert_vlayer, vface->vvert0);
 +              vface->vvert0 = NULL;
 +      }
 +      if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) {
 +              ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1);
 +              free_verse_vertex(vert_vlayer, vface->vvert1);
 +              vface->vvert1 = NULL;
 +      }
 +      if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) {
 +              ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2);
 +              free_verse_vertex(vert_vlayer, vface->vvert2);
 +              vface->vvert2 = NULL;
 +      }
 +      if((vface->vvert3) && (vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) {
 +              ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3);
 +              free_verse_vertex(vert_vlayer, vface->vvert3);
 +              vface->vvert3 = NULL;
 +      }
 +}
 +
 +/*
 + * This function create VerseVert and returns pointer on this vertex
 + */
 +VerseVert* create_verse_vertex(
 +              VLayer *vlayer,
 +              uint32 vertex_id,
 +              real32 x,
 +              real32 y,
 +              real32 z)
 +{
 +      struct VerseVert *vvert;
 +
 +      vvert = (VerseVert*)MEM_mallocN(sizeof(VerseVert), "VerseVert");
 +      
 +      /* set up pointer on parent node */
 +      vvert->vlayer = vlayer;
 +      vvert->id = vertex_id;
 +      /* position */
 +      vvert->co[0] = x;
 +      vvert->co[1] = y;
 +      vvert->co[2] = z;
 +      /* normal */
 +      vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0;
 +      /* blender internals */
 +      vvert->flag = 0;
 +      vvert->counter = 0;
 +      vvert->vertex = NULL;
 +
 +      /* increase layer counter of vertexes */
 +      vlayer->counter++;
 +
 +      return vvert;
 +}
 +
 +/*
 + * this function creates fake VerseEdge and returns pointer at this edge
 + */
 +VerseEdge *create_verse_edge(uint32 v0, uint32 v1)
 +{
 +      struct VerseEdge *vedge;
 +
 +      vedge = (VerseEdge*)MEM_mallocN(sizeof(VerseEdge), "VerseEdge");
 +
 +      vedge->v0 = v0;
 +      vedge->v1 = v1;
 +      vedge->counter = 0;
 +
 +      return vedge;
 +}
 +
 +/*
 + * this function will create new VerseFace and will return pointer on such Face
 + */
 +VerseFace* create_verse_face(
 +              VLayer *vlayer,
 +              uint32 polygon_id,
 +              uint32 v0,
 +              uint32 v1,
 +              uint32 v2,
 +              uint32 v3)
 +{
 +      struct VerseFace *vface;
 +
 +      vface = (VerseFace*)MEM_mallocN(sizeof(VerseFace), "VerseFace");
 +
 +      /* verse data */
 +      vface->vlayer = vlayer;
 +      vface->id = polygon_id;
 +
 +      vface->vvert0 = NULL;
 +      vface->vvert1 = NULL;
 +      vface->vvert2 = NULL;
 +      vface->vvert3 = NULL;
 +
 +      vface->v0 = v0;
 +      vface->v1 = v1;
 +      vface->v2 = v2;
 +      vface->v3 = v3;
 +
 +      /* blender data */
 +      vface->face = NULL;
 +      vface->flag = 0;
 +      vface->counter = 4;
 +
 +      /* increase layer counter of faces */
 +      vlayer->counter++;
 +      
 +      return vface;
 +}
 +
 +/*
 + * create and return VerseLayer
 + */
 +VLayer *create_verse_layer(
 +              VNode *vnode,
 +              VLayerID layer_id,
 +              const char *name,
 +              VNGLayerType type,
 +              uint32 def_integer,
 +              real64 def_real)
 +{
 +      struct VLayer *vlayer;
 +
 +      /* add layer to the DynamicList */
 +      vlayer = (VLayer*)MEM_mallocN(sizeof(VLayer), "VerseLayer");
 +
 +      /* store all relevant info to the vlayer and set up vlayer */
 +      vlayer->vnode = vnode;
 +      vlayer->id = layer_id;
 +      vlayer->name = (char*)MEM_mallocN(sizeof(char)*(sizeof(name)+1),"Verse Layer name");
 +      strcpy(vlayer->name, name);
 +      vlayer->type = type;
 +      vlayer->def_int = def_integer;
 +      vlayer->def_real = def_real;
 +
 +      if((type == VN_G_LAYER_VERTEX_XYZ) && (layer_id == 0))
 +              vlayer->content = VERTEX_LAYER;
 +      else if((type == VN_G_LAYER_POLYGON_CORNER_UINT32) && (layer_id == 1))
 +              vlayer->content = POLYGON_LAYER;
 +      else
 +              vlayer->content = -1;
 +
 +      /* initialize DynamicList in the vlayer (vertexes, polygons, etc.)*/
 +      BLI_dlist_init(&(vlayer->dl));
 +      /* initialization of queue of layer */
 +      vlayer->queue.first = vlayer->queue.last = NULL;
 +      /* initialization of list of orphans */
 +      vlayer->orphans.first = vlayer->orphans.last = NULL;
 +      /* initialize number of sent items (vertexes, faces, etc) */
 +      vlayer->counter = 0;
 +      /* initialize flag */
 +      vlayer->flag = 0;
 +
 +      /* set up methods */
 +      vlayer->post_layer_create = post_layer_create;
 +      vlayer->post_layer_destroy = post_layer_destroy;
 +
 +      return vlayer;
 +}
 +
 +/*
 + * create geometry data
 + */
 +VGeomData *create_geometry_data(void)
 +{
 +      struct VGeomData *geom;
 +
 +      geom = (VGeomData*)MEM_mallocN(sizeof(VGeomData), "VerseGeometryData");
 +      BLI_dlist_init(&(geom->layers));
 +      geom->vlink = NULL;
 +      geom->queue.first = geom->queue.last = NULL;
 +      geom->mesh = NULL;
 +      geom->editmesh = NULL;
 +
 +      /* initialize list of fake verse edges and initialize verse edge hash */
 +      geom->edges.first = geom->edges.last = NULL;
 +      geom->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
 +
 +      /* set up methods */
 +      geom->post_vertex_create = post_vertex_create;
 +      geom->post_vertex_set_xyz = post_vertex_set_xyz;
 +      geom->post_vertex_delete = post_vertex_delete;
 +      geom->post_vertex_free_constraint = post_vertex_free_constraint;
 +      geom->post_polygon_create = post_polygon_create;
 +      geom->post_polygon_set_corner = post_polygon_set_corner;
 +      geom->post_polygon_delete = post_polygon_delete;
 +      geom->post_polygon_free_constraint = post_polygon_free_constraint;
 +      geom->post_geometry_free_constraint = post_geometry_free_constraint;
 +      geom->post_polygon_set_uint8 = post_polygon_set_uint8;
 +
 +      return geom;
 +}
 +
 +/* Create item containing 4 floats */
 +static quat_real32_item *create_quat_real32_item(
 +              VLayer *vlayer,
 +              uint32 item_id,
 +              real32 v0,
 +              real32 v1,
 +              real32 v2,
 +              real32 v3)
 +{
 +      struct quat_real32_item *item;
 +
 +      item = (quat_real32_item*)MEM_mallocN(sizeof(quat_real32_item), "quat_real32_item");
 +
 +      item->vlayer = vlayer;
 +      item->id = item_id;
 +      item->value[0] = v0;
 +      item->value[1] = v1;
 +      item->value[2] = v2;
 +      item->value[3] = v3;
 +
 +      return item;
 +}
 +
 +/* Create item containing 1 float */
 +static real32_item *create_real32_item(VLayer *vlayer, uint32 item_id, real32 value)
 +{
 +      struct real32_item *item;
 +
 +      item = (real32_item*)MEM_mallocN(sizeof(real32_item), "real32_item");
 +
 +      item->vlayer = vlayer;
 +      item->id = item_id;
 +      item->value = value;
 +
 +      return item;
 +}
 +
 +/* Create item containing 1 integer */
 +static uint32_item *create_uint32_item(VLayer *vlayer, uint32 item_id, uint32 value)
 +{
 +      struct uint32_item *item;
 +
 +      item = (uint32_item*)MEM_mallocN(sizeof(uint32_item), "uint32_item");
 +
 +      item->vlayer = vlayer;
 +      item->id = item_id;
 +      item->value = value;
 +
 +      return item;
 +}
 +
 +/* Create item containing 1 byte */
 +static uint8_item *create_uint8_item(VLayer *vlayer, uint32 item_id, uint8 value)
 +{
 +      struct uint8_item *item;
 +
 +      item = (uint8_item*)MEM_mallocN(sizeof(uint8_item), "uint8_item");
 +
 +      item->vlayer = vlayer;
 +      item->id = item_id;
 +      item->value = value;
 +
 +      return item;
 +}
 +
 +/*
 + * callback function: vertex crease was set
 + */
 +static void cb_g_crease_set_vertex(
 +              void *user_data,
 +              VNodeID node_id,
 +              const char *layer,
 +              uint32 def_crease)
 +{
 +}
 +
 +/*
 + * we have to test corretness of incoming data from verse server
 + * no two vertexes can have the same index
 + */
 +static char test_polygon_set_corner_uint32(
 +              uint32 v0,
 +              uint32 v1,
 +              uint32 v2,
 +              uint32 v3)
 +{
 +      if((v0==v1) || (v0==v2) || (v0==v3) || (v1==v2) || (v1==v3) || (v2==v3))
 +              return 0;
 +      else
 +              return 1;
 +}
 +
 +/*
 + * try to find verse layer in sending queue of verse geometry node
 + */
 +static VLayer *find_vlayer_in_sending_queue(VNode *vnode, VLayerID layer_id)
 +{
 +      struct VLayer *vlayer;
 +      
 +      /* try to find verse layyer in sending queue */
 +      vlayer = ((VGeomData*)vnode->data)->queue.first;
 +      while(vlayer) {
 +              if(vlayer->id==layer_id) return vlayer;
 +              vlayer = vlayer->next;
 +      }
 +
 +      return NULL;
 +}
 +
 +/*
 + * this function will find edge in hash table, hash function isn't too optimal (it needs
 + * lot of memory for every verse node), but it works without any bug
 + */
 +static VerseEdge* find_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
 +{
 +      struct HashVerseEdge *hve;
 +
 +      if(((VGeomData*)vnode->data)->hash==NULL)
 +              ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
 +
 +      hve = ((VGeomData*)vnode->data)->hash + VEDHASH(v0, v1);;
 +      while(hve) {
 +              /* edge v0---v1 is the same edge as v1---v0 */
 +              if(hve->vedge && ((hve->vedge->v0==v0 && hve->vedge->v1==v1) || (hve->vedge->v0==v1 && hve->vedge->v1==v0))) return hve->vedge;
 +              hve = hve->next;
 +      }
 +
 +      return NULL;
 +}
 +
 +/*
 + * insert hash of verse edge to hash table
 + */
 +static void insert_verse_edgehash(VNode *vnode, VerseEdge *vedge)
 +{
 +      struct HashVerseEdge *first, *hve;
 +
 +      if(((VGeomData*)vnode->data)->hash==NULL)
 +              ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
 +
 +      first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1);
 +
 +      if(first->vedge==NULL) {
 +              first->vedge = vedge;
 +      }
 +      else {
 +              hve = &(vedge->hash);
 +              hve->vedge = vedge;
 +              hve->next = first->next;
 +              first->next = hve;
 +      }
 +}
 +
 +/*
 + * remove hash of verse edge from hash table
 + */
 +static void remove_verse_edgehash(VNode *vnode, VerseEdge *vedge)
 +{
 +      struct HashVerseEdge *first, *hve, *prev;
 +
 +      hve = first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1);
 +
 +      while(hve) {
 +              if(hve->vedge == vedge) {
 +                      if(hve==first) {
 +                              if(first->next) {
 +                                      hve = first->next;
 +                                      first->vedge = hve->vedge;
 +                                      first->next = hve->next;
 +                              }
 +                              else {
 +                                      hve->vedge = NULL;
 +                              }
 +                      }
 +                      else {
 +                              prev->next = hve->next;
 +                      }
 +                      return;
 +              }
 +              prev = hve;
 +              hve = hve->next;
 +      }
 +}
 +
 +/*
 + * this function will try to remove existing fake verse edge, when this verse
 + * edge is still used by some faces, then counter will be only decremented
 + */
 +static void remove_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
 +{
 +      struct VerseEdge *vedge;
 +
 +      vedge = find_verse_edge(vnode, v0, v1);
 +      if(vedge) {
 +              vedge->counter--;
 +              if(vedge->counter==0) {
 +                      remove_verse_edgehash(vnode, vedge);
 +                      BLI_freelinkN(&(((VGeomData*)vnode->data)->edges), vedge);
 +              }
 +      }
 +      else {
 +              printf("error: remove_verse_edge %d, %d\n", v0, v1);
 +      }
 +}
 +
 +/*
 + * this function will try to add new fake verse edge, when no such edge exist,
 + * when such edge exist, then only counter of edge will be incremented
 + */
 +static void add_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
 +{
 +      struct VerseEdge *vedge;
 +
 +      vedge = find_verse_edge(vnode, v0, v1);
 +      if(!vedge) {
 +              if(v0!=v1) {
 +                      vedge = create_verse_edge(v0, v1);
 +                      BLI_addtail(&(((VGeomData*)vnode->data)->edges), vedge);
 +                      insert_verse_edgehash(vnode, vedge);
 +              }
 +              else {
 +                      printf("error:add_verse_edge: %d, %d\n", v0, v1);
 +                      return;
 +              }
 +      }
 +      vedge->counter++;
 +}
 +
 +/*
 + * verse face was deleted ... update edge hash
 + */
 +static void update_edgehash_of_deleted_verseface(VNode *vnode, VerseFace *vface)
 +{
 +      uint32 v0, v1, v2, v3;          /* verse vertex indexes of deleted verse face */
 +      
 +      v0 = vface->vvert0->id;
 +      v1 = vface->vvert1->id;
 +      v2 = vface->vvert2->id;
 +      v3 = vface->vvert3 ? vface->vvert3->id : -1;
 +
 +      remove_verse_edge(vnode, v0, v1);
 +      remove_verse_edge(vnode, v1, v2);
 +      if(v3!=-1) {
 +              remove_verse_edge(vnode, v2, v3);
 +              remove_verse_edge(vnode, v3, v0);
 +      }
 +      else {
 +              remove_verse_edge(vnode, v2, v0);
 +      }
 +}
 +
 +/*
 + * existing verse face was changed ... update edge hash
 + */
 +static void update_edgehash_of_changed_verseface(
 +              VNode *vnode,
 +              VerseFace *vface,
 +              uint32 v0,
 +              uint32 v1,
 +              uint32 v2,
 +              uint32 v3)
 +{
 +      uint32 ov0, ov1, ov2, ov3;      /* old indexes at verse vertexes*/
 +      
 +      ov0 = vface->vvert0->id;
 +      ov1 = vface->vvert1->id;
 +      ov2 = vface->vvert2->id;
 +      ov3 = vface->vvert3 ? vface->vvert3->id : -1;
 +
 +      /* 1st edge */
 +      if(v0!=ov0 || v1!=ov1) {
 +              remove_verse_edge(vnode, ov0, ov1);
 +              add_verse_edge(vnode, v0, v1);
 +      }
 +      
 +      /* 2nd edge */
 +      if(v1!=ov1 || v2!=ov2) {
 +              remove_verse_edge(vnode, ov1, ov2);
 +              add_verse_edge(vnode, v1, v2);
 +      }
 +
 +      /* 3rd edge */
 +      if(v2!=ov2 || v3!=ov3 || v0!=ov0) {
 +              if(ov3!=-1) {
 +                      remove_verse_edge(vnode, ov2, ov3);
 +                      if(v3!=-1) {
 +                              add_verse_edge(vnode, v2, v3);          /* new 3rd edge (quat->quat) */
 +                      }
 +                      else {
 +                              remove_verse_edge(vnode, ov3, ov0);     /* old edge v3,v0 of quat have to be removed */
 +                              add_verse_edge(vnode, v2, v0);          /* new 3rd edge (quat->triangle) */     
 +                      }
 +              }
 +              else {
 +                      remove_verse_edge(vnode, ov2, ov0);
 +                      if(v3!=-1) {
 +                              add_verse_edge(vnode, v2, v3);          /* new 3rd edge (triangle->quat) */
 +                      }
 +                      else {
 +                              add_verse_edge(vnode, v2, v0);          /* new 3rd edge (triangle->triangle) */
 +                      }
 +              }
 +      }
 +
 +      /* 4th edge */
 +      if(v3!=-1 && (v3!=ov3 || v0!=ov0)) {
 +              remove_verse_edge(vnode, ov3, ov0);
 +              add_verse_edge(vnode, v3, v0);
 +      }
 +}
 +
 +/*
 + * new verse face was created ... update list of edges and edge has
 + */
 +static void update_edgehash_of_new_verseface(
 +              VNode *vnode,
 +              uint32 v0,
 +              uint32 v1,
 +              uint32 v2,
 +              uint32 v3)
 +{
 +      /* when edge already exists, then only its counter is incremented,
 +       * look at commentary of add_verse_edge() function */
 +      add_verse_edge(vnode, v0, v1);
 +      add_verse_edge(vnode, v1, v2);
 +      if(v3!=-1) {
 +              add_verse_edge(vnode, v2, v3);
 +              add_verse_edge(vnode, v3, v0);
 +      }
 +      else {
 +              add_verse_edge(vnode, v2, v0);
 +      }
 +}
 +
 +/*
 + * callback function: edge crease was set
 + */
 +static void cb_g_crease_set_edge(
 +              void *user_data,
 +              VNodeID node_id,
 +              const char *layer,
 +              uint32 def_crease)
 +{
 +}
 +
 +/*
 + * callback function: float value for polygon was set up
 + */
 +static void cb_g_polygon_set_face_real32(
 +              void *user_def,
 +              VNodeID node_id,
 +              VLayerID layer_id,
 +              uint32 polygon_id,
 +              real32 value)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VLayer *vlayer;
 +      struct real32_item *item;
 +
 +      if(!session) return;
 +
 +      /* find needed node (we can be sure, that it is geometry node) */
 +      vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +
 +      /* find layer containing uint_8 data */
 +      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
 +
 +      /* try to find item*/
 +      item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
 +
 +      if(item) {
 +              item->value = value;
 +      }
 +      else {
 +              item = create_real32_item(vlayer, polygon_id, value);
 +              BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
 +      }
 +}
 +
 +/*
 + * callback function: int values for polygon was set up
 + */
 +static void cb_g_polygon_set_face_uint32(
 +              void *user_def,
 +              VNodeID node_id,
 +              VLayerID layer_id,
 +              uint32 polygon_id,
 +              uint32 value)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VLayer *vlayer;
 +      struct uint32_item *item;
 +
 +      if(!session) return;
 +
 +      /* find needed node (we can be sure, that it is geometry node) */
 +      vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +
 +      /* find layer containing uint_8 data */
 +      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
 +
 +      /* try to find item*/
 +      item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
 +
 +      if(item) {
 +              item->value = value;
 +      }
 +      else {
 +              item = create_uint32_item(vlayer, polygon_id, value);
 +              BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
 +      }
 +}
 +
 +/*
 + * callback function: uint8 value for polygon was set up
 + */
 +static void cb_g_polygon_set_face_uint8(
 +              void *user_def,
 +              VNodeID node_id,
 +              VLayerID layer_id,
 +              uint32 polygon_id,
 +              uint8 value)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VLayer *vlayer;
 +      struct uint8_item *item;
 +
 +      if(!session) return;
 +
 +      /* find needed node (we can be sure, that it is geometry node) */
 +      vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +
 +      /* find layer containing uint_8 data */
 +      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
 +
 +      /* try to find item*/
 +      item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
 +
 +      if(item) {
 +              item->value = value;
 +      }
 +      else {
 +              item = create_uint8_item(vlayer, polygon_id, value);
 +              BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
 +      }
 +}
 +
 +/*
 + * callback function: float value for polygon corner was set up
 + */
 +static void cb_g_polygon_set_corner_real32(
 +              void *user_def,
 +              VNodeID node_id,
 +              VLayerID layer_id,
 +              uint32 polygon_id,
 +              real32 v0,
 +              real32 v1,
 +              real32 v2,
 +              real32 v3)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VLayer *vlayer;
 +      struct quat_real32_item *item;
 +
 +      if(!session) return;
 +
 +      /* find needed node (we can be sure, that it is geometry node) */
 +      vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +
 +      /* find layer containing uint_8 data */
 +      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
 +
 +      /* try to find item*/
 +      item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
 +
 +      if(item) {
 +              item->value[0] = v0;
 +              item->value[1] = v1;
 +              item->value[2] = v2;
 +              item->value[3] = v3;
 +      }
 +      else {
 +              item = create_quat_real32_item(vlayer, polygon_id, v0, v1, v2, v3);
 +              BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
 +      }
 +}
 +
 +/*
 + * callback function: polygon is deleted
 + */
 +static void cb_g_polygon_delete(
 +              void *user_data,
 +              VNodeID node_id,
 +              uint32 polygon_id)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      VNode *vnode;
 +      VLayer *vlayer;
 +      VerseFace *vface;
 +
 +      if(!session) return;
 +
 +      /* find needed node (we can be sure, that it is geometry node) */
 +      vnode = BLI_dlist_find_link(&(session->nodes), node_id);
 +
 +      /* find layer containing faces */
 +      vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
 +
 +      /* find wanted VerseFace */
 +      vface = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
 +
 +      if(!vface) return;
 +
 +      /* update edge hash */
 +      update_edgehash_of_deleted_verseface(vnode, vface);
 +      
 +      ((VGeomData*)vnode->data)->post_polygon_delete(vface);
 +
 +      /* decrease references at coresponding VerseVertexes */
 +      vface->vvert0->counter--;
 +      vface->vvert1->counter--;
 +      vface->vvert2->counter--;
 +      if(vface->vvert3) vface->vvert3->counter--;
 +
 +      /* delete unneeded VerseVertexes */
 +      free_unneeded_verseverts_of_verseface(vnode, vface);
 +      
 +      free_verse_face(vlayer, vface);
 +}
 +
 +/*
 + * callback function: new polygon (face) created or existing polygon was changed
 + */
 +static void cb_g_polygon_set_corner_uint32(
 +              void *user_data,
 +              VNodeID node_id,
 +              VLayerID layer_id,
 +              uint32 polygon_id,
 +              uint32 v0,
 +              uint32 v1,
 +              uint32 v2,
 +              uint32 v3)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VLayer *vlayer;
 +      struct VerseFace *vface=NULL;
 +
 +      if(!session) return;
 +
 +      /* try to find VerseNode */
 +      vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +      if(!vnode) return;
 +
 +      /* try to find VerseLayer */
 +      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
 +      if(!vlayer) return;
 +
 +      /* we have to test coretness of incoming data */
 +      if(!test_polygon_set_corner_uint32(v0, v1, v2, v3)) return;
 +      
 +      /* Blender uses different order of vertexes */
 +      if(v3!=-1) { /* quat swap */
 +              unsigned int v; v = v1; v1 = v3; v3 = v;
 +      }
 +      else { /* triangle swap */
 +              unsigned int v; v = v1; v1 = v2; v2 = v;
 +      }
 +
 +      /* try to find VerseFace */
 +      vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)polygon_id);
 +
 +      /* try to find modified VerseFace */
 +      if(!vface) {
 +              vface = find_changed_verse_face_in_queue(vlayer, polygon_id);
 +              if(vface) {
 +                      BLI_remlink(&(vlayer->queue), (void*)vface);
 +                      BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id);
 +              }
 +      }
 +
 +      if(!vface) {
 +              /* try to find VerseFace in list of VerseVaces created by me and set up polygon and
 +               * layer ids */
 +              vface = find_verse_face_in_queue(vlayer, node_id, polygon_id, v0, v1, v2, v3);
 +              
 +              /* update edge hash */
 +              update_edgehash_of_new_verseface(vnode, v0, v1, v2, v3);
 +              
 +              if(vface){
 +                      /* I creeated this face ... remove VerseFace from queue */
 +                      BLI_remlink(&(vlayer->queue), (void*)vface);
 +              }
 +              else {
 +                      /* some other client created this face*/
 +                      vface = create_verse_face(vlayer, polygon_id, v0, v1, v2, v3);
 +              }
 +
 +              vface->flag &= ~FACE_SENT;
 +
 +              /* return number of missing verse vertexes */
 +              vface->counter = test_incoming_verseface((VGeomData*)vnode->data, vface);
 +
 +              if(vface->counter < 1) {
 +                      /* when VerseFace received all needed VerseFaces, then it is moved
 +                       * to list of VerseFaces */
 +                      BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id);
 +                      increase_verse_verts_references(vface);
 +                      recalculate_verseface_normals(vnode);
 +                      ((VGeomData*)vnode->data)->post_polygon_create(vface);
 +              }
 +              else {
 +                      /* when all needed VerseVertexes weren't received, then VerseFace is moved to
 +                       * the list of orphans waiting on needed vertexes */
 +                      vface->flag |= FACE_RECEIVED;
 +                      BLI_addtail(&(vlayer->orphans), (void*)vface);
 +              }
 +      }
 +      else {
 +              VLayer *vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
 +              /* VerseVertexes of existing VerseFace were changed (VerseFace will use some different
 +               * VerseVertexes or it will use them in different order) */
 +
 +              /* update fake verse edges */
 +              update_edgehash_of_changed_verseface(vnode, vface, v0, v1, v2, v3);
 +              
 +              /* initialize count of unreceived vertexes needed for this face */
 +              vface->counter = 4;
 +
 +              /* 1st corner */
 +              if(vface->vvert0->id != v0) {
 +                      /* decrease references of obsolete vertexes*/
 +                      vface->vvert0->counter--;
 +                      /* delete this vertex, when it isn't used by any face and it was marked as deleted */
 +                      if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) {
 +                              ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0);
 +                              free_verse_vertex(vert_vlayer, vface->vvert0);
 +                      }
 +                      /* try to set up new pointer at verse vertex */
 +                      vface->v0 = v0;
 +                      vface->vvert0 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v0);
 +                      if(vface->vvert0) {
 +                              /* increase references at new vertex */
 +                              vface->vvert0->counter++;
 +                              /* decrease count of needed vertex to receive */
 +                              vface->counter--;
 +                      }
 +                      
 +              }
 +              else
 +                      /* this corner wasn't changed */
 +                      vface->counter--;
 +
 +              /* 2nd corner */
 +              if(vface->vvert1->id != v1) {
 +                      vface->vvert1->counter--;
 +                      if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) {
 +                              ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1);
 +                              free_verse_vertex(vert_vlayer, vface->vvert1);
 +                      }
 +                      vface->v1 = v1;
 +                      vface->vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v1);
 +                      if(vface->vvert1) {
 +                              vface->vvert1->counter++;
 +                              vface->counter--;
 +                      }
 +              }
 +              else
 +                      vface->counter--;
 +
 +              /* 3rd corner */
 +              if(vface->vvert2->id != v2) {
 +                      vface->vvert2->counter--;
 +                      if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) {
 +                              ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2);
 +                              free_verse_vertex(vert_vlayer, vface->vvert2);
 +                      }
 +                      vface->v2 = v2;
 +                      vface->vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v2);
 +                      if(vface->vvert2) {
 +                              vface->vvert2->counter++;
 +                              vface->counter--;
 +                      }
 +              }
 +              else
 +                      vface->counter--;
 +      
 +              /* 4th corner */        
 +              if(vface->vvert3) {
 +                      if(vface->vvert3->id != v3) {
 +                              vface->vvert3->counter--;
 +                              if((vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) {
 +                                      ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3);
 +                                      free_verse_vertex(vert_vlayer, vface->vvert3);
 +                              }
 +                              vface->v3 = v3;
 +                              if(v3 != -1) {
 +                                      vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3);
 +                                      if(vface->vvert3) {
 +                                              vface->vvert3->counter++;
 +                                              vface->counter--;
 +                                      }
 +                              }
 +                              else {
 +                                      /* this is some special case, this face hase now only 3 corners
 +                                       * quat -> triangle */
 +                                      vface->vvert3 = NULL;
 +                                      vface->counter--;
 +                              }
 +                      }
 +              }
 +              else if(v3 != -1)
 +                      /* this is some special case, 4th corner of this polygon was created
 +                       * triangle -> quat */
 +                      vface->v3 = v3;
 +                      vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3);
 +                      if(vface->vvert3) {
 +                              vface->vvert3->counter++;
 +                              vface->counter--;
 +                      }
 +              else {
 +                      vface->v3 = -1;
 +                      vface->counter--;
 +              }
 +              
 +              vface->flag &= ~FACE_SENT;
 +              vface->flag |= FACE_CHANGED;
 +
 +              if(vface->counter<1) {
 +                      vface->flag &= ~FACE_CHANGED;
 +                      recalculate_verseface_normals(vnode);
 +                      ((VGeomData*)vnode->data)->post_polygon_set_corner(vface);
 +              }
 +              else {
 +                      /* when all needed VerseVertexes weren't received, then VerseFace is added to
 +                       * the list of orphans waiting on needed vertexes */
 +                      BLI_dlist_rem_item(&(vlayer->dl), vface->id);
 +                      BLI_addtail(&(vlayer->orphans), (void*)vface);
 +              }
 +      }
 +}
 +
 +/*
 + * callback function: float value was set up for VerseVert with vertex_id
 + */
 +static void cb_g_vertex_set_real32(
 +              void *user_def,
 +              VNodeID node_id,
 +              VLayerID layer_id,
 +              uint32 vertex_id,
 +              real32 value)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VLayer *vlayer;
 +      struct real32_item *item;
 +
 +      if(!session) return;
 +
 +      /* find needed node (we can be sure, that it is geometry node) */
 +      vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +
 +      /* find layer containing uint_8 data */
 +      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
 +
 +      /* try to find item*/
 +      item = BLI_dlist_find_link(&(vlayer->dl), vertex_id);
 +
 +      if(item) {
 +              item->value = value;
 +      }
 +      else {
 +              item = create_real32_item(vlayer, vertex_id, value);
 +              BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
 +      }
 +}
 +
 +/*
 + * callback function: int value was set up for VerseVert with vertex_id
 + */
 +static void cb_g_vertex_set_uint32(
 +              void *user_def,
 +              VNodeID node_id,
 +              VLayerID layer_id,
 +              uint32 vertex_id,
 +              uint32 value)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VLayer *vlayer;
 +      struct uint32_item *item;
 +
 +      if(!session) return;
 +
 +      /* find needed node (we can be sure, that it is geometry node) */
 +      vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +
 +      /* find layer containing uint_8 data */
 +      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
 +
 +      /* try to find item*/
 +      item = BLI_dlist_find_link(&(vlayer->dl), vertex_id);
 +
 +      if(item) {
 +              item->value = value;
 +      }
 +      else {
 +              item = create_uint32_item(vlayer, vertex_id, value);
 +              BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
 +      }
 +}
 +
 +/*
 + * callback function: polygon was deleted
 + */
 +static void cb_g_vertex_delete_real32(
 +              void *user_data,
 +              VNodeID node_id,
 +              uint32 vertex_id)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      VNode *vnode=NULL;
 +      VLayer *vert_vlayer=NULL;
 +      VerseVert *vvert=NULL;
 +
 +      if(!session) return;
 +
 +      vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +
 +      vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
 +
 +      vvert = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vertex_id);
 +
 +      if(!vvert) return;
 +
 +      if(vvert->counter < 1) {
 +              ((VGeomData*)vnode->data)->post_vertex_delete(vvert);
 +              BLI_dlist_free_item(&(vert_vlayer->dl), (unsigned int)vertex_id);
 +      }
 +      else {
 +              /* some VerseFace(s) still need VerseVert, remove verse vert from
 +               * list verse vertexes and put it to list of orphans */
 +              vvert->flag |= VERT_DELETED;
 +              BLI_dlist_rem_item(&(vert_vlayer->dl), (unsigned int)vertex_id);
 +              BLI_addtail(&(vert_vlayer->orphans), vvert);
 +      }
 +}
 +
 +/*
 + * callback function: position of one vertex was changed or new vertex was created
 + */
 +static void cb_g_vertex_set_xyz_real32(
 +              void *user_data,
 +              VNodeID node_id,
 +              VLayerID layer_id,
 +              uint32 vertex_id,
 +              real32 x,
 +              real32 y,
 +              real32 z)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode = NULL;
 +      struct VLayer *vlayer = NULL;
 +      struct VerseVert *vvert = NULL;
 +      real32 tmp;
 +
 +      if(!session) return;
 +
 +      vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +      if(!vnode)return;
 +
 +      vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
 +      if(!vlayer) return;
 +
 +      /* switch axis orientation */
 +      tmp = y;
 +      y = -z;
 +      z = tmp;
 +      
 +      if(vlayer->id == 0) {
 +              /* try to pick up verse vert from DynamicList */
 +              vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)vertex_id);
 +
 +              if(vvert) {
 +                      if(vvert->flag & VERT_OBSOLETE) return;
 +
 +                      if (vvert->flag & VERT_LOCKED) {
 +                              /* this application changed position of this vertex */
 +                              if((vvert->co[0]==x) && (vvert->co[1]==y) && (vvert->co[2]==z)) {
 +                                      /* unlock vertex position */
 +                                      vvert->flag &= ~VERT_LOCKED;
 +                                      /* call post_vertex_set_xyz only, when position of vertex is
 +                                       * obsolete ... the new vertex position will be sent to
 +                                       * verse server */
 +                                      if (vvert->flag & VERT_POS_OBSOLETE) {
 +                                              ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert);
 +                                      }
 +                              }
 +                      }
 +                      else {
 +                              /* somebody else changed position of this vertex*/
 +                              if((vvert->co[0]!=x) || (vvert->co[1]!=y) || (vvert->co[2]!=z)) {
 +                                      vvert->co[0] = x;
 +                                      vvert->co[1] = y;
 +                                      vvert->co[2] = z;
 +                                      recalculate_verseface_normals(vnode);
 +                                      ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert);
 +                              }
 +                      }
 +              }
 +              else {
 +                      /* create new verse vert */
 +
 +                      /* test if we are authors of this vertex :-) */
 +                      vvert = find_verse_vert_in_queue(vlayer, node_id, vertex_id, x, y, z);
 +
 +                      if(vvert) {
 +                              /* remove vert from queue */
 +                              BLI_remlink(&(vlayer->queue), (void*)vvert);
 +                              /* add vvert to the dynamic list */
 +                              BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id);
 +                              /* set VerseVert flags */
 +                              vvert->flag |= VERT_RECEIVED;
 +                              if(!(vvert->flag & VERT_POS_OBSOLETE))
 +                                      vvert->flag &= ~VERT_LOCKED;
 +                              /* find VerseFaces orphans */
 +                              find_vlayer_orphans(vnode, vvert);
 +                              /* find unsent VerseFaces */
 +                              find_unsent_faces(vnode, vvert);
 +                      }
 +                      else {
 +                              /* create new VerseVert */
 +                              vvert = create_verse_vertex(vlayer, vertex_id, x, y, z);
 +                              /* add VerseVert to list of VerseVerts */
 +                              BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id);
 +                              /* set VerseVert flags */
 +                              vvert->flag |= VERT_RECEIVED;
 +                              /* find VerseFaces orphans */
 +                              find_vlayer_orphans(vnode, vvert);
 +                      }
 +
 +                      ((VGeomData*)vnode->data)->post_vertex_create(vvert);
 +              }
 +      }
 +}
 +
 +/*
 + * callback function for destroyng of verse layer
 + */
 +static void cb_g_layer_destroy(
 +              void *user_data,
 +              VNodeID node_id,
 +              VLayerID layer_id)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VLayer *vlayer;
 +
 +      if(!session) return;
 +
 +      vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), node_id);
 +      if(!vnode) return;
 +
 +      vlayer = (VLayer*) BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), layer_id);
 +
 +      if(vlayer){
 +              /* free VerseLayer data */
 +              free_verse_layer_data(vnode, vlayer);
 +              /* remove VerseLayer from list of verse layers */
 +              BLI_dlist_rem_item(&(((VGeomData*)vnode->data)->layers), layer_id);
 +              /* do client dependent actions */
 +              vlayer->post_layer_destroy(vlayer);
 +              /* free vlayer itself */
 +              MEM_freeN(vlayer);
 +      }
 +
 +}
 +
 +/*
 + * callback function: new layer was created
 + */
 +static void cb_g_layer_create(
 +              void *user_data,
 +              VNodeID node_id,
 +              VLayerID layer_id,
 +              const char *name,
 +              VNGLayerType type,
 +              uint32 def_integer,
 +              real64 def_real)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode=NULL;
 +      struct VLayer *vlayer=NULL;
 +
 +      if(!session) return;
 +
 +      /* find node of this layer*/
 +      vnode = BLI_dlist_find_link(&(session->nodes), node_id);
 +      if(!vnode) return;
 +
 +      /* when we created this layer, then subscribe to this layer */
 +      if(vnode->owner_id == VN_OWNER_MINE || session->flag & VERSE_AUTOSUBSCRIBE)
 +              verse_send_g_layer_subscribe(node_id, layer_id, 0);
 +
 +      /* try to find */
 +      if(vnode->owner_id == VN_OWNER_MINE)
 +              vlayer = find_vlayer_in_sending_queue(vnode, layer_id);
 +
 +      if(vlayer) {
 +              /* remove vlayer form sending queue add verse layer to list of verse layers */
 +              BLI_remlink(&((VGeomData*)vnode->data)->queue, vlayer);
 +              BLI_dlist_add_item_index(&((VGeomData*)vnode->data)->layers, (void*)vlayer, (unsigned int)vlayer->id);
 +              /* send all not sent vertexes to verse server
 +               * other items waiting in sending queue will be automaticaly sent to verse server,
 +               * when verse vertexes will be received from verse server */
 +              if((vlayer->type == VN_G_LAYER_VERTEX_XYZ) && (layer_id==0)) {
 +                      struct VerseVert *vvert = (VerseVert*)vlayer->queue.first;
 +                      while(vvert) {
 +                              send_verse_vertex(vvert);
 +                              vvert = vvert->next;
 +                      }
 +              }
 +      }
 +      else {
 +              /* create new VerseLayer */
 +              vlayer = create_verse_layer(vnode, layer_id, name, type, def_integer, def_real);
 +              /* add layer to the list of VerseLayers */
 +              BLI_dlist_add_item_index(&(((VGeomData*)vnode->data)->layers), (void*)vlayer, (unsigned int)layer_id);
 +      }
 +
 +      vlayer->flag |= LAYER_RECEIVED;
 +
 +      /* post callback function */
 +      vlayer->post_layer_create(vlayer);
 +}
 +
 +/*
 + * this function will send destroy commands for all VerseVertexes and
 + * VerseFaces to verse server, but it will not send destroy commands
 + * for VerseLayers or geometry node, it can be used in other functions
 + * (undo, destroy geom node, some edit mesh commands, ... ), parameter of
 + * this function has to be geometry verse node
 + */
 +void destroy_geometry(VNode *vnode)
 +{
 +      struct VLayer *vert_vlayer, *face_vlayer;
 +      struct VerseFace *vface;
 +      struct VerseVert *vvert;
 +
 +      if(vnode->type != V_NT_GEOMETRY) return;
 +
 +      face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
 +      vface = face_vlayer->dl.lb.first;
 +
 +      while(vface) {
 +              send_verse_face_delete(vface);
 +              vface = vface->next;
 +      }
 +
 +      vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
 +      vvert = vert_vlayer->dl.lb.first;
 +
 +      while(vvert) {
 +              send_verse_vertex_delete(vvert);
 +              vvert = vvert->next;
 +      }
 +
 +      /* own destruction of local verse date will be executed, when client will
 +       * receive apropriate callback commands from verse server */
 +}
 +
 +/*
 + * free VGeomData
 + */
 +void free_geom_data(VNode *vnode)
 +{
 +      struct VerseSession *session = vnode->session;
 +      struct VLayer *vlayer;
 +
 +      if(vnode->data){
 +              vlayer = (VLayer*)((VGeomData*)vnode->data)->layers.lb.first;
 +              while(vlayer){
 +                      /* unsubscribe from layer */
 +                      if(session->flag & VERSE_CONNECTED)
 +                              verse_send_g_layer_unsubscribe(vnode->id, vlayer->id);
 +                      /* free VerseLayer data */
 +                      free_verse_layer_data(vnode, vlayer);
 +                      /* next layer */
 +                      vlayer = vlayer->next;
 +              }
 +              /* free constraint between vnode and mesh */
 +              ((VGeomData*)vnode->data)->post_geometry_free_constraint(vnode);
 +              /* free all VerseLayers */
 +              BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers));
 +              /* free fake verse edges */
 +              BLI_freelistN(&((VGeomData*)vnode->data)->edges);
 +              /* free edge hash */
 +              MEM_freeN(((VGeomData*)vnode->data)->hash);
 +      }
 +}
 +
 +void set_geometry_callbacks(void)
 +{
 +      /* new layer created */
 +      verse_callback_set(verse_send_g_layer_create, cb_g_layer_create, NULL);
 +      /* layer was destroyed */
 +      verse_callback_set(verse_send_g_layer_destroy, cb_g_layer_destroy, NULL);
 +
 +      /* position of vertex was changed */
 +      verse_callback_set(verse_send_g_vertex_set_xyz_real32, cb_g_vertex_set_xyz_real32, NULL);
 +      /* vertex was deleted */
 +      verse_callback_set(verse_send_g_vertex_delete_real32, cb_g_vertex_delete_real32, NULL);
 +
 +      /* callback functions for values being associated with vertexes */
 +      verse_callback_set(verse_send_g_vertex_set_uint32, cb_g_vertex_set_uint32, NULL);
 +      verse_callback_set(verse_send_g_vertex_set_real32, cb_g_vertex_set_real32, NULL);
 +
 +      /* new polygon was created / vertex(es) of polygon was set */
 +      verse_callback_set(verse_send_g_polygon_set_corner_uint32, cb_g_polygon_set_corner_uint32, NULL);
 +      /* polygon was deleted */
 +      verse_callback_set(verse_send_g_polygon_delete, cb_g_polygon_delete, NULL);
 +
 +      /* callback functions for values being associated with polygon corners */
 +      verse_callback_set(verse_send_g_polygon_set_corner_real32, cb_g_polygon_set_corner_real32, NULL);
 +      /* callback functions for values being associated with faces */
 +      verse_callback_set(verse_send_g_polygon_set_face_uint8, cb_g_polygon_set_face_uint8, NULL);
 +      verse_callback_set(verse_send_g_polygon_set_face_uint32, cb_g_polygon_set_face_uint32, NULL);
 +      verse_callback_set(verse_send_g_polygon_set_face_real32, cb_g_polygon_set_face_real32, NULL);
 +
 +      /* crease of vertex was set */
 +      verse_callback_set(verse_send_g_crease_set_vertex, cb_g_crease_set_vertex, NULL);
 +      /* crease of edge was set */
 +      verse_callback_set(verse_send_g_crease_set_edge, cb_g_crease_set_edge, NULL);
 +}
 +
 +#endif
index 89b5282acfd8011e8a0cac4b5ec18b71919e3d98,0000000000000000000000000000000000000000..20f7e2c9f9d65aff4fb8ff567f9ff2de1edc9408
mode 100644,000000..100644
--- /dev/null
@@@ -1,523 -1,0 +1,523 @@@
- #include "BLI_arithb.h"
 +/**
 + * $Id$
 + *
 + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version. The Blender
 + * Foundation also sells licenses for use in proprietary software under
 + * the Blender License.  See http://www.blender.org/BL/ for information
 + * about this.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * Contributor(s): Nathan Letwory. 
 + *
 + * ***** END GPL/BL DUAL LICENSE BLOCK *****
 + */
 +
 +#ifdef WITH_VERSE
 +
 +#include <string.h>
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "DNA_listBase.h"
 +#include "DNA_userdef_types.h"
 +#include "DNA_text_types.h"
 +
 +#include "BLI_dynamiclist.h"
 +#include "BLI_blenlib.h"
++#include "BLI_math.h"
 +
 +#include "BIF_verse.h"
 +
 +#include "BKE_bad_level_calls.h"
 +#include "BKE_library.h"
 +#include "BKE_text.h"
 +#include "BKE_verse.h"
 +#include "BKE_global.h"
 +#include "BKE_main.h"
 +
 +#include "verse.h"
 +
 +/* helper struct for creating method descriptions */
 +typedef struct VMethodInfo {
 +      const char *name;
 +      uint8 param_count;
 +      const VNOParamType param_type[4];
 +      const char *param_name[4];
 +      uint16 id;
 +} VMethodInfo;
 +
 +#ifdef VERSECHAT
 +/* array with methods for verse chat */
 +static VMethodInfo vmethod_info[] = {
 +      { "join", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}},
 +      { "leave", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}},
 +      { "hear", 3, { VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING }, { "channel", "from", "msg"}}
 +};
 +#endif
 +
 +/* lookup a method group based on its name */
 +struct VMethodGroup *lookup_vmethodgroup_name(ListBase *lb, const char *name) {
 +      struct VMethodGroup *vmg;
 +
 +      for(vmg= lb->first; vmg; vmg= vmg->next)
 +              if(strcmp(vmg->name,name)==0) break;
 +      
 +      return vmg;
 +}
 +
 +/* lookup a method group based on its group_id */
 +struct VMethodGroup *lookup_vmethodgroup(ListBase *lb, uint16 group_id) {
 +      struct VMethodGroup *vmg;
 +
 +      for(vmg= lb->first; vmg; vmg= vmg->next)
 +              if(vmg->group_id==group_id) break;
 +      
 +      return vmg;
 +}
 +
 +/* lookup a method based on its name */
 +struct VMethod *lookup_vmethod_name(ListBase *lb, const char *name) {
 +      struct VMethod *vm;
 +      for(vm= lb->first; vm; vm= vm->next)
 +              if(strcmp(vm->name,name)==0) break;
 +
 +      return vm;
 +}
 +
 +/* lookup a method based on its method_id */
 +struct VMethod *lookup_vmethod(ListBase *lb, uint8 method_id) {
 +      struct VMethod *vm;
 +      for(vm= lb->first; vm; vm= vm->next)
 +              if(vm->id==method_id) break;
 +
 +      return vm;
 +}
 +
 +#ifdef VERSECHAT
 +/*
 + * send say command
 + */
 +void send_say(const char *chan, const char *utter)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VMethodGroup *vmg;
 +      struct VMethod *vm;
 +      VNOPackedParams *utterpack;
 +      VNOParam args[2];
 +      
 +      vnode= (VNode *)(session->nodes.lb.first);
 +
 +      for( ; vnode; vnode= vnode->next) {
 +              if(strcmp(vnode->name, "tawksrv")==0) {
 +                      vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
 +                      if(!vmg) break;
 +                      vm= lookup_vmethod_name(&(vmg->methods), "say");
 +                      if(!vm) break;
 +                      args[0].vstring= (char *)chan;
 +                      args[1].vstring= (char *)utter;
 +                      if((utterpack= verse_method_call_pack(vm->param_count, vm->param_type, args))!=NULL) {
 +                              verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, utterpack);
 +                      }
 +                      break;
 +              }
 +
 +      }
 +}
 +
 +/*
 + * send logout command
 + */
 +void send_logout(VNode *vnode)
 +{
 +      struct VMethodGroup *vmg;
 +      struct VMethod *vm;
 +      VNOPackedParams *pack;
 +
 +      vnode->chat_flag = CHAT_LOGGED;
 +      vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
 +      if(!vmg) return;
 +      vm= lookup_vmethod_name(&(vmg->methods), "logout");
 +      if(!vm) return;
 +
 +      if((pack= verse_method_call_pack(vm->param_count, vm->param_type, NULL))!=NULL) {
 +              verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, pack);
 +      }
 +      vnode->chat_flag = CHAT_NOTLOGGED;
 +}
 +
 +/*
 + * send join command
 + */
 +void send_join(VNode *vnode, const char *chan)
 +{
 +      struct VMethodGroup *vmg;
 +      struct VMethod *vm;
 +      VNOPackedParams *join;
 +      VNOParam channel[1];
 +
 +      vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
 +      if(!vmg) return;
 +      vm= lookup_vmethod_name(&(vmg->methods), "join");
 +      if(!vm) return;
 +
 +      channel[0].vstring= (char *)chan;
 +      if((join= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) {
 +              verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, join);
 +      }
 +}
 +
 +/*
 + * send leave command
 + */
 +void send_leave(VNode *vnode, const char *chan)
 +{
 +      struct VMethodGroup *vmg;
 +      struct VMethod *vm;
 +      VNOPackedParams *leave;
 +      VNOParam channel[1];
 +
 +      vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
 +      if(!vmg) return;
 +      vm= lookup_vmethod_name(&(vmg->methods), "leave");
 +      if(!vm) return;
 +
 +      channel[0].vstring= (char *)chan;
 +      if((leave= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) {
 +              verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, leave);
 +      }
 +}
 +
 +/*
 + * send login command
 + */
 +void send_login(VNode *vnode)
 +{
 +      struct VMethodGroup *vmg;
 +      struct VMethod *vm;
 +      VNOPackedParams *login;
 +      VNOParam param[1];
 +
 +      vnode->chat_flag = CHAT_LOGGED;
 +      vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
 +      if(!vmg) return;
 +      vm= lookup_vmethod_name(&(vmg->methods), "login");
 +      if(!vm) return;
 +
 +      param[0].vstring= U.verseuser;
 +
 +      if((login= verse_method_call_pack(vm->param_count, vm->param_type, param))!=NULL) {
 +              verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, login);
 +      }
 +      vnode->chat_flag = CHAT_LOGGED;
 +
 +      vnode= lookup_vnode(vnode->session, vnode->session->avatar);
 +      vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk-client");
 +      if(!vmg)
 +              verse_send_o_method_group_create(vnode->session->avatar, ~0, "tawk-client");
 +}
 +#endif
 +
 +/*
 + * Free a VMethod
 + */
 +void free_verse_method(VMethod *vm) {
 +      if(!vm) return;
 +
 +      MEM_freeN(vm->param_type);
 +}
 +
 +/*
 + * Free methods for VMethodGroup
 + */
 +void free_verse_methodgroup(VMethodGroup *vmg)
 +{
 +      struct VMethod *vm, *tmpvm;
 +
 +      if(!vmg) return;
 +
 +      vm= vmg->methods.first;
 +      while(vm) {
 +              tmpvm=vm->next;
 +              free_verse_method(vm);
 +              vm= tmpvm;
 +      }
 +      BLI_freelistN(&(vmg->methods));
 +}
 +
 +/* callback for method group creation */
 +static void cb_o_method_group_create(
 +              void *user_data,
 +              VNodeID node_id,
 +              uint16 group_id,
 +              const char *name)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VMethodGroup *vmg;
 +
 +      if(!session) return;
 +
 +      vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +
 +      vmg = lookup_vmethodgroup(&(vnode->methodgroups), group_id);
 +      
 +      /* create method group holder in node node_id */
 +      if(!vmg) {
 +              vmg= MEM_mallocN(sizeof(VMethodGroup), "VMethodGroup");
 +              vmg->group_id = group_id;
 +              vmg->methods.first = vmg->methods.last = NULL;
 +              BLI_addtail(&(vnode->methodgroups), vmg);
 +              printf("new method group with name %s (group_id %d) for node %u created\n", name, group_id, node_id);
 +      }
 +
 +      /* this ensures name of an existing group gets updated, in case it is changed */
 +      BLI_strncpy(vmg->name, (char *)name, 16);
 +
 +      /* subscribe to method group */
 +      verse_send_o_method_group_subscribe(node_id, group_id);
 +
 +#ifdef VERSECHAT
 +      /* if this is our own method group, register our methods */
 +      if(node_id==session->avatar) {
 +              verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[0].name,
 +                              vmethod_info[0].param_count,
 +                              (VNOParamType *)vmethod_info[0].param_type,
 +                              (const char **)vmethod_info[0].param_name);
 +              b_verse_update();
 +              verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[1].name,
 +                              vmethod_info[1].param_count,
 +                              (VNOParamType *)vmethod_info[1].param_type,
 +                              (const char **)vmethod_info[1].param_name);
 +              b_verse_update();
 +              verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[2].name,
 +                              vmethod_info[2].param_count,
 +                              (VNOParamType *)vmethod_info[2].param_type,
 +                              (const char **)vmethod_info[2].param_name);
 +              b_verse_update();
 +      }
 +#endif
 +}
 +
 +/* callback for method group destruction */
 +static void cb_o_method_group_destroy(
 +              void *user_data,
 +              VNodeID node_id,
 +              uint16 group_id,
 +              const char *name)
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VMethodGroup *vmg;
 +      struct VMethod *vm;
 +
 +      printf("method group %d destroyed\n", group_id);
 +
 +      if(!session) return;
 +
 +      vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
 +      for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next)
 +              if(vmg->group_id==group_id) break;
 +
 +      if(!vmg) return; /* method group doesn't exist? */
 +
 +      vmg->group_id = 0;
 +      vmg->name[0] = '\0';
 +      vm= vmg->methods.first;
 +      while(vm) {
 +              /* free vm */
 +              
 +      }
 +
 +      /* TODO: unsubscribe from method group */
 +      BLI_remlink(&(vnode->methodgroups),vmg);
 +      MEM_freeN(vmg);
 +}
 +
 +/* callback for method creation */
 +static void cb_o_method_create(
 +              void *user_data,
 +              VNodeID node_id,
 +              uint16 group_id,
 +              uint16 method_id,
 +              const char *name,
 +              uint8 param_count,
 +              const VNOParamType *param_type,
 +              const char *param_name[])
 +{
 +      struct VerseSession *session = (VerseSession*)current_verse_session();
 +      struct VNode *vnode;
 +      struct VMethodGroup *vmg;
 +      struct VMethod *vm;
 +      unsigned int size;
 +      unsigned int i;
 +      char *put;
 +
 +      if(!session) return;