merge with 2.5 (not trunk, last merge message said that on accident) at r22252
authorJoseph Eagar <joeedh@gmail.com>
Thu, 6 Aug 2009 09:56:14 +0000 (09:56 +0000)
committerJoseph Eagar <joeedh@gmail.com>
Thu, 6 Aug 2009 09:56:14 +0000 (09:56 +0000)
56 files changed:
1  2 
SConstruct
projectfiles_vc9/blender/BPY_python/BPY_python.vcproj
projectfiles_vc9/blender/blender.sln
projectfiles_vc9/blender/blenkernel/BKE_blenkernel.vcproj
projectfiles_vc9/blender/editors/ED_editors.vcproj
projectfiles_vc9/blender/makesdna/DNA_makesdna.vcproj
source/blender/blenkernel/BKE_modifier.h
source/blender/blenkernel/SConscript
source/blender/blenkernel/intern/exotic.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/smoke.c
source/blender/blenkernel/intern/softbody.c
source/blender/blenlib/BLI_arithb.h
source/blender/blenlib/intern/arithb.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/armature/meshlaplacian.c
source/blender/editors/mesh/bmesh_tools.c
source/blender/editors/mesh/editmesh.c
source/blender/editors/mesh/editmesh_add.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_ops.c
source/blender/editors/mesh/meshtools.c
source/blender/editors/object/object_edit.c
source/blender/editors/physics/editparticle.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/space_buttons/buttons_ops.c
source/blender/editors/space_image/image_header.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_view3d/SConscript
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/view3d_buttons.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_select.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/uvedit/uvedit_ops.c
source/blender/makesdna/DNA_object_types.h
source/blender/makesrna/SConscript
source/blender/makesrna/intern/SConscript
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_nla.c
source/blender/makesrna/intern/rna_object_api.c
source/blender/python/generic/bpy_internal_import.c
source/blender/render/intern/source/convertblender.c
source/blender/render/intern/source/shadeoutput.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
tools/Blender.py

diff --cc SConstruct
index dab4dde08a311d5df1b96f17ea453b1d6de8a802,5ae8914d77a915fa32e2de9c0b341fdd29cab061..2f93a77d74b336a7bc8f3f253d04f21f0a32d88b
@@@ -573,9 -574,9 +574,9 @@@ if env['OURPLATFORM'] in ('win32-vc', '
        if env['WITH_BF_PYTHON']:
                ver = env["BF_PYTHON_VERSION"].replace(".", "")
                
-               dllsources.append('#release/windows/extra/python' + ver + '.zip')
-               dllsources.append('#release/windows/extra/zlib.pyd')
+               dllsources.append('${LCGDIR}/release/python' + ver + '.zip')
+               dllsources.append('${LCGDIR}/release/zlib.pyd')
 -              if env['BF_DEBUG']:
 +              if env['BF_DEBUG'] and not env["BF_NO_PYDEBUG"]:
                        dllsources.append('${BF_PYTHON_LIBPATH}/${BF_PYTHON_LIB}_d.dll')
                else:
                        dllsources.append('${BF_PYTHON_LIBPATH}/${BF_PYTHON_LIB}.dll')
index 1396564d57864efe39e89d6be61d7c69802d7822,c925cfa8fbe08959a16e5247c9e39bc753c83bf2..dacced09d6569c6713ddcd51f3eebc82dcd19166
@@@ -334,14 -314,10 +341,16 @@@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C
                {E013786A-9575-4F34-81B2-33290357EE87} = {E013786A-9575-4F34-81B2-33290357EE87}\r
        EndProjectSection\r
  EndProject\r
 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BLF_blenfont", "blenfont\BLF_blenfont.vcproj", "{D1A9312F-4557-4982-A0F4-4D08508235F4}"\r
 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BL_bmesh", "..\BL_bmesh\BL_bmesh.vcproj", "{6A51010A-9393-4D77-84B4-5BBCDA6E7C25}"\r
 +      ProjectSection(ProjectDependencies) = postProject\r
 +              {7495FE37-933A-4AC1-BB2A-B3FDB4DE4284} = {7495FE37-933A-4AC1-BB2A-B3FDB4DE4284}\r
 +              {31628053-825D-4C06-8A21-D13883489718} = {31628053-825D-4C06-8A21-D13883489718}\r
 +              {E013786A-9575-4F34-81B2-33290357EE87} = {E013786A-9575-4F34-81B2-33290357EE87}\r
 +              {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94} = {CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}\r
 +      EndProjectSection\r
  EndProject\r
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "INT_smoke", "..\..\intern\smoke\make\msvc_9_0\smoke.vcproj", "{E8904FB3-F8F7-BC21-87A6-029A57B901F4}"\r
+ EndProject\r
  Global\r
        GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
                3D Plugin Debug|Win32 = 3D Plugin Debug|Win32\r
index ae522b029cb5e085dd9d305a2ab4572d47904b83,5b1c7b163ba9d344cc1dbd8e5e1feef03cec65f5..78732be210d95d7a5b7a2c683ab6f235b354b262
@@@ -10,7 -10,7 +10,8 @@@ incs += ' #/intern/iksolver/extern ../b
  incs += ' #/extern/bullet2/src'
  incs += ' #/intern/opennl/extern #/intern/bsp/extern'
  incs += ' ../gpu #/extern/glew/include'
 +incs += ' ../bmesh'
+ incs += ' #/intern/smoke/extern'
  
  incs += ' ' + env['BF_OPENGL_INC']
  incs += ' ' + env['BF_ZLIB_INC']
index 0000000000000000000000000000000000000000,3f23fbda484beb996bddc98ded51e6bc2501aa08..b461592f35f8b9528715f8aa6296dfc6aa2a04bd
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1503 +1,1503 @@@
 -                      MFace *mface = dm->getFaceArray(dm);
+ /**
+  * BKE_cloth.h
+  *
+  * $Id$
+  *
+  * ***** 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) Blender Foundation.
+  * All rights reserved.
+  *
+  * The Original Code is: all of this file.
+  *
+  * Contributor(s): Daniel Genrich
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ /* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
+ #include <GL/glew.h>
+ #include "MEM_guardedalloc.h"
+ #include <float.h>
+ #include <math.h>
+ #include "stdio.h"
+ #include "BLI_linklist.h"
+ #include "BLI_rand.h"
+ #include "BLI_jitter.h"
+ #include "BLI_blenlib.h"
+ #include "BLI_arithb.h"
+ #include "BLI_edgehash.h"
+ #include "BLI_kdtree.h"
+ #include "BLI_kdopbvh.h"
+ #include "BKE_bvhutils.h"
+ #include "BKE_cdderivedmesh.h"
+ #include "BKE_customdata.h"
+ #include "BKE_DerivedMesh.h"
+ #include "BKE_modifier.h"
+ #include "BKE_particle.h"
+ #include "BKE_utildefines.h"
+ #include "DNA_customdata_types.h"
+ #include "DNA_group_types.h"
+ #include "DNA_mesh_types.h"
+ #include "DNA_meshdata_types.h"
+ #include "DNA_modifier_types.h"
+ #include "DNA_object_types.h"
+ #include "DNA_particle_types.h"
+ #include "DNA_scene_types.h"
+ #include "DNA_smoke_types.h"
+ #include "smoke_API.h"
+ #include "BKE_smoke.h"
+ #ifdef _WIN32
+ #include <time.h>
+ #include <stdio.h>
+ #include <conio.h>
+ #include <windows.h>
+ static LARGE_INTEGER liFrequency;
+ static LARGE_INTEGER liStartTime;
+ static LARGE_INTEGER liCurrentTime;
+ static void tstart ( void )
+ {
+       QueryPerformanceFrequency ( &liFrequency );
+       QueryPerformanceCounter ( &liStartTime );
+ }
+ static void tend ( void )
+ {
+       QueryPerformanceCounter ( &liCurrentTime );
+ }
+ static double tval()
+ {
+       return ((double)( (liCurrentTime.QuadPart - liStartTime.QuadPart)* (double)1000.0/(double)liFrequency.QuadPart ));
+ }
+ #else
+ #include <sys/time.h>
+ static struct timeval _tstart, _tend;
+ static struct timezone tz;
+ static void tstart ( void )
+ {
+       gettimeofday ( &_tstart, &tz );
+ }
+ static void tend ( void )
+ {
+       gettimeofday ( &_tend,&tz );
+ }
+ static double tval()
+ {
+       double t1, t2;
+       t1 = ( double ) _tstart.tv_sec*1000 + ( double ) _tstart.tv_usec/ ( 1000 );
+       t2 = ( double ) _tend.tv_sec*1000 + ( double ) _tend.tv_usec/ ( 1000 );
+       return t2-t1;
+ }
+ #endif
+ struct Object;
+ struct Scene;
+ struct DerivedMesh;
+ struct SmokeModifierData;
+ // forward declerations
+ static void get_cell(struct SmokeModifierData *smd, float *pos, int *cell, int correct);
+ static void get_bigcell(struct SmokeModifierData *smd, float *pos, int *cell, int correct);
+ void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *tris, int numfaces, int numtris, int **tridivs, float cell_len);
+ #define TRI_UVOFFSET (1./4.)
+ BVHTree *bvhtree_build_from_smoke ( float mat[4][4], MFace *mfaces, unsigned int numfaces, MVert *x, unsigned int numverts, float epsilon )
+ {
+       BVHTree *tree;
+       float co[12];
+       int i;
+       MFace *tface = mfaces;
+       // calc quads 
+       // todo
+       tree = BLI_bvhtree_new ( numfaces, epsilon, 2, 6 );
+       // fill tree
+       for ( i = 0; i < numfaces; i++, tface++ )
+       {
+               VECCOPY ( &co[0*3], x[tface->v1].co );
+               Mat4MulVecfl (mat, &co[0*3]);
+               VECCOPY ( &co[1*3], x[tface->v2].co );
+               Mat4MulVecfl (mat, &co[1*3]);
+               VECCOPY ( &co[2*3], x[tface->v3].co );
+               Mat4MulVecfl (mat, &co[2*3]);
+               if ( tface->v4 )
+               {
+                       VECCOPY ( &co[3*3], x[tface->v4].co );
+                       Mat4MulVecfl (mat, &co[3*3]);
+               }
+               BLI_bvhtree_insert ( tree, i, co, ( mfaces->v4 ? 4 : 3 ) );
+       }
+       // balance tree
+       BLI_bvhtree_balance ( tree );
+       return tree;
+ }
+ void bvhtree_update_from_smoke ( float mat[4][4], BVHTree * bvhtree, MFace *faces, int numfaces, MVert *x, int numverts)
+ {
+       int i;
+       MFace *mfaces = faces;
+       float co[12];
+       int ret = 0;
+       if ( !bvhtree )
+               return;
+       if ( x )
+       {
+               for ( i = 0; i < numfaces; i++, mfaces++ )
+               {
+                       VECCOPY ( &co[0*3], x[mfaces->v1].co );
+                       Mat4MulVecfl (mat, &co[0*3]);
+                       VECCOPY ( &co[1*3], x[mfaces->v2].co );
+                       Mat4MulVecfl (mat, &co[1*3]);
+                       VECCOPY ( &co[2*3], x[mfaces->v3].co );
+                       Mat4MulVecfl (mat, &co[2*3]);
+                       if ( mfaces->v4 )
+                       {
+                               VECCOPY ( &co[3*3], x[mfaces->v4].co );
+                               Mat4MulVecfl (mat, &co[3*3]);
+                       }
+                       ret = BLI_bvhtree_update_node ( bvhtree, i, co, NULL, ( mfaces->v4 ? 4 : 3 ) );
+                       // check if tree is already full
+                       if ( !ret )
+                               break;
+               }
+               BLI_bvhtree_update_tree ( bvhtree );
+       }
+ }
+ int smokeModifier_init (SmokeModifierData *smd, Object *ob, Scene *scene, DerivedMesh *dm)
+ {
+       if((smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain && !smd->domain->fluid)
+       {
+               size_t i;
+               float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
+               float size[3];
+               MVert *verts = dm->getVertArray(dm);
+               float scale = 0.0;
+               int res;                
+               res = smd->domain->maxres;
+               // get BB of domain
+               for(i = 0; i < dm->getNumVerts(dm); i++)
+               {
+                       float tmp[3];
+                       VECCOPY(tmp, verts[i].co);
+                       Mat4MulVecfl(ob->obmat, tmp);
+                       // min BB
+                       min[0] = MIN2(min[0], tmp[0]);
+                       min[1] = MIN2(min[1], tmp[1]);
+                       min[2] = MIN2(min[2], tmp[2]);
+                       // max BB
+                       max[0] = MAX2(max[0], tmp[0]);
+                       max[1] = MAX2(max[1], tmp[1]);
+                       max[2] = MAX2(max[2], tmp[2]);
+               }
+               VECCOPY(smd->domain->p0, min);
+               VECCOPY(smd->domain->p1, max);
+               // calc other res with max_res provided
+               VECSUB(size, max, min);
+               if(size[0] > size[1])
+               {
+                       if(size[0] > size[1])
+                       {
+                               scale = res / size[0];
+                               smd->domain->dx = size[0] / res;
+                               smd->domain->res[0] = res;
+                               smd->domain->res[1] = (int)(size[1] * scale + 0.5);
+                               smd->domain->res[2] = (int)(size[2] * scale + 0.5);
+                       }
+                       else
+                       {
+                               scale = res / size[1];
+                               smd->domain->dx = size[1] / res;
+                               smd->domain->res[1] = res;
+                               smd->domain->res[0] = (int)(size[0] * scale + 0.5);
+                               smd->domain->res[2] = (int)(size[2] * scale + 0.5);
+                       }
+               }
+               else
+               {
+                       if(size[1] > size[2])
+                       {
+                               scale = res / size[1];
+                               smd->domain->dx = size[1] / res;
+                               smd->domain->res[1] = res;
+                               smd->domain->res[0] = (int)(size[0] * scale + 0.5);
+                               smd->domain->res[2] = (int)(size[2] * scale + 0.5);
+                       }
+                       else
+                       {
+                               scale = res / size[2];
+                               smd->domain->dx = size[2] / res;
+                               smd->domain->res[2] = res;
+                               smd->domain->res[0] = (int)(size[0] * scale + 0.5);
+                               smd->domain->res[1] = (int)(size[1] * scale + 0.5);
+                       }
+               }
+               // TODO: put in failsafe if res<=0 - dg
+               // printf("res[0]: %d, res[1]: %d, res[2]: %d\n", smd->domain->res[0], smd->domain->res[1], smd->domain->res[2]);
+               // dt max is 0.1
+               smd->domain->fluid = smoke_init(smd->domain->res, smd->domain->amplify, smd->domain->p0, smd->domain->p1, 2.5 / FPS);
+               smd->time = scene->r.cfra;
+               smd->domain->firstframe = smd->time;
+               
+               smoke_initBlenderRNA(smd->domain->fluid, &(smd->domain->alpha), &(smd->domain->beta));
+               return 1;
+       }
+       else if((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow)
+       {
+               // handle flow object here
+               // XXX TODO
+               smd->time = scene->r.cfra;
+               // update particle lifetime to be one frame
+               // smd->flow->psys->part->lifetime = scene->r.efra + 1;
+               return 1;
+       }
+       else if((smd->type & MOD_SMOKE_TYPE_COLL))
+       {
+               smd->time = scene->r.cfra;
+               // todo: delete this when loading colls work -dg
+               if(!smd->coll)
+                       smokeModifier_createType(smd);
+               if(!smd->coll->points)
+               {
+                       // init collision points
+                       SmokeCollSettings *scs = smd->coll;
+                       MVert *mvert = dm->getVertArray(dm);
 -                      smd->coll->bvhtree = bvhtree_build_from_smoke ( ob->obmat, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
++                      MFace *mface = dm->getTessFaceArray(dm);
+                       size_t i = 0, divs = 0;
+                       int *tridivs = NULL;
+                       float cell_len = 1.0 / 50.0; // for res = 50
+                       size_t newdivs = 0;
+                       size_t max_points = 0;
+                       size_t quads = 0, facecounter = 0;
+                       // count quads
+                       for(i = 0; i < dm->getNumFaces(dm); i++)
+                       {
+                               if(mface[i].v4)
+                                       quads++;
+                       }
+                       calcTriangleDivs(ob, mvert, dm->getNumVerts(dm), mface,  dm->getNumFaces(dm), dm->getNumFaces(dm) + quads, &tridivs, cell_len);
+                       // count triangle divisions
+                       for(i = 0; i < dm->getNumFaces(dm) + quads; i++)
+                       {
+                               divs += (tridivs[3 * i] + 1) * (tridivs[3 * i + 1] + 1) * (tridivs[3 * i + 2] + 1);
+                       }
+                       // printf("divs: %d\n", divs);
+                       scs->points = MEM_callocN(sizeof(float) * (dm->getNumVerts(dm) + divs) * 3, "SmokeCollPoints");
+                       for(i = 0; i < dm->getNumVerts(dm); i++)
+                       {
+                               float tmpvec[3];
+                               VECCOPY(tmpvec, mvert[i].co);
+                               Mat4MulVecfl (ob->obmat, tmpvec);
+                               VECCOPY(&scs->points[i * 3], tmpvec);
+                       }
+                       
+                       for(i = 0, facecounter = 0; i < dm->getNumFaces(dm); i++)
+                       {
+                               int again = 0;
+                               do
+                               {
+                                       size_t j, k;
+                                       int divs1 = tridivs[3 * facecounter + 0];
+                                       int divs2 = tridivs[3 * facecounter + 1];
+                                       int divs3 = tridivs[3 * facecounter + 2];
+                                       float side1[3], side2[3], trinormorg[3], trinorm[3];
+                                       
+                                       if(again == 1 && mface[i].v4)
+                                       {
+                                               VECSUB(side1,  mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
+                                               VECSUB(side2,  mvert[ mface[i].v4 ].co, mvert[ mface[i].v1 ].co);
+                                       }
+                                       else
+                                       {
+                                               VECSUB(side1,  mvert[ mface[i].v2 ].co, mvert[ mface[i].v1 ].co);
+                                               VECSUB(side2,  mvert[ mface[i].v3 ].co, mvert[ mface[i].v1 ].co);
+                                       }
+                                       Crossf(trinormorg, side1, side2);
+                                       Normalize(trinormorg);
+                                       VECCOPY(trinorm, trinormorg);
+                                       VecMulf(trinorm, 0.25 * cell_len);
+                                       for(j = 0; j <= divs1; j++)
+                                       {
+                                               for(k = 0; k <= divs2; k++)
+                                               {
+                                                       float p1[3], p2[3], p3[3], p[3]={0,0,0}; 
+                                                       const float uf = (float)(j + TRI_UVOFFSET) / (float)(divs1 + 0.0);
+                                                       const float vf = (float)(k + TRI_UVOFFSET) / (float)(divs2 + 0.0);
+                                                       float tmpvec[3];
+                                                       
+                                                       if(uf+vf > 1.0) 
+                                                       {
+                                                               // printf("bigger - divs1: %d, divs2: %d\n", divs1, divs2);
+                                                               continue;
+                                                       }
+                                                       VECCOPY(p1, mvert[ mface[i].v1 ].co);
+                                                       if(again == 1 && mface[i].v4)
+                                                       {
+                                                               VECCOPY(p2, mvert[ mface[i].v3 ].co);
+                                                               VECCOPY(p3, mvert[ mface[i].v4 ].co);
+                                                       }
+                                                       else
+                                                       {
+                                                               VECCOPY(p2, mvert[ mface[i].v2 ].co);
+                                                               VECCOPY(p3, mvert[ mface[i].v3 ].co);
+                                                       }
+                                                       VecMulf(p1, (1.0-uf-vf));
+                                                       VecMulf(p2, uf);
+                                                       VecMulf(p3, vf);
+                                                       
+                                                       VECADD(p, p1, p2);
+                                                       VECADD(p, p, p3);
+                                                       if(newdivs > divs)
+                                                               printf("mem problem\n");
+                                                       // mMovPoints.push_back(p + trinorm);
+                                                       VECCOPY(tmpvec, p);
+                                                       VECADD(tmpvec, tmpvec, trinorm);
+                                                       Mat4MulVecfl (ob->obmat, tmpvec);
+                                                       VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
+                                                       newdivs++;
+                                                       if(newdivs > divs)
+                                                               printf("mem problem\n");
+                                                       // mMovPoints.push_back(p - trinorm);
+                                                       VECCOPY(tmpvec, p);
+                                                       VECSUB(tmpvec, tmpvec, trinorm);
+                                                       Mat4MulVecfl (ob->obmat, tmpvec);
+                                                       VECCOPY(&scs->points[3 * (dm->getNumVerts(dm) + newdivs)], tmpvec);
+                                                       newdivs++;
+                                               }
+                                       }
+                                       if(again == 0 && mface[i].v4)
+                                               again++;
+                                       else
+                                               again = 0;
+                                       facecounter++;
+                               } while(again!=0);
+                       }
+                       scs->numpoints = dm->getNumVerts(dm) + newdivs;
+                       MEM_freeN(tridivs);
+               }
+               if(!smd->coll->bvhtree)
+               {
 -                              bvhtree_update_from_smoke ( ob->obmat, smd->coll->bvhtree, dm->getFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm));
++                      smd->coll->bvhtree = bvhtree_build_from_smoke ( ob->obmat, dm->getTessFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm), 0.0 );
+               }
+       }
+       return 0;
+ }
+ /*! init triangle divisions */
+ void calcTriangleDivs(Object *ob, MVert *verts, int numverts, MFace *faces, int numfaces, int numtris, int **tridivs, float cell_len) 
+ {
+       // mTriangleDivs1.resize( faces.size() );
+       // mTriangleDivs2.resize( faces.size() );
+       // mTriangleDivs3.resize( faces.size() );
+       size_t i = 0, facecounter = 0;
+       float maxscale[3] = {1,1,1}; // = channelFindMaxVf(mcScale);
+       float maxpart = ABS(maxscale[0]);
+       float scaleFac = 0;
+       float fsTri = 0;
+       if(ABS(maxscale[1])>maxpart) maxpart = ABS(maxscale[1]);
+       if(ABS(maxscale[2])>maxpart) maxpart = ABS(maxscale[2]);
+       scaleFac = 1.0 / maxpart;
+       // featureSize = mLevel[mMaxRefine].nodeSize
+       fsTri = cell_len * 0.5 * scaleFac;
+       if(*tridivs)
+               MEM_freeN(*tridivs);
+       *tridivs = MEM_callocN(sizeof(int) * numtris * 3, "Smoke_Tridivs");
+       for(i = 0, facecounter = 0; i < numfaces; i++) 
+       {
+               float p0[3], p1[3], p2[3];
+               float side1[3];
+               float side2[3];
+               float side3[3];
+               int divs1=0, divs2=0, divs3=0;
+               VECCOPY(p0, verts[faces[i].v1].co);
+               Mat4MulVecfl (ob->obmat, p0);
+               VECCOPY(p1, verts[faces[i].v2].co);
+               Mat4MulVecfl (ob->obmat, p1);
+               VECCOPY(p2, verts[faces[i].v3].co);
+               Mat4MulVecfl (ob->obmat, p2);
+               VECSUB(side1, p1, p0);
+               VECSUB(side2, p2, p0);
+               VECSUB(side3, p1, p2);
+               if(INPR(side1, side1) > fsTri*fsTri) 
+               { 
+                       float tmp = Normalize(side1);
+                       divs1 = (int)(tmp/fsTri); 
+               }
+               if(INPR(side2, side2) > fsTri*fsTri) 
+               { 
+                       float tmp = Normalize(side2);
+                       divs2 = (int)(tmp/fsTri); 
+                       
+                       /*
+                       // debug
+                       if(i==0)
+                               printf("b tmp: %f, fsTri: %f, divs2: %d\n", tmp, fsTri, divs2);
+                       */
+               }
+               (*tridivs)[3 * facecounter + 0] = divs1;
+               (*tridivs)[3 * facecounter + 1] = divs2;
+               (*tridivs)[3 * facecounter + 2] = divs3;
+               // TODO quad case
+               if(faces[i].v4)
+               {
+                       divs1=0, divs2=0, divs3=0;
+                       facecounter++;
+                       
+                       VECCOPY(p1, verts[faces[i].v3].co);
+                       Mat4MulVecfl (ob->obmat, p1);
+                       VECCOPY(p2, verts[faces[i].v4].co);
+                       Mat4MulVecfl (ob->obmat, p2);
+                       VECSUB(side1, p1, p0);
+                       VECSUB(side2, p2, p0);
+                       VECSUB(side3, p1, p2);
+                       if(INPR(side1, side1) > fsTri*fsTri) 
+                       { 
+                               float tmp = Normalize(side1);
+                               divs1 = (int)(tmp/fsTri); 
+                       }
+                       if(INPR(side2, side2) > fsTri*fsTri) 
+                       { 
+                               float tmp = Normalize(side2);
+                               divs2 = (int)(tmp/fsTri); 
+                       }
+                       (*tridivs)[3 * facecounter + 0] = divs1;
+                       (*tridivs)[3 * facecounter + 1] = divs2;
+                       (*tridivs)[3 * facecounter + 2] = divs3;
+               }
+               facecounter++;
+       }
+ }
+ void smokeModifier_freeDomain(SmokeModifierData *smd)
+ {
+       if(smd->domain)
+       {
+               // free visualisation buffers
+               if(smd->domain->bind)
+               {
+                       glDeleteTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind);
+                       MEM_freeN(smd->domain->bind);
+               }
+               smd->domain->max_textures = 0; // unnecessary but let's be sure
+               if(smd->domain->tray)
+                       MEM_freeN(smd->domain->tray);
+               if(smd->domain->tvox)
+                       MEM_freeN(smd->domain->tvox);
+               if(smd->domain->traybig)
+                       MEM_freeN(smd->domain->traybig);
+               if(smd->domain->tvoxbig)
+                       MEM_freeN(smd->domain->tvoxbig);
+               if(smd->domain->fluid)
+               {
+                       smoke_free(smd->domain->fluid);
+               }
+               MEM_freeN(smd->domain);
+               smd->domain = NULL;
+       }
+ }
+ void smokeModifier_freeFlow(SmokeModifierData *smd)
+ {
+       if(smd->flow)
+       {
+               MEM_freeN(smd->flow);
+               smd->flow = NULL;
+       }
+ }
+ void smokeModifier_freeCollision(SmokeModifierData *smd)
+ {
+       if(smd->coll)
+       {
+               if(smd->coll->points)
+               {
+                       MEM_freeN(smd->coll->points);
+                       smd->coll->points = NULL;
+               }
+               if(smd->coll->bvhtree)
+               {
+                       BLI_bvhtree_free(smd->coll->bvhtree);
+                       smd->coll->bvhtree = NULL;
+               }
+               MEM_freeN(smd->coll);
+               smd->coll = NULL;
+       }
+ }
+ void smokeModifier_reset(struct SmokeModifierData *smd)
+ {
+       if(smd)
+       {
+               if(smd->domain)
+               {
+                       // free visualisation buffers
+                       if(smd->domain->bind)
+                       {
+                               glDeleteTextures(smd->domain->max_textures, (GLuint *)smd->domain->bind);
+                               MEM_freeN(smd->domain->bind);
+                               smd->domain->bind = NULL;
+                       }
+                       smd->domain->max_textures = 0;
+                       smd->domain->viewsettings = 0; // reset view for new frame
+                       if(smd->domain->tray)
+                               MEM_freeN(smd->domain->tray);
+                       if(smd->domain->tvox)
+                               MEM_freeN(smd->domain->tvox);
+                       if(smd->domain->traybig)
+                               MEM_freeN(smd->domain->traybig);
+                       if(smd->domain->tvoxbig)
+                               MEM_freeN(smd->domain->tvoxbig);
+                       smd->domain->tvox = NULL;
+                       smd->domain->tray = NULL;
+                       smd->domain->tvoxbig = NULL;
+                       smd->domain->traybig = NULL;
+                       if(smd->domain->fluid)
+                       {
+                               smoke_free(smd->domain->fluid);
+                               smd->domain->fluid = NULL;
+                       }
+               }
+               else if(smd->flow)
+               {
+                                               
+               }
+               else if(smd->coll)
+               {
+                       if(smd->coll->points)
+                       {
+                               MEM_freeN(smd->coll->points);
+                               smd->coll->points = NULL;
+                       }
+                       if(smd->coll->bvhtree)
+                       {
+                               BLI_bvhtree_free(smd->coll->bvhtree);
+                               smd->coll->bvhtree = NULL;
+                       }
+               }
+       }
+ }
+ void smokeModifier_free (SmokeModifierData *smd)
+ {
+       if(smd)
+       {
+               smokeModifier_freeDomain(smd);
+               smokeModifier_freeFlow(smd);
+               smokeModifier_freeCollision(smd);
+       }
+ }
+ void smokeModifier_createType(struct SmokeModifierData *smd)
+ {
+       if(smd)
+       {
+               if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
+               {
+                       if(smd->domain)
+                               smokeModifier_freeDomain(smd);
+                       smd->domain = MEM_callocN(sizeof(SmokeDomainSettings), "SmokeDomain");
+                       smd->domain->smd = smd;
+                       /* set some standard values */
+                       smd->domain->fluid = NULL;
+                       smd->domain->eff_group = NULL;
+                       smd->domain->fluid_group = NULL;
+                       smd->domain->coll_group = NULL;
+                       smd->domain->maxres = 32;
+                       smd->domain->amplify = 2;
+                       smd->domain->omega = 1.0;
+                       smd->domain->alpha = -0.001;
+                       smd->domain->beta = 0.1;
+                       smd->domain->flags = 0;
+                       smd->domain->noise = MOD_SMOKE_NOISEWAVE;
+                       smd->domain->visibility = 1;
+                       // init 3dview buffer
+                       smd->domain->tvox = NULL;
+                       smd->domain->tray = NULL;
+                       smd->domain->tvoxbig = NULL;
+                       smd->domain->traybig = NULL;
+                       smd->domain->viewsettings = 0;
+                       smd->domain->bind = NULL;
+                       smd->domain->max_textures = 0;
+               }
+               else if(smd->type & MOD_SMOKE_TYPE_FLOW)
+               {
+                       if(smd->flow)
+                               smokeModifier_freeFlow(smd);
+                       smd->flow = MEM_callocN(sizeof(SmokeFlowSettings), "SmokeFlow");
+                       smd->flow->smd = smd;
+                       /* set some standard values */
+                       smd->flow->density = 1.0;
+                       smd->flow->temp = 1.0;
+                       smd->flow->psys = NULL;
+               }
+               else if(smd->type & MOD_SMOKE_TYPE_COLL)
+               {
+                       if(smd->coll)
+                               smokeModifier_freeCollision(smd);
+                       smd->coll = MEM_callocN(sizeof(SmokeCollSettings), "SmokeColl");
+                       smd->coll->smd = smd;
+                       smd->coll->points = NULL;
+                       smd->coll->numpoints = 0;
+                       smd->coll->bvhtree = NULL;
+               }
+       }
+ }
+ // forward declaration
+ void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big);
+ void smokeModifier_do(SmokeModifierData *smd, Scene *scene, Object *ob, DerivedMesh *dm, int useRenderParams, int isFinalCalc)
+ {     
+       if(scene->r.cfra >= smd->time)
+               smokeModifier_init(smd, ob, scene, dm);
+       if((smd->type & MOD_SMOKE_TYPE_FLOW))
+       {
+               if(scene->r.cfra > smd->time)
+               {
+                       // XXX TODO
+                       smd->time = scene->r.cfra;
+               }
+               else if(scene->r.cfra < smd->time)
+               {
+                       smd->time = scene->r.cfra;
+                       smokeModifier_reset(smd);
+               }
+       }
+       else if(smd->type & MOD_SMOKE_TYPE_COLL)
+       {
+               if(scene->r.cfra > smd->time)
+               {
+                       // XXX TODO
+                       smd->time = scene->r.cfra;
+                       
+                       if(smd->coll->bvhtree)
++                              bvhtree_update_from_smoke ( ob->obmat, smd->coll->bvhtree, dm->getTessFaceArray(dm), dm->getNumFaces(dm), dm->getVertArray(dm), dm->getNumVerts(dm));
+                       else
+                               printf("smoke coll with no bvh\n");
+               }
+               else if(scene->r.cfra < smd->time)
+               {
+                       smd->time = scene->r.cfra;
+                       smokeModifier_reset(smd);
+               }
+       }
+       else if(smd->type & MOD_SMOKE_TYPE_DOMAIN)
+       {
+               SmokeDomainSettings *sds = smd->domain;
+               
+               if(scene->r.cfra > smd->time)
+               {
+                       GroupObject *go = NULL;
+                       Base *base = NULL;
+                       int cnt_domain = 0;
+                       
+                       tstart();
+                       sds->viewsettings = 0; // reset view for new frame
+                       // check for 2nd domain, if not there -> no groups are necessary
+                       for(base = scene->base.first; base; base= base->next) 
+                       {
+                               Object *ob1= base->object;
+                               
+                               if(ob1 && ob1 != ob)
+                               {
+                                       ModifierData *tmd = modifiers_findByType(ob1, eModifierType_Smoke);
+                                       if(tmd && tmd->mode & (eModifierMode_Realtime | eModifierMode_Render))
+                                       {
+                                               SmokeModifierData *tsmd = (SmokeModifierData *)tmd;
+                                               if((tsmd->type & MOD_SMOKE_TYPE_DOMAIN))
+                                               {
+                                                       cnt_domain++;
+                                               }
+                                       }
+                               }
+                       }
+                       // do flows and fluids
+                       if(sds->fluid_group || !cnt_domain)
+                       {
+                               Object *otherobj = NULL;
+                               ModifierData *md = NULL;
+                               if(cnt_domain && !sds->fluid_group) // we use groups since we have 2 domains
+                                       go = sds->fluid_group->gobject.first;
+                               else
+                                       base = scene->base.first;
+                               while(base || go)
+                               {
+                                       otherobj = NULL;
+                                       if(cnt_domain && !sds->fluid_group) 
+                                       {
+                                               if(go->ob)
+                                                       otherobj = go->ob;
+                                       }
+                                       else
+                                               otherobj = base->object;
+                                       if(!otherobj)
+                                       {
+                                               if(cnt_domain && !sds->fluid_group)
+                                                       go = go->next;
+                                               else
+                                                       base= base->next;
+                                               continue;
+                                       }
+                                       md = modifiers_findByType(otherobj, eModifierType_Smoke);
+                                       
+                                       // check for active smoke modifier
+                                       if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
+                                       {
+                                               SmokeModifierData *smd2 = (SmokeModifierData *)md;
+                                               
+                                               // check for initialized smoke object
+                                               if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow)
+                                               {
+                                                       // we got nice flow object
+                                                       SmokeFlowSettings *sfs = smd2->flow;
+                                                       
+                                                       if(sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected
+                                                       {
+                                                               ParticleSystem *psys = sfs->psys;
+                                                               ParticleSettings *part=psys->part;
+                                                               ParticleData *pa = NULL;
+                                                               int p = 0;
+                                                               float *density = smoke_get_density(sds->fluid);
+                                                               float *bigdensity = smoke_get_bigdensity(sds->fluid);
+                                                               float *heat = smoke_get_heat(sds->fluid);
+                                                               float *velocity_x = smoke_get_velocity_x(sds->fluid);
+                                                               float *velocity_y = smoke_get_velocity_y(sds->fluid);
+                                                               float *velocity_z = smoke_get_velocity_z(sds->fluid);
+                                                               int bigres[3];
+                                                               smoke_get_bigres(smd->domain->fluid, bigres);
+                                                               
+                                                               // mostly copied from particle code
+                                                               for(p=0, pa=psys->particles; p<psys->totpart; p++, pa++)
+                                                               {
+                                                                       int cell[3];
+                                                                       size_t i = 0;
+                                                                       size_t index = 0;
+                                                                       int badcell = 0;
+                                                                       
+                                                                       if(pa->alive == PARS_KILLED) continue;
+                                                                       else if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue;
+                                                                       else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0) continue;
+                                                                       else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue;
+                                                                       
+                                                                       // VECCOPY(pos, pa->state.co);
+                                                                       // Mat4MulVecfl (ob->imat, pos);
+                                                                       
+                                                                       // 1. get corresponding cell
+                                                                       get_cell(smd, pa->state.co, cell, 0);
+                                                               
+                                                                       // check if cell is valid (in the domain boundary)
+                                                                       for(i = 0; i < 3; i++)
+                                                                       {
+                                                                               if((cell[i] > sds->res[i] - 1) || (cell[i] < 0))
+                                                                               {
+                                                                                       badcell = 1;
+                                                                                       break;
+                                                                               }
+                                                                       }
+                                                                               
+                                                                       if(badcell)
+                                                                               continue;
+                                                                       
+                                                                       // 2. set cell values (heat, density and velocity)
+                                                                       index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);
+                                                                       
+                                                                       if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW)) // this is inflow
+                                                                       {
+                                                                               heat[index] = sfs->temp;
+                                                                               density[index] = sfs->density;
+                                                                               velocity_x[index] = pa->state.vel[0];
+                                                                               velocity_y[index] = pa->state.vel[1];
+                                                                               velocity_z[index] = pa->state.vel[2];
+                                                                               // we need different handling for the high-res feature
+                                                                               if(bigdensity)
+                                                                               {
+                                                                                       // init all surrounding cells according to amplification, too
+                                                                                       int i, j, k;
+                                                                                       for(i = 0; i < smd->domain->amplify; i++)
+                                                                                               for(j = 0; j < smd->domain->amplify; j++)
+                                                                                                       for(k = 0; k < smd->domain->amplify; k++)
+                                                                                                       {
+                                                                                                               index = smoke_get_index(smd->domain->amplify * cell[0] + i, bigres[0], smd->domain->amplify * cell[1] + j, bigres[1], smd->domain->amplify * cell[2] + k);
+                                                                                                               bigdensity[index] = sfs->density;
+                                                                                                       }
+                                                                               }
+                                                                       }
+                                                                       else // outflow
+                                                                       {
+                                                                               heat[index] = 0.f;
+                                                                               density[index] = 0.f;
+                                                                               velocity_x[index] = 0.f;
+                                                                               velocity_y[index] = 0.f;
+                                                                               velocity_z[index] = 0.f;
+                                                                               // we need different handling for the high-res feature
+                                                                               if(bigdensity)
+                                                                               {
+                                                                                       // init all surrounding cells according to amplification, too
+                                                                                       int i, j, k;
+                                                                                       for(i = 0; i < smd->domain->amplify; i++)
+                                                                                               for(j = 0; j < smd->domain->amplify; j++)
+                                                                                                       for(k = 0; k < smd->domain->amplify; k++)
+                                                                                                       {
+                                                                                                               index = smoke_get_index(smd->domain->amplify * cell[0] + i, bigres[0], smd->domain->amplify * cell[1] + j, bigres[1], smd->domain->amplify * cell[2] + k);
+                                                                                                               bigdensity[index] = 0.f;
+                                                                                                       }
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }       
+                                               }       
+                                       }
+                                       if(cnt_domain && !sds->fluid_group)
+                                               go = go->next;
+                                       else
+                                               base= base->next;
+                               }
+                       }
+                       // do effectors
+                       /*
+                       if(sds->eff_group)
+                       {
+                               for(go = sds->eff_group->gobject.first; go; go = go->next) 
+                               {
+                                       if(go->ob)
+                                       {
+                                               if(ob->pd)
+                                               {
+                                                       
+                                               }
+                                       }
+                               }
+                       }
+                       */
+                       // do collisions        
+                       if(sds->coll_group || !cnt_domain)
+                       {
+                               Object *otherobj = NULL;
+                               ModifierData *md = NULL;
+                               if(cnt_domain && !sds->coll_group) // we use groups since we have 2 domains
+                                       go = sds->coll_group->gobject.first;
+                               else
+                                       base = scene->base.first;
+                               while(base || go)
+                               {
+                                       otherobj = NULL;
+                                       if(cnt_domain && !sds->coll_group) 
+                                       {
+                                               if(go->ob)
+                                                       otherobj = go->ob;
+                                       }
+                                       else
+                                               otherobj = base->object;
+                                       if(!otherobj)
+                                       {
+                                               if(cnt_domain && !sds->coll_group)
+                                                       go = go->next;
+                                               else
+                                                       base= base->next;
+                                               continue;
+                                       }
+                       
+                                       md = modifiers_findByType(otherobj, eModifierType_Smoke);
+                                       
+                                       // check for active smoke modifier
+                                       if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render))
+                                       {
+                                               SmokeModifierData *smd2 = (SmokeModifierData *)md;
+                                               if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
+                                               {
+                                                       // we got nice collision object
+                                                       SmokeCollSettings *scs = smd2->coll;
+                                                       int cell[3];
+                                                       size_t index = 0;
+                                                       size_t i, j;
+                                                       unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid);
+                                                       // int BLI_bvhtree_find_nearest(BVHTree *tree, const float *co, BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata);
+                                                       for(i = 0; i < scs->numpoints; i++)
+                                                       {
+                                                               int badcell = 0;
+                                                               // 1. get corresponding cell
+                                                               get_cell(smd, &scs->points[3 * i], cell, 0);
+                                                       
+                                                               // check if cell is valid (in the domain boundary)
+                                                               for(j = 0; j < 3; j++)
+                                                                       if((cell[j] > sds->res[j] - 1) || (cell[j] < 0))
+                                                                       {
+                                                                               badcell = 1;
+                                                                               break;
+                                                                       }
+                                                                               
+                                                               if(badcell)
+                                                                       continue;
+                                                               // 2. set cell values (heat, density and velocity)
+                                                               index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]);
+                                                               
+                                                               // printf("cell[0]: %d, cell[1]: %d, cell[2]: %d\n", cell[0], cell[1], cell[2]);
+                                                               // printf("res[0]: %d, res[1]: %d, res[2]: %d, index: %d\n\n", sds->res[0], sds->res[1], sds->res[2], index);
+                                                                       
+                                                               obstacles[index] = 1;
+                                                               // for moving gobstacles
+                                                               /*
+                                                               const LbmFloat maxVelVal = 0.1666;
+                                                               const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5;
+                                                               LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { 
+                                                               const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; 
+                                                               USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); 
+                                                               if(usqr>maxusqr) { 
+                                                                       // cutoff at maxVelVal 
+                                                                       for(int jj=0; jj<3; jj++) { 
+                                                                               if(objvel[jj]>0.) objvel[jj] =  maxVelVal;  
+                                                                               if(objvel[jj]<0.) objvel[jj] = -maxVelVal; 
+                                                                       } 
+                                                               } } 
+                                                               const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); 
+                                                               const LbmVec oldov=objvel; // debug
+                                                               objvel = vec2L((*pNormals)[n]) *dp;
+                                                               */
+                                                       }
+                                               }
+                                       }
+                                       if(cnt_domain && !sds->coll_group)
+                                               go = go->next;
+                                       else
+                                               base= base->next;
+                               }
+                       }
+                       
+                       // set new time
+                       smd->time = scene->r.cfra;
+                       // simulate the actual smoke (c++ code in intern/smoke)
+                       smoke_step(sds->fluid);
+                       tend();
+                       printf ( "Frame: %d, Time: %f\n", (int)smd->time, ( float ) tval() );
+               }
+               else if(scene->r.cfra < smd->time)
+               {
+                       // we got back in time, reset smoke in this case (TODO: use cache later)
+                       smd->time = scene->r.cfra;
+                       smokeModifier_reset(smd);
+               }
+       }
+ }
+ // update necessary information for 3dview
+ void smoke_prepare_View(SmokeModifierData *smd, float *light)
+ {
+       float *density = NULL;
+       int x, y, z;
+       if(!smd->domain->tray)
+       {
+               // TRay is for self shadowing
+               smd->domain->tray = MEM_callocN(sizeof(float)*smd->domain->res[0]*smd->domain->res[1]*smd->domain->res[2], "Smoke_tRay");
+       }
+       if(!smd->domain->tvox)
+       {
+               // TVox is for tranaparency
+               smd->domain->tvox = MEM_callocN(sizeof(float)*smd->domain->res[0]*smd->domain->res[1]*smd->domain->res[2], "Smoke_tVox");
+       }
+       // update 3dview
+       density = smoke_get_density(smd->domain->fluid);
+       for(x = 0; x < smd->domain->res[0]; x++)
+                       for(y = 0; y < smd->domain->res[1]; y++)
+                               for(z = 0; z < smd->domain->res[2]; z++)
+                               {
+                                       size_t index;
+                                       index = smoke_get_index(x, smd->domain->res[0], y, smd->domain->res[1], z);
+                                       // Transparency computation
+                                       // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4
+                                       // T_vox = exp(-C_ext * h)
+                                       // C_ext/sigma_t = density * C_ext
+                                       smoke_set_tvox(smd, index, exp(-density[index] * 7.0 * smd->domain->dx));
+       }
+       smoke_calc_transparency(smd, light, 0);
+ }
+ // update necessary information for 3dview ("high res" option)
+ void smoke_prepare_bigView(SmokeModifierData *smd, float *light)
+ {
+       float *density = NULL;
+       size_t i = 0;
+       int bigres[3];
+       smoke_get_bigres(smd->domain->fluid, bigres);
+       if(!smd->domain->traybig)
+       {
+               // TRay is for self shadowing
+               smd->domain->traybig = MEM_callocN(sizeof(float)*bigres[0]*bigres[1]*bigres[2], "Smoke_tRayBig");
+       }
+       if(!smd->domain->tvoxbig)
+       {
+               // TVox is for tranaparency
+               smd->domain->tvoxbig = MEM_callocN(sizeof(float)*bigres[0]*bigres[1]*bigres[2], "Smoke_tVoxBig");
+       }
+       density = smoke_get_bigdensity(smd->domain->fluid);
+       for (i = 0; i < bigres[0] * bigres[1] * bigres[2]; i++)
+       {
+               // Transparency computation
+               // formula taken from "Visual Simulation of Smoke" / Fedkiw et al. pg. 4
+               // T_vox = exp(-C_ext * h)
+               // C_ext/sigma_t = density * C_ext
+               smoke_set_bigtvox(smd, i, exp(-density[i] * 7.0 * smd->domain->dx / smd->domain->amplify) );
+       }
+       smoke_calc_transparency(smd, light, 1);
+ }
+ float smoke_get_tvox(SmokeModifierData *smd, size_t index)
+ {
+       return smd->domain->tvox[index];
+ }
+ void smoke_set_tvox(SmokeModifierData *smd, size_t index, float tvox)
+ {
+       smd->domain->tvox[index] = tvox;
+ }
+ float smoke_get_tray(SmokeModifierData *smd, size_t index)
+ {
+       return smd->domain->tray[index];
+ }
+ void smoke_set_tray(SmokeModifierData *smd, size_t index, float transparency)
+ {
+       smd->domain->tray[index] = transparency;
+ }
+ float smoke_get_bigtvox(SmokeModifierData *smd, size_t index)
+ {
+       return smd->domain->tvoxbig[index];
+ }
+ void smoke_set_bigtvox(SmokeModifierData *smd, size_t index, float tvox)
+ {
+       smd->domain->tvoxbig[index] = tvox;
+ }
+ float smoke_get_bigtray(SmokeModifierData *smd, size_t index)
+ {
+       return smd->domain->traybig[index];
+ }
+ void smoke_set_bigtray(SmokeModifierData *smd, size_t index, float transparency)
+ {
+       smd->domain->traybig[index] = transparency;
+ }
+ long long smoke_get_mem_req(int xres, int yres, int zres, int amplify)
+ {
+         int totalCells = xres * yres * zres;
+         int amplifiedCells = totalCells * amplify * amplify * amplify;
+         // print out memory requirements
+         long long int coarseSize = sizeof(float) * totalCells * 22 +
+                          sizeof(unsigned char) * totalCells;
+         long long int fineSize = sizeof(float) * amplifiedCells * 7 + // big grids
+                        sizeof(float) * totalCells * 8 +     // small grids
+                        sizeof(float) * 128 * 128 * 128;     // noise tile
+         long long int totalMB = (coarseSize + fineSize) / (1024 * 1024);
+         return totalMB;
+ }
+ static void calc_voxel_transp(SmokeModifierData *smd, int *pixel, float *tRay)
+ {
+       // printf("Pixel(%d, %d, %d)\n", pixel[0], pixel[1], pixel[2]);
+       const size_t index = smoke_get_index(pixel[0], smd->domain->res[0], pixel[1], smd->domain->res[1], pixel[2]);
+       // T_ray *= T_vox
+       *tRay *= smoke_get_tvox(smd, index);
+ }
+ static void calc_voxel_transp_big(SmokeModifierData *smd, int *pixel, float *tRay)
+ {
+       int bigres[3];
+       size_t index;
+       smoke_get_bigres(smd->domain->fluid, bigres);
+       index = smoke_get_index(pixel[0], bigres[0], pixel[1], bigres[1], pixel[2]);
+       /*
+       if(index > bigres[0]*bigres[1]*bigres[2])
+               printf("pixel[0]: %d, [1]: %d, [2]: %d\n", pixel[0], pixel[1], pixel[2]);
+       */
+       // T_ray *= T_vox
+       *tRay *= smoke_get_bigtvox(smd, index);
+ }
+ static void bresenham_linie_3D(SmokeModifierData *smd, int x1, int y1, int z1, int x2, int y2, int z2, float *tRay, int big)
+ {
+     int dx, dy, dz, i, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
+     int pixel[3];
+     pixel[0] = x1;
+     pixel[1] = y1;
+     pixel[2] = z1;
+     dx = x2 - x1;
+     dy = y2 - y1;
+     dz = z2 - z1;
+     x_inc = (dx < 0) ? -1 : 1;
+     l = abs(dx);
+     y_inc = (dy < 0) ? -1 : 1;
+     m = abs(dy);
+     z_inc = (dz < 0) ? -1 : 1;
+     n = abs(dz);
+     dx2 = l << 1;
+     dy2 = m << 1;
+     dz2 = n << 1;
+     if ((l >= m) && (l >= n)) {
+         err_1 = dy2 - l;
+         err_2 = dz2 - l;
+         for (i = 0; i < l; i++) {
+               if(!big)
+                               calc_voxel_transp(smd, pixel, tRay);
+                       else
+                               calc_voxel_transp_big(smd, pixel, tRay);
+               if(*tRay < 0.0f)
+                       return;
+             if (err_1 > 0) {
+                 pixel[1] += y_inc;
+                 err_1 -= dx2;
+             }
+             if (err_2 > 0) {
+                 pixel[2] += z_inc;
+                 err_2 -= dx2;
+             }
+             err_1 += dy2;
+             err_2 += dz2;
+             pixel[0] += x_inc;
+         }
+     } else if ((m >= l) && (m >= n)) {
+         err_1 = dx2 - m;
+         err_2 = dz2 - m;
+         for (i = 0; i < m; i++) {
+               if(!big)
+                               calc_voxel_transp(smd, pixel, tRay);
+                       else
+                               calc_voxel_transp_big(smd, pixel, tRay);
+               if(*tRay < 0.0f)
+                       return;
+             if (err_1 > 0) {
+                 pixel[0] += x_inc;
+                 err_1 -= dy2;
+             }
+             if (err_2 > 0) {
+                 pixel[2] += z_inc;
+                 err_2 -= dy2;
+             }
+             err_1 += dx2;
+             err_2 += dz2;
+             pixel[1] += y_inc;
+         }
+     } else {
+         err_1 = dy2 - n;
+         err_2 = dx2 - n;
+         for (i = 0; i < n; i++) {
+               if(!big)
+                               calc_voxel_transp(smd, pixel, tRay);
+                       else
+                               calc_voxel_transp_big(smd, pixel, tRay);
+               if(*tRay < 0.0f)
+                       return;
+             if (err_1 > 0) {
+                 pixel[1] += y_inc;
+                 err_1 -= dz2;
+             }
+             if (err_2 > 0) {
+                 pixel[0] += x_inc;
+                 err_2 -= dz2;
+             }
+             err_1 += dy2;
+             err_2 += dx2;
+             pixel[2] += z_inc;
+         }
+     }
+     if(!big)
+       calc_voxel_transp(smd, pixel, tRay);
+     else
+       calc_voxel_transp_big(smd, pixel, tRay);
+ }
+ static void get_cell(struct SmokeModifierData *smd, float *pos, int *cell, int correct)
+ {
+       float tmp[3];
+       VECSUB(tmp, pos, smd->domain->p0);
+       VecMulf(tmp, 1.0 / smd->domain->dx);
+       if(correct)
+       {
+               cell[0] = MIN2(smd->domain->res[0] - 1, MAX2(0, (int)floor(tmp[0])));
+               cell[1] = MIN2(smd->domain->res[1] - 1, MAX2(0, (int)floor(tmp[1])));
+               cell[2] = MIN2(smd->domain->res[2] - 1, MAX2(0, (int)floor(tmp[2])));
+       }
+       else
+       {
+               cell[0] = (int)floor(tmp[0]);
+               cell[1] = (int)floor(tmp[1]);
+               cell[2] = (int)floor(tmp[2]);
+       }
+ }
+ static void get_bigcell(struct SmokeModifierData *smd, float *pos, int *cell, int correct)
+ {
+       float tmp[3];
+       int res[3];
+       smoke_get_bigres(smd->domain->fluid, res);
+       VECSUB(tmp, pos, smd->domain->p0);
+       VecMulf(tmp, smd->domain->amplify / smd->domain->dx );
+       if(correct)
+       {
+               cell[0] = MIN2(res[0] - 1, MAX2(0, (int)floor(tmp[0])));
+               cell[1] = MIN2(res[1] - 1, MAX2(0, (int)floor(tmp[1])));
+               cell[2] = MIN2(res[2] - 1, MAX2(0, (int)floor(tmp[2])));
+       }
+       else
+       {
+               cell[0] = (int)floor(tmp[0]);
+               cell[1] = (int)floor(tmp[1]);
+               cell[2] = (int)floor(tmp[2]);
+       }
+ }
+ void smoke_calc_transparency(struct SmokeModifierData *smd, float *light, int big)
+ {
+       int x, y, z;
+       float bv[6];
+       int res[3];
+       float bigfactor = 1.0;
+       // x
+       bv[0] = smd->domain->p0[0];
+       bv[1] = smd->domain->p1[0];
+       // y
+       bv[2] = smd->domain->p0[1];
+       bv[3] = smd->domain->p1[1];
+       // z
+       bv[4] = smd->domain->p0[2];
+       bv[5] = smd->domain->p1[2];
+ /*
+       printf("bv[0]: %f, [1]: %f, [2]: %f, [3]: %f, [4]: %f, [5]: %f\n", bv[0], bv[1], bv[2], bv[3], bv[4], bv[5]);
+       printf("p0[0]: %f, p0[1]: %f, p0[2]: %f\n", smd->domain->p0[0], smd->domain->p0[1], smd->domain->p0[2]);
+       printf("p1[0]: %f, p1[1]: %f, p1[2]: %f\n", smd->domain->p1[0], smd->domain->p1[1], smd->domain->p1[2]);
+       printf("dx: %f, amp: %d\n", smd->domain->dx, smd->domain->amplify);
+ */
+       if(!big)
+       {
+               res[0] = smd->domain->res[0];
+               res[1] = smd->domain->res[1];
+               res[2] = smd->domain->res[2];
+       }
+       else
+       {
+               smoke_get_bigres(smd->domain->fluid, res);
+               bigfactor = 1.0 / smd->domain->amplify;
+       }
+ #pragma omp parallel for schedule(static) private(y, z) shared(big, smd, light, res, bigfactor)
+       for(x = 0; x < res[0]; x++)
+               for(y = 0; y < res[1]; y++)
+                       for(z = 0; z < res[2]; z++)
+                       {
+                               float voxelCenter[3];
+                               size_t index;
+                               float pos[3];
+                               int cell[3];
+                               float tRay = 1.0;
+                               index = smoke_get_index(x, res[0], y, res[1], z);
+                               // voxelCenter = m_voxelarray[i].GetCenter();
+                               voxelCenter[0] = smd->domain->p0[0] + smd->domain->dx * bigfactor * x + smd->domain->dx * bigfactor * 0.5;
+                               voxelCenter[1] = smd->domain->p0[1] + smd->domain->dx * bigfactor * y + smd->domain->dx * bigfactor * 0.5;
+                               voxelCenter[2] = smd->domain->p0[2] + smd->domain->dx * bigfactor * z + smd->domain->dx * bigfactor * 0.5;
+                               // printf("vc[0]: %f, vc[1]: %f, vc[2]: %f\n", voxelCenter[0], voxelCenter[1], voxelCenter[2]);
+                               // printf("light[0]: %f, light[1]: %f, light[2]: %f\n", light[0], light[1], light[2]);
+                               // get starting position (in voxel coords)
+                               if(BLI_bvhtree_bb_raycast(bv, light, voxelCenter, pos) > FLT_EPSILON)
+                               {
+                                       // we're ouside
+                                       // printf("out: pos[0]: %f, pos[1]: %f, pos[2]: %f\n", pos[0], pos[1], pos[2]);
+                                       if(!big)
+                                               get_cell(smd, pos, cell, 1);
+                                       else
+                                               get_bigcell(smd, pos, cell, 1);
+                               }
+                               else
+                               {
+                                       // printf("in: pos[0]: %f, pos[1]: %f, pos[2]: %f\n", light[0], light[1], light[2]);
+                                       // we're inside
+                                       if(!big)
+                                               get_cell(smd, light, cell, 1);
+                                       else
+                                               get_bigcell(smd, light, cell, 1);
+                               }
+                               // printf("cell - [0]: %d, [1]: %d, [2]: %d\n", cell[0], cell[1], cell[2]);
+                               bresenham_linie_3D(smd, cell[0], cell[1], cell[2], x, y, z, &tRay, big);
+                               if(!big)
+                                       smoke_set_tray(smd, index, tRay);
+                               else
+                                       smoke_set_bigtray(smd, index, tRay);
+                       }
+ }
Simple merge
index 4576280a38dd0b1b9bcd48e7e7995910ff113bfa,0000000000000000000000000000000000000000..269c9a4e972d3ab825b49847e509c5e25fcf41af
mode 100644,000000..100644
--- /dev/null
@@@ -1,1692 -1,0 +1,1682 @@@
-       int ret;
 + /* $Id: bmesh_tools.c
 + *
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * The Original Code is Copyright (C) 2004 by Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): Joseph Eagar
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +#include <stdlib.h>
 +#include <stdarg.h>
 +#include <string.h>
 +#include <math.h>
 +#include <float.h>
 +
 +#include "MEM_guardedalloc.h"
 +#include "PIL_time.h"
 +
 +#include "BLO_sys_types.h" // for intptr_t support
 +
 +#include "DNA_mesh_types.h"
 +#include "DNA_material_types.h"
 +#include "DNA_meshdata_types.h"
 +#include "DNA_modifier_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_scene_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_view3d_types.h"
 +#include "DNA_key_types.h"
 +#include "DNA_windowmanager_types.h"
 +
 +#include "RNA_types.h"
 +#include "RNA_define.h"
 +#include "RNA_access.h"
 +
 +#include "BLI_blenlib.h"
 +#include "BLI_arithb.h"
 +#include "BLI_editVert.h"
 +#include "BLI_rand.h"
 +#include "BLI_ghash.h"
 +#include "BLI_linklist.h"
 +#include "BLI_heap.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_customdata.h"
 +#include "BKE_depsgraph.h"
 +#include "BKE_global.h"
 +#include "BKE_library.h"
 +#include "BKE_mesh.h"
 +#include "BKE_object.h"
 +#include "BKE_utildefines.h"
 +#include "BKE_bmesh.h"
 +#include "BKE_report.h"
 +#include "BKE_tessmesh.h"
 +
 +#include "BIF_gl.h"
 +#include "BIF_glutil.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +
 +#include "ED_mesh.h"
 +#include "ED_view3d.h"
 +#include "ED_util.h"
 +#include "ED_screen.h"
 +#include "ED_transform.h"
 +
 +#include "UI_interface.h"
 +
 +#include "mesh_intern.h"
 +#include "bmesh.h"
 +
 +static void add_normal_aligned(float *nor, float *add)
 +{
 +      if( INPR(nor, add) < -0.9999f)
 +              VecSubf(nor, nor, add);
 +      else
 +              VecAddf(nor, nor, add);
 +}
 +
 +
 +static int subdivide_exec(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      int cuts= RNA_int_get(op->ptr,"number_cuts");
 +      float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
 +      float fractal= RNA_float_get(op->ptr, "fractal")/100;
 +      int flag= 0;
 +
 +      if(smooth != 0.0f)
 +              flag |= B_SMOOTH;
 +      if(fractal != 0.0f)
 +              flag |= B_FRACTAL;
 +
 +      BM_esubdivideflag(obedit, em->bm, BM_SELECT, smooth, fractal, scene->toolsettings->editbutflag|flag, cuts, 0);
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_subdivide(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Subdivide";
 +      ot->idname= "MESH_OT_subdivide";
 +
 +      /* api callbacks */
 +      ot->exec= subdivide_exec;
 +      ot->poll= ED_operator_editmesh;
 +
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +
 +      /* properties */
 +      RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
 +      RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
 +      RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, 1000.0f, "Smoothness", "Smoothness factor.", 0.0f, FLT_MAX);
 +}
 +
 +#if 0
 +static int subdivide_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      
 +      BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, 1, 0);
 +              
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_subdivide(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Subdivide";
 +      ot->idname= "MESH_OT_subdivide";
 +      
 +      /* api callbacks */
 +      ot->exec= subdivide_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +static int subdivide_multi_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      
 +      BM_esubdivideflag(obedit, em->bm, 1, 0.0, scene->toolsettings->editbutflag, RNA_int_get(op->ptr,"number_cuts"), 0);
 +              
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_subdivide_multi(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Subdivide Multi";
 +      ot->idname= "MESH_OT_subdivide_multi";
 +      
 +      /* api callbacks */
 +      ot->exec= subdivide_multi_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* props */
 +      RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX);
 +}
 +
 +static int subdivide_multi_fractal_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +
 +      BM_esubdivideflag(obedit, em->bm, 1, -(RNA_float_get(op->ptr, "random_factor")/100), scene->toolsettings->editbutflag, RNA_int_get(op->ptr, "number_cuts"), 0);
 +              
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_subdivide_multi_fractal(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Subdivide Multi Fractal";
 +      ot->idname= "MESH_OT_subdivide_multi_fractal";
 +      
 +      /* api callbacks */
 +      ot->exec= subdivide_multi_fractal_exec;
 +      ot->poll= ED_operator_editmesh;
 +
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* properties */
 +      RNA_def_int(ot->srna, "number_cuts", 4, 1, 100, "Number of Cuts", "", 1, INT_MAX);
 +      RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f);
 +}
 +
 +static int subdivide_smooth_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +
 +      BM_esubdivideflag(obedit, em->bm, 1, 0.292f*RNA_float_get(op->ptr, "smoothness"), scene->toolsettings->editbutflag | B_SMOOTH, 1, 0);
 +              
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_subdivide_smooth(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Subdivide Smooth";
 +      ot->idname= "MESH_OT_subdivide_smooth";
 +      
 +      /* api callbacks */
 +      ot->exec= subdivide_smooth_exec;
 +      ot->poll= ED_operator_editmesh;
 +
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* props */
 +      RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX);
 +}
 +
 +static int subdivs_invoke(bContext *C, wmOperator *op, wmEvent *event)
 +{
 +      uiPopupMenu *pup;
 +      uiLayout *layout;
 +
 +      pup= uiPupMenuBegin(C, "Subdivision Type", 0);
 +      layout= uiPupMenuLayout(pup);
 +      uiItemsEnumO(layout, "MESH_OT_subdivs", "type");
 +      uiPupMenuEnd(C, pup);
 +      
 +      return OPERATOR_CANCELLED;
 +}
 +
 +static int subdivs_exec(bContext *C, wmOperator *op)
 +{     
 +      switch(RNA_int_get(op->ptr, "type"))
 +      {
 +              case 0: // simple
 +                      subdivide_exec(C,op);
 +                      break;
 +              case 1: // multi
 +                      subdivide_multi_exec(C,op);
 +                      break;
 +              case 2: // fractal;
 +                      subdivide_multi_fractal_exec(C,op);
 +                      break;
 +              case 3: //smooth
 +                      subdivide_smooth_exec(C,op);
 +                      break;
 +      }
 +                                       
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_subdivs(wmOperatorType *ot)
 +{
 +      static EnumPropertyItem type_items[]= {
 +              {0, "SIMPLE", 0, "Simple", ""},
 +              {1, "MULTI", 0, "Multi", ""},
 +              {2, "FRACTAL", 0, "Fractal", ""},
 +              {3, "SMOOTH", 0, "Smooth", ""},
 +              {0, NULL, NULL}};
 +
 +      /* identifiers */
 +      ot->name= "subdivs";
 +      ot->idname= "MESH_OT_subdivs";
 +      
 +      /* api callbacks */
 +      ot->invoke= subdivs_invoke;
 +      ot->exec= subdivs_exec;
 +      
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /*props */
 +      RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
 +      
 +      /* this is temp, the ops are different, but they are called from subdivs, so all the possible props should be here as well*/
 +      RNA_def_int(ot->srna, "number_cuts", 4, 1, 10, "Number of Cuts", "", 1, INT_MAX);
 +      RNA_def_float(ot->srna, "random_factor", 5.0, 0.0f, FLT_MAX, "Random Factor", "", 0.0f, 1000.0f);
 +      RNA_def_float(ot->srna, "smoothness", 1.0f, 0.0f, 1000.0f, "Smoothness", "", 0.0f, FLT_MAX);            
 +}
 +#endif
 +
 +/* individual face extrude */
 +/* will use vertex normals for extrusion directions, so *nor is unaffected */
 +short EDBM_Extrude_face_indiv(BMEditMesh *em, short flag, float *nor)
 +{
 +      return 'g';
 +#if 0
 +      EditVert *eve, *v1, *v2, *v3, *v4;
 +      EditEdge *eed;
 +      EditFace *efa, *nextfa;
 +      
 +      if(em==NULL) return 0;
 +      
 +      /* selected edges with 1 or more selected face become faces */
 +      /* selected faces each makes new faces */
 +      /* always remove old faces, keeps volumes manifold */
 +      /* select the new extrusion, deselect old */
 +      
 +      /* step 1; init, count faces in edges */
 +      recalc_editnormals(em);
 +      
 +      for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;      // new select flag
 +
 +      for(eed= em->edges.first; eed; eed= eed->next) {
 +              eed->f2= 0; // amount of unselected faces
 +      }
 +      for(efa= em->faces.first; efa; efa= efa->next) {
 +              if(efa->f & SELECT);
 +              else {
 +                      efa->e1->f2++;
 +                      efa->e2->f2++;
 +                      efa->e3->f2++;
 +                      if(efa->e4) efa->e4->f2++;
 +              }
 +      }
 +
 +      /* step 2: make new faces from faces */
 +      for(efa= em->faces.last; efa; efa= efa->prev) {
 +              if(efa->f & SELECT) {
 +                      v1= addvertlist(em, efa->v1->co, efa->v1);
 +                      v2= addvertlist(em, efa->v2->co, efa->v2);
 +                      v3= addvertlist(em, efa->v3->co, efa->v3);
 +                      
 +                      v1->f1= v2->f1= v3->f1= 1;
 +                      VECCOPY(v1->no, efa->n);
 +                      VECCOPY(v2->no, efa->n);
 +                      VECCOPY(v3->no, efa->n);
 +                      if(efa->v4) {
 +                              v4= addvertlist(em, efa->v4->co, efa->v4); 
 +                              v4->f1= 1;
 +                              VECCOPY(v4->no, efa->n);
 +                      }
 +                      else v4= NULL;
 +                      
 +                      /* side faces, clockwise */
 +                      addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
 +                      addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
 +                      if(efa->v4) {
 +                              addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
 +                              addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
 +                      }
 +                      else {
 +                              addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
 +                      }
 +                      /* top face */
 +                      addfacelist(em, v1, v2, v3, v4, efa, NULL);
 +              }
 +      }
 +      
 +      /* step 3: remove old faces */
 +      efa= em->faces.first;
 +      while(efa) {
 +              nextfa= efa->next;
 +              if(efa->f & SELECT) {
 +                      BLI_remlink(&em->faces, efa);
 +                      free_editface(em, efa);
 +              }
 +              efa= nextfa;
 +      }
 +
 +      /* step 4: redo selection */
 +      EM_clear_flag_all(em, SELECT);
 +      
 +      for(eve= em->verts.first; eve; eve= eve->next) {
 +              if(eve->f1)  eve->f |= SELECT;
 +      }
 +      
 +      EM_select_flush(em);
 +      
 +      return 'n';
 +#endif
 +}
 +
 +
 +/* extrudes individual edges */
 +/* nor is filled with constraint vector */
 +short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor) 
 +{
 +#if 0
 +      EditVert *eve;
 +      EditEdge *eed;
 +      EditFace *efa;
 +      
 +      for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
 +      for(eed= em->edges.first; eed; eed= eed->next) {
 +              eed->tmp.f = NULL;
 +              eed->f2= ((eed->f & flag)!=0);
 +      }
 +      
 +      set_edge_directions_f2(em, 2);
 +
 +      /* sample for next loop */
 +      for(efa= em->faces.first; efa; efa= efa->next) {
 +              efa->e1->tmp.f = efa;
 +              efa->e2->tmp.f = efa;
 +              efa->e3->tmp.f = efa;
 +              if(efa->e4) efa->e4->tmp.f = efa;
 +      }
 +      /* make the faces */
 +      for(eed= em->edges.first; eed; eed= eed->next) {
 +              if(eed->f & flag) {
 +                      if(eed->v1->tmp.v == NULL)
 +                              eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
 +                      if(eed->v2->tmp.v == NULL)
 +                              eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
 +
 +                      if(eed->dir==1) 
 +                              addfacelist(em, eed->v1, eed->v2, 
 +                                                      eed->v2->tmp.v, eed->v1->tmp.v, 
 +                                                      eed->tmp.f, NULL);
 +                      else 
 +                              addfacelist(em, eed->v2, eed->v1, 
 +                                                      eed->v1->tmp.v, eed->v2->tmp.v, 
 +                                                      eed->tmp.f, NULL);
 +
 +                      /* for transform */
 +                      if(eed->tmp.f) {
 +                              efa = eed->tmp.f;
 +                              if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
 +                      }
 +              }
 +      }
 +      Normalize(nor);
 +      
 +      /* set correct selection */
 +      EM_clear_flag_all(em, SELECT);
 +      for(eve= em->verts.last; eve; eve= eve->prev) {
 +              if(eve->tmp.v) {
 +                      eve->tmp.v->f |= flag;
 +              }
 +      }
 +
 +      for(eed= em->edges.first; eed; eed= eed->next) {
 +              if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
 +      }
 +      
 +      if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
 +#endif
 +      return 'n';  // n is for normal constraint
 +}
 +
 +/* extrudes individual vertices */
 +short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) 
 +{
 +      BMOperator bmop;
 +      BMOIter siter;
 +      BMVert *v;
 +
 +      EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
 +
 +      /*deselect original verts*/
 +      BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "verts", BM_SELECT);
 +
 +      BMO_Exec_Op(em->bm, &bmop);
 +
 +      BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT);
 +      if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
 +
 +      return 'g'; // g is grab
 +}
 +
 +short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
 +{
 +      BMesh *bm = em->bm;
 +      BMIter iter;
 +      BMOIter siter;
 +      BMOperator extop;
 +      BMVert *vert;
 +      BMEdge *edge;
 +      BMFace *f;
 +      ModifierData *md;
 +      BMHeader *el;
 +      
 +      BMO_Init_Op(&extop, "extrudefaceregion");
 +      BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
 +                             flag, BM_VERT|BM_EDGE|BM_FACE);
 +
 +      BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) {
 +              BM_Select(bm, vert, 0);
 +      }
 +
 +      BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
 +              BM_Select(bm, edge, 0);
 +      }
 +
 +      BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
 +              BM_Select(bm, f, 0);
 +      }
 +
 +      /* If a mirror modifier with clipping is on, we need to adjust some 
 +       * of the cases above to handle edges on the line of symmetry.
 +       */
 +      md = obedit->modifiers.first;
 +      for (; md; md=md->next) {
 +              if (md->type==eModifierType_Mirror) {
 +                      MirrorModifierData *mmd = (MirrorModifierData*) md;     
 +              
 +                      if(mmd->flag & MOD_MIR_CLIPPING) {
 +                              float mtx[4][4];
 +                              if (mmd->mirror_ob) {
 +                                      float imtx[4][4];
 +                                      Mat4Invert(imtx, mmd->mirror_ob->obmat);
 +                                      Mat4MulMat4(mtx, obedit->obmat, imtx);
 +                              }
 +
 +                              for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
 +                                   edge; edge=BMIter_Step(&iter))
 +                              {
 +                                      if(edge->head.flag & flag) {
 +                                              float co1[3], co2[3];
 +
 +                                              VecCopyf(co1, edge->v1->co);
 +                                              VecCopyf(co2, edge->v2->co);
 +
 +                                              if (mmd->mirror_ob) {
 +                                                      VecMat4MulVecfl(co1, mtx, co1);
 +                                                      VecMat4MulVecfl(co2, mtx, co2);
 +                                              }
 +
 +                                              if (mmd->flag & MOD_MIR_AXIS_X)
 +                                                      if ( (fabs(co1[0]) < mmd->tolerance) &&
 +                                                               (fabs(co2[0]) < mmd->tolerance) )
 +                                                              BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
 +
 +                                              if (mmd->flag & MOD_MIR_AXIS_Y)
 +                                                      if ( (fabs(co1[1]) < mmd->tolerance) &&
 +                                                               (fabs(co2[1]) < mmd->tolerance) )
 +                                                              BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
 +
 +                                              if (mmd->flag & MOD_MIR_AXIS_Z)
 +                                                      if ( (fabs(co1[2]) < mmd->tolerance) &&
 +                                                               (fabs(co2[2]) < mmd->tolerance) )
 +                                                              BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
 +      BMO_Exec_Op(bm, &extop);
 +
 +      nor[0] = nor[1] = nor[2] = 0.0f;
 +      
 +      BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
 +              BM_Select(bm, el, 1);
 +
 +              if (el->type == BM_FACE) {
 +                      f = (BMFace*)el;
 +                      add_normal_aligned(nor, f->no);
 +              };
 +      }
 +
 +      Normalize(nor);
 +
 +      BMO_Finish_Op(bm, &extop);
 +
 +      if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
 +      return 'n'; // normal constraint 
 +
 +}
 +short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
 +{
 +              BMIter iter;
 +              BMEdge *eed;
 +              
 +              /*ensure vert flags are consistent for edge selections*/
 +              eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
 +              for ( ; eed; eed=BMIter_Step(&iter)) {
 +                      if (BM_TestHFlag(eed, flag)) {
 +                              if (flag != BM_SELECT) {
 +                                      BM_SetHFlag(eed->v1, flag);
 +                                      BM_SetHFlag(eed->v2, flag);
 +                              } else {
 +                                      BM_Select(em->bm, eed->v1, 1);
 +                                      BM_Select(em->bm, eed->v2, 1);
 +                              }
 +                      } else {
 +                              if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) {
 +                                      if (flag != BM_SELECT)
 +                                              BM_SetHFlag(eed, flag);
 +                                      else BM_Select(em->bm, eed, 1);
 +                              }
 +                      }
 +              }
 +
 +              return EDBM_Extrude_edge(obedit, em, flag, nor);
 +
 +}
 +
 +static int extrude_repeat_mesh(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
 +      RegionView3D *rv3d = CTX_wm_region_view3d(C);           
 +              
 +      int steps = RNA_int_get(op->ptr,"steps");
 +      
 +      float offs = RNA_float_get(op->ptr,"offset");
 +
 +      float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
 +      short a;
 +
 +      /* dvec */
 +      dvec[0]= rv3d->persinv[2][0];
 +      dvec[1]= rv3d->persinv[2][1];
 +      dvec[2]= rv3d->persinv[2][2];
 +      Normalize(dvec);
 +      dvec[0]*= offs;
 +      dvec[1]*= offs;
 +      dvec[2]*= offs;
 +
 +      /* base correction */
 +      Mat3CpyMat4(bmat, obedit->obmat);
 +      Mat3Inv(tmat, bmat);
 +      Mat3MulVecfl(tmat, dvec);
 +
 +      for(a=0; a<steps; a++) {
 +              EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
 +              //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
 +              BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
 +              //extrudeflag(obedit, em, SELECT, nor);
 +              //translateflag(em, SELECT, dvec);
 +      }
 +      
 +      EDBM_RecalcNormals(em);
 +
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_extrude_repeat(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Extrude Repeat Mesh";
 +      ot->idname= "MESH_OT_extrude_repeat";
 +      
 +      /* api callbacks */
 +      ot->exec= extrude_repeat_mesh;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* props */
 +      RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
 +      RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
 +}
 +
 +/* generic extern called extruder */
 +int EDBM_Extrude_Mesh(Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
 +{
 +      Scene *scene= NULL;             // XXX CTX!
 +      short nr, transmode= 0;
 +      float stacknor[3] = {0.0f, 0.0f, 0.0f};
 +      float *nor = norin ? norin : stacknor;
 +
 +      nor[0] = nor[1] = nor[2] = 0.0f;
 +      if(em->selectmode & SCE_SELECT_VERTEX) {
 +              if(em->bm->totvertsel==0) nr= 0;
 +              else if(em->bm->totvertsel==1) nr= 4;
 +              else if(em->bm->totedgesel==0) nr= 4;
 +              else if(em->bm->totfacesel==0) 
 +                      nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
 +              else if(em->bm->totfacesel==1)
 +                      nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
 +              else 
 +                      nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
 +      }
 +      else if(em->selectmode & SCE_SELECT_EDGE) {
 +              if (em->bm->totedgesel==0) nr = 0;
 +              
 +              nr = 1;
 +              /*else if (em->totedgesel==1) nr = 3;
 +              else if(em->totfacesel==0) nr = 3;
 +              else if(em->totfacesel==1)
 +                      nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
 +              else
 +                      nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
 +              */
 +      }
 +      else {
 +              if (em->bm->totfacesel == 0) nr = 0;
 +              else if (em->bm->totfacesel == 1) nr = 1;
 +              else
 +                      nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
 +      }
 +              
 +      if(nr<1) return 'g';
 +
 +      if(nr==1 && em->selectmode & SCE_SELECT_VERTEX) 
 +              transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
 +      else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
 +      else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
 +      else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, SELECT, nor);
 +      else transmode= EDBM_Extrude_face_indiv(em, SELECT, nor);
 +      
 +      if(transmode==0) {
 +              BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
 +      }
 +      else {
 +              
 +                      /* We need to force immediate calculation here because 
 +                      * transform may use derived objects (which are now stale).
 +                      *
 +                      * This shouldn't be necessary, derived queries should be
 +                      * automatically building this data if invalid. Or something.
 +                      */
 +//            DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
 +              object_handle_update(scene, obedit);
 +
 +              /* individual faces? */
 +//            BIF_TransformSetUndo("Extrude");
 +              if(nr==2) {
 +//                    initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
 +//                    Transform();
 +              }
 +              else {
 +//                    initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
 +                      if(transmode=='n') {
 +                              Mat4MulVecfl(obedit->obmat, nor);
 +                              VecSubf(nor, nor, obedit->obmat[3]);
 +//                            BIF_setSingleAxisConstraint(nor, "along normal");
 +                      }
 +//                    Transform();
 +              }
 +      }
 +      
 +      return transmode;
 +}
 +
 +static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
 +{
 +      Scene *scene= CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
 +      int constraint_axis[3] = {0, 0, 1};
 +      int tmode;
 +
 +      tmode = EDBM_Extrude_Mesh(obedit, em, op, NULL);
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      RNA_enum_set(op->ptr, "proportional", 0);
 +      RNA_boolean_set(op->ptr, "mirror", 0);
 +
 +      if (tmode == 'n') {
 +              RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
 +              RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
 +      }
 +      WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +/* extrude without transform */
 +static int mesh_extrude_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
 +      
 +      EDBM_Extrude_Mesh(obedit, em, op, NULL);
 +      
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      
 +      return OPERATOR_FINISHED;       
 +}
 +
 +
 +void MESH_OT_extrude(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Extrude";
 +      ot->idname= "MESH_OT_extrude";
 +      
 +      /* api callbacks */
 +      ot->invoke= mesh_extrude_invoke;
 +      ot->exec= mesh_extrude_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +
 +      /* to give to transform */
 +      Properties_Proportional(ot);
 +      Properties_Constraints(ot);
 +      RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
 +}
 +
 +/* ******************** (de)select all operator **************** */
 +
 +void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */
 +{
 +      if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
 +              EDBM_clear_flag_all(em, SELECT);
 +      else 
 +              EDBM_set_flag_all(em, SELECT);
 +}
 +
 +static int toggle_select_all_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      
 +      EDBM_toggle_select_all(em);
 +      
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_select_all_toggle(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Select/Deselect All";
 +      ot->idname= "MESH_OT_select_all_toggle";
 +      
 +      /* api callbacks */
 +      ot->exec= toggle_select_all_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +/* *************** add-click-mesh (extrude) operator ************** */
 +
 +static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
 +{
 +      ViewContext vc;
 +      BMVert *v1;
 +      BMIter iter;
 +      float min[3], max[3];
 +      int done= 0;
 +      
 +      em_setup_viewcontext(C, &vc);
 +      
 +      INIT_MINMAX(min, max);
 +      
 +      BM_ITER_SELECT(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL)
 +              DO_MINMAX(v1->co, min, max);
 +              done= 1;
 +      }
 +
 +      /* call extrude? */
 +      if(done) {
 +              BMEdge *eed;
 +              float vec[3], cent[3], mat[3][3];
 +              float nor[3]= {0.0, 0.0, 0.0};
 +              
 +              /* check for edges that are half selected, use for rotation */
 +              done= 0;
 +              BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) {
 +                      if (BM_TestHFlag(eed->v1, BM_SELECT) ^ BM_TestHFlag(eed->v2, BM_SELECT)) {
 +                              if(BM_TestHFlag(eed->v1, BM_SELECT)) 
 +                                      VecSubf(vec, eed->v1->co, eed->v2->co);
 +                              else 
 +                                      VecSubf(vec, eed->v2->co, eed->v1->co);
 +                              VecAddf(nor, nor, vec);
 +                              done= 1;
 +                      }
 +              }
 +              if(done) Normalize(nor);
 +              
 +              /* center */
 +              VecAddf(cent, min, max);
 +              VecMulf(cent, 0.5f);
 +              VECCOPY(min, cent);
 +              
 +              Mat4MulVecfl(vc.obedit->obmat, min);    // view space
 +              view3d_get_view_aligned_coordinate(&vc, min, event->mval);
 +              Mat4Invert(vc.obedit->imat, vc.obedit->obmat); 
 +              Mat4MulVecfl(vc.obedit->imat, min); // back in object space
 +              
 +              VecSubf(min, min, cent);
 +              
 +              /* calculate rotation */
 +              Mat3One(mat);
 +              if(done) {
 +                      float dot;
 +                      
 +                      VECCOPY(vec, min);
 +                      Normalize(vec);
 +                      dot= INPR(vec, nor);
 +
 +                      if( fabs(dot)<0.999) {
 +                              float cross[3], si, q1[4];
 +                              
 +                              Crossf(cross, nor, vec);
 +                              Normalize(cross);
 +                              dot= 0.5f*saacos(dot);
 +                              si= (float)sin(dot);
 +                              q1[0]= (float)cos(dot);
 +                              q1[1]= cross[0]*si;
 +                              q1[2]= cross[1]*si;
 +                              q1[3]= cross[2]*si;
 +                              
 +                              QuatToMat3(q1, mat);
 +                      }
 +              }
 +              
 +
 +              EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor);
 +              EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
 +                      BM_SELECT, cent, mat);
 +              EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
 +                      BM_SELECT, min);
 +      }
 +      else {
 +              float *curs= give_cursor(vc.scene, vc.v3d);
 +              BMOperator bmop;
 +              BMOIter oiter;
 +              
 +              VECCOPY(min, curs);
 +
 +              view3d_get_view_aligned_coordinate(&vc, min, event->mval);
 +              Mat4Invert(vc.obedit->imat, vc.obedit->obmat); 
 +              Mat4MulVecfl(vc.obedit->imat, min); // back in object space
 +              
 +              EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min);
 +              BMO_Exec_Op(vc.em->bm, &bmop);
 +
 +              BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
 +                      BM_Select(vc.em->bm, v1, 1);
 +              }
 +
 +              if (!EDBM_FinishOp(vc.em, &bmop, op, 1))
 +                      return OPERATOR_CANCELLED;
 +      }
 +
 +      //retopo_do_all();
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit); 
 +      DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Duplicate or Extrude at 3D Cursor";
 +      ot->idname= "MESH_OT_dupli_extrude_cursor";
 +      
 +      /* api callbacks */
 +      ot->invoke= dupli_extrude_cursor;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +static int delete_mesh(Object *obedit, wmOperator *op, int event, Scene *scene)
 +{
 +      BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh;
 +      
 +      if(event<1) return OPERATOR_CANCELLED;
 +
 +      if(event==10 ) {
 +              //"Erase Vertices";
 +
 +              if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS))
 +                      return OPERATOR_CANCELLED;
 +      } 
 +      else if(event==11) {
 +              //"Edge Loop"
 +              if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT))
 +                      return OPERATOR_CANCELLED;
 +      }
 +      else if(event==7) {
 +              //"Dissolve"
 +              if (bem->selectmode & SCE_SELECT_FACE) {
 +                      if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT))
 +                              return OPERATOR_CANCELLED;
 +              } else if (bem->selectmode & SCE_SELECT_EDGE) {
 +                      if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT))
 +                              return OPERATOR_CANCELLED;
 +              } else if (bem->selectmode & SCE_SELECT_VERTEX) {
 +                      if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT))
 +                              return OPERATOR_CANCELLED;
 +              }
 +      }
 +      else if(event==4) {
 +              //Edges and Faces
 +              if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES))
 +                      return OPERATOR_CANCELLED;
 +      } 
 +      else if(event==1) {
 +              //"Erase Edges"
 +              if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES))
 +                      return OPERATOR_CANCELLED;
 +      }
 +      else if(event==2) {
 +              //"Erase Faces";
 +              if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES))
 +                      return OPERATOR_CANCELLED;
 +      }
 +      else if(event==5) {
 +              //"Erase Only Faces";
 +              if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
 +                                BM_SELECT, DEL_ONLYFACES))
 +                      return OPERATOR_CANCELLED;
 +      }
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +/* Note, these values must match delete_mesh() event values */
 +static EnumPropertyItem prop_mesh_delete_types[] = {
 +      {7, "DISSOLVE",         0, "Dissolve", ""},
 +      {10,"VERT",             0, "Vertices", ""},
 +      {1, "EDGE",             0, "Edges", ""},
 +      {2, "FACE",             0, "Faces", ""},
 +      {11, "EDGE_LOOP", 0, "Edge Loop", ""},
 +      {4, "EDGE_FACE", 0, "Edges & Faces", ""},
 +      {5, "ONLY_FACE", 0, "Only Faces", ""},
 +      {0, NULL, 0, NULL, NULL}
 +};
 +
 +static int delete_mesh_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +
 +      delete_mesh(obedit, op, RNA_enum_get(op->ptr, "type"), scene);
 +      
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA|ND_GEOM_SELECT, obedit);
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_delete(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Delete";
 +      ot->idname= "MESH_OT_delete";
 +      
 +      /* api callbacks */
 +      ot->invoke= WM_menu_invoke;
 +      ot->exec= delete_mesh_exec;
 +      
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /*props */
 +      RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
 +}
 +
 +
 +static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
 +{
 +      BMOperator bmop;
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      
 +      if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT))
 +              return OPERATOR_CANCELLED;
 +      
 +      BMO_Exec_Op(em->bm, &bmop);
 +      BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT);
 +
 +      if (!EDBM_FinishOp(em, &bmop, op, 1))
 +              return OPERATOR_CANCELLED;
 +
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);     
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_edge_face_add(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Make Edge/Face";
 +      ot->idname= "MESH_OT_edge_face_add";
 +      
 +      /* api callbacks */
 +      ot->exec= addedgeface_mesh_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +}
 +
 +static EnumPropertyItem prop_mesh_edit_types[] = {
 +      {1, "VERT", 0, "Vertices", ""},
 +      {2, "EDGE", 0, "Edges", ""},
 +      {3, "FACE", 0, "Faces", ""},
 +      {0, NULL, 0, NULL, NULL}
 +};
 +
 +static int mesh_selection_type_exec(bContext *C, wmOperator *op)
 +{             
 +      
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      int type = RNA_enum_get(op->ptr,"type");
 +
 +      switch (type) {
 +              case 1:
 +                      em->selectmode = SCE_SELECT_VERTEX;
 +                      break;
 +              case 2:
 +                      em->selectmode = SCE_SELECT_EDGE;
 +                      break;
 +              case 3:
 +                      em->selectmode = SCE_SELECT_FACE;
 +                      break;
 +      }
 +
 +      EDBM_selectmode_set(em);
 +      CTX_data_scene(C)->toolsettings->selectmode = em->selectmode;
 +
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_selection_type(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Selection Mode";
 +      ot->idname= "MESH_OT_selection_type";
 +      
 +      /* api callbacks */
 +      ot->invoke= WM_menu_invoke;
 +      ot->exec= mesh_selection_type_exec;
 +      
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* props */
 +      RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
 +      RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode");       
 +}
 +
 +/* ************************* SEAMS AND EDGES **************** */
 +
 +static int editbmesh_mark_seam(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      Mesh *me= ((Mesh *)obedit->data);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      BMesh *bm = em->bm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int clear = RNA_boolean_get(op->ptr, "clear");
 +      
 +      /* auto-enable seams drawing */
 +      if(clear==0) {
 +              me->drawflag |= ME_DRAWSEAMS;
 +      }
 +
 +      if(clear) {
 +              BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
 +                      BM_ClearHFlag(eed, BM_SEAM);
 +              }
 +      }
 +      else {
 +              BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
 +                      BM_SetHFlag(eed, BM_SEAM);
 +              }
 +      }
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_mark_seam(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Mark Seam";
 +      ot->idname= "MESH_OT_mark_seam";
 +      
 +      /* api callbacks */
 +      ot->exec= editbmesh_mark_seam;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
 +}
 +
 +static int editbmesh_mark_sharp(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      Mesh *me= ((Mesh *)obedit->data);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      BMesh *bm = em->bm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int clear = RNA_boolean_get(op->ptr, "clear");
 +
 +      /* auto-enable sharp edge drawing */
 +      if(clear == 0) {
 +              me->drawflag |= ME_DRAWSHARP;
 +      }
 +
 +      if(!clear) {
 +              BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
 +                      BM_SetHFlag(eed, BM_SHARP);
 +              }
 +      } else {
 +              BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
 +                      BM_ClearHFlag(eed, BM_SHARP);
 +              }
 +      }
 +
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_mark_sharp(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Mark Sharp";
 +      ot->idname= "MESH_OT_mark_sharp";
 +      
 +      /* api callbacks */
 +      ot->exec= editbmesh_mark_sharp;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
 +}
 +
 +
 +static int editbmesh_vert_connect(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      Mesh *me= ((Mesh *)obedit->data);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      BMesh *bm = em->bm;
 +      BMOperator bmop;
 +      int len = 0;
 +      
 +      BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT);
 +      BMO_Exec_Op(bm, &bmop);
 +      len = BMO_GetSlot(&bmop, "edgeout")->len;
 +      BMO_Finish_Op(bm, &bmop);
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 +}
 +
 +void MESH_OT_vert_connect(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Vertex Connect";
 +      ot->idname= "MESH_OT_vert_connect";
 +      
 +      /* api callbacks */
 +      ot->exec= editbmesh_vert_connect;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +static int editbmesh_edge_split(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      Mesh *me= ((Mesh *)obedit->data);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      BMesh *bm = em->bm;
 +      BMOperator bmop;
 +      int len = 0;
 +      
 +      BMO_InitOpf(bm, &bmop, "edgesplit edges=%he numcuts=%d", BM_SELECT, RNA_int_get(op->ptr,"number_cuts"));
 +      BMO_Exec_Op(bm, &bmop);
 +      len = BMO_GetSlot(&bmop, "outsplit")->len;
 +      BMO_Finish_Op(bm, &bmop);
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 +}
 +
 +void MESH_OT_edge_split(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Edge Split";
 +      ot->idname= "MESH_OT_edge_split";
 +      
 +      /* api callbacks */
 +      ot->exec= editbmesh_edge_split;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +
 +      RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
 +}
 +
 +/****************** add duplicate operator ***************/
 +
 +static int mesh_duplicate_exec(bContext *C, wmOperator *op)
 +{
 +      Scene *scene= CTX_data_scene(C);
 +      Object *ob= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
 +      BMOperator bmop;
 +
 +      EDBM_InitOpf(em, &bmop, op, "dupe geom=%hvef", BM_SELECT);
 +      
 +      BMO_Exec_Op(em->bm, &bmop);
 +      EDBM_clear_flag_all(em, BM_SELECT);
 +
 +      BMO_HeaderFlag_Buffer(em->bm, &bmop, "newout", BM_SELECT);
 +
 +      if (!EDBM_FinishOp(em, &bmop, op, 1))
 +              return OPERATOR_CANCELLED;
 +
 +      DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
 +{
-       ret = mesh_duplicate_exec(C, op);
 +      WM_cursor_wait(1);
-       if (ret == OPERATOR_CANCELLED)
-               return OPERATOR_CANCELLED;
-       
-       RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
-       WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
++      mesh_duplicate_exec(C, op);
 +      WM_cursor_wait(0);
-       BMO_ITER(eed, &siter, em->bm, &bmop, "edgeout", BM_EDGE) {
-               BM_Select(em->bm, eed, 1);
-       }
 +      
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_duplicate(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Duplicate";
 +      ot->idname= "MESH_OT_duplicate";
 +      
 +      /* api callbacks */
 +      ot->invoke= mesh_duplicate_invoke;
 +      ot->exec= mesh_duplicate_exec;
 +      
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* to give to transform */
 +      RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
 +}
 +
 +static int flip_normals(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
 +      
 +      if (!EDBM_CallOpf(em, op, "reversefaces facaes=%hf", BM_SELECT))
 +              return OPERATOR_CANCELLED;
 +      
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_flip_normals(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Flip Normals";
 +      ot->idname= "MESH_OT_flip_normals";
 +      
 +      /* api callbacks */
 +      ot->exec= flip_normals;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +#define DIRECTION_CW  1
 +#define DIRECTION_CCW 2
 +
 +static const EnumPropertyItem direction_items[]= {
 +      {DIRECTION_CW, "CW", 0, "Clockwise", ""},
 +      {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""},
 +      {0, NULL, 0, NULL, NULL}};
 +
 +/* only accepts 1 selected edge, or 2 selected faces */
 +static int edge_rotate_selected(bContext *C, wmOperator *op)
 +{
 +      Scene *scene= CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      BMOperator bmop;
 +      BMOIter siter;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int ccw = RNA_int_get(op->ptr, "direction") == 1; // direction == 2 when clockwise and ==1 for counter CW.
 +      short edgeCount = 0;
 +      
 +      if (!(em->bm->totfacesel == 2 || em->bm->totedgesel == 1)) {
 +              BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      /*first see if we have two adjacent faces*/
 +      BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
 +              if (BM_Edge_FaceCount(eed) == 2) {
 +                      if ((BM_TestHFlag(eed->loop->f, BM_SELECT) && BM_TestHFlag(((BMLoop*)eed->loop->radial.next->data)->f, BM_SELECT))
 +                           && !(BM_TestHFlag(eed->loop->f, BM_HIDDEN) || BM_TestHFlag(((BMLoop*)eed->loop->radial.next->data)->f, BM_HIDDEN)))
 +                      {
 +                              break;
 +                      }
 +              }
 +      }
 +      
 +      /*ok, we don't have two adjacent faces, but we do have two selected ones.
 +        that's an error condition.*/
 +      if (!eed && em->bm->totfacesel == 2) {
 +              BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
 +              return OPERATOR_CANCELLED;
 +      }
 +
 +      if (!eed) {
 +              BM_ITER_SELECT(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL)
 +                      if (BM_TestHFlag(eed, BM_SELECT))
 +                              break;
 +              }
 +      }
 +
 +      /*this should never happen*/
 +      if (!eed)
 +              return OPERATOR_CANCELLED;
 +      
 +      EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, ccw);
 +      BMO_Exec_Op(em->bm, &bmop);
 +
++      BMO_HeaderFlag_Slot(em->bm, &bmop, "edgeout", BM_SELECT);
 +
 +      if (!EDBM_FinishOp(em, &bmop, op, 1))
 +              return OPERATOR_CANCELLED;
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +void MESH_OT_edge_rotate(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Rotate Selected Edge";
 +      ot->idname= "MESH_OT_edge_rotate";
 +
 +      /* api callbacks */
 +      ot->exec= edge_rotate_selected;
 +      ot->poll= ED_operator_editmesh;
 +
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +
 +      /* props */
 +      RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "direction", "direction to rotate edge around.");
 +}
 +
 +/* swap is 0 or 1, if 1 it hides not selected */
 +void EDBM_hide_mesh(BMEditMesh *em, int swap)
 +{
 +      BMIter iter;
 +      BMHeader *h;
 +      int itermode;
 +
 +      if(em==NULL) return;
 +      
 +      if (em->selectmode & SCE_SELECT_VERTEX)
 +              itermode = BM_VERTS_OF_MESH;
 +      else if (em->selectmode & SCE_SELECT_EDGE)
 +              itermode = BM_EDGES_OF_MESH;
 +      else
 +              itermode = BM_FACES_OF_MESH;
 +
 +      BM_ITER(h, &iter, em->bm, itermode, NULL) {
 +              if (BM_TestHFlag(h, BM_SELECT) ^ swap)
 +                      BM_Hide(em->bm, h, 1);
 +      }
 +
 +      /*original hide flushing comment (OUTDATED): 
 +        hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
 +      /*  - vertex hidden, always means edge is hidden too
 +              - edge hidden, always means face is hidden too
 +              - face hidden, only set face hide
 +              - then only flush back down what's absolute hidden
 +      */
 +
 +}
 +
 +static int hide_mesh_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
 +      
 +      EDBM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
 +              
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_hide(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Hide Selection";
 +      ot->idname= "MESH_OT_hide";
 +      
 +      /* api callbacks */
 +      ot->exec= hide_mesh_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* props */
 +      RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
 +}
 +
 +
 +void EDBM_reveal_mesh(BMEditMesh *em)
 +{
 +      BMIter iter;
 +      BMHeader *ele;
 +      int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
 +      int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & SCE_SELECT_VERTEX | SCE_SELECT_EDGE)};
 +
 +      for (i=0; i<3; i++) {
 +              BM_ITER(ele, &iter, em->bm, types[i], NULL) {
 +                      if (BM_TestHFlag(ele, BM_HIDDEN)) {
 +                              BM_Hide(em->bm, ele, 0);
 +
 +                              if (sels[i])
 +                                      BM_Select(em->bm, ele, 1);
 +                      }
 +              }
 +      }
 +
 +      EDBM_selectmode_flush(em);
 +}
 +
 +static int reveal_mesh_exec(bContext *C, wmOperator *op)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
 +      
 +      EDBM_reveal_mesh(em);
 +
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_reveal(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Reveal Hidden";
 +      ot->idname= "MESH_OT_reveal";
 +      
 +      /* api callbacks */
 +      ot->exec= reveal_mesh_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
 +static int normals_make_consistent_exec(bContext *C, wmOperator *op)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit= CTX_data_edit_object(C);
 +      BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
 +      
 +      if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf", BM_SELECT))
 +              return OPERATOR_CANCELLED;
 +      
 +      if (RNA_boolean_get(op->ptr, "inside"))
 +              EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT);
 +
 +      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); //TODO is this needed ?
 +
 +      return OPERATOR_FINISHED;       
 +}
 +
 +void MESH_OT_normals_make_consistent(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Make Normals Consistent";
 +      ot->idname= "MESH_OT_normals_make_consistent";
 +      
 +      /* api callbacks */
 +      ot->exec= normals_make_consistent_exec;
 +      ot->poll= ED_operator_editmesh;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
 +}
 +
index dea78545fac1bdf94f8d9c15d48a4a9fbb503520,d29a4e21913a47a4ade75282cefb4da3a179994b..c1497ce1a06bf0c36be8afc704876695b1646247
@@@ -4701,10 -4991,9 +4701,10 @@@ static int mesh_rip_invoke(bContext *C
  
        BKE_mesh_end_editmesh(obedit->data, em);
  
-       RNA_enum_set(op->ptr, "proportional", 0);
-       RNA_boolean_set(op->ptr, "mirror", 0);
-       WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
+ //    RNA_enum_set(op->ptr, "proportional", 0);
+ //    RNA_boolean_set(op->ptr, "mirror", 0);
+ //    WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
 +#endif
  
        return OPERATOR_FINISHED;
  }
index ebdef22349b547f2232428acbd641a30f73e6a9a,edb131d7da2e9f556a5462b098c8fda0dc3a420a..f3a504bb214bfee58ad2523e97a5cc1c86850b1a
@@@ -313,9 -315,20 +315,21 @@@ void ED_operatortypes_mesh(void
        WM_operatortype_append(MESH_OT_edge_specials);
        WM_operatortype_append(MESH_OT_face_specials);
        WM_operatortype_append(MESH_OT_specials);
 +      WM_operatortype_append(MESH_OT_vert_connect);
 +      WM_operatortype_append(MESH_OT_edge_split);
+       
+       /* macros */
+       ot= WM_operatortype_append_macro("MESH_OT_duplicate_move", "Add Duplicate", OPTYPE_UNDO|OPTYPE_REGISTER);
+       WM_operatortype_macro_define(ot, "MESH_OT_duplicate");
+       WM_operatortype_macro_define(ot, "TFM_OT_translate");
+       ot= WM_operatortype_append_macro("MESH_OT_rip_move", "Rip", OPTYPE_UNDO|OPTYPE_REGISTER);
+       WM_operatortype_macro_define(ot, "MESH_OT_rip");
+       WM_operatortype_macro_define(ot, "TFM_OT_translate");
 -      ot= WM_operatortype_append_macro("MESH_OT_extrude_move", "Extrude", OPTYPE_UNDO|OPTYPE_REGISTER);
++      /*ot= WM_operatortype_append_macro("MESH_OT_extrude_move", "Extrude", OPTYPE_UNDO|OPTYPE_REGISTER);
+       WM_operatortype_macro_define(ot, "MESH_OT_extrude");
 -      WM_operatortype_macro_define(ot, "TFM_OT_translate");
 -      
++      WM_operatortype_macro_define(ot, "TFM_OT_translate");*/
  }
  
  /* note mesh keymap also for other space? */
index b90ac30cd415110fecb6fb9a156caa48169f4a8c,4eb9f3f5ecb85b49997a7db3a91b87a7daeb2815..b6cb91609afe31d66acd21467f313a533c9204e2
@@@ -7,7 -7,8 +7,8 @@@ defs = [
  incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
  incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
  incs += ' ../../render/extern/include #/intern/guardedalloc'
- incs += ' ../../gpu ../../makesrna ../../blenfont ../../bmesh '
 -incs += ' ../../gpu ../../makesrna ../../blenfont'
++incs += ' ../../gpu ../../makesrna ../../blenfont ../../bmesh'
+ incs += ' #/intern/smoke/extern'
  
  if env['WITH_BF_GAMEENGINE']:
        defs.append('GAMEBLENDER=1')
index 122a1965af629419cff01575be485f14be415e33,f9d46cff9e685d9be63efc6c63dba96069ff0a33..43dacd28ca047557517e4460abacc45c2c0b82ee
  #include "BKE_object.h"
  #include "BKE_particle.h"
  #include "BKE_property.h"
+ #include "BKE_smoke.h"
  #include "BKE_utildefines.h"
 +#include "BKE_tessmesh.h"
 +
+ #include "smoke_API.h"
  #include "BIF_gl.h"
  #include "BIF_glutil.h"
  
index 2eb1a505a1992f3a38472606551099c21567b482,c1fbb67617921ef3de9e48414b4f6b93f9dca9d8..d0c0a63eb1a960a75ef22d78610186a8a2137cf0
@@@ -82,7 -81,8 +82,8 @@@
  #include "ED_screen.h"
  #include "ED_types.h"
  #include "ED_util.h"
 +#include "ED_retopo.h"
+ #include "ED_mball.h"
  
  #include "UI_interface.h"
  #include "UI_resources.h"
index f2d2d3edb8d8a099fee19aca25fa4f8e3e469b6b,bb5a8b1dd40e11481d4ee1d064f6790c12ae8e50..4a15b61736073807d60ccb8079e5b4cbd2378f48
@@@ -1354,19 -1126,16 +1354,19 @@@ static int stitch_exec(bContext *C, wmO
        SpaceImage *sima;
        Scene *scene;
        Object *obedit;
 -      EditMesh *em;
 -      EditFace *efa;
 -      EditVert *eve;
 +      BMEditMesh *em;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      BMVert *eve;
        Image *ima;
 -      MTFace *tf;
 +      MTexPoly *tf;
 +      MLoopUV *luv;
        
-       sima= (SpaceImage*)CTX_wm_space_data(C);
+       sima= CTX_wm_space_image(C);
        scene= CTX_data_scene(C);
        obedit= CTX_data_edit_object(C);
 -      em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 +      em= ((Mesh*)obedit->data)->edit_btmesh;
        ima= CTX_data_edit_image(C);
        
        if(RNA_boolean_get(op->ptr, "use_limit")) {
@@@ -2438,16 -2223,13 +2438,16 @@@ static void select_uv_inside_ellipse(BM
  
  int circle_select_exec(bContext *C, wmOperator *op)
  {
-       SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
+       SpaceImage *sima= CTX_wm_space_image(C);
        Scene *scene= CTX_data_scene(C);
        Object *obedit= CTX_data_edit_object(C);
 -      EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
        ARegion *ar= CTX_wm_region(C);
 -      EditFace *efa;
 -      MTFace *tface;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MLoopUV *luv;
 +      MTexPoly *tface;
        int x, y, radius, width, height, select;
        float zoomx, zoomy, offset[2], ellipse[2];
  
@@@ -2883,16 -2694,12 +2883,16 @@@ void UV_OT_select_pinned(wmOperatorTyp
  
  static int hide_exec(bContext *C, wmOperator *op)
  {
-       SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
+       SpaceImage *sima= CTX_wm_space_image(C);
        ToolSettings *ts= CTX_data_tool_settings(C);
        Object *obedit= CTX_data_edit_object(C);
 -      EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 -      EditFace *efa;
 -      MTFace *tf;
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MTexPoly *tf;
 +      MLoopUV *luv;
        int swap= RNA_boolean_get(op->ptr, "unselected");
  
        if(ts->uv_flag & UV_SYNC_SELECTION) {
@@@ -2953,43 -2837,110 +2953,43 @@@ void UV_OT_hide(wmOperatorType *ot
  
  static int reveal_exec(bContext *C, wmOperator *op)
  {
-       SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
+       SpaceImage *sima= CTX_wm_space_image(C);
        ToolSettings *ts= CTX_data_tool_settings(C);
        Object *obedit= CTX_data_edit_object(C);
 -      EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 -      EditFace *efa;
 -      MTFace *tf;
 +      Scene *scene = CTX_data_scene(C);
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMVert *v;
 +      BMIter iter, liter;
 +      MTexPoly *tf;
 +      MLoopUV *luv;
        
 +      BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
 +              BMINDEX_SET(v, BM_TestHFlag(v, BM_SELECT));
 +      }
 +
        /* call the mesh function if we are in mesh sync sel */
        if(ts->uv_flag & UV_SYNC_SELECTION) {
 -              EM_reveal_mesh(em);
 +              EDBM_reveal_mesh(em);
                WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
  
 -              BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_FINISHED;
        }
 -      
 -      if(sima->flag & SI_SELACTFACE) {
 -              if(em->selectmode == SCE_SELECT_FACE) {
 -                      for(efa= em->faces.first; efa; efa= efa->next) {
 -                              if(!(efa->h) && !(efa->f & SELECT)) {
 -                                      tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -                                      EM_select_face(efa, 1);
 -                                      tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
 -                              }
 -                      }
 -              }
 -              else {
 -                      /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
 -                      if(sima->sticky == SI_STICKY_DISABLE) {
 -                              for(efa= em->faces.first; efa; efa= efa->next) {
 -                                      if(!(efa->h) && !(efa->f & SELECT)) {
 -                                              /* All verts must be unselected for the face to be selected in the UV view */
 -                                              if((efa->v1->f&SELECT)==0 && (efa->v2->f&SELECT)==0 && (efa->v3->f&SELECT)==0 && (efa->v4==0 || (efa->v4->f&SELECT)==0)) {
 -                                                      tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -
 -                                                      tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
 -                                                      /* Cant use EM_select_face here because it unselects the verts
 -                                                       * and we cant tell if the face was totally unselected or not */
 -                                                      /*EM_select_face(efa, 1);
 -                                                       * 
 -                                                       * See Loop with EM_select_face() below... */
 -                                                      efa->f |= SELECT;
 -                                              }
 -                                      }
 -                              }
 -                      }
 -                      else {
 -                              for(efa= em->faces.first; efa; efa= efa->next) {
 -                                      if(!(efa->h) && !(efa->f & SELECT)) {
 -                                              tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -
 -                                              if((efa->v1->f & SELECT)==0)                            {tf->flag |= TF_SEL1;}
 -                                              if((efa->v2->f & SELECT)==0)                            {tf->flag |= TF_SEL2;}
 -                                              if((efa->v3->f & SELECT)==0)                            {tf->flag |= TF_SEL3;}
 -                                              if((efa->v4 && (efa->v4->f & SELECT)==0))       {tf->flag |= TF_SEL4;}
  
 -                                              efa->f |= SELECT;
 -                                      }
 +      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +              if (em->selectmode == SCE_SELECT_FACE) {
 +                      uvedit_face_select(scene, em, efa);
 +              } else {
 +                      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                              if (!BMINDEX_GET(l->v)) {
 +                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                      luv->flag |= MLOOPUV_VERTSEL;
                                }
                        }
 -                      
 -                      /* Select all edges and verts now */
 -                      for(efa= em->faces.first; efa; efa= efa->next)
 -                              /* we only selected the face flags, and didnt changes edges or verts, fix this now */
 -                              if(!(efa->h) && (efa->f & SELECT))
 -                                      EM_select_face(efa, 1);
 -
 -                      EM_select_flush(em);
                }
 -      }
 -      else if(em->selectmode == SCE_SELECT_FACE) {
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      if(!(efa->h) && !(efa->f & SELECT)) {
 -                              tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -                              efa->f |= SELECT;
 -                              tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
 -                      }
 -              }
 -              
 -              /* Select all edges and verts now */
 -              for(efa= em->faces.first; efa; efa= efa->next)
 -                      /* we only selected the face flags, and didnt changes edges or verts, fix this now */
 -                      if(!(efa->h) && (efa->f & SELECT))
 -                              EM_select_face(efa, 1);
 -      }
 -      else {
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      if(!(efa->h) && !(efa->f & SELECT)) {
 -                              tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -
 -                              if((efa->v1->f & SELECT)==0)                            {tf->flag |= TF_SEL1;}
 -                              if((efa->v2->f & SELECT)==0)                            {tf->flag |= TF_SEL2;}
 -                              if((efa->v3->f & SELECT)==0)                            {tf->flag |= TF_SEL3;}
 -                              if((efa->v4 && (efa->v4->f & SELECT)==0))       {tf->flag |= TF_SEL4;}
  
 -                              efa->f |= SELECT;
 -                      }
 -              }
 -              
 -              /* Select all edges and verts now */
 -              for(efa= em->faces.first; efa; efa= efa->next)
 -                      /* we only selected the face flags, and didnt changes edges or verts, fix this now */
 -                      if(!(efa->h) && (efa->f & SELECT))
 -                              EM_select_face(efa, 1);
 +              BM_Select(em->bm, efa, 1);
        }
  
        WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
Simple merge
index 518c72280cc13211d85d52ab03dad867d1148c40,525814f1f5e2dd632eb5b26a5ab78aa04a51ad71..33b95aa53a1508c31a4da96be4823d99fc65ed5d
@@@ -854,9 -904,16 +866,16 @@@ static void rna_def_mface(BlenderRNA *b
        prop= RNA_def_property(srna, "smooth", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SMOOTH);
        RNA_def_property_ui_text(prop, "Smooth", "");
+       
+       prop= RNA_def_property(srna, "normal", PROP_FLOAT, PROP_VECTOR);
+       RNA_def_property_array(prop, 3);
+       RNA_def_property_range(prop, -1.0f, 1.0f);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+       RNA_def_property_float_funcs(prop, "rna_MeshFace_normal_get", NULL, NULL);
+       RNA_def_property_ui_text(prop, "face normal", "local space unit length normal vector for this face");
  }
  
 -static void rna_def_mtface(BlenderRNA *brna)
 +static void rna_def_mtexpoly(BlenderRNA *brna)
  {
        StructRNA *srna;
        PropertyRNA *prop;
index a32086912f0165e4a06fda69cd139bfc7c1477eb,6bb77e3cc852929ef3e120d8c2daabc975b8a98a..d45a9749a7d2adc7e1ad17a531906a9f5750bb96
@@@ -161,12 -160,10 +161,12 @@@ def setup_syslibs(lenv)
  
        syslibs += Split(lenv['BF_FREETYPE_LIB'])
        if lenv['WITH_BF_PYTHON'] and not lenv['WITH_BF_STATICPYTHON']:
-               #if not lenv['BF_NO_PYDEBUG'] and lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc'):
-               #       print "using debug py"
-               #       syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
-               #else:
-                       #print "not using debug py"
 -              if lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
++              if not lenv['BF_NO_PYDEBUG'] and lenv['BF_DEBUG'] and lenv['OURPLATFORM'] in ('win32-vc'):
++                      print "using debug py"
+                       syslibs.append(lenv['BF_PYTHON_LIB']+'_d')
+               else:
 -                      syslibs.append(lenv['BF_PYTHON_LIB'])
++                      print "not using debug py"
 +              syslibs.append(lenv['BF_PYTHON_LIB'])
        if lenv['WITH_BF_INTERNATIONAL']:
                syslibs += Split(lenv['BF_GETTEXT_LIB'])
        if lenv['WITH_BF_OPENAL']: