svn merge -r36725:36801 https://svn.blender.org/svnroot/bf-blender/trunk/blender
authorCampbell Barton <ideasman42@gmail.com>
Fri, 20 May 2011 16:52:10 +0000 (16:52 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 20 May 2011 16:52:10 +0000 (16:52 +0000)
42 files changed:
1  2 
source/blender/blenkernel/BKE_subsurf.h
source/blender/blenkernel/intern/blender.c
source/blender/blenkernel/intern/multires.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/shrinkwrap.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/blenlib/BLI_math_geom.h
source/blender/blenlib/BLI_utildefines.h
source/blender/blenlib/intern/math_geom.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/armature/editarmature.c
source/blender/editors/curve/editcurve.c
source/blender/editors/gpencil/gpencil_paint.c
source/blender/editors/include/ED_view3d.h
source/blender/editors/mesh/editbmesh_bvh.c
source/blender/editors/mesh/knifetool.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/render/CMakeLists.txt
source/blender/editors/render/render_shading.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_utils.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_manipulator.c
source/blender/editors/transform/transform_snap.c
source/blender/editors/uvedit/uvedit_ops.c
source/blender/makesrna/intern/rna_scene.c
source/blender/modifiers/intern/MOD_subsurf.c
source/blender/modifiers/intern/MOD_uvproject.c
source/blender/windowmanager/intern/wm_init_exit.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp

index ae6ea6f41157bde1fb2e82456244abe0fc0119d6,a66caf8879f2b79679d9d9032e51ac108a864b4b..652b667499b1151aed7bcd5d5a9468cf604a51f2
@@@ -3031,9 -2623,9 +3031,9 @@@ struct DerivedMesh *subsurf_make_derive
        int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr;
        int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
        int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
 -      CCGDerivedMesh *result;
 +      CCGDerivedMesh *result = NULL;
  
-       if(editMode) {
+       if(forEditMode) {
                int levels= (smd->modifier.scene)? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels): smd->levels;
  
                smd->emCache = _getSubSurf(smd->emCache, levels, useAging, 0,
index 2a2583b1cc264911486feb5520253f3a263c9cc6,a376d04841254608687b740486b7160a512247fd..c81ab01e4689e3c90566c7211e3832b30e32c5f3
  
  #define VECADD(v1,v2,v3)      {*(v1)= *(v2) + *(v3); *(v1+1)= *(v2+1) + *(v3+1); *(v1+2)= *(v2+2) + *(v3+2);}
  #define VECSUB(v1,v2,v3)      {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1); *(v1+2)= *(v2+2) - *(v3+2);}
- #define VECSUB2D(v1,v2,v3, fac)       {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1);}
+ #define VECSUB2D(v1,v2,v3)    {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1);}
 +#define VECINTERP(v1,v2,v3, fac) {*(v1) = *(v2) + (*(v3)-*(v2))*(fac); *(v1+1) = *(v2+1) + (*(v3+1)-*(v2+1))*(fac); *(v1+2) = *(v2+2) + (*(v3+2)-*(v2+2))*(fac);}
  #define VECADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac);}
  #define VECSUBFAC(v1,v2,v3,fac) {*(v1)= *(v2) - *(v3)*(fac); *(v1+1)= *(v2+1) - *(v3+1)*(fac); *(v1+2)= *(v2+2) - *(v3+2)*(fac);}
  #define QUATADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac); *(v1+3)= *(v2+3) + *(v3+3)*(fac);}
index 4e693bb819c70a1c9c8f91b6dc87451b325d1af2,2f99cf1609304b45e193ec39d7fb719a1b16c93f..afb70491a129909e04dc89cf6972f59c0cbba3c3
@@@ -110,15 -171,8 +174,9 @@@ void project_float_noclip(struct ARegio
  void get_object_clip_range(struct Object *ob, float *lens, float *clipsta, float *clipend);
  int get_view3d_cliprange(struct View3D *v3d, struct RegionView3D *rv3d, float *clipsta, float *clipend);
  int get_view3d_viewplane(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi, struct rctf *viewplane, float *clipsta, float *clipend, float *pixsize);
- int get_view3d_ortho(struct View3D *v3d, struct RegionView3D *rv3d);
  void view3d_get_object_project_mat(struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
  void view3d_project_float(struct ARegion *a, const float vec[3], float adr[2], float mat[4][4]);
 +void view3d_project_float_v3(struct ARegion *a, float *vec, float *adr, float mat[4][4]);
  void view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar, struct RegionView3D *rv3d, struct View3D *v3d, struct rctf *viewborder_r, short do_shift);
  
  /* drawobject.c iterators */
index f238f817d9d544858522515365e009353d594eb0,0000000000000000000000000000000000000000..fcefeb6ce6bfda41cd4a93f6d6bdfe83d309af61
mode 100644,000000..100644
--- /dev/null
@@@ -1,724 -1,0 +1,724 @@@
-       float m[2], end[3];
 + /* $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) 2010 by Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): Joseph Eagar
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +#define IN_EDITMESHBVH
 +
 +#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 "RNA_types.h"
 +#include "RNA_define.h"
 +#include "RNA_access.h"
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_math.h"
 +#include "BLI_editVert.h"
 +#include "BLI_rand.h"
 +#include "BLI_ghash.h"
 +#include "BLI_linklist.h"
 +#include "BLI_heap.h"
 +#include "BLI_array.h"
 +#include "BLI_kdopbvh.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_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"
 +
 +#include "editbmesh_bvh.h"
 +
 +typedef struct BMBVHTree {
 +      BMEditMesh *em;
 +      BMesh *bm;
 +      BVHTree *tree;
 +      float epsilon;
 +      float maxdist; //for nearest point search
 +
 +      /*stuff for topological vert search*/
 +      BMVert *v, *curv;
 +      GHash *gh;
 +      float curw, curd;
 +      float co[3];
 +      int curtag;
 +} BMBVHTree;
 +
 +BMBVHTree *BMBVH_NewBVH(BMEditMesh *em)
 +{
 +      BMBVHTree *tree = MEM_callocN(sizeof(*tree), "BMBVHTree");
 +      float cos[3][3];
 +      int i;
 +
 +      BMEdit_RecalcTesselation(em);
 +
 +      tree->em = em;
 +      tree->bm = em->bm;
 +      tree->epsilon = FLT_EPSILON*2.0f;
 +
 +      tree->tree = BLI_bvhtree_new(em->tottri, tree->epsilon, 8, 8);
 +
 +      for (i=0; i<em->tottri; i++) {
 +              VECCOPY(cos[0], em->looptris[i][0]->v->co);
 +              VECCOPY(cos[1], em->looptris[i][1]->v->co);
 +              VECCOPY(cos[2], em->looptris[i][2]->v->co);
 +
 +              BLI_bvhtree_insert(tree->tree, i, (float*)cos, 3);
 +      }
 +      
 +      BLI_bvhtree_balance(tree->tree);
 +      
 +      return tree;
 +}
 +
 +void BMBVH_FreeBVH(BMBVHTree *tree)
 +{
 +      BLI_bvhtree_free(tree->tree);
 +      MEM_freeN(tree);
 +}
 +
 +/*taken from bvhutils.c*/
 +static float ray_tri_intersection(const BVHTreeRay *ray, const float UNUSED(m_dist), float *v0, 
 +                                float *v1, float *v2, float *uv, float UNUSED(e))
 +{
 +      float dist;
 +#if 0
 +      float vv1[3], vv2[3], vv3[3], cent[3];
 +
 +      /*expand triangle by an epsilon.  this is probably a really stupid
 +        way of doing it, but I'm too tired to do better work.*/
 +      VECCOPY(vv1, v0);
 +      VECCOPY(vv2, v1);
 +      VECCOPY(vv3, v2);
 +
 +      add_v3_v3v3(cent, vv1, vv2);
 +      add_v3_v3v3(cent, cent, vv3);
 +      mul_v3_fl(cent, 1.0f/3.0f);
 +
 +      sub_v3_v3v3(vv1, vv1, cent);
 +      sub_v3_v3v3(vv2, vv2, cent);
 +      sub_v3_v3v3(vv3, vv3, cent);
 +
 +      mul_v3_fl(vv1, 1.0f + e);
 +      mul_v3_fl(vv2, 1.0f + e);
 +      mul_v3_fl(vv3, 1.0f + e);
 +
 +      add_v3_v3v3(vv1, vv1, cent);
 +      add_v3_v3v3(vv2, vv2, cent);
 +      add_v3_v3v3(vv3, vv3, cent);
 +
 +      if(isect_ray_tri_v3((float*)ray->origin, (float*)ray->direction, vv1, vv2, vv3, &dist, uv))
 +              return dist;
 +#else
 +      if(isect_ray_tri_v3((float*)ray->origin, (float*)ray->direction, v0, v1, v2, &dist, uv))
 +              return dist;
 +#endif
 +
 +      return FLT_MAX;
 +}
 +
 +static void raycallback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
 +{
 +      BMBVHTree *tree = userdata;
 +      BMLoop **ls = tree->em->looptris[index];
 +      float dist, uv[2];
 +       
 +      if (!ls[0] || !ls[1] || !ls[2])
 +              return;
 +      
 +      dist = ray_tri_intersection(ray, hit->dist, ls[0]->v->co, ls[1]->v->co,
 +                                  ls[2]->v->co, uv, tree->epsilon);
 +      if (dist < hit->dist) {
 +              hit->dist = dist;
 +              hit->index = index;
 +              
 +              VECCOPY(hit->no, ls[0]->v->no);
 +
 +              copy_v3_v3(hit->co, ray->direction);
 +              normalize_v3(hit->co);
 +              mul_v3_fl(hit->co, dist);
 +              add_v3_v3(hit->co, ray->origin);
 +      }
 +}
 +
 +BMFace *BMBVH_RayCast(BMBVHTree *tree, float *co, float *dir, float *hitout)
 +{
 +      BVHTreeRayHit hit;
 +
 +      hit.dist = FLT_MAX;
 +      hit.index = -1;
 +
 +      BLI_bvhtree_ray_cast(tree->tree, co, dir, 0.0f, &hit, raycallback, tree);
 +      if (hit.dist != FLT_MAX && hit.index != -1) {
 +              if (hitout) {
 +                      VECCOPY(hitout, hit.co);
 +              }
 +
 +              return tree->em->looptris[hit.index][0]->f;
 +      }
 +
 +      return NULL;
 +}
 +
 +BVHTree *BMBVH_BVHTree(BMBVHTree *tree)
 +{
 +      return tree->tree;
 +}
 +
 +static void vertsearchcallback(void *userdata, int index, const float *UNUSED(co), BVHTreeNearest *hit)
 +{
 +      BMBVHTree *tree = userdata;
 +      BMLoop **ls = tree->em->looptris[index];
 +      float dist, maxdist, v[3];
 +      int i;
 +
 +      maxdist = tree->maxdist;
 +
 +      for (i=0; i<3; i++) {
 +              sub_v3_v3v3(v, hit->co, ls[i]->v->co);
 +
 +              dist = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
 +              if (dist < hit->dist && dist < maxdist) {
 +                      VECCOPY(hit->co, ls[i]->v->co);
 +                      VECCOPY(hit->no, ls[i]->v->no);
 +                      hit->dist = dist;
 +              }
 +      }
 +}
 +
 +BMVert *BMBVH_FindClosestVert(BMBVHTree *tree, float *co, float maxdist)
 +{
 +      BVHTreeNearest hit;
 +
 +      VECCOPY(hit.co, co);
 +      hit.dist = maxdist*5;
 +      hit.index = -1;
 +
 +      tree->maxdist = maxdist;
 +
 +      BLI_bvhtree_find_nearest(tree->tree, co, &hit, vertsearchcallback, tree);
 +      if (hit.dist != FLT_MAX && hit.index != -1) {
 +              BMLoop **ls = tree->em->looptris[hit.index];
 +              float dist, curdist = tree->maxdist, v[3];
 +              int cur=0, i;
 +
 +              maxdist = tree->maxdist;
 +
 +              for (i=0; i<3; i++) {
 +                      sub_v3_v3v3(v, hit.co, ls[i]->v->co);
 +
 +                      dist = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
 +                      if (dist < curdist) {
 +                              cur = i;
 +                              curdist = dist;
 +                      }
 +              }
 +
 +              return ls[i]->v;
 +      }
 +
 +      return NULL;
 +}
 +
 +typedef struct walklist {
 +      BMVert *v;
 +      int valence;
 +      int depth;
 +      float w, r;
 +      int totwalked;
 +
 +      /*state data*/
 +      BMVert *lastv;
 +      BMLoop *curl, *firstl;
 +      BMEdge *cure;
 +} walklist;
 +
 +
 +static short winding(float *v1, float *v2, float *v3)
 +/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
 +{
 +      double inp;
 +
 +      //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
 +      inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]);
 +
 +      if(inp<0.0) return 0;
 +      else if(inp==0) {
 +              if(v1[0]==v3[0] && v1[1]==v3[1]) return 0;
 +              if(v2[0]==v3[0] && v2[1]==v3[1]) return 0;
 +      }
 +      return 1;
 +}
 +
 +static float topo_compare(BMesh *bm, BMVert *v1, BMVert *v2)
 +{
 +      BMIter iter1, iter2;
 +      BMEdge *e1, *e2, *cure1 = NULL, *cure2 = NULL;
 +      BMLoop *l1, *l2;
 +      BMVert *lastv1, *lastv2;
 +      GHash *gh;
 +      walklist *stack1=NULL, *stack2=NULL;
 +      BLI_array_declare(stack1);
 +      BLI_array_declare(stack2);
 +      float vec1[3], vec2[3], minangle=FLT_MAX, w;
 +      int lvl=1;
 +      static int maxlevel = 3;
 +
 +      /*ok.  see how similar v is to v2, based on topological similaritys in the local
 +        topological neighborhood*/
 +
 +      /*step 1: find two edges, one that contains v and one that contains v2, with the
 +        smallest angle between the two edges*/
 +
 +      BM_ITER(e1, &iter1, bm, BM_EDGES_OF_VERT, v1) {
 +              BM_ITER(e2, &iter2, bm, BM_EDGES_OF_VERT, v2) {
 +                      float angle;
 +                      
 +                      if (e1->v1 == e2->v1 || e1->v2 == e2->v2 || e1->v1 == e2->v2 || e1->v2 == e2->v1)
 +                              continue;
 +
 +                      sub_v3_v3v3(vec1, BM_OtherEdgeVert(e1, v1)->co, v1->co);
 +                      sub_v3_v3v3(vec2, BM_OtherEdgeVert(e2, v2)->co, v2->co);
 +
 +                      angle = fabs(angle_v3v3(vec1, vec2));
 +
 +                      if (angle < minangle) {
 +                              minangle = angle;
 +                              cure1 = e1;
 +                              cure2 = e2;
 +                      }
 +              }
 +      }
 +
 +      if (!cure1 || !cure1->l || !cure2->l) {
 +              /*just return 1.0 in this case*/
 +              return 1.0f;
 +      }
 +
 +      /*assumtions
 +      
 +        we assume a 2-manifold mesh here.  if at any time this isn't the case,
 +        e.g. a hole or an edge with more then 2 faces around it, we um ignore
 +        that edge I guess, and try to make the algorithm go around as necassary.*/
 +
 +      l1 = cure1->l;
 +      l2 = cure2->l;
 +
 +      lastv1 = l1->v == v1 ? ((BMLoop*)l1->next)->v : ((BMLoop*)l1->prev)->v;
 +      lastv2 = l2->v == v2 ? ((BMLoop*)l2->next)->v : ((BMLoop*)l2->prev)->v;
 +
 +      /*we can only provide meaningful comparisons if v1 and v2 have the same valence*/
 +      if (BM_Vert_EdgeCount(v1) != BM_Vert_EdgeCount(v2))
 +              return 1.0f; /*full mismatch*/
 +
 +      gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh bvh");
 +
 +#define SPUSH(s, d, vt, lv, e)\
 +      if (BLI_array_count(s) <= lvl) BLI_array_growone(s);\
 +      memset((s+lvl), 0, sizeof(*s));\
 +      s[lvl].depth = d;\
 +      s[lvl].v = vt;\
 +      s[lvl].cure = e;\
 +      s[lvl].lastv = lv;\
 +      s[lvl].valence = BM_Vert_EdgeCount(vt);\
 +
 +      lvl = 0;
 +
 +      SPUSH(stack1, 0, v1, lastv1, cure1);
 +      SPUSH(stack2, 0, v2, lastv2, cure2);
 +
 +      BLI_srand( BLI_rand() ); /* random seed */
 +
 +      lvl = 1;
 +      while (lvl) {
 +              int term = 0;
 +              walklist *s1 = stack1 + lvl - 1, *s2 = stack2 + lvl - 1;
 +
 +              /*pop from the stack*/
 +              lvl--;
 +
 +              if (s1->curl && s1->curl->e == s1->cure)
 +                      term = 1;
 +              if (s2->curl && s2->curl->e == s2->cure)
 +                      term = 1;
 +
 +              /*find next case to do*/
 +              if (!s1->curl)
 +                      s1->curl = s1->cure->l;
 +              if (!s2->curl) {
 +                      float no1[3], no2[3], angle;
 +                      int wind1, wind2;
 +                      
 +                      s2->curl = s2->cure->l;
 +
 +                      /*find which of two possible faces to use*/
 +                      l1 = BM_OtherFaceLoop(s1->curl->e, s1->curl->f, s1->lastv);
 +                      l2 = BM_OtherFaceLoop(s2->curl->e, s2->curl->f, s2->lastv);
 +
 +                      if (l1->v == s2->lastv) {
 +                              l1 = (BMLoop*) l1->next;
 +                              if (l1->v == s2->v)
 +                                      l1 = (BMLoop*) l1->prev->prev;
 +                      } else if (l1->v == s2->v) {
 +                              l1 = (BMLoop*) l1->next;
 +                              if (l1->v == s2->lastv)
 +                                      l1 = (BMLoop*) l1->prev->prev;
 +                      }
 +
 +                      if (l2->v == s2->lastv) {
 +                              l2 = (BMLoop*) l2->next;
 +                              if (l2->v == s2->v)
 +                                      l2 = (BMLoop*) l2->prev->prev;
 +                      } else if (l2->v == s2->v) {
 +                              l2 = (BMLoop*) l2->next;
 +                              if (l2->v == s2->lastv)
 +                                      l2 = (BMLoop*) l2->prev->prev;
 +                      }
 +
 +                      wind1 = winding(s1->v->co, s1->lastv->co, l1->v->co);
 +
 +                      wind2 = winding(s2->v->co, s2->lastv->co, l2->v->co);
 +                      
 +                      /*if angle between the two adjacent faces is greater then 90 degrees,
 +                        we need to flip wind2*/
 +                      l1 = l2;
 +                      l2 = s2->curl->radial_next;
 +                      l2 = BM_OtherFaceLoop(l2->e, l2->f, s2->lastv);
 +                      
 +                      if (l2->v == s2->lastv) {
 +                              l2 = (BMLoop*) l2->next;
 +                              if (l2->v == s2->v)
 +                                      l2 = (BMLoop*) l2->prev->prev;
 +                      } else if (l2->v == s2->v) {
 +                              l2 = (BMLoop*) l2->next;
 +                              if (l2->v == s2->lastv)
 +                                      l2 = (BMLoop*) l2->prev->prev;
 +                      }
 +
 +                      normal_tri_v3(no1, s2->v->co, s2->lastv->co, l1->v->co);
 +                      normal_tri_v3(no2, s2->v->co, s2->lastv->co, l2->v->co);
 +                      
 +                      /*enforce identical winding as no1*/
 +                      mul_v3_fl(no2, -1.0);
 +
 +                      angle = angle_v3v3(no1, no2);
 +                      if (angle > M_PI/2 - FLT_EPSILON*2)
 +                              wind2 = !wind2;
 +
 +                      if (wind1 == wind2)
 +                              s2->curl = s2->curl->radial_next;
 +              }
 +
 +              /*handle termination cases of having already looped through all child
 +                nodes, or the valence mismatching between v1 and v2, or we hit max
 +                recursion depth*/
 +              term |= s1->valence != s2->valence || lvl+1 > maxlevel;
 +              term |= s1->curl->radial_next == (BMLoop*)l1;
 +              term |= s2->curl->radial_next == (BMLoop*)l2;
 +
 +              if (!term) {
 +                      lastv1 = s1->v;
 +                      lastv2 = s2->v;
 +                      v1 = BM_OtherEdgeVert(s1->curl->e, lastv1);
 +                      v2 = BM_OtherEdgeVert(s2->curl->e, lastv2);
 +                      
 +                      e1 = s1->curl->e;
 +                      e2 = s2->curl->e;
 +
 +                      if (!BLI_ghash_haskey(gh, v1) && !BLI_ghash_haskey(gh, v2)) {
 +                              /*repush the current stack item*/
 +                              lvl++;
 +                              
 +                              //if (maxlevel % 2 == 0) {
 +                                      BLI_ghash_insert(gh, v1, NULL);
 +                                      BLI_ghash_insert(gh, v2, NULL);
 +                              //}
 +
 +                              /*now push the child node*/
 +                              SPUSH(stack1, lvl, v1, lastv1, e1);
 +                              SPUSH(stack2, lvl, v2, lastv2, e2);
 +
 +                              lvl++;
 +
 +                              s1 = stack1 + lvl - 2;
 +                              s2 = stack2 + lvl - 2;
 +                      }
 +
 +                      s1->curl = s1->curl->v == s1->v ? (BMLoop*) s1->curl->prev : (BMLoop*) s1->curl->next;
 +                      s2->curl = s2->curl->v == s2->v ? (BMLoop*) s2->curl->prev : (BMLoop*) s2->curl->next;
 +              
 +                      s1->curl = (BMLoop*) s1->curl->radial_next;
 +                      s2->curl = (BMLoop*) s2->curl->radial_next;
 +              }
 +
 +#define WADD(stack, s)\
 +              if (lvl) {/*silly attempt to make this non-commutative: randomize\
 +                            how much this particular weight adds to the total*/\
 +                      stack[lvl-1].r += r;\
 +                      s->w *= r;\
 +                      stack[lvl-1].totwalked++;\
 +                      stack[lvl-1].w += s->w;\
 +              }
 +
 +              /*if no next case to do, update parent weight*/
 +              if (term) {
 +                      float r = 0.8f + BLI_frand()*0.2f - FLT_EPSILON;
 +
 +                      if (s1->totwalked) {
 +                              s1->w /= s1->r;
 +                      } else
 +                              s1->w = s1->valence == s2->valence ? 1.0f : 0.0f;
 +
 +                      WADD(stack1, s1);
 +
 +                      if (s2->totwalked) {
 +                              s2->w /= s2->r;
 +                      } else
 +                              s2->w = s1->valence == s2->valence ? 1.0f : 0.0f;
 +                      
 +                      WADD(stack2, s2);
 +
 +                      /*apply additional penalty to weight mismatch*/
 +                      if (s2->w != s1->w)
 +                              s2->w *= 0.8f;
 +              }
 +      }
 +
 +      w = (stack1[0].w + stack2[0].w)*0.5f;
 +
 +      BLI_array_free(stack1);
 +      BLI_array_free(stack2);
 +
 +      BLI_ghash_free(gh, NULL, NULL);
 +
 +      return 1.0f - w;
 +}
 +
 +static void vertsearchcallback_topo(void *userdata, int index, const float *UNUSED(co), BVHTreeNearest *UNUSED(hit))
 +{
 +      BMBVHTree *tree = userdata;
 +      BMLoop **ls = tree->em->looptris[index];
 +      int i;
 +      float maxdist, vec[3], w;
 +
 +      maxdist = tree->maxdist;
 +
 +      for (i=0; i<3; i++) {
 +              float dis;
 +
 +              if (BLI_ghash_haskey(tree->gh, ls[i]->v))
 +                      continue;
 +
 +              sub_v3_v3v3(vec, tree->co, ls[i]->v->co);
 +              dis = dot_v3v3(vec, vec);
 +
 +              w = topo_compare(tree->em->bm, tree->v, ls[i]->v);
 +              tree->curtag++;
 +              
 +              if (w < tree->curw-FLT_EPSILON*4) {
 +                      tree->curw = w;
 +                      tree->curv = ls[i]->v;
 +                 
 +                      sub_v3_v3v3(vec, tree->co, ls[i]->v->co);
 +                      tree->curd = dot_v3v3(vec, vec);
 +
 +                      /*we deliberately check for equality using (smallest possible float)*4 
 +                        comparison factor, to always prefer distance in cases of verts really
 +                        close to each other*/
 +              } else if (fabs(tree->curw - w) < FLT_EPSILON*4) {
 +                      /*if w is equal to hitex->curw, sort by distance*/
 +                      sub_v3_v3v3(vec, tree->co, ls[i]->v->co);
 +                      dis = dot_v3v3(vec, vec);
 +
 +                      if (dis < tree->curd) {
 +                              tree->curd = dis;
 +                              tree->curv = ls[i]->v;
 +                      }
 +              }
 +
 +              BLI_ghash_insert(tree->gh, ls[i]->v, NULL);
 +      }
 +}
 +
 +BMVert *BMBVH_FindClosestVertTopo(BMBVHTree *tree, float *co, float maxdist, BMVert *sourcev)
 +{
 +      BVHTreeNearest hit;
 +
 +      memset(&hit, 0, sizeof(hit));
 +
 +      VECCOPY(hit.co, co);
 +      VECCOPY(tree->co, co);
 +      hit.index = -1;
 +      hit.dist = maxdist;
 +
 +      tree->curw = FLT_MAX;
 +      tree->curd = FLT_MAX;
 +      tree->curv = NULL;
 +      tree->curtag = 1;
 +
 +      tree->gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh bvh");
 +
 +      tree->maxdist = maxdist;
 +      tree->v = sourcev;
 +
 +      BLI_bvhtree_find_nearest(tree->tree, co, &hit, vertsearchcallback_topo, tree);
 +      
 +      BLI_ghash_free(tree->gh, NULL, NULL);
 +      tree->gh = NULL;
 +
 +      return tree->curv;
 +}
 +
 +
 +#if 0 //BMESH_TODO: not implemented yet
 +int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d)
 +{
 +
 +}
 +#endif
 +
 +static BMFace *edge_ray_cast(BMBVHTree *tree, float *co, float *dir, float *hitout, BMEdge *e)
 +{
 +      BMFace *f = BMBVH_RayCast(tree, co, dir, hitout);
 +      
 +      if (f && BM_Edge_In_Face(f, e))
 +              return NULL;
 +
 +      return f;
 +}
 +
 +static void scale_point(float *c1, float *p, float s)
 +{
 +      sub_v3_v3(c1, p);
 +      mul_v3_fl(c1, s);
 +      add_v3_v3(c1, p);
 +}
 +
 +
 +int BMBVH_EdgeVisible(BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v3d, Object *obedit)
 +{
 +      BMFace *f;
 +      float co1[3], co2[3], co3[3], dir1[4], dir2[4], dir3[4];
 +      float origin[3], invmat[4][4];
 +      float epsilon = 0.01f; 
-       m[0] = ar->winx/2.0;
-       m[1] = ar->winy/2.0;
-       viewline(ar, v3d, m, origin, end);
++      float mval_f[2], end[3];
 +      
 +      if (!ar) {
 +              printf("error in BMBVH_EdgeVisible!\n");
 +              return 0;
 +      }
 +      
++      mval_f[0] = ar->winx/2.0;
++      mval_f[1] = ar->winy/2.0;
++      ED_view3d_win_to_segment_clip(ar, v3d, mval_f, origin, end);
 +      
 +      invert_m4_m4(invmat, obedit->obmat);
 +      mul_m4_v3(invmat, origin);
 +
 +      VECCOPY(co1, e->v1->co);
 +      add_v3_v3v3(co2, e->v1->co, e->v2->co);
 +      mul_v3_fl(co2, 0.5f);
 +      VECCOPY(co3, e->v2->co);
 +      
 +      scale_point(co1, co2, 0.99);
 +      scale_point(co3, co2, 0.99);
 +      
 +      /*ok, idea is to generate rays going from the camera origin to the 
 +        three points on the edge (v1, mid, v2)*/
 +      sub_v3_v3v3(dir1, origin, co1);
 +      sub_v3_v3v3(dir2, origin, co2);
 +      sub_v3_v3v3(dir3, origin, co3);
 +      
 +      normalize_v3(dir1);
 +      normalize_v3(dir2);
 +      normalize_v3(dir3);
 +
 +      mul_v3_fl(dir1, epsilon);
 +      mul_v3_fl(dir2, epsilon);
 +      mul_v3_fl(dir3, epsilon);
 +      
 +      /*offset coordinates slightly along view vectors, to avoid
 +        hitting the faces that own the edge.*/
 +      add_v3_v3v3(co1, co1, dir1);
 +      add_v3_v3v3(co2, co2, dir2);
 +      add_v3_v3v3(co3, co3, dir3);
 +
 +      normalize_v3(dir1);
 +      normalize_v3(dir2);
 +      normalize_v3(dir3);
 +
 +      /*do three samplings: left, middle, right*/
 +      f = edge_ray_cast(tree, co1, dir1, NULL, e);
 +      if (f && !edge_ray_cast(tree, co2, dir2, NULL, e))
 +              return 1;
 +      else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e))
 +              return 1;
 +      else if (!f)
 +              return 1;
 +
 +      return 0;
 +}
index 3b8ab2f748f6bcbdb05089e93ad81f3537b4ab24,0000000000000000000000000000000000000000..7184d99ff3b5d7bfa3fffe95bd9928e054612a4c
mode 100755,000000..100755
--- /dev/null
@@@ -1,1932 -1,0 +1,1932 @@@
-       viewline(kcd->ar, kcd->vc.v3d, s1, v1, v3);
-       viewline(kcd->ar, kcd->vc.v3d, s2, v2, v4);
 +/**
 + * $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) 2007 Blender Foundation.
 + * All rights reserved.
 + *
 + * 
 + * Contributor(s): Joseph Eagar, Joshua Leung
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +#include <float.h>
 +#define _USE_MATH_DEFINES
 +#include <math.h>
 +#include <string.h>
 +#include <ctype.h>
 +#include <stdio.h>
 +
 +#include "DNA_ID.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_scene_types.h"
 +#include "DNA_userdef_types.h"
 +#include "DNA_object_types.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "PIL_time.h"
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_dynstr.h" /*for WM_operator_pystring */
 +#include "BLI_editVert.h"
 +#include "BLI_array.h"
 +#include "BLI_ghash.h"
 +#include "BLI_memarena.h"
 +#include "BLI_mempool.h"
 +#include "BLI_math.h"
 +#include "BLI_rand.h"
 +#include "BLI_kdopbvh.h"
 +#include "BLI_smallhash.h"
 +#include "BLI_scanfill.h"
 +
 +#include "BKE_blender.h"
 +#include "BKE_context.h"
 +#include "BKE_depsgraph.h"
 +#include "BKE_scene.h"
 +#include "BKE_mesh.h"
 +#include "BKE_tessmesh.h"
 +#include "BKE_depsgraph.h"
 +
 +#include "BIF_gl.h"
 +#include "BIF_glutil.h" /* for paint cursor */
 +
 +#include "IMB_imbuf_types.h"
 +
 +#include "ED_screen.h"
 +#include "ED_space_api.h"
 +#include "ED_view3d.h"
 +#include "ED_mesh.h"
 +
 +#include "RNA_access.h"
 +#include "RNA_define.h"
 +
 +#include "UI_interface.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +
 +#include "mesh_intern.h"
 +#include "editbmesh_bvh.h"
 +
 +/* this code here is kindof messy. . .I might need to eventually rework it - joeedh*/
 +
 +#define MAXGROUP      30
 +#define KMAXDIST      25      /*max mouse distance from edge before not detecting it*/
 +
 +/* knifetool operator */
 +typedef struct KnifeVert {
 +      BMVert *v; /*non-NULL if this is an original vert*/
 +      ListBase edges;
 +
 +      float co[3], sco[3]; /*sco is screen coordinates*/
 +      short flag, draw, isface, inspace;
 +} KnifeVert;
 +
 +typedef struct Ref {
 +      struct Ref *next, *prev;
 +      void *ref;
 +} Ref;
 +
 +typedef struct KnifeEdge {
 +      KnifeVert *v1, *v2;
 +      BMFace *basef; /*face to restrict face fill to*/
 +      ListBase faces;
 +      int draw;
 +      
 +      BMEdge *e, *oe; /*non-NULL if this is an original edge*/
 +} KnifeEdge;
 +
 +typedef struct BMEdgeHit {
 +      KnifeEdge *kfe;
 +      float hit[3];
 +      float realhit[3]; /*used in midpoint mode*/
 +      float schit[3];
 +      float l; /*lambda along line*/
 +      KnifeVert *v; //set if snapped to a vert
 +      BMFace *f;
 +} BMEdgeHit;
 +
 +/* struct for properties used while drawing */
 +typedef struct knifetool_opdata {
 +      ARegion *ar;            /* region that knifetool was activated in */
 +      void *draw_handle;      /* for drawing preview loop */
 +      ViewContext vc;
 +      bContext *C;
 +      
 +      Object *ob;
 +      BMEditMesh *em;
 +      
 +      MemArena *arena;
 +
 +      GHash *origvertmap;
 +      GHash *origedgemap;
 +      
 +      GHash *kedgefacemap;
 +      
 +      BMBVHTree *bmbvh;
 +
 +      BLI_mempool *kverts;
 +      BLI_mempool *kedges;
 +      
 +      float vthresh;
 +      float ethresh;
 +      
 +      float vertco[3];
 +      float prevco[3];
 +      
 +      /*used for drag-cutting*/
 +      BMEdgeHit *linehits;
 +      int totlinehit;
 +      
 +      /*if curedge is NULL, attach to curvert;
 +        if curvert is NULL, attach to curbmface,
 +        otherwise create null vert*/
 +      KnifeEdge *curedge, *prevedge;
 +      KnifeVert *curvert, *prevvert;
 +      BMFace *curbmface, *prevbmface;
 +
 +      int totkedge, totkvert, cutnr;
 +      
 +      BLI_mempool *refs;
 +      
 +      float projmat[4][4];
 +      int is_ortho;
 +      float clipsta, clipend;
 +      
 +      enum {
 +              MODE_IDLE,
 +              MODE_DRAGGING,
 +              MODE_CONNECT,
 +              MODE_PANNING,
 +      } mode;
 +      
 +      int snap_midpoints, prevmode, extend;
 +      int ignore_edge_snapping, ignore_vert_snapping;
 +      
 +      int is_space, prev_is_space; /*1 if current cut location, vertco, isn't on the mesh*/
 +} knifetool_opdata;
 +
 +static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f);
 +
 +static void knife_project_v3(knifetool_opdata *kcd, float co[3], float sco[3])
 +{
 +      if (kcd->is_ortho) {
 +              mul_v3_m4v3(sco, kcd->projmat, co);
 +              
 +              sco[0] = (float)(kcd->ar->winx/2.0f)+(kcd->ar->winx/2.0f)*sco[0];
 +              sco[1] = (float)(kcd->ar->winy/2.0f)+(kcd->ar->winy/2.0f)*sco[1];
 +      } else
 +              view3d_project_float(kcd->ar, co, sco, kcd->projmat);
 +}
 +
 +static KnifeEdge *new_knife_edge(knifetool_opdata *kcd)
 +{
 +      kcd->totkedge++;
 +      return BLI_mempool_calloc(kcd->kedges);
 +}
 +
 +static KnifeVert *new_knife_vert(knifetool_opdata *kcd, float *co)
 +{
 +      KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts);
 +      
 +      kcd->totkvert++;
 +      
 +      copy_v3_v3(kfv->co, co);
 +      copy_v3_v3(kfv->sco, co);
 +
 +      knife_project_v3(kcd, kfv->co, kfv->sco);
 +
 +      return kfv;
 +}
 +
 +/*get a KnifeVert wrapper for an existing BMVert*/
 +static KnifeVert *get_bm_knife_vert(knifetool_opdata *kcd, BMVert *v)
 +{
 +      KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v);
 +      
 +      if (!kfv) {
 +              kfv = new_knife_vert(kcd, v->co);
 +              kfv->v = v;
 +              BLI_ghash_insert(kcd->origvertmap, v, kfv);
 +      }
 +      
 +      return kfv;
 +}
 +
 +/*get a KnifeEdge wrapper for an existing BMEdge*/
 +static KnifeEdge *get_bm_knife_edge(knifetool_opdata *kcd, BMEdge *e)
 +{
 +      KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e);
 +      if (!kfe) {
 +              Ref *ref;
 +              BMIter iter;
 +              BMFace *f;
 +              
 +              kfe = new_knife_edge(kcd);
 +              kfe->e = e;
 +              kfe->v1 = get_bm_knife_vert(kcd, e->v1);
 +              kfe->v2 = get_bm_knife_vert(kcd, e->v2);
 +              
 +              ref = BLI_mempool_calloc(kcd->refs);
 +              ref->ref = kfe;
 +              BLI_addtail(&kfe->v1->edges, ref);
 +
 +              ref = BLI_mempool_calloc(kcd->refs);
 +              ref->ref = kfe;
 +              BLI_addtail(&kfe->v2->edges, ref);
 +              
 +              BLI_ghash_insert(kcd->origedgemap, e, kfe);
 +              
 +              BM_ITER(f, &iter, kcd->em->bm, BM_FACES_OF_EDGE, e) {
 +                      ref = BLI_mempool_calloc(kcd->refs);
 +                      ref->ref = f;
 +                      BLI_addtail(&kfe->faces, ref);
 +                      
 +                      /*ensures the kedges lst for this f is initialized,
 +                        it automatically adds kfe by itself*/
 +                      knife_get_face_kedges(kcd, f);
 +              }
 +      }
 +      
 +      return kfe;
 +}
 +
 +static void knife_start_cut(knifetool_opdata *kcd)
 +{
 +      kcd->prevedge = kcd->curedge;
 +      kcd->prevvert = kcd->curvert;
 +      kcd->prevbmface = kcd->curbmface;
 +      kcd->cutnr++;
 +      kcd->prev_is_space = kcd->is_space;
 +      kcd->is_space = 0;
 +      
 +      copy_v3_v3(kcd->prevco, kcd->vertco);
 +}
 +
 +static Ref *find_ref(ListBase *lb, void *ref)
 +{
 +      Ref *ref1;
 +      
 +      for (ref1=lb->first; ref1; ref1=ref1->next) {
 +              if (ref1->ref == ref)
 +                      return ref1;
 +      }
 +      
 +      return NULL;
 +}
 +
 +static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f)
 +{
 +      ListBase *lst = BLI_ghash_lookup(kcd->kedgefacemap, f);
 +      
 +      if (!lst) {
 +              BMIter iter;
 +              BMEdge *e;
 +              
 +              lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase));
 +              lst->first = lst->last = NULL;
 +              
 +              BM_ITER(e, &iter, kcd->em->bm, BM_EDGES_OF_FACE, f) {
 +                      Ref *ref = BLI_mempool_calloc(kcd->refs);
 +                      ref->ref = get_bm_knife_edge(kcd, e);
 +                      BLI_addtail(lst, ref);
 +              }
 +              
 +              BLI_ghash_insert(kcd->kedgefacemap, f, lst);
 +      }
 +      
 +      return lst;
 +}
 +
 +/*finds the proper face to restrict face fill to*/
 +static void knife_find_basef(knifetool_opdata *kcd, KnifeEdge *kfe)
 +{
 +      if (!kfe->basef) {
 +              Ref *r1, *r2, *r3, *r4;
 +              
 +              if (kfe->v1->isface || kfe->v2->isface) {
 +                      if (kfe->v2->isface)
 +                              kfe->basef = kcd->curbmface;
 +                      else 
 +                              kfe->basef = kcd->prevbmface;
 +              } else {                
 +                      for (r1=kfe->v1->edges.first; r1 && !kfe->basef; r1=r1->next) {
 +                              KnifeEdge *ke1 = r1->ref;
 +                              for (r2=ke1->faces.first; r2 && !kfe->basef; r2=r2->next) {
 +                                      for (r3=kfe->v2->edges.first; r3 && !kfe->basef; r3=r3->next) {
 +                                              KnifeEdge *ke2 = r3->ref;
 +                                      
 +                                              for (r4=ke2->faces.first; r4 && !kfe->basef; r4=r4->next) {
 +                                                      if (r2->ref == r4->ref) {
 +                                                              kfe->basef = r2->ref;
 +                                                      }
 +                                              }       
 +                                      }
 +                              }
 +                      }
 +              }
 +              /*ok, at this point kfe->basef should be set if any valid possibility
 +                exists*/
 +      }
 +}
 +
 +static KnifeVert *knife_split_edge(knifetool_opdata *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out)
 +{
 +      KnifeEdge *newkfe = new_knife_edge(kcd);
 +      ListBase *lst;
 +      Ref *ref;
 +      
 +      newkfe->v1 = kfe->v1;
 +      newkfe->v2 = new_knife_vert(kcd, co);
 +      newkfe->v2->draw = 1;
 +      newkfe->basef = kfe->basef;
 +      
 +      ref = find_ref(&kfe->v1->edges, kfe);
 +      BLI_remlink(&kfe->v1->edges, ref);
 +      
 +      kfe->v1 = newkfe->v2;
 +      BLI_addtail(&kfe->v1->edges, ref);
 +      
 +      for (ref=kfe->faces.first; ref; ref=ref->next) {
 +              Ref *ref2 = BLI_mempool_calloc(kcd->refs);
 +              
 +              /*add kedge ref to bm faces*/
 +              lst = knife_get_face_kedges(kcd, ref->ref);
 +              ref2->ref = newkfe;
 +              BLI_addtail(lst, ref2);
 +
 +              ref2 = BLI_mempool_calloc(kcd->refs);
 +              ref2->ref = ref->ref;
 +              BLI_addtail(&newkfe->faces, ref2);
 +      }
 +
 +      ref = BLI_mempool_calloc(kcd->refs);
 +      ref->ref = newkfe;
 +      BLI_addtail(&newkfe->v1->edges, ref);
 +
 +      ref = BLI_mempool_calloc(kcd->refs);
 +      ref->ref = newkfe;
 +      BLI_addtail(&newkfe->v2->edges, ref);
 +      
 +      newkfe->draw = kfe->draw;
 +      newkfe->e = kfe->e;
 +      
 +      *newkfe_out = newkfe;
 +                      
 +      return newkfe->v2;
 +}
 +
 +static void knife_edge_append_face(knifetool_opdata *kcd, KnifeEdge *kfe, BMFace *f)
 +{
 +      ListBase *lst = knife_get_face_kedges(kcd, f);
 +      Ref *ref = BLI_mempool_calloc(kcd->refs);
 +      
 +      ref->ref = kfe;
 +      BLI_addtail(lst, ref);
 +      
 +      ref = BLI_mempool_calloc(kcd->refs);
 +      ref->ref = f;
 +      BLI_addtail(&kfe->faces, ref);
 +}
 +
 +#if 0
 +static void knife_copy_edge_facelist(knifetool_opdata *kcd, KnifeEdge *dest, KnifeEdge *source) 
 +{
 +      Ref *ref, *ref2;
 +      
 +      for (ref2 = source->faces.first; ref2; ref2=ref2->next) {
 +              ListBase *lst = knife_get_face_kedges(kcd, ref2->ref);
 +              
 +              /*add new edge to face knife edge list*/
 +              ref = BLI_mempool_calloc(kcd->refs);
 +              ref->ref = dest;
 +              BLI_addtail(lst, ref);
 +              
 +              /*add face to new edge's face list*/
 +              ref = BLI_mempool_calloc(kcd->refs);
 +              ref->ref = ref2->ref;
 +              BLI_addtail(&dest->faces, ref);
 +      }
 +}
 +#endif
 +
 +static void knife_add_single_cut(knifetool_opdata *kcd)
 +{
 +      KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL;
 +      Ref *ref;
 +      
 +      if (kcd->prevvert && kcd->prevvert == kcd->curvert)
 +              return;
 +      if (kcd->prevedge && kcd->prevedge == kcd->curedge)
 +              return;
 +      
 +      kfe->draw = 1;
 +
 +      if (kcd->prevvert) {
 +              kfe->v1 = kcd->prevvert;
 +      } else if (kcd->prevedge) {
 +              kfe->v1 = knife_split_edge(kcd, kcd->prevedge, kcd->prevco, &kfe2);
 +      } else {
 +              kfe->v1 = new_knife_vert(kcd, kcd->prevco);
 +              kfe->v1->draw = kfe->draw = !kcd->prev_is_space;
 +              kfe->v1->inspace = kcd->prev_is_space;
 +              kfe->draw = !kcd->prev_is_space;
 +              kfe->v1->isface = 1;
 +      }
 +      
 +      if (kcd->curvert) {
 +              kfe->v2 = kcd->curvert;
 +      } else if (kcd->curedge) {
 +              kfe->v2 = knife_split_edge(kcd, kcd->curedge, kcd->vertco, &kfe3);
 +      
 +              kcd->curvert = kfe->v2;
 +      } else {
 +              kfe->v2 = new_knife_vert(kcd, kcd->vertco);
 +              kfe->v2->draw = !kcd->is_space;
 +              kfe->v2->isface = 1;
 +              kfe->v2->inspace = kcd->is_space;
 +              
 +              if (kcd->is_space)
 +                      kfe->draw = 0;
 +
 +              kcd->curvert = kfe->v2;
 +      }
 +      
 +      knife_find_basef(kcd, kfe);
 +      
 +      ref = BLI_mempool_calloc(kcd->refs);
 +      ref->ref = kfe; 
 +      BLI_addtail(&kfe->v1->edges, ref);
 +
 +      ref = BLI_mempool_calloc(kcd->refs);
 +      ref->ref = kfe;
 +      BLI_addtail(&kfe->v2->edges, ref);      
 +      
 +      if (kfe->basef && !find_ref(&kfe->faces, kfe->basef))
 +              knife_edge_append_face(kcd, kfe, kfe->basef);
 +
 +      /*sanity check to make sure we're in the right edge/face lists*/
 +      if (kcd->curbmface) {
 +              if (!find_ref(&kfe->faces, kcd->curbmface)) {
 +                      knife_edge_append_face(kcd, kfe, kcd->curbmface);
 +              }
 +
 +              if (kcd->prevbmface && kcd->prevbmface != kcd->curbmface) {
 +                      if (!find_ref(&kfe->faces, kcd->prevbmface)) {
 +                              knife_edge_append_face(kcd, kfe, kcd->prevbmface);
 +                      }
 +              }
 +      }
 +              
 +      /*set up for next cut*/
 +      kcd->prevbmface = kcd->curbmface;
 +      kcd->prevvert = kcd->curvert;
 +      kcd->prevedge = kcd->curedge;
 +      copy_v3_v3(kcd->prevco, kcd->vertco);
 +      kcd->prev_is_space = kcd->is_space;
 +}
 +
 +static int verge_linehit(const void *vlh1, const void *vlh2)
 +{
 +      const BMEdgeHit *lh1=vlh1, *lh2=vlh2;
 +
 +      if (lh1->l < lh2->l) return -1;
 +      else if (lh1->l > lh2->l) return 1;
 +      else return 0;
 +}
 +
 +static void knife_add_cut(knifetool_opdata *kcd)
 +{
 +      /*BMEditMesh *em = kcd->em;*/ /*UNUSED*/
 +      knifetool_opdata oldkcd = *kcd;
 +      
 +      if (kcd->linehits) {
 +              BMEdgeHit *lh, *lastlh, *firstlh;
 +              int i;
 +              
 +              qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit);
 +              
 +              lh = kcd->linehits;
 +              lastlh = firstlh = NULL;
 +              for (i=0; i<kcd->totlinehit; i++, (lastlh=lh), lh++) {
 +                      BMFace *f = lastlh ? lastlh->f : lh->f;
 +                      
 +                      if (lastlh && len_v3v3(lastlh->hit, lh->hit) == 0.0f) {
 +                              if (!firstlh)
 +                                      firstlh = lastlh;
 +                              continue;
 +                      } else if (lastlh && firstlh) {
 +                              if (firstlh->v || lastlh->v) {
 +                                      KnifeVert *kfv = firstlh->v ? firstlh->v : lastlh->v;
 +                                      
 +                                      kcd->prevvert = kfv;
 +                                      copy_v3_v3(kcd->prevco, firstlh->hit);
 +                                      kcd->prevedge = NULL;
 +                                      kcd->prevbmface = f;
 +                              }
 +                              lastlh = firstlh = NULL;
 +                      }
 +                      
 +                      if (len_v3v3(kcd->prevco, lh->realhit) < FLT_EPSILON*80)
 +                              continue;
 +                      if (len_v3v3(kcd->vertco, lh->realhit) < FLT_EPSILON*80)
 +                              continue;
 +                      
 +                      if (kcd->prev_is_space || kcd->is_space) {
 +                              kcd->prev_is_space = kcd->is_space = 0;
 +                              copy_v3_v3(kcd->prevco, lh->hit);
 +                              kcd->prevedge = lh->kfe;
 +                              kcd->curbmface = lh->f;
 +                              continue;
 +                      }                       
 +                      
 +                      kcd->is_space = 0;
 +                      kcd->curedge = lh->kfe;
 +                      kcd->curbmface = lh->f;
 +                      kcd->curvert = lh->v;
 +                      copy_v3_v3(kcd->vertco, lh->hit);
 +
 +                      knife_add_single_cut(kcd);
 +              }
 +              
 +              kcd->curbmface = oldkcd.curbmface;
 +              kcd->curvert = oldkcd.curvert;
 +              kcd->curedge = oldkcd.curedge;
 +              kcd->is_space = oldkcd.is_space;
 +              copy_v3_v3(kcd->vertco, oldkcd.vertco);
 +              
 +              knife_add_single_cut(kcd);
 +              
 +              MEM_freeN(kcd->linehits);
 +              kcd->linehits = NULL;
 +              kcd->totlinehit = 0;
 +      } else {
 +              knife_add_single_cut(kcd);
 +      }
 +}
 +
 +static void knife_finish_cut(knifetool_opdata *UNUSED(kcd))
 +{
 +
 +}
 +
 +/* modal loop selection drawing callback */
 +static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
 +{
 +      knifetool_opdata *kcd = arg;
 +      
 +      glDisable(GL_DEPTH_TEST);
 +      
 +      glPolygonOffset(1.0f, 1.0f);
 +      
 +      glPushMatrix();
 +      glMultMatrixf(kcd->ob->obmat);
 +      
 +      if (kcd->mode == MODE_DRAGGING) {
 +              glColor3f(0.1, 0.1, 0.1);
 +              glLineWidth(2.0);
 +              
 +              glBegin(GL_LINES);
 +              glVertex3fv(kcd->prevco);       
 +              glVertex3fv(kcd->vertco);
 +              glEnd();
 +              
 +              glLineWidth(1.0);       
 +      }
 +      
 +      if (kcd->curedge) {
 +              glColor3f(0.5, 0.3, 0.15);
 +              glLineWidth(2.0);
 +              
 +              glBegin(GL_LINES);
 +              glVertex3fv(kcd->curedge->v1->co);      
 +              glVertex3fv(kcd->curedge->v2->co);
 +              glEnd();
 +              
 +              glLineWidth(1.0);
 +      } else if (kcd->curvert) {
 +              glColor3f(0.8, 0.2, 0.1);
 +              glPointSize(11);
 +              
 +              glBegin(GL_POINTS);
 +              glVertex3fv(kcd->vertco);
 +              glEnd();
 +      }
 +      
 +      if (kcd->curbmface) {           
 +              glColor3f(0.1, 0.8, 0.05);
 +              glPointSize(9);
 +              
 +              glBegin(GL_POINTS);
 +              glVertex3fv(kcd->vertco);
 +              glEnd();
 +      }
 +      
 +      if (kcd->totlinehit > 0) {
 +              BMEdgeHit *lh;
 +              int i;
 +              
 +              glEnable(GL_BLEND);
 +              glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 +              
 +              /*draw any snapped verts first*/
 +              glColor4f(0.8, 0.2, 0.1, 0.4);
 +              glPointSize(11);
 +              glBegin(GL_POINTS);
 +              lh = kcd->linehits;
 +              for (i=0; i<kcd->totlinehit; i++, lh++) {
 +                      float sv1[3], sv2[3];
 +                      
 +                      knife_project_v3(kcd, lh->kfe->v1->co, sv1);
 +                      knife_project_v3(kcd, lh->kfe->v2->co, sv2);
 +                      knife_project_v3(kcd, lh->hit, lh->schit);
 +                      
 +                      if (len_v2v2(lh->schit, sv1) < kcd->vthresh/4) {
 +                              copy_v3_v3(lh->hit, lh->kfe->v1->co);
 +                              glVertex3fv(lh->hit);
 +                              lh->v = lh->kfe->v1;
 +                      } else if (len_v2v2(lh->schit, sv2) < kcd->vthresh/4) {
 +                              copy_v3_v3(lh->hit, lh->kfe->v2->co);
 +                              glVertex3fv(lh->hit);
 +                              lh->v = lh->kfe->v2;
 +                      }
 +              }
 +              glEnd();
 +              
 +              /*now draw the rest*/
 +              glColor4f(0.1, 0.8, 0.05, 0.4);
 +              glPointSize(7);
 +              glBegin(GL_POINTS);
 +              lh = kcd->linehits;
 +              for (i=0; i<kcd->totlinehit; i++, lh++) {
 +                      glVertex3fv(lh->hit);
 +              }
 +              glEnd();
 +              glDisable(GL_BLEND);
 +      }
 +      
 +      if (kcd->totkedge > 0) {
 +              BLI_mempool_iter iter;
 +              KnifeEdge *kfe;
 +              
 +              glLineWidth(1.0);
 +              glBegin(GL_LINES);
 +
 +              BLI_mempool_iternew(kcd->kedges, &iter);
 +              for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) {
 +                      if (!kfe->draw)
 +                              continue;
 +                              
 +                      glColor3f(0.2, 0.2, 0.2);
 +                      
 +                      glVertex3fv(kfe->v1->co);
 +                      glVertex3fv(kfe->v2->co);
 +              }
 +              
 +              glEnd();                
 +              glLineWidth(1.0);       
 +      }
 +
 +      if (kcd->totkvert > 0) {
 +              BLI_mempool_iter iter;
 +              KnifeVert *kfv;
 +              
 +              glPointSize(5.0);
 +                              
 +              glBegin(GL_POINTS);
 +              BLI_mempool_iternew(kcd->kverts, &iter);
 +              for (kfv=BLI_mempool_iterstep(&iter); kfv; kfv=BLI_mempool_iterstep(&iter)) {
 +                      if (!kfv->draw)
 +                              continue;
 +                              
 +                      glColor3f(0.6, 0.1, 0.2);
 +                      
 +                      glVertex3fv(kfv->co);
 +              }
 +              
 +              glEnd();                
 +      }
 +
 +      glPopMatrix();
 +      glEnable(GL_DEPTH_TEST);
 +}
 +
 +static void _print_smhash(SmallHash *hash)
 +{
 +      int i, linecol=79, c=0;
 +      
 +      printf("{");
 +      for (i=0; i<hash->size; i++) {
 +              if (hash->table[i].val == CELL_UNUSED) {
 +                      printf("--u-");
 +              } else if (hash->table[i].val == CELL_FREE) {
 +                      printf("--f-");
 +              } else  {
 +                      printf("%2x", (unsigned int)hash->table[i].key);
 +              }
 +              
 +              if (i != hash->size-1)
 +                      printf(", ");
 +              
 +              c += 6;
 +              
 +              if (c >= linecol) {
 +                      printf("\n ");
 +                      c = 0;
 +              }
 +      }
 +      
 +      fflush(stdout);
 +}
 +
 +static int kfe_vert_in_edge(KnifeEdge *e, KnifeVert *v) {
 +      return e->v1 == v || e->v2 == v;
 +}
 +
 +static int point_on_line(float p[3], float v1[3], float v2[3])
 +{
 +      float d = dist_to_line_segment_v3(p, v1, v2);
 +      if (d < 0.01) {
 +              d = len_v3v3(v1, v2);
 +              if (d == 0.0)
 +                      return 0;
 +              
 +              d = len_v3v3(p, v1) / d;
 +              
 +              if (d >= -FLT_EPSILON*10 || d <= 1.0+FLT_EPSILON*10)
 +                      return 1;
 +      }
 +      
 +      return 0;
 +}
 +
 +static BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float v1[3], 
 +                              float v2[3], float v3[3], SmallHash *ehash, bglMats *mats, int *count)
 +{
 +      BVHTree *tree2 = BLI_bvhtree_new(3, FLT_EPSILON*4, 8, 8), *tree = BMBVH_BVHTree(bmtree);
 +      BMEdgeHit *edges = NULL;
 +      BLI_array_declare(edges);
 +      BVHTreeOverlap *results, *result;
 +      BMLoop **ls;
 +      float cos[9], uv[3], lambda;
 +      unsigned int tot=0;
 +      int i, j;
 +      
 +      copy_v3_v3(cos, v1);
 +      copy_v3_v3(cos+3, v2);
 +      copy_v3_v3(cos+6, v3);
 +      
 +      BLI_bvhtree_insert(tree2, 0, cos, 3);
 +      BLI_bvhtree_balance(tree2);
 +      
 +      result = results = BLI_bvhtree_overlap(tree, tree2, &tot);
 +      
 +      for (i=0; i<tot; i++, result++) {
 +              float p[3];
 +              
 +              ls = (BMLoop**)kcd->em->looptris[result->indexA];
 +              
 +              for (j=0; j<3; j++) {
 +                      BMLoop *l1 = ls[j];
 +                      BMFace *hitf;
 +                      ListBase *lst = knife_get_face_kedges(kcd, l1->f);
 +                      Ref *ref, *ref2;
 +                      
 +                      for (ref=lst->first; ref; ref=ref->next) {                      
 +                              KnifeEdge *kfe = ref->ref;
 +                              
 +                              if (kfe == kcd->curedge || kfe== kcd->prevedge)
 +                                      continue;
 +                              
 +                              if (isect_line_tri_v3(kfe->v1->co, kfe->v2->co, v1, v2, v3, &lambda, uv)) {
 +                                      float no[3], view[3], sp[3];
 +                                      
 +                                      sub_v3_v3v3(p, kfe->v2->co, kfe->v1->co);
 +                                      mul_v3_fl(p, lambda);
 +                                      add_v3_v3(p, kfe->v1->co);
 +                                      
 +                                      if (kcd->curedge && point_on_line(p, kcd->curedge->v1->co, kcd->curedge->v2->co))
 +                                              continue;
 +                                      if (kcd->prevedge && point_on_line(p, kcd->prevedge->v1->co, kcd->prevedge->v2->co))
 +                                              continue;
 +                                      if (kcd->curvert && len_v3v3(kcd->curvert->co, p) < FLT_EPSILON*50)
 +                                              continue;
 +                                      if (kcd->prevvert && len_v3v3(kcd->prevvert->co, p) < FLT_EPSILON*50)
 +                                              continue;
 +                                      if (len_v3v3(kcd->prevco, p) < FLT_EPSILON*50 || len_v3v3(kcd->vertco, p) < FLT_EPSILON*50)
 +                                              continue;
 +
 +                                      knife_project_v3(kcd, p, sp);
 +                                      view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
 +                                      mul_m4_v3(kcd->ob->imat, view);
 +
 +                                      sub_v3_v3v3(view, p, view);
 +                                      normalize_v3(view);;
 +      
 +                                      copy_v3_v3(no, view);
 +                                      mul_v3_fl(no, -0.0003);
 +                                      
 +                                      /*go backwards toward view a bit*/
 +                                      add_v3_v3(p, no);
 +                                      
 +                                      hitf = BMBVH_RayCast(bmtree, p, no, NULL);
 +                                      for (ref2=kfe->faces.first; ref2; ref2=ref2->next) {
 +                                              if (ref2->ref == hitf)
 +                                                      hitf = NULL;
 +                                      }
 +                                      
 +                                      if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
 +                                              BMEdgeHit hit;
 +                                              
 +                                              if (len_v3v3(p, kcd->vertco) < FLT_EPSILON*50 || len_v3v3(p, kcd->prevco) < FLT_EPSILON*50)
 +                                                      continue;
 +                                              
 +                                              hit.kfe = kfe;
 +                                              hit.v = NULL;
 +                                              
 +                                              knife_find_basef(kcd, kfe);
 +                                              hit.f = kfe->basef;
 +                                              
 +                                              copy_v3_v3(hit.realhit, p);
 +                                              
 +                                              if (kcd->snap_midpoints) {
 +                                                      add_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co);
 +                                                      mul_v3_fl(hit.hit, 0.5f);
 +                                              } else {
 +                                                      copy_v3_v3(hit.hit, p);
 +                                              }
 +                                              knife_project_v3(kcd, hit.hit, hit.schit);
 +                                              
 +                                              BLI_array_append(edges, hit);
 +                                              BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +      
 +      if (results)
 +              MEM_freeN(results);
 +      
 +      BLI_bvhtree_free(tree2);
 +      *count = BLI_array_count(edges);
 +      
 +      return edges;
 +}
 +
 +static void knife_bgl_get_mats(knifetool_opdata *UNUSED(kcd), bglMats *mats)
 +{
 +      bgl_get_mats(mats);
 +      //copy_m4_m4(mats->modelview, kcd->vc.rv3d->viewmat);
 +      //copy_m4_m4(mats->projection, kcd->vc.rv3d->winmat);
 +}
 +
 +/*finds (visible) edges that intersects the current screen drag line*/
 +static void knife_find_line_hits(knifetool_opdata *kcd)
 +{
 +      bglMats mats;
 +      BMEdgeHit *e1, *e2;
 +      SmallHash hash, *ehash = &hash;
 +      float vec[3], v1[3], v2[3], v3[3], v4[4], s1[3], s2[3], view[3];
 +      int i, c1, c2;
 +      
 +      knife_bgl_get_mats(kcd, &mats);
 +      
 +      if (kcd->linehits) {
 +              MEM_freeN(kcd->linehits);
 +              kcd->linehits = NULL;
 +              kcd->totlinehit = 0;
 +      }
 +      
 +      copy_v3_v3(v1, kcd->prevco);
 +      copy_v3_v3(v2, kcd->vertco);
 +      
 +      /*project screen line's 3d coordinates back into 2d*/
 +      knife_project_v3(kcd, v1, s1);
 +      knife_project_v3(kcd, v2, s2);
 +      
 +      if (len_v2v2(s1, s2) < 1)
 +              return; 
 +
 +      /*unproject screen line*/
++      ED_view3d_win_to_segment_clip(kcd->ar, kcd->vc.v3d, s1, v1, v3);
++      ED_view3d_win_to_segment_clip(kcd->ar, kcd->vc.v3d, s2, v2, v4);
 +      
 +      /*view3d_unproject(&mats, v1, s1[0], s1[1], 0.0f);
 +      view3d_unproject(&mats, v2, s2[0], s2[1], 0.0f);
 +      view3d_unproject(&mats, v3, s1[0], s1[1], 1.0f-FLT_EPSILON);
 +      view3d_unproject(&mats, v4, s2[0], s2[1], 1.0f-FLT_EPSILON);*/
 +      
 +      mul_m4_v3(kcd->ob->imat, v1);
 +      mul_m4_v3(kcd->ob->imat, v2);
 +      mul_m4_v3(kcd->ob->imat, v3);
 +      mul_m4_v3(kcd->ob->imat, v4);
 +      
 +      sub_v3_v3v3(vec, v2, v1);
 +      normalize_v3(vec);
 +      mul_v3_fl(vec, 0.01);
 +      add_v3_v3(v1, vec);
 +      add_v3_v3(v3, vec);
 +
 +      sub_v3_v3v3(vec, v4, v2);
 +      normalize_v3(vec);
 +      mul_v3_fl(vec, 0.01);
 +      add_v3_v3(v4, vec);
 +      add_v3_v3(v2, vec);
 +      
 +      sub_v3_v3v3(view, v4, v1);
 +      normalize_v3(view);
 +      
 +      BLI_smallhash_init(ehash);
 +      
 +      /*test two triangles of sceen line's plane*/
 +      e1 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v2, v3, ehash, &mats, &c1);
 +      e2 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v3, v4, ehash, &mats, &c2);
 +      if (c1 && c2) {
 +              e1 = MEM_reallocN(e1, sizeof(BMEdgeHit)*(c1+c2));
 +              memcpy(e1+c1, e2, sizeof(BMEdgeHit)*c2);
 +              MEM_freeN(e2);
 +      } else if (c2) {
 +              e1 = e2;
 +      }
 +      
 +      kcd->linehits = e1;
 +      kcd->totlinehit = c1+c2;
 +
 +      /*find position along screen line, used for sorting*/
 +      for (i=0; i<kcd->totlinehit; i++) {
 +              BMEdgeHit *lh = e1+i;
 +              
 +              lh->l = len_v2v2(lh->schit, s1) / len_v2v2(s2, s1);
 +      }
 +      
 +      BLI_smallhash_release(ehash);
 +}
 +
 +static BMFace *knife_find_closest_face(knifetool_opdata *kcd, float co[3], int *is_space)
 +{
 +      BMFace *f;
 +      bglMats mats;
 +      float origin[3], ray[3];
 +      float mval[2], imat[3][3];
 +      int dist = KMAXDIST; 
 +      
 +      knife_bgl_get_mats(kcd, &mats);
 +
 +      mval[0] = kcd->vc.mval[0]; mval[1] = kcd->vc.mval[1];
 +      
 +      /*unproject to find view ray*/
 +      view3d_unproject(&mats, origin, mval[0], mval[1], 0.0f);
 +
 +      sub_v3_v3v3(ray, origin, kcd->vc.rv3d->viewinv[3]);
 +      normalize_v3(ray);
 +      
 +      /*transform into object space*/
 +      invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
 +      copy_m3_m4(imat, kcd->ob->obmat);
 +      invert_m3(imat);
 +      
 +      mul_m4_v3(kcd->ob->imat, origin);
 +      mul_m3_v3(imat, ray);
 +      
 +      copy_v3_v3(co, origin);
 +      add_v3_v3(co, ray);
 +
 +      f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co);
 +      
 +      if (is_space)
 +              *is_space = !f; 
 +      
 +      if (!f) {
 +              /*try to use backbuffer selection method if ray casting failed*/
 +              f = EDBM_findnearestface(&kcd->vc, &dist);
 +              
 +              /*cheat for now; just put in the origin instead 
 +                of a true coordinate on the face*/
 +              copy_v3_v3(co, origin);
 +              add_v3_v3(co, ray);
 +      }
 +      
 +      return f;
 +}
 +
 +/*find the 2d screen space density of vertices within a radius.  used to scale snapping
 +  distance for picking edges/verts.*/
 +static int knife_sample_screen_density(knifetool_opdata *kcd, float radius)
 +{
 +      BMFace *f;
 +      int is_space;
 +      float co[3], sco[3];
 +      
 +      f = knife_find_closest_face(kcd, co, &is_space);
 +      
 +      if (f && !is_space) {
 +              ListBase *lst;
 +              Ref *ref;
 +              float dis;
 +              int c = 0;
 +              
 +              knife_project_v3(kcd, co, sco);
 +              
 +              lst = knife_get_face_kedges(kcd, f);
 +              for (ref=lst->first; ref; ref=ref->next) {
 +                      KnifeEdge *kfe = ref->ref;
 +                      int i;
 +                      
 +                      for (i=0; i<2; i++) {
 +                              KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
 +                              
 +                              knife_project_v3(kcd, kfv->co, kfv->sco);
 +                              
 +                              dis = len_v2v2(kfv->sco, sco);
 +                              if (dis < radius) {
 +                                      if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
 +                                              float vec[3];
 +                                              
 +                                              copy_v3_v3(vec, kfv->co);
 +                                              mul_m4_v3(kcd->vc.obedit->obmat, vec);
 +                      
 +                                              if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) {
 +                                                      c++;
 +                                              }
 +                                      } else {
 +                                              c++;
 +                                      }
 +                              }
 +                      }
 +              }
 +              
 +              return c;
 +      }
 +              
 +      return 0;
 +}
 +
 +/*returns snapping distance for edges/verts, scaled by the density of the
 +  surrounding mesh (in screen space)*/
 +static float knife_snap_size(knifetool_opdata *kcd, float maxsize)
 +{
 +      float density = (float)knife_sample_screen_density(kcd, maxsize*2.0f);
 +      
 +      density = MAX2(density, 1);
 +      
 +      return MIN2(maxsize / (density*0.5f), maxsize);
 +}
 +
 +/*p is closest point on edge to the mouse cursor*/
 +static KnifeEdge *knife_find_closest_edge(knifetool_opdata *kcd, float p[3], BMFace **fptr, int *is_space)
 +{
 +      BMFace *f;
 +      float co[3], sco[3], maxdist = knife_snap_size(kcd, kcd->ethresh);
 +      
 +      if (kcd->ignore_vert_snapping)
 +              maxdist *= 0.5;
 +
 +      f = knife_find_closest_face(kcd, co, NULL);
 +      *is_space = !f;
 +      
 +      /*set p to co, in case we don't find anything, means a face cut*/
 +      copy_v3_v3(p, co);
 +      kcd->curbmface = f;
 +      
 +      if (f) {
 +              KnifeEdge *cure = NULL;
 +              ListBase *lst;
 +              Ref *ref;
 +              float dis, curdis=FLT_MAX;
 +              
 +              knife_project_v3(kcd, co, sco);
 +              
 +              /*look through all edges associated with this face*/
 +              lst = knife_get_face_kedges(kcd, f);
 +              for (ref=lst->first; ref; ref=ref->next) {
 +                      KnifeEdge *kfe = ref->ref;
 +                      
 +                      /*project edge vertices into screen space*/
 +                      knife_project_v3(kcd, kfe->v1->co, kfe->v1->sco);
 +                      knife_project_v3(kcd, kfe->v2->co, kfe->v2->sco);
 +
 +                      dis = dist_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
 +                      if (dis < curdis && dis < maxdist) {
 +                              if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
 +                                      float labda= labda_PdistVL2Dfl(sco, kfe->v1->sco, kfe->v2->sco);
 +                                      float vec[3];
 +              
 +                                      vec[0]= kfe->v1->co[0] + labda*(kfe->v2->co[0] - kfe->v1->co[0]);
 +                                      vec[1]= kfe->v1->co[1] + labda*(kfe->v2->co[1] - kfe->v1->co[1]);
 +                                      vec[2]= kfe->v1->co[2] + labda*(kfe->v2->co[2] - kfe->v1->co[2]);
 +                                      mul_m4_v3(kcd->vc.obedit->obmat, vec);
 +              
 +                                      if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) {
 +                                              cure = kfe;
 +                                              curdis = dis;
 +                                      }
 +                              } else {
 +                                      cure = kfe;
 +                                      curdis = dis;                           
 +                              }
 +                      }
 +              }
 +              
 +              if (fptr)
 +                      *fptr = f;
 +              
 +              if (cure && p) {
 +                      float d;
 +
 +                      if (!kcd->ignore_edge_snapping || !(cure->e)) {
 +                              
 +                              closest_to_line_segment_v3(p, sco, cure->v1->sco, cure->v2->sco);
 +                              sub_v3_v3(p, cure->v1->sco);
 +                              
 +                              if (kcd->snap_midpoints) {
 +                                      d = 0.5f;       
 +                              } else {
 +                                      d = len_v3v3(cure->v1->sco, cure->v2->sco);
 +                                      if (d != 0.0) {
 +                                              d = len_v3(p) / d;
 +                                      }
 +                              }
 +                              
 +                              interp_v3_v3v3(p, cure->v1->co, cure->v2->co, d);
 +                      } else {
 +                              return NULL;
 +                      }
 +              }
 +              
 +              return cure;
 +      }
 +              
 +      if (fptr)
 +              *fptr = NULL;
 +      
 +      return NULL;
 +}
 +
 +/*find a vertex near the mouse cursor, if it exists*/
 +static KnifeVert *knife_find_closest_vert(knifetool_opdata *kcd, float p[3], BMFace **fptr, int *is_space)
 +{
 +      BMFace *f;
 +      float co[3], sco[3], maxdist = knife_snap_size(kcd, kcd->vthresh);
 +      
 +      if (kcd->ignore_vert_snapping)
 +              maxdist *= 0.5;
 +      
 +      f = knife_find_closest_face(kcd, co, is_space);
 +      
 +      /*set p to co, in case we don't find anything, means a face cut*/
 +      copy_v3_v3(p, co);
 +      kcd->curbmface = f;
 +      
 +      if (f) {
 +              ListBase *lst;
 +              Ref *ref;
 +              KnifeVert *curv = NULL;
 +              float dis, curdis=FLT_MAX;
 +              
 +              knife_project_v3(kcd, co, sco);
 +              
 +              lst = knife_get_face_kedges(kcd, f);
 +              for (ref=lst->first; ref; ref=ref->next) {
 +                      KnifeEdge *kfe = ref->ref;
 +                      int i;
 +                      
 +                      for (i=0; i<2; i++) {
 +                              KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
 +                              
 +                              knife_project_v3(kcd, kfv->co, kfv->sco);
 +                              
 +                              dis = len_v2v2(kfv->sco, sco);
 +                              if (dis < curdis && dis < maxdist) {
 +                                      if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
 +                                              float vec[3];
 +                                              
 +                                              copy_v3_v3(vec, kfv->co);
 +                                              mul_m4_v3(kcd->vc.obedit->obmat, vec);
 +                      
 +                                              if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) {
 +                                                      curv = kfv;
 +                                                      curdis = dis;
 +                                              }
 +                                      } else {
 +                                              curv = kfv;
 +                                              curdis = dis;                           
 +                                      }
 +                              }
 +                      }
 +              }
 +              
 +              if (!kcd->ignore_vert_snapping || !(curv && curv->v)) {
 +                      if (fptr)
 +                              *fptr = f;
 +              
 +                      if (curv && p) {
 +                              copy_v3_v3(p, curv->co);
 +                      }
 +                      
 +                      return curv;
 +              } else {
 +                      if (fptr)
 +                              *fptr = f;
 +                      
 +                      return NULL;
 +              }
 +      }
 +              
 +      if (fptr)
 +              *fptr = NULL;
 +      
 +      return NULL;
 +}
 +
 +/*update active knife edge/vert pointers*/
 +static int knife_update_active(knifetool_opdata *kcd)
 +{
 +      kcd->curvert = NULL; kcd->curedge = NULL; kcd->curbmface = NULL;
 +      
 +      kcd->curvert = knife_find_closest_vert(kcd, kcd->vertco, &kcd->curbmface, &kcd->is_space);
 +      if (!kcd->curvert) {
 +              kcd->curedge = knife_find_closest_edge(kcd, kcd->vertco, &kcd->curbmface, &kcd->is_space);
 +      }
 +      
 +      if (kcd->mode == MODE_DRAGGING) {
 +              knife_find_line_hits(kcd);
 +      }
 +      return 1;
 +}
 +
 +#define MARK                  4
 +#define DEL                           8       
 +#define VERT_ON_EDGE  16
 +#define VERT_ORIG             32
 +#define FACE_FLIP             64
 +#define BOUNDARY              128
 +#define FACE_NEW              256
 +
 +typedef struct facenet_entry {
 +      struct facenet_entry *next, *prev;
 +      KnifeEdge *kfe;
 +} facenet_entry;
 +
 +static void rnd_offset_co(float co[3], float scale)
 +{
 +      int i;
 +      
 +      for (i=0; i<3; i++) {
 +              co[i] += (BLI_drand()-0.5)*scale;
 +      }
 +}
 +
 +static void remerge_faces(knifetool_opdata *kcd)
 +{
 +      BMesh *bm = kcd->em->bm;
 +      SmallHash svisit, *visit=&svisit;
 +      BMIter iter;
 +      BMFace *f;
 +      BMFace **stack = NULL;
 +      BLI_array_declare(stack);
 +      BMFace **faces = NULL;
 +      BLI_array_declare(faces);
 +      BMOperator bmop;
 +      int idx;
 +      
 +      BMO_InitOpf(bm, &bmop, "beautify_fill faces=%ff constrain_edges=%fe", FACE_NEW, BOUNDARY);
 +      
 +      BMO_Exec_Op(bm, &bmop);
 +      BMO_Flag_Buffer(bm, &bmop, "geomout", FACE_NEW, BM_FACE);
 +      
 +      BMO_Finish_Op(bm, &bmop);
 +      
 +      BLI_smallhash_init(visit);
 +      BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
 +              BMIter eiter;
 +              BMEdge *e;
 +              BMFace *f2;
 +              
 +              if (!BMO_TestFlag(bm, f, FACE_NEW))
 +                      continue;
 +              
 +              if (BLI_smallhash_haskey(visit, (intptr_t)f))
 +                      continue;
 +              
 +              BLI_array_empty(stack);
 +              BLI_array_empty(faces);
 +              BLI_array_append(stack, f);
 +              BLI_smallhash_insert(visit, (intptr_t)f, NULL);
 +              
 +              do {
 +                      f2 = BLI_array_pop(stack);
 +                      
 +                      BLI_array_append(faces, f2);
 +                      
 +                      BM_ITER(e, &eiter, bm, BM_EDGES_OF_FACE, f2) {
 +                              BMIter fiter;
 +                              BMFace *f3;
 +                              
 +                              if (BMO_TestFlag(bm, e, BOUNDARY))
 +                                      continue;
 +                              
 +                              BM_ITER(f3, &fiter, bm, BM_FACES_OF_EDGE, e) {
 +                                      if (!BMO_TestFlag(bm, f3, FACE_NEW))
 +                                              continue;
 +                                      if (BLI_smallhash_haskey(visit, (intptr_t)f3))
 +                                              continue;
 +                                      
 +                                      BLI_smallhash_insert(visit, (intptr_t)f3, NULL);
 +                                      BLI_array_append(stack, f3);
 +                              }
 +                      }       
 +              } while (BLI_array_count(stack) > 0);
 +              
 +              if (BLI_array_count(faces) > 0) {
 +                      idx = BM_GetIndex(faces[0]);
 +                      
 +                      f2 = BM_Join_Faces(bm, faces, BLI_array_count(faces));
 +                      if (f2)  {
 +                              BMO_SetFlag(bm, f2, FACE_NEW);
 +                              BM_SetIndex(f2, idx);
 +                      }
 +              }
 +      }
 +}
 +
 +/*use edgenet to fill faces.  this is a bit annoying and convoluted.*/
 +static void knifenet_fill_faces(knifetool_opdata *kcd)
 +{
 +      BMesh *bm = kcd->em->bm;
 +      BMIter bmiter;
 +      BLI_mempool_iter iter;
 +      BMFace *f;
 +      BMEdge *e;
 +      KnifeVert *kfv;
 +      KnifeEdge *kfe;
 +      facenet_entry *entry;
 +      ListBase *face_nets = MEM_callocN(sizeof(ListBase)*bm->totface, "face_nets");
 +      BMFace **faces = MEM_callocN(sizeof(BMFace*)*bm->totface, "faces knife");
 +      MemArena *arena = BLI_memarena_new(1<<16, "knifenet_fill_faces");
 +      SmallHash shash, *hash = &shash;
 +      /* SmallHash shash2, *visited = &shash2; */ /*UNUSED*/
 +      int i, j, k=0, totface=bm->totface;
 +      
 +      BMO_push(bm, NULL);
 +      bmesh_begin_edit(bm, BMOP_UNTAN_MULTIRES);
 +      
 +      i = 0;
 +      BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
 +              BM_SetIndex(f, i);
 +              faces[i] = f;
 +              i++;
 +      }
 +      
 +      BM_ITER(e, &bmiter, bm, BM_EDGES_OF_MESH, NULL) {
 +              BMO_SetFlag(bm, e, BOUNDARY);
 +      }
 +
 +      /*turn knife verts into real verts, as necassary*/
 +      BLI_mempool_iternew(kcd->kverts, &iter);
 +      for (kfv=BLI_mempool_iterstep(&iter); kfv; kfv=BLI_mempool_iterstep(&iter)) {
 +              if (!kfv->v) {
 +                      kfv->v = BM_Make_Vert(bm, kfv->co, NULL);
 +                      kfv->flag = 1;
 +                      BMO_SetFlag(bm, kfv->v, DEL);
 +              } else {
 +                      kfv->flag = 0;
 +                      BMO_SetFlag(bm, kfv->v, VERT_ORIG);
 +              }
 +
 +              BMO_SetFlag(bm, kfv->v, MARK);
 +      }
 +      
 +      /*we want to only do changed faces.  first, go over new edges and add to
 +      face net lists.*/
 +      i=0; j=0; k=0;
 +      BLI_mempool_iternew(kcd->kedges, &iter);
 +      for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) {
 +              Ref *ref;
 +              if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace)
 +                      continue;
 +
 +              i++;
 +
 +              if (kfe->e && kfe->v1->v == kfe->e->v1 && kfe->v2->v == kfe->e->v2) {
 +                      kfe->oe = kfe->e;
 +                      continue;
 +              }
 +              
 +              j++;
 +              
 +              if (kfe->e) {
 +                      kfe->oe = kfe->e;
 +
 +                      BMO_SetFlag(bm, kfe->e, DEL);
 +                      BMO_ClearFlag(bm, kfe->e, BOUNDARY);
 +                      kfe->e = NULL;
 +              }
 +              
 +              kfe->e = BM_Make_Edge(bm, kfe->v1->v, kfe->v2->v, NULL, 1);
 +              BMO_SetFlag(bm, kfe->e, BOUNDARY);
 +              
 +              for (ref=kfe->faces.first; ref; ref=ref->next) {
 +                      f = ref->ref;
 +                      
 +                      entry = BLI_memarena_alloc(arena, sizeof(*entry));
 +                      entry->kfe = kfe;
 +                      BLI_addtail(face_nets+BM_GetIndex(f), entry);
 +              }
 +      }
 +      
 +      /*go over original edges, and add to faces with new geometry*/
 +      BLI_mempool_iternew(kcd->kedges, &iter);
 +      for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) {
 +              Ref *ref;
 +              
 +              if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace)
 +                      continue;
 +              if (!(kfe->oe && kfe->v1->v == kfe->oe->v1 && kfe->v2->v == kfe->oe->v2))
 +                      continue;
 +              
 +              k++;
 +              
 +              BMO_SetFlag(bm, kfe->e, BOUNDARY);
 +              kfe->oe = kfe->e;
 +              
 +              for (ref=kfe->faces.first; ref; ref=ref->next) {
 +                      f = ref->ref;
 +                      
 +                      if (face_nets[BM_GetIndex(f)].first) {
 +                              entry = BLI_memarena_alloc(arena, sizeof(*entry));
 +                              entry->kfe = kfe;
 +                              BLI_addtail(face_nets+BM_GetIndex(f), entry);
 +                      }
 +              }
 +      }
 +      
 +      for (i=0; i<totface; i++) {
 +              EditFace *efa;
 +              EditVert *eve, *lasteve;
 +              int j;
 +              float rndscale = FLT_EPSILON*25;
 +              
 +              f = faces[i];
 +              BLI_smallhash_init(hash);
 +              
 +              if (face_nets[i].first)
 +                      BMO_SetFlag(bm, f, DEL);
 +              
 +              BLI_begin_edgefill();
 +              
 +              for (entry=face_nets[i].first; entry; entry=entry->next) {
 +                      if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v1)) {
 +                              eve = BLI_addfillvert(entry->kfe->v1->v->co);
 +                              eve->xs = 0;
 +                              rnd_offset_co(eve->co, rndscale);
 +                              eve->tmp.p = entry->kfe->v1->v;
 +                              BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v1, eve);
 +                      }
 +
 +                      if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v2)) {
 +                              eve = BLI_addfillvert(entry->kfe->v2->v->co);
 +                              eve->xs = 0;
 +                              rnd_offset_co(eve->co, rndscale);
 +                              eve->tmp.p = entry->kfe->v2->v;
 +                              BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v2, eve);
 +                      }                                                
 +              }
 +              
 +              for (j=0, entry=face_nets[i].first; entry; entry=entry->next, j++) {
 +                      lasteve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1);
 +                      eve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2);
 +                      
 +                      eve->xs++;
 +                      lasteve->xs++;
 +              }
 +              
 +              for (j=0, entry=face_nets[i].first; entry; entry=entry->next, j++) {
 +                      lasteve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1);
 +                      eve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2);
 +                      
 +                      if (eve->xs > 1 && lasteve->xs > 1) {
 +                              BLI_addfilledge(lasteve, eve);
 +                              
 +                              BMO_ClearFlag(bm, entry->kfe->e->v1, DEL);
 +                              BMO_ClearFlag(bm, entry->kfe->e->v2, DEL);
 +                      } else {
 +                              if (lasteve->xs < 2)
 +                                      BLI_remlink(&fillvertbase, lasteve);
 +                              if (eve->xs < 2)
 +                                      BLI_remlink(&fillvertbase, eve);
 +                      }
 +              }
 +              
 +              BLI_edgefill(0);
 +              
 +              for (efa=fillfacebase.first; efa; efa=efa->next) {
 +                      BMVert *v1=efa->v3->tmp.p, *v2=efa->v2->tmp.p, *v3=efa->v1->tmp.p;
 +                      BMFace *f2;
 +                      BMLoop *l;
 +                      BMVert *verts[3] = {v1, v2, v3};
 +                      
 +                      if (v1 == v2 || v2 == v3 || v1 == v3)
 +                              continue;       
 +                      if (BM_Face_Exists(bm, verts, 3, &f2))
 +                              continue;
 +              
 +                      f2 = BM_Make_QuadTri(bm, v1, v2, v3, NULL, NULL, 0);
 +                      BMO_SetFlag(bm, f2, FACE_NEW);
 +                      
 +                      l = bm_firstfaceloop(f2);
 +                      do {
 +                              BMO_ClearFlag(bm, l->e, DEL);
 +                              l = l->next;
 +                      } while (l != bm_firstfaceloop(f2));
 +      
 +                      BMO_ClearFlag(bm, f2, DEL);
 +                      BM_SetIndex(f2, i);
 +                      
 +                      BM_Face_UpdateNormal(bm, f2);
 +                      if (dot_v3v3(f->no, f2->no) < 0.0) {
 +                              BM_flip_normal(bm, f2);
 +                      }
 +              }
 +              
 +              BLI_end_edgefill();
 +              BLI_smallhash_release(hash);
 +      }
 +      
 +      /* interpolate customdata */
 +      BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
 +              BMLoop *l1;
 +              BMFace *f2; 
 +              BMIter liter1;
 +              
 +              if (!BMO_TestFlag(bm, f, FACE_NEW))
 +                      continue;
 +              
 +              f2 = faces[BM_GetIndex(f)];
 +              if (BM_GetIndex(f) < 0 || BM_GetIndex(f) >= totface) {
 +                      printf("eek!!\n");
 +              }
 +
 +              BM_Copy_Attributes(bm, bm, f2, f);
 +              
 +              BM_ITER(l1, &liter1, bm, BM_LOOPS_OF_FACE, f) {
 +                      BM_loop_interp_from_face(bm, l1, f2, 1, 1);
 +              }
 +      }
 +      
 +      /*merge triangles back into faces*/
 +      remerge_faces(kcd);
 +
 +      /*delete left over faces*/
 +      BMO_CallOpf(bm, "del geom=%ff context=%i", DEL, DEL_ONLYFACES);
 +      BMO_CallOpf(bm, "del geom=%fe context=%i", DEL, DEL_EDGES);
 +      BMO_CallOpf(bm, "del geom=%fv context=%i", DEL, DEL_VERTS);
 +
 +      if (face_nets) 
 +              MEM_freeN(face_nets);
 +      if (faces)
 +              MEM_freeN(faces);
 +      BLI_memarena_free(arena);
 +      BLI_smallhash_release(hash);    
 +      
 +      BMO_ClearStack(bm); /*remerge_faces sometimes raises errors, so make sure to clear them*/
 +
 +      bmesh_end_edit(bm, BMOP_UNTAN_MULTIRES);
 +      BMO_pop(bm);
 +}
 +
 +/*called on tool confirmation*/
 +static void knifetool_finish(bContext *C, wmOperator *op)
 +{
 +      knifetool_opdata *kcd= op->customdata;
 +      
 +      knifenet_fill_faces(kcd);
 +      
 +      DAG_id_tag_update(kcd->ob->data, OB_RECALC_DATA);
 +      WM_event_add_notifier(C, NC_GEOM|ND_DATA, kcd->ob->data);
 +}
 +
 +/*copied from paint_image.c*/
 +static int project_knife_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
 +{
 +      int orth= get_view3d_cliprange(v3d, rv3d, clipsta, clipend);
 +
 +      if (orth) { /* only needed for ortho */
 +              float fac = 2.0f / ((*clipend) - (*clipsta));
 +              *clipsta *= fac;
 +              *clipend *= fac;
 +      }
 +
 +      return orth;
 +}
 +
 +static void knife_recalc_projmat(knifetool_opdata *kcd)
 +{
 +      ARegion *ar = CTX_wm_region(kcd->C);
 +      
 +      if (!ar)
 +              return;
 +      
 +      invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
 +      view3d_get_object_project_mat(ar->regiondata, kcd->ob, kcd->projmat);
 +      //mul_m4_m4m4(kcd->projmat, kcd->vc.rv3d->viewmat, kcd->vc.rv3d->winmat);
 +      
 +      kcd->is_ortho = project_knife_view_clip(kcd->vc.v3d, kcd->vc.rv3d, 
 +                                              &kcd->clipsta, &kcd->clipend);
 +}
 +
 +/* called when modal loop selection is done... */
 +static void knifetool_exit (bContext *UNUSED(C), wmOperator *op)
 +{
 +      knifetool_opdata *kcd= op->customdata;
 +      
 +      if (!kcd)
 +              return;
 +              
 +      /* deactivate the extra drawing stuff in 3D-View */
 +      ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle);
 +      
 +      /* free the custom data */
 +      BLI_mempool_destroy(kcd->refs);
 +      BLI_mempool_destroy(kcd->kverts);
 +      BLI_mempool_destroy(kcd->kedges);
 +
 +      BLI_ghash_free(kcd->origedgemap, NULL, NULL);
 +      BLI_ghash_free(kcd->origvertmap, NULL, NULL);
 +      BLI_ghash_free(kcd->kedgefacemap, NULL, NULL);
 +      
 +      BMBVH_FreeBVH(kcd->bmbvh);
 +      BLI_memarena_free(kcd->arena);
 +      
 +      /* tag for redraw */
 +      ED_region_tag_redraw(kcd->ar);
 +
 +      /* destroy kcd itself */
 +      MEM_freeN(kcd);
 +      op->customdata= NULL;                   
 +}
 +
 +/* called when modal loop selection gets set up... */
 +static int knifetool_init (bContext *C, wmOperator *op, int UNUSED(do_cut))
 +{
 +      knifetool_opdata *kcd;
 +      
 +      /* alloc new customdata */
 +      kcd= op->customdata= MEM_callocN(sizeof(knifetool_opdata), "knifetool Modal Op Data");
 +      
 +      /* assign the drawing handle for drawing preview line... */
 +      kcd->ar= CTX_wm_region(C);
 +      kcd->C = C;
 +      kcd->draw_handle= ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW);
 +      em_setup_viewcontext(C, &kcd->vc);
 +
 +      kcd->ob = CTX_data_edit_object(C);
 +      kcd->em= ((Mesh *)kcd->ob->data)->edit_btmesh;
 +      kcd->bmbvh = BMBVH_NewBVH(kcd->em);
 +      kcd->arena = BLI_memarena_new(1<<15, "knife");
 +      kcd->vthresh = KMAXDIST-1;
 +      kcd->ethresh = KMAXDIST;
 +      
 +      kcd->extend = 1;
 +      
 +      knife_recalc_projmat(kcd);
 +      
 +      ED_region_tag_redraw(kcd->ar);
 +      
 +      kcd->refs = BLI_mempool_create(sizeof(Ref), 1, 2048, 0, 0);
 +      kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 1, 512, 0, 1);
 +      kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 1, 512, 0, 1);
 +      
 +      kcd->origedgemap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origedgemap");
 +      kcd->origvertmap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origvertmap");
 +      kcd->kedgefacemap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origvertmap");
 +
 +      return 1;
 +}
 +
 +static int knifetool_cancel (bContext *C, wmOperator *op)
 +{
 +      /* this is just a wrapper around exit() */
 +      knifetool_exit(C, op);
 +      return OPERATOR_CANCELLED;
 +}
 +
 +static int knifetool_invoke (bContext *C, wmOperator *op, wmEvent *evt)
 +{
 +      knifetool_opdata *kcd;
 +
 +      view3d_operator_needs_opengl(C);
 +
 +      if (!knifetool_init(C, op, 0))
 +              return OPERATOR_CANCELLED;
 +      
 +      /* add a modal handler for this operator - handles loop selection */
 +      WM_event_add_modal_handler(C, op);
 +
 +      kcd = op->customdata;
 +      kcd->vc.mval[0] = evt->mval[0];
 +      kcd->vc.mval[1] = evt->mval[1];
 +      
 +      return OPERATOR_RUNNING_MODAL;
 +}
 +
 +enum {
 +      KNF_MODAL_CANCEL=1,
 +      KNF_MODAL_CONFIRM,
 +      KNF_MODAL_MIDPOINT_ON,
 +      KNF_MODAL_MIDPOINT_OFF,
 +      KNF_MODAL_NEW_CUT,
 +      KNF_MODEL_IGNORE_SNAP_ON,
 +      KNF_MODEL_IGNORE_SNAP_OFF,
 +      KNF_MODAL_ADD_CUT,
 +};
 +
 +wmKeyMap* knifetool_modal_keymap(wmKeyConfig *keyconf)
 +{
 +      static EnumPropertyItem modal_items[] = {
 +      {KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
 +      {KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
 +      {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap To Midpoints On", ""},
 +      {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""},
 +      {KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""},
 +      {KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""},
 +      {KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""},
 +      {KNF_MODAL_ADD_CUT, "ADD_CUT", 0, "Add Cut", ""},
 +
 +      {0, NULL, 0, NULL, NULL}};
 +      
 +      wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Knife Tool Modal Map");
 +      
 +      /* this function is called for each spacetype, only needs to add map once */
 +      if(keymap) return NULL;
 +      
 +      keymap= WM_modalkeymap_add(keyconf, "Knife Tool Modal Map", modal_items);
 +      
 +      /* items for modal map */
 +      WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
 +      WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_ADD_CUT);
 +      WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
 +      WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
 +      WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM);
 +      WM_modalkeymap_add_item(keymap, EKEY, KM_PRESS, 0, 0, KNF_MODAL_NEW_CUT);
 +
 +      WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_MIDPOINT_ON);
 +      WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KNF_MODAL_MIDPOINT_OFF);
 +      WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_MIDPOINT_ON);
 +      WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_RELEASE, KM_ANY, 0, KNF_MODAL_MIDPOINT_OFF);
 +
 +      WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_ON);
 +      WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_OFF);
 +      WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_PRESS, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_ON);
 +      WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_RELEASE, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_OFF);
 +      
 +      WM_modalkeymap_assign(keymap, "MESH_OT_knifetool");
 +      
 +      return keymap;
 +}
 +
 +static int knifetool_modal (bContext *C, wmOperator *op, wmEvent *event)
 +{
 +      Object *obedit;
 +      knifetool_opdata *kcd= op->customdata;
 +      
 +      if (!C) {
 +              return OPERATOR_FINISHED;
 +      }
 +      
 +      obedit = CTX_data_edit_object(C);
 +      if (!obedit || obedit->type != OB_MESH || ((Mesh*)obedit->data)->edit_btmesh != kcd->em) {
 +              knifetool_exit(C, op);
 +              return OPERATOR_FINISHED;
 +      }
 +
 +      view3d_operator_needs_opengl(C);
 +      
 +      if (kcd->mode == MODE_PANNING)
 +              kcd->mode = kcd->prevmode;
 +      
 +      /* handle modal keymap */
 +      if (event->type == EVT_MODAL_MAP) {
 +              switch (event->val) {
 +                      case KNF_MODAL_CANCEL:
 +                              /* finish */
 +                              ED_region_tag_redraw(kcd->ar);
 +                              
 +                              knifetool_exit(C, op);
 +                              
 +                              return OPERATOR_CANCELLED;
 +                      case KNF_MODAL_CONFIRM:
 +                              /* finish */
 +                              ED_region_tag_redraw(kcd->ar);
 +                              
 +                              knifetool_finish(C, op);
 +                              knifetool_exit(C, op);
 +                              
 +                              return OPERATOR_FINISHED;
 +                      case KNF_MODAL_MIDPOINT_ON:
 +                              ED_region_tag_redraw(kcd->ar);
 +                              kcd->snap_midpoints = 1;
 +                              break;
 +                      case KNF_MODAL_MIDPOINT_OFF:
 +                              ED_region_tag_redraw(kcd->ar);
 +                              kcd->snap_midpoints = 0;
 +                              break;
 +                      case KNF_MODEL_IGNORE_SNAP_ON:
 +                              ED_region_tag_redraw(kcd->ar);
 +                              kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 1;
 +                              break;
 +                      case KNF_MODEL_IGNORE_SNAP_OFF:
 +                              ED_region_tag_redraw(kcd->ar);
 +                              kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 0;
 +                              break;
 +                      case KNF_MODAL_NEW_CUT:
 +                              ED_region_tag_redraw(kcd->ar);
 +                              knife_finish_cut(kcd);
 +                              kcd->mode = MODE_IDLE;
 +                              break;
 +                      case KNF_MODAL_ADD_CUT:
 +                              knife_recalc_projmat(kcd);
 +
 +                              if (kcd->mode == MODE_DRAGGING) {
 +                                      knife_add_cut(kcd);
 +                                      if (!kcd->extend) {
 +                                              knife_finish_cut(kcd);
 +                                              kcd->mode = MODE_IDLE;
 +                                      }
 +                              } else if (kcd->mode != MODE_PANNING) {
 +                                      knife_start_cut(kcd);
 +                                      kcd->mode = MODE_DRAGGING;
 +                              }
 +              
 +                              ED_region_tag_redraw(kcd->ar);
 +                              break;
 +                      }
 +      } else { /*non-modal-mapped events*/
 +              switch (event->type) {
 +                      case WHEELUPMOUSE:
 +                      case WHEELDOWNMOUSE:
 +                              return OPERATOR_PASS_THROUGH;
 +                      case MIDDLEMOUSE:
 +                              if (event->val != KM_RELEASE) {
 +                                      if (kcd->mode != MODE_PANNING)
 +                                              kcd->prevmode = kcd->mode;
 +                                      kcd->mode = MODE_PANNING;
 +                              } else {
 +                                      kcd->mode = kcd->prevmode;
 +                              }
 +                              
 +                              ED_region_tag_redraw(kcd->ar);
 +                              return OPERATOR_PASS_THROUGH;
 +                              
 +                      case MOUSEMOVE:  /* mouse moved somewhere to select another loop */
 +                              if (kcd->mode != MODE_PANNING) {
 +                                      knife_recalc_projmat(kcd);
 +                                      kcd->vc.mval[0] = event->mval[0];
 +                                      kcd->vc.mval[1] = event->mval[1];
 +                                      
 +                                      if (knife_update_active(kcd))                                   
 +                                              ED_region_tag_redraw(kcd->ar);
 +                              }
 +      
 +                              break;
 +              }
 +      }
 +      
 +      /* keep going until the user confirms */
 +      return OPERATOR_RUNNING_MODAL;
 +}
 +
 +void MESH_OT_knifetool (wmOperatorType *ot)
 +{
 +      /* description */
 +      ot->name= "Knife Topology Tool";
 +      ot->idname= "MESH_OT_knifetool";
 +      ot->description= "Cut new topology";
 +      
 +      /* callbacks */
 +      ot->invoke= knifetool_invoke;
 +      ot->modal= knifetool_modal;
 +      ot->cancel= knifetool_cancel;
 +      ot->poll= ED_operator_editmesh_view3d;
 +      
 +      /* flags */
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
 +}
index 1a672355e0ea4d4b2dfd78014347ddda61b9036e,09f5c32bea0a71c5faa7c83cc85ebfb24349651e..4f2cd0160d119c33ce7bfa3280e44c32021193bf
@@@ -144,12 -148,12 +148,12 @@@ static void imapaint_tri_weights(Objec
  }
  
  /* compute uv coordinates of mouse in face */
- void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, int *xy, float *uv)
+ void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2])
  {
        DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
 -      const int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
 -      MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
 -      int numfaces = dm->getNumFaces(dm), a, findex;
 +      const int *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
 +      MTFace *tface = dm->getTessFaceDataArray(dm, CD_MTFACE), *tf;
 +      int numfaces = dm->getNumTessFaces(dm), a, findex;
        float p[2], w[3], absw, minabsw;
        MFace mf;
        MVert mv[4];
index 2d74b7b382e61a944f5b2c9bea8a52bfc3bc32af,692d33bd091ea3438f13a5e5d000962a8c5adb6a..a143456c223a9ef520d9973effde7d395d3cb119
@@@ -1809,8 -1724,7 +1809,8 @@@ static int vpaint_stroke_test_start(bCo
        return 1;
  }
  
- static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, float mval[2], float pressure, int UNUSED(flip))
 +#if 0
+ static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, const float mval[2], float pressure, int UNUSED(flip))
  {
        ViewContext *vc = &vpd->vc;
        Brush *brush = paint_brush(&vp->paint);
index 48865d3ed5fdad28e01908d02d5680fa6853cba9,f780721ca07206b0eed1af9485e9cce0506aa8f4..61b7de7183ad45a2e78cb60752430009b5e99e97
@@@ -100,10 -100,10 +100,10 @@@ static DerivedMesh *applyModifier(Modif
        DerivedMesh *result;
  
        result = subsurf_make_derived_from_derived(derivedData, smd,
-                       useRenderParams, NULL, isFinalCalc, 0);
+                       useRenderParams, NULL, isFinalCalc, 0, (ob->flag & OB_MODE_EDIT));
        
        if(useRenderParams || !isFinalCalc) {
 -              DerivedMesh *cddm= CDDM_copy(result);
 +              DerivedMesh *cddm= CDDM_copy(result, 0);
                result->release(result);
                result= cddm;
        }
index 6be1002bb004d46477c7aa2c4116f987083efc7b,a5d2e0b38c7cc5e7f8a26fa3295681a63a041c34..afa914e869c00b2d5c83d26f980d45ef33c7404d
@@@ -271,10 -271,10 +271,10 @@@ static DerivedMesh *uvprojectModifier_d
        /* if only one projector, project coords to UVs */
        if(num_projectors == 1 && projectors[0].uci==NULL)
                for(i = 0, co = coords; i < numVerts; ++i, ++co)
-                       mul_project_m4_v4(projectors[0].projmat, *co);
+                       mul_project_m4_v3(projectors[0].projmat, *co);
  
 -      mface = dm->getFaceArray(dm);
 -      numFaces = dm->getNumFaces(dm);
 +      mface = dm->getTessFaceArray(dm);
 +      numFaces = dm->getNumTessFaces(dm);
  
        /* apply coords as UVs, and apply image if tfaces are new */
        for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {