merge with trunk. also tried to fix tesselator code; new code should've worked,...
authorJoseph Eagar <joeedh@gmail.com>
Sat, 28 Feb 2009 12:49:18 +0000 (12:49 +0000)
committerJoseph Eagar <joeedh@gmail.com>
Sat, 28 Feb 2009 12:49:18 +0000 (12:49 +0000)
73 files changed:
1  2 
source/blender/blenkernel/intern/brush.c
source/blender/blenkernel/intern/image.c
source/blender/blenkernel/intern/ipo.c
source/blender/blenloader/intern/readfile.c
source/blender/bmesh/bmesh_operators.h
source/blender/bmesh/bmesh_queries.h
source/blender/bmesh/intern/bmesh_eulers.c
source/blender/bmesh/intern/bmesh_mesh.c
source/blender/bmesh/intern/bmesh_mods.c
source/blender/bmesh/intern/bmesh_opdefines.c
source/blender/bmesh/intern/bmesh_operators.c
source/blender/bmesh/intern/bmesh_polygon.c
source/blender/bmesh/operators/dissolveops.c
source/blender/editors/animation/anim_channels.c
source/blender/editors/animation/anim_filter.c
source/blender/editors/animation/keyframing.c
source/blender/editors/armature/armature_intern.h
source/blender/editors/armature/armature_ops.c
source/blender/editors/armature/editarmature.c
source/blender/editors/include/ED_anim_api.h
source/blender/editors/include/ED_mesh.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/include/UI_interface.h
source/blender/editors/mesh/editmesh_add.c
source/blender/editors/mesh/editmesh_lib.c
source/blender/editors/mesh/editmesh_loop.c
source/blender/editors/mesh/editmesh_mods.c
source/blender/editors/mesh/editmesh_tools.c
source/blender/editors/mesh/mesh_intern.h
source/blender/editors/mesh/mesh_ops.c
source/blender/editors/mesh/meshtools.c
source/blender/editors/object/object_edit.c
source/blender/editors/physics/editparticle.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/paint_ops.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_action/action_draw.c
source/blender/editors/space_action/action_edit.c
source/blender/editors/space_action/action_select.c
source/blender/editors/space_graph/graph_draw.c
source/blender/editors/space_graph/graph_edit.c
source/blender/editors/space_graph/graph_header.c
source/blender/editors/space_graph/graph_ops.c
source/blender/editors/space_graph/space_graph.c
source/blender/editors/space_image/image_intern.h
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_image/image_panels.c
source/blender/editors/space_image/space_image.c
source/blender/editors/space_info/info_header.c
source/blender/editors/space_node/node_edit.c
source/blender/editors/space_view3d/view3d_buttons.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_ops.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/transform_conversions.c
source/blender/makesdna/DNA_scene_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_action.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_particle.c
source/blender/makesrna/intern/rna_scene.c
source/blender/readblenfile/SConscript
source/blender/readblenfile/intern/BLO_readblenfile.c
source/blender/windowmanager/SConscript
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_init_exit.c
source/creator/SConscript

index 08a2b1dcecb482979eb344de41fea674736417fd,e5dd9c2188dca9e1455840999c490315334b6ce0..ab453fb6f44eeb9eb454f446e23c2cd36ff375f9
@@@ -1053,13 -1053,13 +1053,13 @@@ static struct ImBuf *brush_gen_radial_c
        return im;
  }
  
 -void brush_radial_control_invoke(wmOperator *op, Brush *br, float size_weight)
 +void brush_radial_control_invoke(wmOperator *op, Brush *br)
  {
        int mode = RNA_int_get(op->ptr, "mode");
-       float original_value;
+       float original_value= 0;
  
        if(mode == WM_RADIALCONTROL_SIZE)
 -              original_value = br->size * size_weight;
 +              original_value = br->size;
        else if(mode == WM_RADIALCONTROL_STRENGTH)
                original_value = br->alpha;
        else if(mode == WM_RADIALCONTROL_ANGLE)
index 103e2f7edac03462859656b0374a88d20a6e238d,dbb720fb0bc24903d289aa113e3d2f83dd9dde47..440f83e6a4f8ac82c8da149f67b9f860ac81f503
@@@ -1190,10 -1313,15 +1190,15 @@@ static void ipo_to_animato (Ipo *ipo, c
                /* Since an IPO-Curve may end up being made into many F-Curves (i.e. bitflag curves), 
                 * we figure out the best place to put the channel, then tell the curve-converter to just dump there
                 */
-               if (icu->driver)
-                       icu_to_fcurves(drivers, icu, actname, constname);
+               if (icu->driver) {
 -                      /* Blender 2.4x allowed empty drivers, but we don't now, since they cause more trouble than they're worth */
 -                      if ((icu->driver->ob) || (icu->driver->type == IPO_DRIVER_TYPE_PYTHON))
 -                              icu_to_fcurves(NULL, drivers, icu, actname, constname);
++                      /* Blender 2.4x allowed empty drivers */
++                      if(icu->driver->ob || icu->driver->type == IPO_DRIVER_TYPE_PYTHON)
++                              icu_to_fcurves(drivers, icu, actname, constname);
+                       else
+                               MEM_freeN(icu->driver);
+               }
                else
 -                      icu_to_fcurves(animgroups, anim, icu, actname, constname);
 +                      icu_to_fcurves(anim, icu, actname, constname);
                
                /* free this IpoCurve now that it's been converted */
                BLI_freelinkN(&ipo->curve, icu);
@@@ -1401,6 -1530,9 +1406,10 @@@ void do_versions_ipos_to_animato(Main *
                
                /* check PoseChannels for constraints with local data */
                if (ob->pose) {
 -                      
++                      
+                       /* Verify if there's AnimData block */
+                       BKE_id_add_animdata(id);
++
                        for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
                                for (con= pchan->constraints.first; con; con= con->next) {
                                        /* if constraint has own IPO, convert add these to Object 
index 48330c4604a05dc1c9b6ab15211a6a0a724427dc,0000000000000000000000000000000000000000..4af6e89a94ca6c0bb3410e13dcc00bafe604a036
mode 100644,000000..100644
--- /dev/null
@@@ -1,288 -1,0 +1,312 @@@
- /*if msg is null, then the default message for the errorcode is used*/
- void BMOP_RaiseError(BMesh *bm, int errcode, char *msg);
- /*returns error code or 0 if no error*/
- int BMOP_GetError(BMesh *bm, char **msg);
- /*returns 1 if there was an error*/
- int BMOP_CheckError(BMesh *bm);
- int BMOP_PopError(BMesh *bm, char **msg);
 +#ifndef BM_OPERATORS_H
 +#define BM_OPERATORS_H
 +
 +#include "BLI_memarena.h"
 +#include "BLI_ghash.h"
 +
 +#define BMOP_OPSLOT_INT                       0
 +#define BMOP_OPSLOT_FLT                       1
 +#define BMOP_OPSLOT_PNT                       2
 +#define BMOP_OPSLOT_VEC                       6
 +
 +/*after BMOP_OPSLOT_VEC, everything is 
 +  dynamically allocated arrays.  we
 +  leave a space in the identifiers
 +  for future growth.*/
 +#define BMOP_OPSLOT_PNT_BUF           7
 +
 +#define BMOP_OPSLOT_MAPPING           8
 +#define BMOP_OPSLOT_TYPES             9
 +
 +typedef struct BMOpSlot{
 +      int slottype;
 +      int len;
 +      int flag;
 +      int index; /*index within slot array*/
 +      union {
 +              int i;
 +              float f;                                        
 +              void *p;                                        
 +              float vec[3];                           /*vector*/
 +              void *buf;                              /*buffer*/
 +              GHash *ghash;
 +      } data;
 +}BMOpSlot;
 +
 +/*BMOpSlot->flag*/
 +/*is a dynamically-allocated array.  set at runtime.*/
 +#define BMOS_DYNAMIC_ARRAY    1
 +
 +/*operators represent logical, executable mesh modules.*/
 +#define BMOP_MAX_SLOTS                        16              /*way more than probably needed*/
 +
 +typedef struct BMOperator{
 +      int type;
 +      int slottype;
 +      int needflag;
 +      struct BMOpSlot slots[BMOP_MAX_SLOTS];
 +      void (*exec)(struct BMesh *bm, struct BMOperator *op);
 +      MemArena *arena;
 +}BMOperator;
 +
 +/*need to refactor code to use this*/
 +typedef struct BMOpDefine {
 +      int slottypes[BMOP_MAX_SLOTS];
 +      void (*exec)(BMesh *bm, BMOperator *op);
 +      int totslot;
 +      int flag;
 +} BMOpDefine;
 +
 +/*BMOpDefine->flag*/
 +//doesn't do anything at the moment.
 +
 +/*API for operators*/
 +
 +/*data types that use pointers (arrays, etc) should never
 +  have it set directly.  and never use BMO_Set_Pnt to
 +  pass in a list of edges or any arrays, really.*/
 +void BMO_Init_Op(struct BMOperator *op, int opcode);
 +void BMO_Exec_Op(struct BMesh *bm, struct BMOperator *op);
 +void BMO_Finish_Op(struct BMesh *bm, struct BMOperator *op);
 +BMOpSlot *BMO_GetSlot(struct BMOperator *op, int slotcode);
 +void BMO_CopySlot(struct BMOperator *source_op, struct BMOperator *dest_op, int src, int dst);
 +void BMO_Set_Float(struct BMOperator *op, int slotcode, float f);
 +void BMO_Set_Int(struct BMOperator *op, int slotcode, int i);
 +void BMO_Set_Pnt(struct BMOperator *op, int slotcode, void *p);
 +void BMO_Set_Vec(struct BMOperator *op, int slotcode, float *vec);
 +void BMO_SetFlag(struct BMesh *bm, void *element, int flag);
 +void BMO_ClearFlag(struct BMesh *bm, void *element, int flag);
 +int BMO_TestFlag(struct BMesh *bm, void *element, int flag);
 +int BMO_CountFlag(struct BMesh *bm, int flag, int type);
 +void BMO_Flag_To_Slot(struct BMesh *bm, struct BMOperator *op, int slotcode, int flag, int type);
 +void BMO_Flag_Buffer(struct BMesh *bm, struct BMOperator *op, int slotcode, int flag);
 +void BMO_Unflag_Buffer(struct BMesh *bm, struct BMOperator *op, int slotcode, int flag);
 +void BMO_HeaderFlag_To_Slot(struct BMesh *bm, struct BMOperator *op, int slotcode, int flag, int type);
 +int BMO_CountSlotBuf(struct BMesh *bm, struct BMOperator *op, int slotcode);
 +
 +/*copies data, doesn't store a reference to it.*/
 +void BMO_Insert_Mapping(BMesh *bm, BMOperator *op, int slotcode, 
 +                      void *element, void *data, int len);
 +void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, int slotcode, 
 +                      void *element, float val);
 +
 +//returns 1 if the specified element is in the map.
 +int BMO_InMap(BMesh *bm, BMOperator *op, int slotcode, void *element);
 +void *BMO_Get_MapData(BMesh *bm, BMOperator *op, int slotcode,
 +                    void *element);
 +float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, int slotcode,
 +                     void *element);
 +void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op, 
 +                       int slotcode, int flag);
 +
 +/*do NOT use these for non-operator-api-allocated memory! instead
 +  use BMO_Get_MapData, which copies the data.*/
 +void BMO_Insert_MapPointer(BMesh *bm, BMOperator *op, int slotcode, 
 +                      void *element, void *val);
 +void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, int slotcode,
 +                     void *element);
 +
 +struct GHashIterator;
 +typedef struct BMOIter {
 +      BMOpSlot *slot;
 +      int cur; //for arrays
 +      struct GHashIterator giter;
 +      void *val;
 +} BMOIter;
 +
 +void *BMO_IterNew(BMOIter *iter, BMesh *bm, BMOperator *op, 
 +                int slotcode);
 +void *BMO_IterStep(BMOIter *iter);
 +
 +/*returns a pointer to the key value when iterating over mappings.
 +  remember for pointer maps this will be a pointer to a pointer.*/
 +void *BMO_IterMapVal(BMOIter *iter);
 +
- #define BMERR_SELF_INTERSECTING        1
++/*----------- bmop error system ----------*/
++
++/*pushes an error onto the bmesh error stack.
++  if msg is null, then the default message for the errorcode is used.*/
++void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, char *msg);
++
++/*gets the topmost error from the stack.
++  returns error code or 0 if no error.*/
++int BMO_GetError(BMesh *bm, char **msg, BMOperator **op);
++
++/*same as geterror, only pops the error off the stack as well*/
++int BMO_PopError(BMesh *bm, char **msg, BMOperator **op);
++void BMO_ClearStack(BMesh *bm);
++
++#if 0
++//this is meant for handling errors, like self-intersection test failures.
++//it's dangerous to handle errors in general though, so disabled for now.
++
++/*catches an error raised by the op pointed to by catchop.
++  errorcode is either the errorcode, or BMERR_ALL for any 
++  error.*/
++int BMO_CatchOpError(BMesh *bm, BMOperator *catchop, int errorcode, char **msg);
++#endif
 +
 +/*------ error code defines -------*/
 +
 +/*error messages*/
- #define BMOP_DISFACES_FACEIN  0
- #define BMOP_DISFACES_TOTSLOT 1
++#define BMERR_SELF_INTERSECTING                       1
++#define BMERR_DISSOLVEDISK_FAILED             2
 +
 +static char *bmop_error_messages[] = {
 +       0,
 +       "Self intersection error",
++       "Could not dissolve vert",
 +};
 +
 +/*------------begin operator defines (see bmesh_opdefines.c too)------------*/
 +/*split op*/
 +#define BMOP_SPLIT                            0
 +
 +enum {
 +      BMOP_SPLIT_MULTIN,
 +      BMOP_SPLIT_MULTOUT,
 +      BMOP_SPLIT_BOUNDS_EDGEMAP, //bounding edges of split faces
 +      BMOP_SPLIT_TOTSLOT,
 +};
 +
 +/*dupe op*/
 +#define BMOP_DUPE     1
 +
 +enum {
 +      BMOP_DUPE_MULTIN,
 +      BMOP_DUPE_ORIG,
 +      BMOP_DUPE_NEW,
 +      /*we need a map for verts duplicated not connected
 +        to any faces, too.*/  
 +      BMOP_DUPE_BOUNDS_EDGEMAP,
 +      BMOP_DUPE_TOTSLOT
 +};
 +
 +/*delete op*/
 +#define BMOP_DEL      2
 +
 +enum {
 +      BMOP_DEL_MULTIN,
 +      BMOP_DEL_CONTEXT,
 +      BMOP_DEL_TOTSLOT,
 +};
 +
 +#define DEL_VERTS             1
 +#define DEL_EDGES             2
 +#define DEL_ONLYFACES 3
 +#define DEL_EDGESFACES        4
 +#define DEL_FACES             5
 +#define DEL_ALL                       6
 +#define DEL_ONLYTAGGED                7
 +
 +/*BMOP_DEL_CONTEXT*/
 +enum {
 +      BMOP_DEL_VERTS = 1,
 +      BMOP_DEL_EDGESFACES,
 +      BMOP_DEL_ONLYFACES,
 +      BMOP_DEL_FACES,
 +      BMOP_DEL_ALL,
 +};
 +
 +/*editmesh->bmesh op*/
 +#define BMOP_FROM_EDITMESH            3
 +enum {
 +      BMOP_FROM_EDITMESH_EM,
 +      BMOP_FROM_EDITMESH_TOTSLOT,
 +};
 +
 +#define BMOP_TO_EDITMESH              4
 +/*bmesh->editmesh op*/
 +enum {
 +      BMOP_TO_EDITMESH_EMOUT,
 +      BMOP_TO_EDITMESH_TOTSLOT,
 +};
 +
 +/*edge subdivide op*/
 +#define BMOP_ESUBDIVIDE                       5
 +enum {
 +      BMOP_ESUBDIVIDE_EDGES,
 +      BMOP_ESUBDIVIDE_NUMCUTS,
 +      BMOP_ESUBDIVIDE_FLAG, //beauty flag in esubdivide
 +      BMOP_ESUBDIVIDE_RADIUS,
 +
 +      BMOP_ESUBDIVIDE_CUSTOMFILL_FACEMAP,
 +      BMOP_ESUBDIVIDE_PERCENT_EDGEMAP,
 +
 +      /*inner verts/new faces of completely filled faces, e.g.
 +        fully selected face.*/
 +      BMOP_ESUBDIVIDE_INNER_MULTOUT,
 +
 +      /*new edges and vertices from splitting original edges,
 +        doesn't include edges creating by connecting verts.*/
 +      BMOP_ESUBDIVIDE_SPLIT_MULTOUT,  
 +      BMOP_ESUBDIVIDE_TOTSLOT,
 +};
 +/*
 +SUBDIV_SELECT_INNER
 +SUBDIV_SELECT_ORIG
 +SUBDIV_SELECT_INNER_SEL
 +SUBDIV_SELECT_LOOPCUT
 +DOUBLEOPFILL
 +*/
 +
 +/*triangulate*/
 +#define BMOP_TRIANGULATE              6
 +
 +enum {
 +      BMOP_TRIANG_FACEIN,
 +      BMOP_TRIANG_NEW_EDGES,
 +      BMOP_TRIANG_NEW_FACES,
 +      BMOP_TRIANG_TOTSLOT,
 +};
 +
 +/*dissolve faces*/
 +#define BMOP_DISSOLVE_FACES           7
++enum {
++      BMOP_DISFACES_FACEIN,
++      //list of faces that comprise regions of split faces
++      BMOP_DISFACES_REGIONOUT,
++      BMOP_DISFACES_TOTSLOT,
++};
 +
 +/*dissolve verts*/
 +#define BMOP_DISSOLVE_VERTS           8
 +
 +#define BMOP_DISVERTS_VERTIN  0
 +#define BMOP_DISVERTS_TOTSLOT 1
 +
 +#define BMOP_MAKE_FGONS                       9
 +#define BMOP_MAKE_FGONS_TOTSLOT       0
 +
 +#define BMOP_EXTRUDE_EDGECONTEXT      10
 +enum {
 +      BMOP_EXFACE_EDGEFACEIN,
 +      BMOP_EXFACE_EXCLUDEMAP, //exclude edges from skirt connecting
 +      BMOP_EXFACE_MULTOUT, //new geometry
 +      BMOP_EXFACE_TOTSLOT,
 +};
 +
++
 +/*keep this updated!*/
 +#define BMOP_TOTAL_OPS                        11
 +/*-------------------------------end operator defines-------------------------------*/
 +
 +extern BMOpDefine *opdefines[];
 +extern int bmesh_total_ops;
 +
 +/*------specific operator helper functions-------*/
 +
 +/*executes the duplicate operation, feeding elements of 
 +  type flag etypeflag and header flag flag to it.  note,
 +  to get more useful information (such as the mapping from
 +  original to new elements) you should run the dupe op manually.*/
 +struct Object;
++struct EditMesh;
 +
 +void BMOP_DupeFromFlag(struct BMesh *bm, int etypeflag, int flag);
 +void BM_esubdivideflag(struct Object *obedit, struct BMesh *bm, int selflag, float rad, 
 +             int flag, int numcuts, int seltype);
 +void BM_extrudefaceflag(BMesh *bm, int flag);
++int BM_DissolveFaces(struct EditMesh *em, int flag);
 +
 +#endif
index f02375313a10fe765576636fec7b2a1eca1c2abc,0000000000000000000000000000000000000000..a3df439029551fd18be48ba49e969bd131a35ecc
mode 100644,000000..100644
--- /dev/null
@@@ -1,30 -1,0 +1,31 @@@
 +#ifndef BMESH_QUERIES_H
 +#define BMESH_QUERIES_H
++#include <stdio.h>
 +
 +/*Queries*/
 +int BM_Count_Element(struct BMesh *bm, int type);
 +int BM_Vert_In_Edge(struct BMEdge *e, struct BMVert *v);
 +int BM_Vert_In_Face(struct BMFace *f, struct BMVert *v);
 +// int BM_Verts_In_Face(struct BMFace *f, struct BMVert **varr, int len);
 +int BM_Verts_In_Face(struct BMesh *bm, struct BMFace *f, struct BMVert **varr, int len);
 +int BM_Edge_In_Face(struct BMFace *f, struct BMEdge *e);
 +int BM_Verts_In_Edge(struct BMVert *v1, struct BMVert *v2, BMEdge *e);
 +
 +struct BMVert *BM_OtherEdgeVert(struct BMEdge *e, struct BMVert *v);
 +//#define BM_OtherEdgeVert(e, v) (v==e->v1?e->v2:e->v1)
 +
 +struct BMEdge *BM_Edge_Exist(struct BMVert *v1, struct BMVert *v2);
 +int BM_Vert_EdgeCount(struct BMVert *v);
 +int BM_Edge_FaceCount(struct BMEdge *e);
 +int BM_Vert_FaceCount(struct BMVert *v);
 +int BM_Wire_Vert(struct BMesh *bm, struct BMVert *v);
 +int BM_Wire_Edge(struct BMesh *bm, struct BMEdge *e);
 +int BM_Nonmanifold_Vert(struct BMesh *bm, struct BMVert *v);
 +int BM_Nonmanifold_Edge(struct BMesh *bm, struct BMEdge *e);
 +int BM_Boundary_Edge(struct BMEdge *e);
 +int BM_Face_Sharededges(struct BMFace *f1, struct BMFace *f2);
 +float BM_Face_Angle(struct BMesh *bm, struct BMEdge *e);
 +int BM_Exist_Face_Overlaps(struct BMesh *bm, struct BMVert **varr, int len, struct BMFace **existface);
 +int BM_Edge_Share_Faces(struct BMEdge *e1, struct BMEdge *e2);
++int BM_Validate_Face(BMesh *bm, BMFace *face, FILE *err);
 +#endif
index c7f42ae390c9c0554215137de7889bae0c8216ad,0000000000000000000000000000000000000000..bf918c92cca558a8aedbf8f31df35b235bccf0fc
mode 100644,000000..100644
--- /dev/null
@@@ -1,987 -1,0 +1,985 @@@
-       /*need to reinsert logic for checking to make sure that faces only share one edge!*/
 +/**
 + * bmesh_eulers.c    jan 2007
 + *
 + *    BM Euler construction API.
 + *
 + * $Id: bmesh_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
 + *
 + * ***** 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.
 + * about this.        
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * The Original Code is Copyright (C) 2004 Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): Geoffrey Bantle.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "DNA_listBase.h"
 +#include "DNA_meshdata_types.h"
 +#include "DNA_mesh_types.h"
 +
 +#include "BKE_customdata.h"
 +#include "BKE_utildefines.h"
 +
 +#include "bmesh.h"
 +#include "bmesh_private.h"
 +
 +#include "BLI_blenlib.h"
 +#include "BLI_ghash.h"
 +
 +/*********************************************************
 + *                    "Euler API"                        *
 + *                                                       *
 + *                                                       *
 + *     Primitive construction operators for mesh tools.    *
 + *                                                       *
 + **********************************************************/
 +
 +
 +/*
 +      The functions in this file represent the 'primitive' or 'atomic' operators that
 +      mesh tools use to manipulate the topology of the structure.* The purpose of these
 +      functions is to provide a trusted set of operators to manipulate the mesh topology
 +      and which can also be combined together like building blocks to create more 
 +      sophisticated tools. It needs to be stressed that NO manipulation of an existing 
 +      mesh structure should be done outside of these functions.
 +      
 +      In the BM system, each euler is named by an ancronym which describes what it actually does.
 +      Furthermore each Euler has a logical inverse. An important design criteria of all Eulers is that
 +      through a Euler's logical inverse you can 'undo' an operation. (Special note should
 +      be taken of bmesh_loop_reverse, which is its own inverse).
 +              
 +      bmesh_MF/KF: Make Face and Kill Face
 +      bmesh_ME/KE: Make Edge and Kill Edge
 +      bmesh_MV/KV: Make Vert and Kill Vert
 +      bmesh_SEMV/JEKV: Split Edge, Make Vert and Join Edge, Kill Vert
 +      bmesh_SFME/JFKE: Split Face, Make Edge and Join Face, Kill Edge
 +      bmesh_loop_reverse: Reverse a Polygon's loop cycle. (used for flip normals for one)
 +      
 +      Using a combination of these eleven eulers any non-manifold modelling operation can be achieved.
 +      Each Euler operator has a detailed explanation of what is does in the comments preceding its 
 +      code. 
 +
 +   *The term "Euler Operator" is actually a misnomer when referring to a non-manifold 
 +    data structure. Its use is in keeping with the convention established by others.
 +
 +      TODO:
 +      -Make seperate 'debug levels' of validation
 +      -Add in the UnglueFaceRegionMakeVert and GlueFaceRegionKillVert eulers.
 +
 +      NOTE:
 +      -The functions in this file are notoriously difficult to debug and even understand sometimes.
 +       better code comments would be nice....
 +
 +*/
 +
 +
 +/*MAKE Eulers*/
 +
 +/**
 + *                    bmesh_MV
 + *
 + *    MAKE VERT EULER:
 + *    
 + *    Makes a single loose vertex.
 + *
 + *    Returns -
 + *    A BMVert pointer.
 + */
 +
 +BMVert *bmesh_mv(BMesh *bm, float *vec){
 +      BMVert *v = bmesh_addvertlist(bm, NULL);        
 +      VECCOPY(v->co,vec);
 +      return v;
 +}
 +
 +/**
 + *                    bmesh_ME
 + *
 + *    MAKE EDGE EULER:
 + *    
 + *    Makes a single wire edge between two vertices.
 + *    If the caller does not want there to be duplicate
 + *    edges between the vertices, it is up to them to check 
 + *    for this condition beforehand.
 + *
 + *    Returns -
 + *    A BMEdge pointer.
 + */
 +
 +BMEdge *bmesh_me(BMesh *bm, BMVert *v1, BMVert *v2){
 +      BMEdge *e=NULL;
 +      BMNode *d1=NULL, *d2=NULL;
 +      int valance1=0, valance2=0, edok;
 +      
 +      /*edge must be between two distinct vertices...*/
 +      if(v1 == v2) return NULL;
 +      
 +      #ifndef bmesh_FASTEULER
 +      /*count valance of v1*/
 +      if(v1->edge){ 
 +              d1 = bmesh_disk_getpointer(v1->edge,v1);
 +              if(d1) valance1 = bmesh_cycle_length(d1);
 +              else bmesh_error();
 +      }
 +      if(v2->edge){
 +              d2 = bmesh_disk_getpointer(v2->edge,v2);
 +              if(d2) valance2 = bmesh_cycle_length(d2);
 +              else bmesh_error();
 +      }
 +      #endif
 +      
 +      /*go ahead and add*/
 +      e = bmesh_addedgelist(bm, v1, v2, NULL);
 +      bmesh_disk_append_edge(e, e->v1);
 +      bmesh_disk_append_edge(e, e->v2);
 +      
 +      #ifndef bmesh_FASTEULER
 +      /*verify disk cycle lengths*/
 +      d1 = bmesh_disk_getpointer(e, e->v1);
 +      edok = bmesh_cycle_validate(valance1+1, d1);
 +      if(!edok) bmesh_error();
 +      d2 = bmesh_disk_getpointer(e, e->v2);
 +      edok = bmesh_cycle_validate(valance2+1, d2);
 +      if(!edok) bmesh_error();
 +      
 +      /*verify that edge actually made it into the cycle*/
 +      edok = bmesh_disk_hasedge(v1, e);
 +      if(!edok) bmesh_error();
 +      edok = bmesh_disk_hasedge(v2, e);
 +      if(!edok) bmesh_error();
 +      #endif
 +      return e;
 +}
 +
 +
 +
 +/**
 + *                    bmesh_MF
 + *
 + *    MAKE FACE EULER:
 + *    Takes a list of edge pointers which form a closed loop and makes a face 
 + *  from them. The first edge in elist is considered to be the start of the 
 + *    polygon, and v1 and v2 are its vertices and determine the winding of the face 
 + *  Other than the first edge, no other assumptions are made about the order of edges
 + *  in the elist array. To verify that it is a single closed loop and derive the correct 
 + *  order a simple series of verifications is done and all elements are visited.
 + *            
 + *  Returns -
 + *    A BMFace pointer
 + */
 +
 +#define MF_CANDIDATE  1
 +#define MF_VISITED            2
 +#define MF_TAKEN              4 
 +
 +BMFace *bmesh_mf(BMesh *bm, BMVert *v1, BMVert *v2, BMEdge **elist, int len)
 +{
 +      BMFace *f = NULL;
 +      BMEdge *curedge;
 +      BMVert *curvert, *tv, **vlist;
 +      int i, j, done, cont, edok;
 +      
 +      if(len < 2) return NULL;
 +      
 +      /*make sure that v1 and v2 are in elist[0]*/
 +      if(bmesh_verts_in_edge(v1,v2,elist[0]) == 0) return NULL;
 +      
 +      /*clear euler flags*/
 +      for(i=0;i<len;i++) elist[i]->head.eflag1=elist[i]->head.eflag2 = 0;
 +      for(i=0;i<len;i++){
 +              elist[i]->head.eflag1 |= MF_CANDIDATE;
 +              
 +              /*if elist[i] has a loop, count its radial length*/
 +              if(elist[i]->loop) elist[i]->head.eflag2 = bmesh_cycle_length(&(elist[i]->loop->radial));
 +              else elist[i]->head.eflag2 = 0;
 +      }
 +      
 +      /*      For each vertex in each edge, it must have exactly two MF_CANDIDATE edges attached to it
 +              Note that this does not gauruntee that face is a single closed loop. At best it gauruntees
 +              that elist contains a finite number of seperate closed loops.
 +      */
 +      for(i=0; i<len; i++){
 +              edok = bmesh_disk_count_edgeflag(elist[i]->v1, MF_CANDIDATE, 0);
 +              if(edok != 2) return NULL;
 +              edok = bmesh_disk_count_edgeflag(elist[i]->v2, MF_CANDIDATE, 0);
 +              if(edok != 2) return NULL;
 +      }
 +      
 +      /*set start edge, start vert and target vert for our loop traversal*/
 +      curedge = elist[0];
 +      tv = v1;
 +      curvert = v2;
 +      
 +      if(bm->vtarlen < len){
 +              MEM_freeN(bm->vtar);
 +              bm->vtar = MEM_callocN(sizeof(BMVert *)* len, "BM Vert pointer array");
 +              bm->vtarlen = len;
 +      }
 +      /*insert tv into vlist since its the first vertex in face*/
 +      i=0;
 +      vlist=bm->vtar;
 +      vlist[i] = tv;
 +
 +      /*      Basic procedure: Starting with curv we find the edge in it's disk cycle which hasn't 
 +              been visited yet. When we do, we put curv in a linked list and find the next MF_CANDIDATE
 +              edge, loop until we find TV. We know TV is reachable because of test we did earlier.
 +      */
 +      done=0;
 +      while(!done){
 +              /*add curvert to vlist*/
 +              /*insert some error cheking here for overflows*/
 +              i++;
 +              vlist[i] = curvert;
 +              
 +              /*mark curedge as visited*/
 +              curedge->head.eflag1 |= MF_VISITED;
 +              
 +              /*find next edge and vert*/
 +              curedge = bmesh_disk_next_edgeflag(curedge, curvert, MF_CANDIDATE, 0);
 +              curvert = bmesh_edge_getothervert(curedge, curvert);
 +              if(curvert == tv){
 +                      curedge->head.eflag1 |= MF_VISITED;
 +                      done=1;
 +              }
 +      }
 +
 +      /*      Verify that all edges have been visited It's possible that we did reach tv 
 +              from sv, but that several unconnected loops were passed in via elist.
 +      */
 +      cont=1;
 +      for(i=0; i<len; i++){
 +              if((elist[i]->head.eflag1 & MF_VISITED) == 0) cont = 0;
 +      }
 +      
 +      /*if we get this far, its ok to allocate the face and add the loops*/
 +      if(cont){
 +              BMLoop *l;
 +              BMEdge *e;
 +              f = bmesh_addpolylist(bm, NULL);
 +              f->len = len;
 +              for(i=0;i<len;i++){
 +                      curvert = vlist[i];
 +                      l = bmesh_create_loop(bm,curvert,NULL,f,NULL);
 +                      if(!(f->loopbase)) f->loopbase = l;
 +                      bmesh_cycle_append(f->loopbase, l);
 +              }
 +              
 +              /*take care of edge pointers and radial cycle*/
 +              for(i=0, l = f->loopbase; i<len; i++, l=((BMLoop*)(l->head.next))){
 +                      e = NULL;
 +                      if(l == f->loopbase) e = elist[0]; /*first edge*/
 +                      
 +                      else{/*search elist for others*/
 +                              for(j=1; j<len; j++){
 +                                      edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, elist[j]);
 +                                      if(edok){ 
 +                                              e = elist[j];
 +                                              break;
 +                                      }
 +                              }
 +                      }
 +                      l->e = e; /*set pointer*/
 +                      bmesh_radial_append(e, l); /*append into radial*/
 +              }
 +
 +              f->len = len;
 +              
 +              /*Validation Loop cycle*/
 +              edok = bmesh_cycle_validate(len, f->loopbase);
 +              if(!edok) bmesh_error();
 +              for(i=0, l = f->loopbase; i<len; i++, l=((BMLoop*)(l->head.next))){
 +                      /*validate loop vert pointers*/
 +                      edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, l->e);
 +                      if(!edok) bmesh_error();
 +                      /*validate the radial cycle of each edge*/
 +                      edok = bmesh_cycle_length(&(l->radial));
 +                      if(edok != (l->e->head.eflag2 + 1)) bmesh_error();
 +              }
 +      }
 +      return f;
 +}
 +
 +/* KILL Eulers */
 +
 +/**
 + *                    bmesh_KV
 + *
 + *    KILL VERT EULER:
 + *    
 + *    Kills a single loose vertex.
 + *
 + *    Returns -
 + *    1 for success, 0 for failure.
 + */
 +
 +int bmesh_kv(BMesh *bm, BMVert *v){
 +      if(v->edge == NULL){ 
 +              BLI_remlink(&(bm->verts), &(v->head));
 +              bmesh_free_vert(bm,v);
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +/**
 + *                    bmesh_KE
 + *
 + *    KILL EDGE EULER:
 + *    
 + *    Kills a wire edge.
 + *
 + *    Returns -
 + *    1 for success, 0 for failure.
 + */
 +
 +int bmesh_ke(BMesh *bm, BMEdge *e){
 +      int edok;
 +      
 +      /*Make sure that no faces!*/
 +      if(e->loop == NULL){
 +              bmesh_disk_remove_edge(e, e->v1);
 +              bmesh_disk_remove_edge(e, e->v2);
 +              
 +              /*verify that edge out of disk*/
 +              edok = bmesh_disk_hasedge(e->v1, e);
 +              if(edok) bmesh_error();
 +              edok = bmesh_disk_hasedge(e->v2, e);
 +              if(edok) bmesh_error();
 +              
 +              /*remove and deallocate*/
 +              BLI_remlink(&(bm->edges), &(e->head));
 +              bmesh_free_edge(bm, e);
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +/**
 + *                    bmesh_KF
 + *
 + *    KILL FACE EULER:
 + *    
 + *    The logical inverse of bmesh_MF.
 + *    Kills a face and removes each of its loops from the radial that it belongs to.
 + *
 + *  Returns -
 + *    1 for success, 0 for failure.
 +*/
 +
 +int bmesh_kf(BMesh *bm, BMFace *bply){
 +      BMLoop *newbase,*oldbase, *curloop;
 +      int i,len=0;
 +      
 +      /*add validation to make sure that radial cycle is cleaned up ok*/
 +      /*deal with radial cycle first*/
 +      len = bmesh_cycle_length(bply->loopbase);
 +      for(i=0, curloop=bply->loopbase; i < len; i++, curloop = ((BMLoop*)(curloop->head.next))) 
 +              bmesh_radial_remove_loop(curloop, curloop->e);
 +      
 +      /*now deallocate the editloops*/
 +      for(i=0; i < len; i++){
 +              newbase = ((BMLoop*)(bply->loopbase->head.next));
 +              oldbase = bply->loopbase;
 +              bmesh_cycle_remove(oldbase, oldbase);
 +              bmesh_free_loop(bm, oldbase);
 +              bply->loopbase = newbase;
 +      }
 +      
 +      BLI_remlink(&(bm->polys), &(bply->head));
 +      bmesh_free_poly(bm, bply);
 +      return 1;
 +}
 +
 +/*SPLIT Eulers*/
 +
 +/**
 + *                    bmesh_SEMV
 + *
 + *    SPLIT EDGE MAKE VERT:
 + *    Takes a given edge and splits it into two, creating a new vert.
 + *
 + *
 + *            Before: OV---------TV   
 + *            After:  OV----NV---TV
 + *
 + *  Returns -
 + *    BMVert pointer.
 + *
 +*/
 +
 +BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **re){
 +      BMVert *nv, *ov;
 +      BMNode *diskbase;
 +      BMEdge *ne;
 +      int i, edok, valance1=0, valance2=0;
 +      
 +      if(bmesh_vert_in_edge(e,tv) == 0) return NULL;
 +      ov = bmesh_edge_getothervert(e,tv);
 +      //v2 = tv;
 +
 +      /*count valance of v1*/
 +      diskbase = bmesh_disk_getpointer(e, ov);
 +      valance1 = bmesh_cycle_length(diskbase);
 +      /*count valance of v2*/
 +      diskbase = bmesh_disk_getpointer(e, tv);
 +      valance2 = bmesh_cycle_length(diskbase);
 +      
 +      nv = bmesh_addvertlist(bm, tv);
 +      ne = bmesh_addedgelist(bm, nv, tv, e);
 +      
 +      //e->v2 = nv;
 +      /*remove e from v2's disk cycle*/
 +      bmesh_disk_remove_edge(e, tv);
 +      /*swap out tv for nv in e*/
 +      bmesh_edge_swapverts(e, tv, nv);
 +      /*add e to nv's disk cycle*/
 +      bmesh_disk_append_edge(e, nv);
 +      /*add ne to nv's disk cycle*/
 +      bmesh_disk_append_edge(ne, nv);
 +      /*add ne to tv's disk cycle*/
 +      bmesh_disk_append_edge(ne, tv);
 +      /*verify disk cycles*/
 +      diskbase = bmesh_disk_getpointer(ov->edge,ov);
 +      edok = bmesh_cycle_validate(valance1, diskbase);
 +      if(!edok) bmesh_error();
 +      diskbase = bmesh_disk_getpointer(tv->edge,tv);
 +      edok = bmesh_cycle_validate(valance2, diskbase);
 +      if(!edok) bmesh_error();
 +      diskbase = bmesh_disk_getpointer(nv->edge,nv);
 +      edok = bmesh_cycle_validate(2, diskbase);
 +      if(!edok) bmesh_error();
 +      
 +      /*Split the radial cycle if present*/
 +      if(e->loop){
 +              BMLoop *nl,*l;
 +              BMNode *radEBase=NULL, *radNEBase=NULL;
 +              int radlen = bmesh_cycle_length(&(e->loop->radial));
 +              /*Take the next loop. Remove it from radial. Split it. Append to appropriate radials.*/
 +              while(e->loop){
 +                      l=e->loop;
 +                      l->f->len++;
 +                      bmesh_radial_remove_loop(l,e);
 +                      
 +                      nl = bmesh_create_loop(bm,NULL,NULL,l->f,l);
 +                      nl->head.prev = (BMHeader*)l;
 +                      nl->head.next = (BMHeader*)(l->head.next);
 +                      nl->head.prev->next = (BMHeader*)nl;
 +                      nl->head.next->prev = (BMHeader*)nl;
 +                      nl->v = nv;
 +                      
 +                      /*assign the correct edge to the correct loop*/
 +                      if(bmesh_verts_in_edge(nl->v, ((BMLoop*)(nl->head.next))->v, e)){
 +                              nl->e = e;
 +                              l->e = ne;
 +                              
 +                              /*append l into ne's rad cycle*/
 +                              if(!radNEBase){
 +                                      radNEBase = &(l->radial);
 +                                      radNEBase->next = NULL;
 +                                      radNEBase->prev = NULL;
 +                              }
 +                              
 +                              if(!radEBase){
 +                                      radEBase = &(nl->radial);
 +                                      radEBase->next = NULL;
 +                                      radEBase->prev = NULL;
 +                              }
 +                              
 +                              bmesh_cycle_append(radEBase,&(nl->radial));
 +                              bmesh_cycle_append(radNEBase,&(l->radial));
 +                                      
 +                      }
 +                      else if(bmesh_verts_in_edge(nl->v,((BMLoop*)(nl->head.next))->v,ne)){
 +                              nl->e = ne;
 +                              l->e = e;
 +                              
 +                              if(!radNEBase){
 +                                      radNEBase = &(nl->radial);
 +                                      radNEBase->next = NULL;
 +                                      radNEBase->prev = NULL;
 +                              }
 +                              if(!radEBase){
 +                                      radEBase = &(l->radial);
 +                                      radEBase->next = NULL;
 +                                      radEBase->prev = NULL;
 +                              }
 +                              bmesh_cycle_append(radEBase,&(l->radial));
 +                              bmesh_cycle_append(radNEBase,&(nl->radial));
 +                      }
 +                                      
 +              }
 +              
 +              e->loop = radEBase->data;
 +              ne->loop = radNEBase->data;
 +              
 +              /*verify length of radial cycle*/
 +              edok = bmesh_cycle_validate(radlen,&(e->loop->radial));
 +              if(!edok) bmesh_error();
 +              edok = bmesh_cycle_validate(radlen,&(ne->loop->radial));
 +              if(!edok) bmesh_error();
 +              
 +              /*verify loop->v and loop->next->v pointers for e*/
 +              for(i=0,l=e->loop; i < radlen; i++, l = l->radial.next->data){
 +                      if(!(l->e == e)) bmesh_error();
 +                      if(!(l->radial.data == l)) bmesh_error();
 +                      if( ((BMLoop*)(l->head.prev))->e != ne && ((BMLoop*)(l->head.next))->e != ne) bmesh_error();
 +                      edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, e);
 +                      if(!edok) bmesh_error();
 +                      if(l->v == ((BMLoop*)(l->head.next))->v) bmesh_error();
 +                      if(l->e == ((BMLoop*)(l->head.next))->e) bmesh_error();
 +                      /*verify loop cycle for kloop->f*/
 +                      edok = bmesh_cycle_validate(l->f->len, l->f->loopbase);
 +                      if(!edok) bmesh_error();
 +              }
 +              /*verify loop->v and loop->next->v pointers for ne*/
 +              for(i=0,l=ne->loop; i < radlen; i++, l = l->radial.next->data){
 +                      if(!(l->e == ne)) bmesh_error();
 +                      if(!(l->radial.data == l)) bmesh_error();
 +                      if( ((BMLoop*)(l->head.prev))->e != e && ((BMLoop*)(l->head.next))->e != e) bmesh_error();
 +                      edok = bmesh_verts_in_edge(l->v, ((BMLoop*)(l->head.next))->v, ne);
 +                      if(!edok) bmesh_error();
 +                      if(l->v == ((BMLoop*)(l->head.next))->v) bmesh_error();
 +                      if(l->e == ((BMLoop*)(l->head.next))->e) bmesh_error();
 +                      /*verify loop cycle for kloop->f. Redundant*/
 +                      edok = bmesh_cycle_validate(l->f->len, l->f->loopbase);
 +                      if(!edok) bmesh_error();
 +              }
 +      }
 +      
 +      if(re) *re = ne;
 +      return nv;
 +}
 +
 +/**
 + *                    bmesh_SFME
 + *
 + *    SPLIT FACE MAKE EDGE:
 + *
 + *    Takes as input two vertices in a single face. An edge is created which divides the original face
 + *    into two distinct regions. One of the regions is assigned to the original face and it is closed off.
 + *    The second region has a new face assigned to it.
 + *
 + *    Examples:
 + *    
 + *     Before:               After:
 + *     ----------           ----------
 + *     |                |           |        | 
 + *     |        |           |   f1   |
 + *    v1   f1   v2          v1======v2
 + *     |        |           |   f2   |
 + *     |        |           |        |
 + *     ----------           ---------- 
 + *
 + *    Note that the input vertices can be part of the same edge. This will result in a two edged face.
 + *  This is desirable for advanced construction tools and particularly essential for edge bevel. Because
 + *  of this it is up to the caller to decide what to do with the extra edge.
 + *
 + *  Note that the tesselator abuses eflag2 while using this euler! (don't ever ever do this....)
 + *
 + *    Returns -
 + *  A BMFace pointer
 + */
 +BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **rl){
 +
 +      BMFace *f2;
 +      BMLoop *v1loop = NULL, *v2loop = NULL, *curloop, *f1loop=NULL, *f2loop=NULL;
 +      BMEdge *e;
 +      int i, len, f1len, f2len;
 +      
 +      
 +      /*verify that v1 and v2 are in face.*/
 +      len = bmesh_cycle_length(f->loopbase);
 +      for(i = 0, curloop = f->loopbase; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
 +              if(curloop->v == v1) v1loop = curloop;
 +              else if(curloop->v == v2) v2loop = curloop;
 +      }
 +      
 +      if(!v1loop || !v2loop) return NULL;
 +      
 +      /*allocate new edge between v1 and v2*/
 +      e = bmesh_addedgelist(bm, v1, v2,NULL);
 +      bmesh_disk_append_edge(e, v1);
 +      bmesh_disk_append_edge(e, v2);
 +      
 +      f2 = bmesh_addpolylist(bm,f);
 +      f1loop = bmesh_create_loop(bm,v2,e,f,v2loop);
 +      f2loop = bmesh_create_loop(bm,v1,e,f2,v1loop);
 +      
 +      f1loop->head.prev = v2loop->head.prev;
 +      f2loop->head.prev = v1loop->head.prev;
 +      v2loop->head.prev->next = (BMHeader*)f1loop;
 +      v1loop->head.prev->next = (BMHeader*)f2loop;
 +      
 +      f1loop->head.next = (BMHeader*)v1loop;
 +      f2loop->head.next = (BMHeader*)v2loop;
 +      v1loop->head.prev = (BMHeader*)f1loop;
 +      v2loop->head.prev = (BMHeader*)f2loop;
 +      
 +      f2->loopbase = f2loop;
 +      f->loopbase = f1loop;
 +      
 +      /*validate both loops*/
 +      /*I dont know how many loops are supposed to be in each face at this point! FIXME!*/
 +      
 +      /*go through all of f2's loops and make sure they point to it properly.*/
 +      f2len = bmesh_cycle_length(f2->loopbase);
 +      for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ) curloop->f = f2;
 +      
 +      /*link up the new loops into the new edges radial*/
 +      bmesh_radial_append(e, f1loop);
 +      bmesh_radial_append(e, f2loop);
 +      
 +      
 +      f2->len = f2len;
 +      
 +      f1len = bmesh_cycle_length(f->loopbase);
 +      f->len = f1len;
 +      
 +      if(rl) *rl = f2loop;
 +      return f2;
 +}
 +
 +
 +/**
 + *                    bmesh_JEKV
 + *
 + *    JOIN EDGE KILL VERT:
 + *    Takes a an edge and pointer to one of its vertices and collapses
 + *    the edge on that vertex.
 + *    
 + *    Before:    OE      KE
 + *                     ------- -------
 + *               |     ||      |
 + *            OV     KV      TV
 + *
 + *
 + *   After:             OE      
 + *                     ---------------
 + *               |             |
 + *            OV             TV
 + *
 + *
 + *    Restrictions:
 + *    KV is a vertex that must have a valance of exactly two. Furthermore
 + *  both edges in KV's disk cycle (OE and KE) must be unique (no double
 + *  edges).
 + *
 + *    It should also be noted that this euler has the possibility of creating
 + *    faces with just 2 edges. It is up to the caller to decide what to do with
 + *  these faces.
 + *
 + *  Returns -
 + *    1 for success, 0 for failure.
 + */
 +int bmesh_jekv(BMesh *bm, BMEdge *ke, BMVert *kv)
 +{
 +      BMEdge *oe;
 +      BMVert *ov, *tv;
 +      BMNode *diskbase;
 +      BMLoop *killoop,*nextl;
 +      int len,radlen=0, halt = 0, i, valance1, valance2,edok;
 +      
 +      if(bmesh_vert_in_edge(ke,kv) == 0) return 0;
 +      diskbase = bmesh_disk_getpointer(kv->edge, kv);
 +      len = bmesh_cycle_length(diskbase);
 +      
 +      if(len == 2){
 +              oe = bmesh_disk_nextedge(ke, kv);
 +              tv = bmesh_edge_getothervert(ke, kv);
 +              ov = bmesh_edge_getothervert(oe, kv);           
 +              halt = bmesh_verts_in_edge(kv, tv, oe); //check for double edges
 +              
 +              if(halt) return 0;
 +              else{
 +                      
 +                      /*For verification later, count valance of ov and tv*/
 +                      diskbase = bmesh_disk_getpointer(ov->edge, ov);
 +                      valance1 = bmesh_cycle_length(diskbase);
 +                      diskbase = bmesh_disk_getpointer(tv->edge, tv);
 +                      valance2 = bmesh_cycle_length(diskbase);
 +                      
 +                      /*remove oe from kv's disk cycle*/
 +                      bmesh_disk_remove_edge(oe,kv);
 +                      /*relink oe->kv to be oe->tv*/
 +                      bmesh_edge_swapverts(oe, kv, tv);
 +                      /*append oe to tv's disk cycle*/
 +                      bmesh_disk_append_edge(oe, tv);
 +                      /*remove ke from tv's disk cycle*/
 +                      bmesh_disk_remove_edge(ke, tv);
 +              
 +                      
 +
 +                      /*deal with radial cycle of ke*/
 +                      if(ke->loop){
 +                              /*first step, fix the neighboring loops of all loops in ke's radial cycle*/
 +                              radlen = bmesh_cycle_length(&(ke->loop->radial));
 +                              for(i=0,killoop = ke->loop; i<radlen; i++, killoop = bmesh_radial_nextloop(killoop)){
 +                                      /*relink loops and fix vertex pointer*/
 +                                      killoop->head.next->prev = killoop->head.prev;
 +                                      killoop->head.prev->next = killoop->head.next;
 +                                      if( ((BMLoop*)(killoop->head.next))->v == kv) ((BMLoop*)(killoop->head.next))->v = tv;
 +                                      
 +                                      /*fix len attribute of face*/
 +                                      killoop->f->len--;
 +                                      if(killoop->f->loopbase == killoop) killoop->f->loopbase = ((BMLoop*)(killoop->head.next));
 +                              }
 +                              /*second step, remove all the hanging loops attached to ke*/
 +                              killoop = ke->loop;
 +                              radlen = bmesh_cycle_length(&(ke->loop->radial));
 +                              /*make sure we have enough room in bm->lpar*/
 +                              if(bm->lparlen < radlen){
 +                                      MEM_freeN(bm->lpar);
 +                                      bm->lpar = MEM_callocN(sizeof(BMLoop *)* radlen, "BM Loop pointer array");
 +                                      bm->lparlen = bm->lparlen * radlen;
 +                              }
 +                              /*this should be wrapped into a bme_free_radial function to be used by bmesh_KF as well...*/
 +                              i=0;
 +                              while(i<radlen){
 +                                      bm->lpar[i] = killoop;
 +                                      killoop = killoop->radial.next->data;
 +                                      i++;
 +                              }
 +                              i=0;
 +                              while(i<radlen){
 +                                      bmesh_free_loop(bm,bm->lpar[i]);
 +                                      i++;
 +                              }
 +                              /*Validate radial cycle of oe*/
 +                              edok = bmesh_cycle_validate(radlen,&(oe->loop->radial));
 +                              
 +                      }
 +                      
 +
 +                      /*Validate disk cycles*/
 +                      diskbase = bmesh_disk_getpointer(ov->edge,ov);
 +                      edok = bmesh_cycle_validate(valance1, diskbase);
 +                      if(!edok) bmesh_error();
 +                      diskbase = bmesh_disk_getpointer(tv->edge,tv);
 +                      edok = bmesh_cycle_validate(valance2, diskbase);
 +                      if(!edok) bmesh_error();
 +                      
 +                      /*Validate loop cycle of all faces attached to oe*/
 +                      for(i=0,nextl = oe->loop; i<radlen; i++, nextl = bmesh_radial_nextloop(nextl)){
 +                              edok = bmesh_cycle_validate(nextl->f->len,nextl->f->loopbase);
 +                              if(!edok) bmesh_error();
 +                      }
 +                      /*deallocate edge*/
 +                      BLI_remlink(&(bm->edges), &(ke->head));
 +                      bmesh_free_edge(bm, ke);
 +                      /*deallocate vertex*/
 +                      BLI_remlink(&(bm->verts), &(kv->head));
 +                      bmesh_free_vert(bm, kv);        
 +                      return 1;
 +              }
 +      }
 +      return 0;
 +}
 +
 +
 +/**
 + *                    bmesh_loop_reverse
 + *
 + *    FLIP FACE EULER
 + *
 + *    Changes the winding order of a face from CW to CCW or vice versa.
 + *    This euler is a bit peculiar in compairson to others as it is its
 + *    own inverse.
 + *
 + *    TODO: reinsert validation code.
 + *
 + *  Returns -
 + *    1 for success, 0 for failure.
 + */
 +
 +int bmesh_loop_reverse(BMesh *bm, BMFace *f){
 +      BMLoop *l = f->loopbase, *curloop, *oldprev, *oldnext;
 +      int i, j, edok, len = 0;
 +
 +      len = bmesh_cycle_length(l);
 +      if(bm->edarlen < len){
 +              MEM_freeN(bm->edar);
 +              bm->edar = MEM_callocN(sizeof(BMEdge *)* len, "BM Edge pointer array");
 +              bm->edarlen = len;
 +      }
 +      
 +      for(i=0, curloop = l; i< len; i++, curloop= ((BMLoop*)(curloop->head.next)) ){
 +              curloop->e->head.eflag1 = 0;
 +              curloop->e->head.eflag2 = bmesh_cycle_length(&curloop->radial);
 +              bmesh_radial_remove_loop(curloop, curloop->e);
 +              /*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/
 +              curloop->radial.next = curloop->radial.prev = NULL;
 +              bm->edar[i] = curloop->e;
 +      }
 +      
 +      /*actually reverse the loop. This belongs in bmesh_cycle_reverse!*/
 +      for(i=0, curloop = l; i < len; i++){
 +              oldnext = ((BMLoop*)(curloop->head.next));
 +              oldprev = ((BMLoop*)(curloop->head.prev));
 +              curloop->head.next = (BMHeader*)oldprev;
 +              curloop->head.prev = (BMHeader*)oldnext;
 +              curloop = oldnext;
 +      }
 +
 +      if(len == 2){ //two edged face
 +              //do some verification here!
 +              l->e = bm->edar[1];
 +              ((BMLoop*)(l->head.next))->e = bm->edar[0];
 +      }
 +      else{
 +              for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
 +                      edok = 0;
 +                      for(j=0; j < len; j++){
 +                              edok = bmesh_verts_in_edge(curloop->v, ((BMLoop*)(curloop->head.next))->v, bm->edar[j]);
 +                              if(edok){
 +                                      curloop->e = bm->edar[j];
 +                                      break;
 +                              }
 +                      }
 +              }
 +      }
 +      /*rebuild radial*/
 +      for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ) bmesh_radial_append(curloop->e, curloop);
 +      
 +      /*validate radial*/
 +      for(i=0, curloop = l; i < len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
 +              edok = bmesh_cycle_validate(curloop->e->head.eflag2, &(curloop->radial));
 +              if(!edok){
 +                      bmesh_error();
 +              }
 +      }
 +      return 1;
 +}
 +
 +/**
 + *                    bmesh_JFKE
 + *
 + *    JOIN FACE KILL EDGE:
 + *    
 + *    Takes two faces joined by a single 2-manifold edge and fuses them togather.
 + *    The edge shared by the faces must not be connected to any other edges which have
 + *    Both faces in its radial cycle
 + *
 + *    Examples:
 + *    
 + *        A                   B
 + *     ----------           ----------
 + *     |                |           |        | 
 + *     |   f1   |           |   f1   |
 + *    v1========v2 = Ok!    v1==V2==v3 == Wrong!
 + *     |   f2   |           |   f2   |
 + *     |        |           |        |
 + *     ----------           ---------- 
 + *
 + *    In the example A, faces f1 and f2 are joined by a single edge, and the euler can safely be used.
 + *    In example B however, f1 and f2 are joined by multiple edges and will produce an error. The caller
 + *    in this case should call bmesh_JEKV on the extra edges before attempting to fuse f1 and f2.
 + *
 + *    Also note that the order of arguments decides whether or not certain per-face attributes are present
 + *    in the resultant face. For instance vertex winding, material index, smooth flags, ect are inherited
 + *    from f1, not f2.
 + *
 + *  Returns -
 + *    A BMFace pointer
 +*/
 +
 +BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
 +{
 +      
 +      BMLoop *curloop, *f1loop=NULL, *f2loop=NULL;
 +      int loopok = 0, newlen = 0,i, f1len=0, f2len=0, radlen=0, edok, shared;
 +      
 +      if(f1 == f2) return NULL; //can't join a face to itself
 +      /*verify that e is in both f1 and f2*/
 +      f1len = bmesh_cycle_length(f1->loopbase);
 +      f2len = bmesh_cycle_length(f2->loopbase);
 +      for(i=0, curloop = f1->loopbase; i < f1len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
 +              if(curloop->e == e){ 
 +                      f1loop = curloop;
 +                      break;
 +              }
 +      }
 +      for(i=0, curloop = f2->loopbase; i < f2len; i++, curloop = ((BMLoop*)(curloop->head.next)) ){
 +              if(curloop->e==e){
 +                      f2loop = curloop;
 +                      break;
 +              }
 +      }
 +      if(!(f1loop && f2loop)) return NULL;
 +      
 +      /*validate that edge is 2-manifold edge*/
 +      radlen = bmesh_cycle_length(&(f1loop->radial));
 +      if(radlen != 2) return NULL;
 +
 +      /*validate direction of f2's loop cycle is compatible.*/
 +      if(f1loop->v == f2loop->v) return NULL;
 +      
 +      /*
 +              Finally validate that for each face, each vertex has another edge in its disk cycle that is 
 +              not e, and not shared.
 +      */
 +      if(bmesh_radial_find_face( ((BMLoop*)(f1loop->head.next))->e,f2)) return NULL;
 +      if(bmesh_radial_find_face( ((BMLoop*)(f1loop->head.prev))->e,f2)) return NULL;
 +      if(bmesh_radial_find_face( ((BMLoop*)(f2loop->head.next))->e,f1)) return NULL;
 +      if(bmesh_radial_find_face( ((BMLoop*)(f2loop->head.prev))->e,f1)) return NULL;
 +      
 +      /*validate only one shared edge*/
 +      shared = BM_Face_Sharededges(f1,f2);
 +      if(shared > 1) return NULL;
 +
 +      /*join the two loops*/
 +      f1loop->head.prev->next = f2loop->head.next;
 +      f2loop->head.next->prev = f1loop->head.prev;
 +      
 +      f1loop->head.next->prev = f2loop->head.prev;
 +      f2loop->head.prev->next = f1loop->head.next;
 +      
 +      /*if f1loop was baseloop, give f1loop->next the base.*/
 +      if(f1->loopbase == f1loop) f1->loopbase = ((BMLoop*)(f1loop->head.next));
 +      
 +      /*validate the new loop*/
 +      loopok = bmesh_cycle_validate((f1len+f2len)-2, f1->loopbase);
 +      if(!loopok) bmesh_error();
 +      
 +      /*make sure each loop points to the proper face*/
 +      newlen = bmesh_cycle_length(f1->loopbase);
 +      for(i = 0, curloop = f1->loopbase; i < newlen; i++, curloop = ((BMLoop*)(curloop->head.next)) ) curloop->f = f1;
 +      
 +      f1->len = newlen;
 +      
 +      edok = bmesh_cycle_validate(f1->len, f1->loopbase);
 +      if(!edok) bmesh_error();
 +      
 +      /*remove edge from the disk cycle of its two vertices.*/
 +      bmesh_disk_remove_edge(f1loop->e, f1loop->e->v1);
 +      bmesh_disk_remove_edge(f1loop->e, f1loop->e->v2);
 +      
 +      /*deallocate edge and its two loops as well as f2*/
 +      BLI_remlink(&(bm->edges), &(f1loop->e->head));
 +      BLI_remlink(&(bm->polys), &(f2->head));
 +      bmesh_free_edge(bm, f1loop->e);
 +      bmesh_free_loop(bm, f1loop);
 +      bmesh_free_loop(bm, f2loop);
 +      bmesh_free_poly(bm, f2);        
 +      return f1;
 +}
index e8066aa52f938c8319d8491c2478e36d581f43b9,0000000000000000000000000000000000000000..b79a8a5f4ab0909d41dcafbe76c810a0c94f0264
mode 100644,000000..100644
--- /dev/null
@@@ -1,310 -1,0 +1,270 @@@
- /*error system*/
- typedef struct bmop_error {
-        struct bmop_error *next, *prev;
-        int errorcode;
-        char *msg;
- } bmop_error;
- void BMOP_RaiseError(BMesh *bm, int errcode, char *msg)
- {
-        bmop_error *err = MEM_callocN(sizeof(bmop_error), "bmop_error");
-        err->errorcode = errcode;
-        err->msg = msg;
-        BLI_addhead(&bm->errorstack, err);
- }
- /*returns error code or 0 if no error*/
- int BMOP_GetError(BMesh *bm, char **msg)
- {
-        bmop_error *err = bm->errorstack.first;
-        if (!err) return 0;
-        if (msg) *msg = err->msg;
-        return err->errorcode;
- }
- int BMOP_CheckError(BMesh *bm)
- {
-        return bm->errorstack.first != NULL;
- }
- int BMOP_PopError(BMesh *bm, char **msg)
- {
-        int errorcode = BMOP_GetError(bm, msg);
-        if (errorcode)
-                BLI_remlink(&bm->errorstack, &bm->errorstack.first);
-        return errorcode;
- }
 +/**
 + * BME_mesh.c    jan 2007
 + *
 + *    BM mesh level functions.
 + *
 + * $Id: BME_eulers.c,v 1.00 2007/01/17 17:42:01 Briggs Exp $
 + *
 + * ***** 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.
 + * about this.        
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * The Original Code is Copyright (C) 2007 Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): Geoffrey Bantle.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +#include "MEM_guardedalloc.h"
 +#include "DNA_listBase.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_arithb.h"
 +#include "BKE_utildefines.h"
 +
 +#include "bmesh.h"
 +#include "bmesh_private.h"
 +
 +void BME_error(void);
 +
 +/*bmesh_error stub*/
 +void bmesh_error(void)
 +{
 +      printf("BM modelling error!");
 +}
 +
 +/*
 + * BMESH SET SYSFLAG
 + *
 + * Sets a bitflag for a given element.
 + *
 +*/
 +
 +void bmesh_set_sysflag(BMHeader *head, int flag)
 +{
 +      head->flag |= flag;
 +}
 +
 +/*
 + * BMESH CLEAR SYSFLAG
 + * 
 + * Clears a bitflag for a given element.
 + *
 +*/
 +
 +void bmesh_clear_sysflag(BMHeader *head, int flag)
 +{
 +      head->flag &= ~flag;
 +}
 +
 +
 +/*
 + * BMESH TEST SYSFLAG
 + *
 + * Tests whether a bitflag is set for a given element.
 + *
 +*/
 +
 +int bmesh_test_sysflag(BMHeader *head, int flag)
 +{
 +      if(head->flag & flag)
 +              return 1;
 +      return 0;
 +}
 +
 +/*    
 + *    BMESH MAKE MESH
 + *
 + *  Allocates a new BMesh structure.
 + *  Returns -
 + *  Pointer to a BM
 + *
 +*/
 +
 +BMesh *BM_Make_Mesh(int allocsize[4])
 +{
 +      /*allocate the structure*/
 +      BMesh *bm = MEM_callocN(sizeof(BMesh),"BM");
 +      /*allocate the memory pools for the mesh elements*/
 +      bm->vpool = BLI_mempool_create(sizeof(BMVert), allocsize[0], allocsize[0]);
 +      bm->epool = BLI_mempool_create(sizeof(BMEdge), allocsize[1], allocsize[1]);
 +      bm->lpool = BLI_mempool_create(sizeof(BMLoop), allocsize[2], allocsize[2]);
 +      bm->ppool = BLI_mempool_create(sizeof(BMFace), allocsize[3], allocsize[3]);
 +
 +      /*allocate one flag pool that we dont get rid of.*/
 +      bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer), 512, 512);
 +      bm->totflags = 1;
 +
 +      return bm;
 +}
 +/*    
 + *    BMESH FREE MESH
 + *
 + *    Frees a BMesh structure.
 +*/
 +
 +void BM_Free_Mesh(BMesh *bm)
 +{
 +      BMVert *v;
 +      BMEdge *e;
 +      BMLoop *l;
 +      BMFace *f;
 +      
 +
 +      BMIter verts;
 +      BMIter edges;
 +      BMIter faces;
 +      BMIter loops;
 +      
 +      for(v = BMIter_New(&verts, bm, BM_VERTS, bm ); v; v = BMIter_Step(&verts)) CustomData_bmesh_free_block( &(bm->vdata), &(v->data) );
 +      for(e = BMIter_New(&edges, bm, BM_EDGES, bm ); e; e = BMIter_Step(&edges)) CustomData_bmesh_free_block( &(bm->edata), &(e->data) );
 +      for(f = BMIter_New(&faces, bm, BM_FACES, bm ); f; f = BMIter_Step(&faces)){
 +              CustomData_bmesh_free_block( &(bm->pdata), &(f->data) );
 +              for(l = BMIter_New(&loops, bm, BM_LOOPS_OF_FACE, f ); l; l = BMIter_Step(&loops)) CustomData_bmesh_free_block( &(bm->ldata), &(l->data) );
 +      }
 +
 +      /*Free custom data pools, This should probably go in CustomData_free?*/
 +      if(bm->vdata.totlayer) BLI_mempool_destroy(bm->vdata.pool);
 +      if(bm->edata.totlayer) BLI_mempool_destroy(bm->edata.pool);
 +      if(bm->ldata.totlayer) BLI_mempool_destroy(bm->ldata.pool);
 +      if(bm->pdata.totlayer) BLI_mempool_destroy(bm->pdata.pool);
 +
 +      /*free custom data*/
 +      CustomData_free(&bm->vdata,0);
 +      CustomData_free(&bm->edata,0);
 +      CustomData_free(&bm->ldata,0);
 +      CustomData_free(&bm->pdata,0);
 +
 +      /*destroy element pools*/
 +      BLI_mempool_destroy(bm->vpool);
 +      BLI_mempool_destroy(bm->epool);
 +      BLI_mempool_destroy(bm->ppool);
 +      BLI_mempool_destroy(bm->lpool);
 +
 +      /*destroy flag pool*/
 +      BLI_mempool_destroy(bm->flagpool);
 +      
 +      MEM_freeN(bm);  
 +}
 +
 +/*
 + *  BMESH COMPUTE NORMALS
 + *
 + *  Updates the normals of a mesh.
 + *  Note that this can only be called  
 + *
 +*/
 +
 +void BM_Compute_Normals(BMesh *bm)
 +{
 +      BMVert *v;
 +      BMFace *f;
 +      BMLoop *l;
 +      
 +      BMIter verts;
 +      BMIter faces;
 +      BMIter loops;
 +      
 +      unsigned int maxlength = 0;
 +      float (*projectverts)[3];
 +      
 +      /*first, find out the largest face in mesh*/
 +      for(f = BMIter_New(&faces, bm, BM_FACES, bm ); f; f = BMIter_Step(&faces)){
 +              if(f->len > maxlength) maxlength = f->len;
 +      }
 +      
 +      /*make sure we actually have something to do*/
 +      if(maxlength < 3) return; 
 +      
 +      /*allocate projectverts array*/
 +      projectverts = MEM_callocN(sizeof(float) * maxlength * 3, "BM normal computation array");
 +      
 +      /*calculate all face normals*/
 +      for(f = BMIter_New(&faces, bm, BM_FACES, bm ); f; f = BMIter_Step(&faces)){
 +              bmesh_update_face_normal(bm, f, projectverts);          
 +      }
 +      
 +      /*Zero out vertex normals*/
 +      for(v = BMIter_New(&verts, bm, BM_VERTS, bm ); v; v = BMIter_Step(&verts)) v->no[0] = v->no[1] = v->no[2] = 0.0;
 +
 +      /*add face normals to vertices*/
 +      for(f = BMIter_New(&faces, bm, BM_FACES, bm ); f; f = BMIter_Step(&faces)){
 +              for(l = BMIter_New(&loops, bm, BM_LOOPS_OF_FACE, f ); l; l = BMIter_Step(&loops)) VecAddf(l->v->no, l->v->no, f->no);
 +      }
 +      
 +      /*average the vertex normals*/
 +      for(v = BMIter_New(&verts, bm, BM_VERTS, bm ); v; v= BMIter_Step(&verts)){
 +              if (Normalize(v->no)==0.0) {
 +                      VECCOPY(v->no, v->co);
 +                      Normalize(v->no);
 +              }
 +      }
 +      
 +      MEM_freeN(projectverts);
 +}
 +
 +/*    
 + *    BMESH BEGIN/END EDIT
 + *
 + *    Functions for setting up a mesh for editing and cleaning up after 
 + *  the editing operations are done. These are called by the tools/operator 
 + *  API for each time a tool is executed.
 + *
 + *  Returns -
 + *  Nothing
 + *
 +*/
 +
 +void bmesh_begin_edit(BMesh *bm){
 +
 +      /*Initialize some scratch pointer arrays used by eulers*/
 +      bm->vtar = MEM_callocN(sizeof(BMVert *) * 1024, "BM scratch vert array");
 +      bm->edar = MEM_callocN(sizeof(BMEdge *) * 1024, "BM scratch edge array");
 +      bm->lpar = MEM_callocN(sizeof(BMLoop *) * 1024, "BM scratch loop array");
 +      bm->plar = MEM_callocN(sizeof(BMFace *) * 1024, "BM scratch poly array");
 +
 +      bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 1024;
 +}
 +
 +void bmesh_end_edit(BMesh *bm, int flag){
 +      int totvert, totedge, totface;
 +      /*verify element counts*/
 +      totvert = BLI_countlist(&(bm->verts));
 +      totedge = BLI_countlist(&(bm->edges));
 +      totface = BLI_countlist(&(bm->polys));
 +
 +      if(bm->totvert!=totvert || bm->totedge!=totedge || bm->totface!=totface) BME_error();
 +
 +      /*free temp storage*/
 +      if(bm->vtar) MEM_freeN(bm->vtar);
 +      if(bm->edar) MEM_freeN(bm->edar);
 +      if(bm->lpar) MEM_freeN(bm->lpar);
 +      if(bm->plar) MEM_freeN(bm->plar);
 +
 +      /*zero out pointers*/
 +      bm->vtar = NULL;
 +      bm->edar = NULL;
 +      bm->lpar = NULL;
 +      bm->plar = NULL;
 +      bm->vtarlen = bm->edarlen = bm->lparlen = bm->plarlen = 0;
 +
 +      /*compute normals, clear temp flags and flush selections*/
 +      BM_Compute_Normals(bm);
 +      bmesh_selectmode_flush(bm);
 +}
index 05d9fb34efff0741c3b905bf7a3bee5c18099b19,0000000000000000000000000000000000000000..ce59856f8239674017d4fe4ccba2e89e8961a2ab
mode 100644,000000..100644
--- /dev/null
@@@ -1,339 -1,0 +1,388 @@@
-                               if(len == 2 && (e!=baseedge) && (e!=keepedge))
 +#include <limits.h>
 +#include "MEM_guardedalloc.h"
 +
 +#include "DNA_listBase.h"
 +#include "BKE_utildefines.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_linklist.h"
 +#include "BLI_ghash.h"
 +#include "BLI_arithb.h"
 +
 +#include "bmesh.h"
 +#include "bmesh_private.h"
 +
++#include <stdlib.h>
++#include <string.h>
 +
 +/*
 + * BME_MODS.C
 + *
 + * This file contains functions for locally modifying
 + * the topology of existing mesh data. (split, join, flip ect).
 + *
 +*/
 +
 +/**
 + *                    bmesh_dissolve_disk
 + *
 + *  Turns the face region surrounding a manifold vertex into 
 + *  A single polygon.
 + *
 + * 
 + * Example:
 + * 
 + *          |=========|             |=========|
 + *          |  \   /  |             |         |
 + * Before:  |    V    |      After: |         |
 + *          |  /   \  |             |         |
 + *          |=========|             |=========|
 + * 
 + * 
 + */
 +#if 1
 +void BM_Dissolve_Disk(BMesh *bm, BMVert *v) {
 +      BMFace *f, *f2;
 +      BMEdge *e, *keepedge=NULL, *baseedge=NULL;
 +      BMLoop *loop;
 +      int done, len;
 +
 +      if(BM_Nonmanifold_Vert(bm, v)) {
 +              if (!v->edge) bmesh_kv(bm, v);
 +              else if (!v->edge->loop) {
 +                      bmesh_ke(bm, v->edge);
 +                      bmesh_kv(bm, v);
 +              }
 +              return;
 +      }
 +      
 +      if(v->edge){
 +              /*v->edge we keep, what else?*/
 +              e = v->edge;
 +              len = 0;
 +              do{
 +                      e = bmesh_disk_nextedge(e,v);
 +                      if(!(BM_Edge_Share_Faces(e, v->edge))){
 +                              keepedge = e;
 +                              baseedge = v->edge;
 +                              break;
 +                      }
 +                      len++;
 +              }while(e != v->edge);
 +      }
 +      
 +      /*this code for handling 2 and 3-valence verts
 +        may be totally bad.*/
 +      if (keepedge == NULL && len == 3) {
 +              /*handle specific case for three-valence.  solve it by
 +                increasing valence to four.  this may be hackish. . .*/
 +              loop = e->loop;
 +              if (loop->v == v) loop = (BMLoop*) loop->head.next;
 +              BM_Split_Face(bm, loop->f, v, loop->v, NULL, NULL, 0);
 +
 +              BM_Dissolve_Disk(bm, v);
 +              return;
 +      } else if (keepedge == NULL && len == 2) {
 +              /*handle two-valence*/
 +              f = v->edge->loop->f;
 +              f2 = ((BMLoop*)v->edge->loop->radial.next->data)->f;
 +              /*collapse the vertex*/
 +              BM_Collapse_Vert(bm, v->edge, v, 1.0, 0);
 +              BM_Join_Faces(bm, f, f2, NULL, 0, 0);
 +      } else if (len == 1) {
 +              bmesh_ke(bm, v->edge);
 +              bmesh_kv(bm, v);
 +      }
 +
 +      if(keepedge){
 +              done = 0;
 +              while(!done){
 +                      done = 1;
 +                      e = v->edge;
 +                      do{
 +                              f = NULL;
 +                              len = bmesh_cycle_length(&(e->loop->radial));
-               percent = 1.0 / (float)(numcuts + 1 - i);
++                              if(len == 2 && (e!=baseedge) && (e!=keepedge)) {
 +                                      f = BM_Join_Faces(bm, e->loop->f, ((BMLoop*)(e->loop->radial.next->data))->f, e, 0, 0); 
++                                      /*return if couldn't join faces in manifold
++                                        conditions.*/
++                                      //!disabled for testing why bad things happen
++                                      if (!f) return;
++                              }
++
 +                              if(f){
 +                                      done = 0;
 +                                      break;
 +                              }
 +                              e = bmesh_disk_nextedge(e, v);
 +                      }while(e != v->edge);
 +              }
 +
 +              /*get remaining two faces*/
 +              f = v->edge->loop->f;
 +              f2 = ((BMLoop*)v->edge->loop->radial.next->data)->f;
 +              /*collapse the vertex*/
 +              BM_Collapse_Vert(bm, baseedge, v, 1.0, 0);
 +
 +              /*join two remaining faces*/
 +              BM_Join_Faces(bm, f, f2, NULL, 0, 0);
 +      }
 +}
 +#else
 +void BM_Dissolve_Disk(BMesh *bm, BMVert *v){
 +      BMFace *f;
 +      BMEdge *e;
 +      BMIter iter;
 +      int done, len;
 +      
 +      if(v->edge){
 +              done = 0;
 +              while(!done){
 +                      done = 1;
 +                      
 +                      /*loop the edges looking for an edge to dissolve*/
 +                      for (e=BMIter_New(&iter, bm, BM_EDGES_OF_VERT, v); e;
 +                           e = BMIter_Step(&iter)) {
 +                              f = NULL;
 +                              len = bmesh_cycle_length(&(e->loop->radial));
 +                              if(len == 2){
 +                                      f = BM_Join_Faces(bm,e->loop->f,((BMLoop*)
 +                                            (e->loop->radial.next->data))->f, 
 +                                             e, 1, 0);
 +                              }
 +                              if(f){ 
 +                                      done = 0;
 +                                      break;
 +                              }
 +                      };
 +              }
 +              BM_Collapse_Vert(bm, v->edge, v, 1.0, 1);
 +      }
 +}
 +#endif
 +
 +/**
 + *                    bmesh_join_faces
 + *
 + *  joins two adjacenct faces togather. If weldUVs == 1
 + *  and the uv/vcols of the two faces are non-contigous, the
 + *  per-face properties of f2 will be transformed into place
 + *  around f1.
 + * 
 + *  Returns -
 + *    BMFace pointer
 + */
 + 
 +BMFace *BM_Join_Faces(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, int calcnorm, int weldUVs) {
 +
 +      BMLoop *l1, *l2;
 +      BMEdge *jed=NULL;
 +      
 +      jed = e;
 +      if(!jed){
 +              /*search for an edge that has both these faces in its radial cycle*/
 +              l1 = f1->loopbase;
 +              do{
 +                      if( ((BMLoop*)l1->radial.next->data)->f == f2 ){
 +                              jed = l1->e;
 +                              break;
 +                      }
 +                      l1 = ((BMLoop*)(l1->head.next));
 +              }while(l1!=f1->loopbase);
 +      }
 +
 +      l1 = jed->loop;
 +      l2 = l1->radial.next->data;
 +      if (l1->v == l2->v) {
 +              bmesh_loop_reverse(bm, f2);
 +      }
 +
 +      return bmesh_jfke(bm, f1, f2, jed);
 +}
 +
 +/*connects two verts together, automatically (if very naively) finding the
 +  face they both share (if there is one) and splittling it.  use this at your 
 +  own risk, as it doesn't handle the many complex cases it should (like zero-area faces,
 +  multiple faces, etc).
 +
 +  this is really only meant for cases where you don't know before hand the face
 +  the two verts belong to for splitting (e.g. the subdivision operator).
 +*/
 +
 +BMEdge *BM_Connect_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf) {
 +      BMIter iter, iter2;
 +      BMVert *v;
 +      BMLoop *nl;
 +      BMFace *face;
 +
 +      /*this isn't the best thing in the world.  it doesn't handle cases where there's
 +        multiple faces yet.  that might require a convexity test to figure out which
 +        face is "best," and who knows what for non-manifold conditions.*/
 +      for (face = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v1); face; face=BMIter_Step(&iter)) {
 +              for (v=BMIter_New(&iter2, bm, BM_VERTS_OF_FACE, face); v; v=BMIter_Step(&iter2)) {
 +                      if (v == v2) {
 +                              face = BM_Split_Face(bm, face, v1, v2, &nl, NULL, 1);
 +
 +                              if (nf) *nf = face;
 +                              return nl->e;
 +                      }
 +              }
 +      }
 +
 +      return NULL;
 +}
 +
 +/**
 + *                    BM_split_face
 + *
 + *  Splits a single face into two.
 + * 
 + *  Returns -
 + *    BMFace pointer
 + */
 + 
 +BMFace *BM_Split_Face(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **nl, BMEdge *example, int calcnorm)
 +{
 +      BMFace *nf;
 +      nf = bmesh_sfme(bm,f,v1,v2,nl);
 +      
 +      /*
 +      nf->flag = f->flag;
 +      if (example->flag & SELECT) f->flag |= BM_SELECT;
 +      nf->h = f->h;
 +      nf->mat_nr = f->mat_nr;
 +      if (nl && example) {
 +              (*nl)->e->flag = example->flag;
 +              (*nl)->e->h = example->h;
 +              (*nl)->e->crease = example->crease;
 +              (*nl)->e->bweight = example->bweight;
 +      }
 +      */
 +      return nf;
 +}
 +
 +/**
 + *                    bmesh_collapse_vert
 + *
 + *  Collapses a vertex that has only two manifold edges
 + *  onto a vertex it shares an edge with. Fac defines
 + *  the amount of interpolation for Custom Data.
 + *
 + *  Note that this is not a general edge collapse function. For
 + *  that see BM_manifold_edge_collapse 
 + *
 + *  TODO:
 + *    Insert error checking for KV valance.
 + *
 + *  Returns -
 + *    Nothing
 + */
 + 
 +void BM_Collapse_Vert(BMesh *bm, BMEdge *ke, BMVert *kv, float fac, int calcnorm){
 +      void *src[2];
 +      float w[2];
 +      BMLoop *l=NULL, *kvloop=NULL, *tvloop=NULL;
 +      BMVert *tv = bmesh_edge_getothervert(ke,kv);
 +
 +      w[0] = 1.0f - fac;
 +      w[1] = fac;
 +
 +      if(ke->loop){
 +              l = ke->loop;
 +              do{
 +                      if(l->v == tv && ((BMLoop*)(l->head.next))->v == kv){
 +                              tvloop = l;
 +                              kvloop = ((BMLoop*)(l->head.next));
 +
 +                              src[0] = kvloop->data;
 +                              src[1] = tvloop->data;
 +                              CustomData_bmesh_interp(&bm->ldata, src,w, NULL, 2, kvloop->data);                                                              
 +                      }
 +                      l=l->radial.next->data;
 +              }while(l!=ke->loop);
 +      }
 +      BM_Data_Interp_From_Verts(bm, kv, tv, kv, fac);   
 +      bmesh_jekv(bm,ke,kv);
 +}
 +
 +/**
 + *                    BM_split_edge
 + *    
 + *    Splits an edge. v should be one of the vertices in e and
 + *  defines the direction of the splitting operation for interpolation
 + *  purposes.
 + *
 + *  Returns -
 + *    the new vert
 + */
 +
 +BMVert *BM_Split_Edge(BMesh *bm, BMVert *v, BMEdge *e, BMEdge **ne, float percent, int calcnorm) {
 +      BMVert *nv, *v2;
 +
 +      v2 = bmesh_edge_getothervert(e,v);
 +      nv = bmesh_semv(bm,v,e,ne);
 +      if (nv == NULL) return NULL;
 +      VECSUB(nv->co,v2->co,v->co);
 +      VECADDFAC(nv->co,v->co,nv->co,percent);
 +      if (ne) {
 +              if(bmesh_test_sysflag(&(e->head), BM_SELECT)) bmesh_set_sysflag(&((*ne)->head), BM_SELECT);
 +              if(bmesh_test_sysflag(&(e->head), BM_HIDDEN)) bmesh_set_sysflag(&((*ne)->head), BM_HIDDEN);
 +      }
 +      /*v->nv->v2*/
 +      BM_Data_Facevert_Edgeinterp(bm,v2, v, nv, e, percent);  
 +      BM_Data_Interp_From_Verts(bm, v2, v, nv, percent);
 +      return nv;
 +}
 +
 +BMVert  *BM_Split_Edge_Multi(BMesh *bm, BMEdge *e, int numcuts)
 +{
 +      int i;
 +      float percent;
 +      BMVert *nv = NULL;
 +      
 +      for(i=0; i < numcuts; i++){
++              percent = 1.0f / (float)(numcuts + 1 - i);
 +              nv = BM_Split_Edge(bm, e->v2, e, NULL, percent, 0);
 +      }
 +      return nv;
 +}
++
++int BM_Validate_Face(BMesh *bm, BMFace *face, FILE *err) 
++{
++      BMIter iter;
++      V_DECLARE(verts);
++      BMVert **verts = NULL;
++      BMLoop *l;
++      int ret = 1, i, j;
++      
++      if (face->len == 2) {
++              fprintf(err, "warning: found two-edged face. face ptr: %p\n", face);
++              fflush(err);
++      }
++
++      for (l=BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, face);l;l=BMIter_Step(&iter)) {
++              V_GROW(verts);
++              verts[V_COUNT(verts)-1] = l->v;
++              
++              if (l->e->v1 == l->e->v2) {
++                      fprintf(err, "Found bmesh edge with identical verts!\n");
++                      fprintf(err, "  edge ptr: %p, vert: %p\n",  l->e, l->e->v1);
++                      fflush(err);
++                      ret = 0;
++              }
++      }
++
++      for (i=0; i<V_COUNT(verts); i++) {
++              for (j=0; j<V_COUNT(verts); j++) {
++                      if (j == 0) continue;
++                      if (verts[i] == verts[j]) {
++                              fprintf(err, "Found duplicate verts in bmesh face!\n");
++                              fprintf(err, "  face ptr: %p, vert: %p\n", face, verts[i]);
++                              fflush(err);
++                              ret = 0;
++                      }
++              }
++      }
++      
++      V_FREE(verts);
++      return ret;
++}
index af56924fd2efa357e4694ea75e181f9124075891,0000000000000000000000000000000000000000..47841c58ef7f7c76af3e7a6860d1a3e68f2a0e02
mode 100644,000000..100644
--- /dev/null
@@@ -1,111 -1,0 +1,113 @@@
-       {BMOP_OPSLOT_PNT_BUF},
 +#include "bmesh.h"
 +#include "bmesh_private.h"
 +
 +#include <stdio.h>
 +
 +BMOpDefine def_extrudefaceregion = {
 +      {BMOP_OPSLOT_PNT_BUF,
 +       BMOP_OPSLOT_MAPPING,
 +       BMOP_OPSLOT_PNT_BUF},
 +      extrude_edge_context_exec,
 +      BMOP_EXFACE_TOTSLOT,
 +      0
 +};
 +
 +BMOpDefine def_makefgonsop = {
 +      {0},
 +      bmesh_make_fgons_exec,
 +      BMOP_MAKE_FGONS_TOTSLOT,
 +      0
 +};
 +
 +BMOpDefine def_dissolvevertsop = {
 +      {BMOP_OPSLOT_PNT_BUF},
 +      dissolveverts_exec,
 +      BMOP_DISVERTS_TOTSLOT,
 +      0
 +};
 +
 +BMOpDefine def_dissolvefacesop = {
++      {BMOP_OPSLOT_PNT_BUF,
++       BMOP_OPSLOT_PNT_BUF},
 +      dissolvefaces_exec,
 +      BMOP_DISFACES_TOTSLOT,
 +      0
 +};
 +
++
 +BMOpDefine def_triangop = {
 +      {BMOP_OPSLOT_PNT_BUF, 
 +       BMOP_OPSLOT_PNT_BUF,
 +       BMOP_OPSLOT_PNT_BUF},
 +      triangulate_exec,
 +      BMOP_TRIANG_TOTSLOT,
 +      0
 +};
 +
 +BMOpDefine def_subdop = {
 +      {BMOP_OPSLOT_PNT_BUF,
 +       BMOP_OPSLOT_INT,
 +       BMOP_OPSLOT_INT,
 +       BMOP_OPSLOT_FLT,
 +       BMOP_OPSLOT_MAPPING,
 +       BMOP_OPSLOT_MAPPING,
 +       BMOP_OPSLOT_PNT_BUF,
 +       BMOP_OPSLOT_PNT_BUF,
 +       },
 +      esubdivide_exec,
 +      BMOP_ESUBDIVIDE_TOTSLOT,
 +      0
 +};
 +
 +BMOpDefine def_edit2bmesh = {
 +      {BMOP_OPSLOT_PNT},
 +      edit2bmesh_exec,
 +      BMOP_TO_EDITMESH_TOTSLOT,
 +      0
 +};
 +
 +BMOpDefine def_bmesh2edit = {
 +      {BMOP_OPSLOT_PNT},
 +      bmesh2edit_exec,
 +      BMOP_FROM_EDITMESH_TOTSLOT,
 +      0
 +};
 +
 +BMOpDefine def_delop = {
 +      {BMOP_OPSLOT_PNT_BUF, BMOP_OPSLOT_INT},
 +      delop_exec,
 +      BMOP_DEL_TOTSLOT,
 +      0
 +};
 +
 +BMOpDefine def_dupeop = {
 +      {BMOP_OPSLOT_PNT_BUF, BMOP_OPSLOT_PNT_BUF,
 +       BMOP_OPSLOT_PNT_BUF, BMOP_OPSLOT_MAPPING},
 +      dupeop_exec,
 +      BMOP_DUPE_TOTSLOT,
 +      0
 +};
 +
 +BMOpDefine def_splitop = {
 +      {BMOP_OPSLOT_PNT_BUF,
 +       BMOP_OPSLOT_PNT_BUF, BMOP_OPSLOT_MAPPING},
 +      splitop_exec,
 +      BMOP_SPLIT_TOTSLOT,
 +      0
 +};
 +
 +BMOpDefine *opdefines[] = {
 +      &def_splitop,
 +      &def_dupeop,
 +      &def_delop,
 +      &def_edit2bmesh,
 +      &def_bmesh2edit,
 +      &def_subdop,
 +      &def_triangop,
 +      &def_dissolvefacesop,
 +      &def_dissolvevertsop,
 +      &def_makefgonsop,
 +      &def_extrudefaceregion,
 +};
 +
 +int bmesh_total_ops = (sizeof(opdefines) / sizeof(void*));
index 628a9c5715729a63f4ebc87634fa50d31fbae9c9,0000000000000000000000000000000000000000..ca10129b4abe32b286d0f3520b2dbea030d678eb
mode 100644,000000..100644
--- /dev/null
@@@ -1,782 -1,0 +1,833 @@@
 +#include "MEM_guardedalloc.h"
 +
 +#include "BLI_memarena.h"
 +#include "BLI_mempool.h"
 +
 +#include "BKE_utildefines.h"
 +
 +#include "bmesh.h"
 +#include "bmesh_private.h"
 +
 +#include <string.h>
 +
 +/*forward declarations*/
 +static void alloc_flag_layer(BMesh *bm);
 +static void free_flag_layer(BMesh *bm);
 +static void clear_flag_layer(BMesh *bm);
 +
 +typedef void (*opexec)(struct BMesh *bm, struct BMOperator *op);
 +
 +/*mappings map elements to data, which
 +  follows the mapping struct in memory.*/
 +typedef struct element_mapping {
 +      BMHeader *element;
 +      int len;
 +} element_mapping;
 +
 +
 +/*operator slot type information - size of one element of the type given.*/
 +const int BMOP_OPSLOT_TYPEINFO[] = {
 +      sizeof(int),
 +      sizeof(float),
 +      sizeof(void*),
 +      0, /* unused */
 +      0, /* unused */
 +      0, /* unused */
 +      sizeof(void*),  /* pointer buffer */
 +      sizeof(element_mapping)
 +};
 +
 +/*
 + * BMESH OPSTACK PUSH
 + *
 + * Pushes the opstack down one level 
 + * and allocates a new flag layer if
 + * appropriate.
 + *
 +*/
 +
 +void BMO_push(BMesh *bm, BMOperator *op)
 +{
 +      bm->stackdepth++;
 +
 +      /*add flag layer, if appropriate*/
 +      if (bm->stackdepth > 1)
 +              alloc_flag_layer(bm);
 +      else
 +              clear_flag_layer(bm);
 +}
 +
 +/*
 + * BMESH OPSTACK POP
 + *
 + * Pops the opstack one level  
 + * and frees a flag layer if appropriate
 + * TODO: investigate NOT freeing flag
 + * layers.
 + *
 +*/
 +void BMO_pop(BMesh *bm)
 +{
 +      if(bm->stackdepth > 1)
 +              free_flag_layer(bm);
 +
 +      bm->stackdepth--;
 +}
 +
 +/*
 + * BMESH OPSTACK INIT OP
 + *
 + * Initializes an operator structure  
 + * to a certain type
 + *
 +*/
 +
 +void BMO_Init_Op(BMOperator *op, int opcode)
 +{
 +      int i;
 +
 +      memset(op, 0, sizeof(BMOperator));
 +      op->type = opcode;
 +      
 +      /*initialize the operator slot types*/
 +      for(i = 0; i < opdefines[opcode]->totslot; i++) {
 +              op->slots[i].slottype = opdefines[opcode]->slottypes[i];
 +              op->slots[i].index = i;
 +      }
 +
 +      /*callback*/
 +      op->exec = opdefines[opcode]->exec;
 +
 +      /*memarena, used for operator's slot buffers*/
 +      op->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
 +      BLI_memarena_use_calloc (op->arena);
 +}
 +
 +/*
 + *    BMESH OPSTACK EXEC OP
 + *
 + *  Executes a passed in operator. This handles
 + *  the allocation and freeing of temporary flag
 + *  layers and starting/stopping the modelling
 + *  loop. Can be called from other operators
 + *  exec callbacks as well.
 + * 
 +*/
 +
 +void BMO_Exec_Op(BMesh *bm, BMOperator *op)
 +{
 +      
 +      BMO_push(bm, op);
 +
 +      if(bm->stackdepth == 1)
 +              bmesh_begin_edit(bm);
 +      op->exec(bm, op);
 +      
 +      if(bm->stackdepth == 1)
 +              bmesh_end_edit(bm,0);
 +      
 +      BMO_pop(bm);    
 +}
 +
 +/*
 + *  BMESH OPSTACK FINISH OP
 + *
 + *  Does housekeeping chores related to finishing
 + *  up an operator.
 + *
 +*/
 +
 +void BMO_Finish_Op(BMesh *bm, BMOperator *op)
 +{
 +      BMOpSlot *slot;
 +      int i;
 +
 +      for (i=0; i<opdefines[op->type]->totslot; i++) {
 +              slot = &op->slots[i];
 +              if (slot->slottype == BMOP_OPSLOT_MAPPING) {
 +                      if (slot->data.ghash) 
 +                              BLI_ghash_free(slot->data.ghash, NULL, NULL);
 +              }
 +      }
 +
 +      BLI_memarena_free(op->arena);
 +}
 +
 +/*
 + * BMESH OPSTACK GET SLOT
 + *
 + * Returns a pointer to the slot of  
 + * type 'slotcode'
 + *
 +*/
 +
 +BMOpSlot *BMO_GetSlot(BMOperator *op, int slotcode)
 +{
 +      return &(op->slots[slotcode]);
 +}
 +
 +/*
 + * BMESH OPSTACK COPY SLOT
 + *
 + * Copies data from one slot to another 
 + *
 +*/
 +
 +void BMO_CopySlot(BMOperator *source_op, BMOperator *dest_op, int src, int dst)
 +{
 +      BMOpSlot *source_slot = &source_op->slots[src];
 +      BMOpSlot *dest_slot = &dest_op->slots[dst];
 +
 +      if(source_slot == dest_slot)
 +              return;
 +
 +      if(source_slot->slottype != dest_slot->slottype)
 +              return;
 +      
 +      if (dest_slot->slottype > BMOP_OPSLOT_VEC) {
 +              if (dest_slot->slottype != BMOP_OPSLOT_MAPPING) {
 +                      /*do buffer copy*/
 +                      dest_slot->data.buf = NULL;
 +                      dest_slot->len = source_slot->len;
 +                      if(dest_slot->len){
 +                              dest_slot->data.buf = BLI_memarena_alloc(dest_op->arena, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len);
 +                              memcpy(dest_slot->data.buf, source_slot->data.buf, BMOP_OPSLOT_TYPEINFO[dest_slot->slottype] * dest_slot->len);
 +                      }
 +              } else {
 +                      GHashIterator it;
 +                      element_mapping *srcmap, *dstmap;
 +
 +                      /*sanity check*/
 +                      if (!source_slot->data.ghash) return;
 +                      
 +                      if (!dest_slot->data.ghash) {
 +                              dest_slot->data.ghash = 
 +                                    BLI_ghash_new(BLI_ghashutil_ptrhash, 
 +                                    BLI_ghashutil_ptrcmp);
 +                      }
 +
 +                      BLI_ghashIterator_init(&it, source_slot->data.ghash);
 +                      for (;srcmap=BLI_ghashIterator_getValue(&it);
 +                            BLI_ghashIterator_step(&it))
 +                      {
 +                              dstmap = BLI_memarena_alloc(dest_op->arena, 
 +                                          sizeof(*dstmap) + srcmap->len);
 +
 +                              dstmap->element = srcmap->element;
 +                              dstmap->len = srcmap->len;
 +                              memcpy(dstmap+1, srcmap+1, srcmap->len);
 +                              
 +                              BLI_ghash_insert(dest_slot->data.ghash, 
 +                                              dstmap->element, dstmap);                               
 +                      }
 +              }
 +      } else {
 +              dest_slot->data = source_slot->data;
 +      }
 +}
 +
 +/*
 + * BMESH OPSTACK SET XXX
 + *
 + * Sets the value of a slot depending on it's type
 + *
 +*/
 +
 +
 +void BMO_Set_Float(BMOperator *op, int slotcode, float f)
 +{
 +      if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_FLT) )
 +              return;
 +      op->slots[slotcode].data.f = f;
 +}
 +
 +void BMO_Set_Int(BMOperator *op, int slotcode, int i)
 +{
 +      if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_INT) )
 +              return;
 +      op->slots[slotcode].data.i = i;
 +
 +}
 +
 +
 +void BMO_Set_Pnt(BMOperator *op, int slotcode, void *p)
 +{
 +      if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_PNT) )
 +              return;
 +      op->slots[slotcode].data.p = p;
 +}
 +
 +void BMO_Set_Vec(BMOperator *op, int slotcode, float *vec)
 +{
 +      if( !(op->slots[slotcode].slottype == BMOP_OPSLOT_VEC) )
 +              return;
 +
 +      VECCOPY(op->slots[slotcode].data.vec, vec);
 +}
 +
 +/*
 + * BMO_SETFLAG
 + *
 + * Sets a flag for a certain element
 + *
 +*/
 +void BMO_SetFlag(BMesh *bm, void *element, int flag)
 +{
 +      BMHeader *head = element;
 +      head->flags[bm->stackdepth-1].mask |= flag;
 +}
 +
 +/*
 + * BMO_CLEARFLAG
 + *
 + * Clears a specific flag from a given element
 + *
 +*/
 +
 +void BMO_ClearFlag(BMesh *bm, void *element, int flag)
 +{
 +      BMHeader *head = element;
 +      head->flags[bm->stackdepth-1].mask &= ~flag;
 +}
 +
 +/*
 + * BMO_TESTFLAG
 + *
 + * Tests whether or not a flag is set for a specific element
 + *
 + *
 +*/
 +
 +int BMO_TestFlag(BMesh *bm, void *element, int flag)
 +{
 +      BMHeader *head = element;
 +      if(head->flags[bm->stackdepth-1].mask & flag)
 +              return 1;
 +      return 0;
 +}
 +
 +/*
 + * BMO_COUNTFLAG
 + *
 + * Counts the number of elements of a certain type that
 + * have a specific flag set.
 + *
 +*/
 +
 +int BMO_CountFlag(BMesh *bm, int flag, int type)
 +{
 +      BMIter elements;
 +      BMHeader *e;
 +      int count = 0;
 +
 +      if(type & BM_VERT){
 +              for(e = BMIter_New(&elements, bm, BM_VERTS, bm); e; e = BMIter_Step(&elements)){
 +                      if(BMO_TestFlag(bm, e, flag))
 +                              count++;
 +              }
 +      }
 +      if(type & BM_EDGE){
 +              for(e = BMIter_New(&elements, bm, BM_EDGES, bm); e; e = BMIter_Step(&elements)){
 +                      if(BMO_TestFlag(bm, e, flag))
 +                              count++;
 +              }
 +      }
 +      if(type & BM_FACE){
 +              for(e = BMIter_New(&elements, bm, BM_FACES, bm); e; e = BMIter_Step(&elements)){
 +                      if(BMO_TestFlag(bm, e, flag))
 +                              count++;
 +              }
 +      }
 +
 +      return count;   
 +}
 +
 +int BMO_CountSlotBuf(struct BMesh *bm, struct BMOperator *op, int slotcode)
 +{
 +      BMOpSlot *slot = &op->slots[slotcode];
 +      
 +      /*check if its actually a buffer*/
 +      if( !(slot->slottype > BMOP_OPSLOT_VEC) )
 +              return 0;
 +
 +      return slot->len;
 +}
 +
 +#if 0
 +void *BMO_Grow_Array(BMesh *bm, BMOperator *op, int slotcode, int totadd) {
 +      BMOpSlot *slot = &op->slots[slotcode];
 +      void *tmp;
 +      
 +      /*check if its actually a buffer*/
 +      if( !(slot->slottype > BMOP_OPSLOT_VEC) )
 +              return NULL;
 +
 +      if (slot->flag & BMOS_DYNAMIC_ARRAY) {
 +              if (slot->len >= slot->size) {
 +                      slot->size = (slot->size+1+totadd)*2;
 +
 +                      tmp = slot->data.buf;
 +                      slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * slot->size, "opslot dynamic array");
 +                      memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * slot->size);
 +                      MEM_freeN(tmp);
 +              }
 +
 +              slot->len += totadd;
 +      } else {
 +              slot->flag |= BMOS_DYNAMIC_ARRAY;
 +              slot->len += totadd;
 +              slot->size = slot->len+2;
 +              tmp = slot->data.buf;
 +              slot->data.buf = MEM_callocN(BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * slot->len, "opslot dynamic array");
 +              memcpy(slot->data.buf, tmp, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * slot->len);
 +      }
 +
 +      return slot->data.buf;
 +}
 +#endif
 +
 +void BMO_Insert_Mapping(BMesh *bm, BMOperator *op, int slotcode, 
 +                      void *element, void *data, int len) {
 +      element_mapping *mapping;
 +      BMOpSlot *slot = &op->slots[slotcode];
 +
 +      /*sanity check*/
 +      if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
 +      
 +      mapping = BLI_memarena_alloc(op->arena, sizeof(*mapping) + len);
 +
 +      mapping->element = element;
 +      mapping->len = len;
 +      memcpy(mapping+1, data, len);
 +
 +      if (!slot->data.ghash) {
 +              slot->data.ghash = BLI_ghash_new(BLI_ghashutil_ptrhash, 
 +                                                   BLI_ghashutil_ptrcmp);
 +      }
 +      
 +      BLI_ghash_insert(slot->data.ghash, element, mapping);
 +}
 +
 +void BMO_Mapping_To_Flag(struct BMesh *bm, struct BMOperator *op, 
 +                       int slotcode, int flag)
 +{
 +      GHashIterator it;
 +      BMOpSlot *slot = &op->slots[slotcode];
 +      BMHeader *ele;
 +
 +      /*sanity check*/
 +      if (slot->slottype != BMOP_OPSLOT_MAPPING) return;
 +      if (!slot->data.ghash) return;
 +
 +      BLI_ghashIterator_init(&it, slot->data.ghash);
 +      for (;ele=BLI_ghashIterator_getKey(&it);BLI_ghashIterator_step(&it)) {
 +              BMO_SetFlag(bm, ele, flag);
 +      }
 +}
 +
 +void BMO_Insert_MapFloat(BMesh *bm, BMOperator *op, int slotcode, 
 +                      void *element, float val)
 +{
 +      BMO_Insert_Mapping(bm, op, slotcode, element, &val, sizeof(float));
 +}
 +
 +void BMO_Insert_MapPointer(BMesh *bm, BMOperator *op, int slotcode, 
 +                      void *element, void *val)
 +{
 +      BMO_Insert_Mapping(bm, op, slotcode, element, &val, sizeof(void*));
 +}
 +
 +int BMO_InMap(BMesh *bm, BMOperator *op, int slotcode, void *element)
 +{
 +      BMOpSlot *slot = &op->slots[slotcode];
 +
 +      /*sanity check*/
 +      if (slot->slottype != BMOP_OPSLOT_MAPPING) return 0;
 +      if (!slot->data.ghash) return 0;
 +
 +      return BLI_ghash_haskey(slot->data.ghash, element);
 +}
 +
 +void *BMO_Get_MapData(BMesh *bm, BMOperator *op, int slotcode,
 +                    void *element)
 +{
 +      element_mapping *mapping;
 +      BMOpSlot *slot = &op->slots[slotcode];
 +
 +      /*sanity check*/
 +      if (slot->slottype != BMOP_OPSLOT_MAPPING) return NULL;
 +      if (!slot->data.ghash) return NULL;
 +
 +      mapping = BLI_ghash_lookup(slot->data.ghash, element);
 +      
 +      if (!mapping) return NULL;
 +
 +      return mapping + 1;
 +}
 +
 +float BMO_Get_MapFloat(BMesh *bm, BMOperator *op, int slotcode,
 +                     void *element)
 +{
 +      float *val = BMO_Get_MapData(bm, op, slotcode, element);
 +      if (val) return *val;
 +
 +      return 0.0f;
 +}
 +
 +void *BMO_Get_MapPointer(BMesh *bm, BMOperator *op, int slotcode,
 +                     void *element)
 +{
 +      void **val = BMO_Get_MapData(bm, op, slotcode, element);
 +      if (val) return *val;
 +
 +      return NULL;
 +}
 +
 +static void *alloc_slot_buffer(BMOperator *op, int slotcode, int len){
 +
 +      /*check if its actually a buffer*/
 +      if( !(op->slots[slotcode].slottype > BMOP_OPSLOT_VEC) )
 +              return NULL;
 +      
 +      op->slots[slotcode].len = len;
 +      if(len)
 +              op->slots[slotcode].data.buf = BLI_memarena_alloc(op->arena, BMOP_OPSLOT_TYPEINFO[opdefines[op->type]->slottypes[slotcode]] * len);
 +      return op->slots[slotcode].data.buf;
 +}
 +
 +/*
 + *
 + * BMO_HEADERFLAG_TO_SLOT
 + *
 + * Copies elements of a certain type, which have a certain header flag set 
 + * into an output slot for an operator.
 + *
 +*/
 +
 +void BMO_HeaderFlag_To_Slot(BMesh *bm, BMOperator *op, int slotcode, int flag, int type)
 +{
 +      BMIter elements;
 +      BMHeader *e;
 +      BMOpSlot *output = BMO_GetSlot(op, slotcode);
 +      int totelement=0, i=0;
 +      
 +      totelement = BM_CountFlag(bm, type, BM_SELECT);
 +
 +      if(totelement){
 +              alloc_slot_buffer(op, slotcode, totelement);
 +
 +              if (type & BM_VERT) {
 +                      for (e = BMIter_New(&elements, bm, BM_VERTS, bm); e; e = BMIter_Step(&elements)) {
 +                              if(e->flag & flag) {
 +                                      ((BMHeader**)output->data.p)[i] = e;
 +                                      i++;
 +                              }
 +                      }
 +              }
 +
 +              if (type & BM_EDGE) {
 +                      for (e = BMIter_New(&elements, bm, BM_EDGES, bm); e; e = BMIter_Step(&elements)) {
 +                              if(e->flag & flag){
 +                                      ((BMHeader**)output->data.p)[i] = e;
 +                                      i++;
 +                              }
 +                      }
 +              }
 +
 +              if (type & BM_FACE) {
 +                      for (e = BMIter_New(&elements, bm, BM_FACES, bm); e; e = BMIter_Step(&elements)) {
 +                              if(e->flag & flag){
 +                                      ((BMHeader**)output->data.p)[i] = e;
 +                                      i++;
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +/*
 + *
 + * BMO_FLAG_TO_SLOT
 + *
 + * Copies elements of a certain type, which have a certain flag set 
 + * into an output slot for an operator.
 + *
 +*/
 +void BMO_Flag_To_Slot(BMesh *bm, BMOperator *op, int slotcode, int flag, int type)
 +{
 +      BMIter elements;
 +      BMHeader *e;
 +      BMOpSlot *output = BMO_GetSlot(op, slotcode);
 +      int totelement = BMO_CountFlag(bm, flag, type), i=0;
 +
 +      if(totelement){
 +              alloc_slot_buffer(op, slotcode, totelement);
 +
 +              if (type & BM_VERT) {
 +                      for (e = BMIter_New(&elements, bm, BM_VERTS, bm); e; e = BMIter_Step(&elements)) {
 +                              if(BMO_TestFlag(bm, e, flag)){
 +                                      ((BMHeader**)output->data.p)[i] = e;
 +                                      i++;
 +                              }
 +                      }
 +              }
 +
 +              if (type & BM_EDGE) {
 +                      for (e = BMIter_New(&elements, bm, BM_EDGES, bm); e; e = BMIter_Step(&elements)) {
 +                              if(BMO_TestFlag(bm, e, flag)){
 +                                      ((BMHeader**)output->data.p)[i] = e;
 +                                      i++;
 +                              }
 +                      }
 +              }
 +
 +              if (type & BM_FACE) {
 +                      for (e = BMIter_New(&elements, bm, BM_FACES, bm); e; e = BMIter_Step(&elements)) {
 +                              if(BMO_TestFlag(bm, e, flag)){
 +                                      ((BMHeader**)output->data.p)[i] = e;
 +                                      i++;
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +/*
 + *
 + * BMO_FLAG_BUFFER
 + *
 + * Flags elements in a slots buffer
 + *
 +*/
 +
 +void BMO_Flag_Buffer(BMesh *bm, BMOperator *op, int slotcode, int flag)
 +{
 +      BMOpSlot *slot = BMO_GetSlot(op, slotcode);
 +      BMHeader **data =  slot->data.p;
 +      int i;
 +      
 +      for(i = 0; i < slot->len; i++)
 +              BMO_SetFlag(bm, data[i], flag);
 +}
 +
 +/*
 + *
 + * BMO_FLAG_BUFFER
 + *
 + * Removes flags from elements in a slots buffer
 + *
 +*/
 +
 +void BMO_Unflag_Buffer(BMesh *bm, BMOperator *op, int slotcode, int flag)
 +{
 +      BMOpSlot *slot = BMO_GetSlot(op, slotcode);
 +      BMHeader **data =  slot->data.p;
 +      int i;
 +      
 +      for(i = 0; i < slot->len; i++)
 +              BMO_ClearFlag(bm, data[i], flag);
 +}
 +
 +
 +/*
 + *
 + *    ALLOC/FREE FLAG LAYER
 + *
 + *  Used by operator stack to free/allocate 
 + *  private flag data. This is allocated
 + *  using a mempool so the allocation/frees
 + *  should be quite fast.
 + *
 + *  TODO:
 + *    Investigate not freeing flag layers until
 + *  all operators have been executed. This would
 + *  save a lot of realloc potentially.
 + *
 +*/
 +
 +static void alloc_flag_layer(BMesh *bm)
 +{
 +      BMVert *v;
 +      BMEdge *e;
 +      BMFace *f;
 +
 +      BMIter verts;
 +      BMIter edges;
 +      BMIter faces;
 +      BLI_mempool *oldpool = bm->flagpool;            /*old flag pool*/
 +      void *oldflags;
 +      
 +      /*allocate new flag pool*/
 +      bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer)*(bm->totflags+1), 512, 512 );
 +      
 +      /*now go through and memcpy all the flags. Loops don't get a flag layer at this time...*/
 +      for(v = BMIter_New(&verts, bm, BM_VERTS, bm); v; v = BMIter_Step(&verts)){
 +              oldflags = v->head.flags;
 +              v->head.flags = BLI_mempool_calloc(bm->flagpool);
 +              memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags); /*dont know if this memcpy usage is correct*/
 +      }
 +      for(e = BMIter_New(&edges, bm, BM_EDGES, bm); e; e = BMIter_Step(&edges)){
 +              oldflags = e->head.flags;
 +              e->head.flags = BLI_mempool_calloc(bm->flagpool);
 +              memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
 +      }
 +      for(f = BMIter_New(&faces, bm, BM_FACES, bm); f; f = BMIter_Step(&faces)){
 +              oldflags = f->head.flags;
 +              f->head.flags = BLI_mempool_calloc(bm->flagpool);
 +              memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
 +      }
 +      bm->totflags++;
 +      BLI_mempool_destroy(oldpool);
 +}
 +
 +static void free_flag_layer(BMesh *bm)
 +{
 +      BMVert *v;
 +      BMEdge *e;
 +      BMFace *f;
 +
 +      BMIter verts;
 +      BMIter edges;
 +      BMIter faces;
 +      BLI_mempool *oldpool = bm->flagpool;
 +      void *oldflags;
 +      
 +      /*de-increment the totflags first...*/
 +      bm->totflags--;
 +      /*allocate new flag pool*/
 +      bm->flagpool = BLI_mempool_create(sizeof(BMFlagLayer)*bm->totflags, 512, 512);
 +      
 +      /*now go through and memcpy all the flags*/
 +      for(v = BMIter_New(&verts, bm, BM_VERTS, bm); v; v = BMIter_Step(&verts)){
 +              oldflags = v->head.flags;
 +              v->head.flags = BLI_mempool_calloc(bm->flagpool);
 +              memcpy(v->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);  /*correct?*/
 +      }
 +      for(e = BMIter_New(&edges, bm, BM_EDGES, bm); e; e = BMIter_Step(&edges)){
 +              oldflags = e->head.flags;
 +              e->head.flags = BLI_mempool_calloc(bm->flagpool);
 +              memcpy(e->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
 +      }
 +      for(f = BMIter_New(&faces, bm, BM_FACES, bm); f; f = BMIter_Step(&faces)){
 +              oldflags = f->head.flags;
 +              f->head.flags = BLI_mempool_calloc(bm->flagpool);
 +              memcpy(f->head.flags, oldflags, sizeof(BMFlagLayer)*bm->totflags);
 +      }
 +
 +      BLI_mempool_destroy(oldpool);
 +}
 +
 +static void clear_flag_layer(BMesh *bm)
 +{
 +      BMVert *v;
 +      BMEdge *e;
 +      BMFace *f;
 +      
 +      BMIter verts;
 +      BMIter edges;
 +      BMIter faces;
 +      
 +      /*now go through and memcpy all the flags*/
 +      for(v = BMIter_New(&verts, bm, BM_VERTS, bm); v; v = BMIter_Step(&verts)){
 +              memset(v->head.flags+bm->totflags-1, 0, sizeof(BMFlagLayer));
 +      }
 +      for(e = BMIter_New(&edges, bm, BM_EDGES, bm); e; e = BMIter_Step(&edges)){
 +              memset(e->head.flags+bm->totflags-1, 0, sizeof(BMFlagLayer));
 +      }
 +      for(f = BMIter_New(&faces, bm, BM_FACES, bm); f; f = BMIter_Step(&faces)){
 +              memset(f->head.flags+bm->totflags-1, 0, sizeof(BMFlagLayer));
 +      }
 +}
 +
 +void *BMO_IterNew(BMOIter *iter, BMesh *bm, BMOperator *op, 
 +                int slotcode)
 +{
 +      BMOpSlot *slot = &op->slots[slotcode];
 +
 +      iter->slot = slot;
 +      iter->cur = 0;
 +
 +      if (iter->slot->slottype == BMOP_OPSLOT_MAPPING)
 +              if (iter->slot->data.ghash)
 +                      BLI_ghashIterator_init(&iter->giter, slot->data.ghash);
 +
 +      return BMO_IterStep(iter);
 +}
 +
 +void *BMO_IterStep(BMOIter *iter)
 +{
 +      if (iter->slot->slottype == BMOP_OPSLOT_PNT_BUF) {
 +              if (iter->cur >= iter->slot->len) return NULL;
 +
 +              return ((void**)iter->slot->data.buf)[iter->cur++];
 +      } else if (iter->slot->slottype == BMOP_OPSLOT_MAPPING) {
 +              struct element_mapping *map; 
 +              void *ret = BLI_ghashIterator_getKey(&iter->giter);
 +              map = BLI_ghashIterator_getValue(&iter->giter);
 +              
 +              iter->val = map + 1;
 +
 +              BLI_ghashIterator_step(&iter->giter);
 +
 +              return ret;
 +      }
 +
 +      return NULL;
 +}
 +
 +/*used for iterating over mappings*/
 +void *BMO_IterMapVal(BMOIter *iter)
 +{
 +      return iter->val;
 +}
++
++
++/*error system*/
++typedef struct bmop_error {
++       struct bmop_error *next, *prev;
++       int errorcode;
++       BMOperator *op;
++       char *msg;
++} bmop_error;
++
++void BMO_ClearStack(BMesh *bm)
++{
++      while (BMO_PopError(bm, NULL, NULL));
++}
++
++void BMO_RaiseError(BMesh *bm, BMOperator *owner, int errcode, char *msg)
++{
++      bmop_error *err = MEM_callocN(sizeof(bmop_error), "bmop_error");
++      
++      err->errorcode = errcode;
++      err->msg = msg;
++      err->op = owner;
++      
++      BLI_addhead(&bm->errorstack, err);
++}
++
++/*returns error code or 0 if no error*/
++int BMO_GetError(BMesh *bm, char **msg, BMOperator **op)
++{
++      bmop_error *err = bm->errorstack.first;
++      if (!err) return 0;
++
++      if (msg) *msg = err->msg;
++      if (op) *op = err->op;
++      
++      return err->errorcode;
++}
++
++int BMO_PopError(BMesh *bm, char **msg, BMOperator **op)
++{
++      int errorcode = BMO_GetError(bm, msg, op);
++      
++      if (errorcode) {
++              bmop_error *err = bm->errorstack.first;
++              
++              BLI_remlink(&bm->errorstack, &bm->errorstack.first);
++              MEM_freeN(err);
++      }
++
++      return errorcode;
++}
index b5a65932743a9d1f62c9c2a55d512843dafc04d6,0000000000000000000000000000000000000000..1bf9f7daa081afc513f84ec9f618d905addd5dc2
mode 100644,000000..100644
--- /dev/null
@@@ -1,414 -1,0 +1,491 @@@
-               *area = atmp / 2.0;     
 +#include "bmesh.h"
 +#include "bmesh_private.h"
 +
 +#include "BLI_arithb.h"
 +#include "BKE_utildefines.h"
 +#include <string.h>
 +
 +/*
 + *
 + * BME POLYGON.C
 + *
 + * This file contains code for dealing
 + * with polygons (normal/area calculation,
 + * tesselation, ect)
 + *
 + * TODO:
 + *   -Add in Tesselator frontend that creates
 + *     BMTriangles from copied faces
 + *  -Add in Function that checks for and flags
 + *   degenerate faces.
 + *
 +*/
 +
 +/*
 + * TEST EDGE SIDE and POINT IN TRIANGLE
 + *
 + * Point in triangle tests stolen from scanfill.c.
 + * Used for tesselator
 + *
 +*/
 +
 +static short testedgeside(float *v1, float *v2, float *v3)
 +/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
 +{
 +      float inp;
 +
 +      //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
 +      inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]);
 +
 +      if(inp<0.0) return 0;
 +      else if(inp==0) {
 +              if(v1[0]==v3[0] && v1[1]==v3[1]) return 0;
 +              if(v2[0]==v3[0] && v2[1]==v3[1]) return 0;
 +      }
 +      return 1;
 +}
 +
 +static int point_in_triangle(float *v1, float *v2, float *v3, float *pt)
 +{
 +      if(testedgeside(v1,v2,pt) && testedgeside(v2,v3,pt) && testedgeside(v3,v1,pt))
 +              return 1;
 +      return 0;
 +}
 +
 +/*
 + * CONVEX ANGLE 
 + *
 + * Tests whether or not a given angle in
 + * a polygon is convex or not. Note that 
 + * this assumes that the polygon has been
 + * projected to the x/y plane
 + *
 +*/
 +static int convexangle(float *v1t, float *v2t, float *v3t)
 +{
 +      float v1[3], v3[3], n[3];
 +      VecSubf(v1, v1t, v2t);
 +      VecSubf(v3, v3t, v2t);
 +
 +      Normalize(v1);
 +      Normalize(v3);
 +      Crossf(n, v1, v3);
 +      
 +      if(n[2] < 0.0)
 +              return 0;
 +
 +      return 1;
 +}
 +
 +/*
 + * COMPUTE POLY NORMAL
 + *
 + * Computes the normal of a planar 
 + * polygon See Graphics Gems for 
 + * computing newell normal.
 + *
 +*/
 +static void compute_poly_normal(float normal[3], float (*verts)[3], int nverts)
 +{
 +
 +      float *u,  *v;
 +      int i;
 +
 +      normal[0] = 0.0;
 +      normal[1] = 0.0;
 +      normal[2] = 0.0;
 +      
 +      for(i = 0; i < nverts; i++){
 +              u = verts[i];
 +              v = verts[(i+1) % nverts];
 +              
 +              normal[0] += (u[1] - v[1]) * (u[2] + v[2]);
 +              normal[1] += (u[2] - v[2]) * (u[0] + v[0]);
 +              normal[2] += (u[0] - v[0]) * (u[1] + v[1]);
 +              i++;
 +      }
 +
 +      Normalize(normal);
 +}
 +
 +/*
 + * COMPUTE POLY CENTER
 + *
 + * Computes the centroid and
 + * area of a polygon in the X/Y
 + * plane.
 + *
 +*/
 +
 +static int compute_poly_center(float center[3], float *area, float (*verts)[3], int nverts)
 +{
 +      int i, j;
 +      float atmp = 0.0, xtmp = 0.0, ytmp = 0.0, ai;
 +      
 +      center[0] = center[1] = center[2] = 0.0;        
 +
 +      if(nverts < 3) 
 +              return 0;
 +
 +      i = nverts-1;
 +      j = 0;
 +      
 +      while(j < nverts){
 +              ai = verts[i][0] * verts[j][1] - verts[j][0] * verts[i][1];                             
 +              atmp += ai;
 +              xtmp += (verts[j][0] + verts[i][0]) * ai;
 +              ytmp += (verts[j][1] + verts[i][1]) * ai;
 +              i = j;
 +              j += 1;
 +      }
 +
 +      if(area)
-               center[0] = xtmp /  (3.0 * atmp);
-               center[1] = xtmp /  (3.0 * atmp);
++              *area = atmp / 2.0f;    
 +      
 +      if (atmp != 0){
- static BMLoop *find_ear(BMFace *f, float (*verts)[3])
++              center[0] = xtmp /  (3.0f * atmp);
++              center[1] = xtmp /  (3.0f * atmp);
 +              return 1;
 +      }
 +      return 0;
 +}
 +
 +
 +/*
 + * COMPUTE POLY PLANE
 + *
 + * Projects a set polygon's vertices to 
 + * a plane defined by the average
 + * of its edges cross products
 + *
 +*/
 +
 +void compute_poly_plane(float (*verts)[3], int nverts)
 +{
 +      
 +      float avgc[3], norm[3], temp[3], mag, avgn[3];
 +      float *v1, *v2, *v3;
 +      int i;
 +      
 +      if(nverts < 3) 
 +              return;
 +
 +      avgn[0] = avgn[1] = avgn[2] = 0.0;
 +      avgc[0] = avgc[1] = avgc[2] = 0.0;
 +
 +      for(i = 0; i < nverts; i++){
 +              v1 = verts[i];
 +              v2 = verts[(i+1) % nverts];
 +              v3 = verts[(i+2) % nverts];
 +              CalcNormFloat(v1, v2, v3, norm);        
 +      
 +              avgn[0] += norm[0];
 +              avgn[1] += norm[1];
 +              avgn[2] += norm[2];
 +      }
 +
 +      /*what was this bit for?*/
 +      if(avgn[0] == 0.0 && avgn[1] == 0.0 && avgn[2] == 0.0){
 +              avgn[0] = 0.0;
 +              avgn[1] = 0.0;
 +              avgn[2] = 1.0;
 +      } else {
 +              avgn[0] /= nverts;
 +              avgn[1] /= nverts;
 +              avgn[2] /= nverts;
 +              Normalize(avgn);
 +      }
 +      
 +      for(i = 0; i < nverts; i++){
 +              v1 = verts[i];
 +              VECCOPY(temp, v1);
 +              mag = 0.0;
 +              mag += (temp[0] * avgn[0]);
 +              mag += (temp[1] * avgn[1]);
 +              mag += (temp[2] * avgn[2]);
 +              
 +              temp[0] = (avgn[0] * mag);
 +              temp[1] = (avgn[1] * mag);
 +              temp[2] = (avgn[2] * mag);
 +
 +              VecSubf(v1, v1, temp);
 +      }       
 +}
 +
 +/*
 + * POLY ROTATE PLANE
 + *
 + * Rotates a polygon so that it's
 + * normal is pointing towards the mesh Z axis
 + *
 +*/
 +
 +void poly_rotate_plane(float normal[3], float (*verts)[3], int nverts)
 +{
 +
 +      float up[3] = {0.0,0.0,1.0}, axis[3], angle, q[4];
 +      float mat[3][3];
 +      int i;
 +
 +      Crossf(axis, up, normal);
 +      angle = VecAngle2(normal, up);
++
++      if (angle == 0.0) return;
 +      
 +      AxisAngleToQuat(q, axis, angle);
 +      QuatToMat3(q, mat);
 +
 +      for(i = 0;  i < nverts;  i++)
 +              Mat3MulVecfl(mat, verts[i]);
 +}
 +
 +/*
 + * BMESH UPDATE FACE NORMAL
 + *
 + * Updates the stored normal for the
 + * given face. Requires that a buffer
 + * of sufficient length to store projected
 + * coordinates for all of the face's vertices
 + * is passed in as well.
 + *
 +*/
 +
 +void bmesh_update_face_normal(BMesh *bm, BMFace *f, float (*projectverts)[3])
 +{
 +      BMLoop *l;
 +      int i;
 +
 +      if(f->len > 4){
 +              i = 0;
 +              l = f->loopbase;
 +              do{
 +                      VECCOPY(projectverts[i], l->v->co);
 +                      l = (BMLoop*)(l->head.next);
 +              }while(l!=f->loopbase);
 +
 +              compute_poly_plane(projectverts, f->len);
 +              compute_poly_normal(f->no, projectverts, f->len);       
 +      }
 +      else if(f->len == 3){
 +              BMVert *v1, *v2, *v3;
 +              v1 = f->loopbase->v;
 +              v2 = ((BMLoop*)(f->loopbase->head.next))->v;
 +              v3 = ((BMLoop*)(f->loopbase->head.next->next))->v;
 +              CalcNormFloat(v1->co, v2->co, v3->co, f->no);
 +      }
 +      else if(f->len == 4){
 +              BMVert *v1, *v2, *v3, *v4;
 +              v1 = f->loopbase->v;
 +              v2 = ((BMLoop*)(f->loopbase->head.next))->v;
 +              v3 = ((BMLoop*)(f->loopbase->head.next->next))->v;
 +              v4 = ((BMLoop*)(f->loopbase->head.prev))->v;
 +              CalcNormFloat4(v1->co, v2->co, v3->co, v4->co, f->no);
 +      }
 +      else{ /*horrible, two sided face!*/
 +              f->no[0] = 0.0;
 +              f->no[1] = 0.0;
 +              f->no[2] = 1.0;
 +      }
 +
 +}
 +
 +
 +/*
 + * BMESH FLIP NORMAL
 + * 
 + *  Reverses the winding of a  faces
 + *  Note that this does *not* update the calculated 
 + *  Normal 
 +*/
 +void BM_flip_normal(BMesh *bm, BMFace *f)
 +{     
 +      bmesh_loop_reverse(bm, f);
 +}
 +
 +
 +
++int winding(float *a, float *b, float *c)
++{
++      float v1[3], v2[3], v[3];
++      
++      VecSubf(v1, b, a);
++      VecSubf(v2, b, c);
++      
++      v1[2] = 0;
++      v2[2] = 0;
++      
++      Normalize(v1);
++      Normalize(v2);
++      
++      Crossf(v, v1, v2);
++      return !!(v[2] > 0);
++}
++
++/* detects if two line segments cross each other (intersects).
++   note, there could be more winding cases then there needs to be. */
++int linecrosses(float *v1, float *v2, float *v3, float *v4)
++{
++      int w1, w2, w3, w4, w5;
++
++      w1 = winding(v1, v3, v2);
++      w2 = winding(v2, v4, v1);
++      w3 = !winding(v1, v2, v3);
++      w4 = winding(v3, v2, v4);
++      w5 = !winding(v3, v1, v4);
++      return w1 == w2 && w2 == w3 && w3 == w4 && w4==w5;
++}
++
++int goodline(float (*projectverts)[3], int v1i, int v2i, int nvert)
++{
++      /*the hardcoded stuff here, 200000, 0.999, and 1.0001 may be problems
++        in the future, not sure. - joeedh*/
++      static float outv[3] = {20000000.0f, 20000000.0f, 0.0f};
++      float v1[3], v2[3], p[3], vv1[3], vv2[3], mid[3], a[3], b[3];
++      int i = 0, lcount=0;
++      
++      VECCOPY(v1, projectverts[v1i])
++      VECCOPY(v2, projectverts[v2i])
++      
++      VecAddf(p, v1, v2);
++      VecMulf(p, 0.5f);
++      
++      VecSubf(a, v1, p);
++      VecSubf(b, v2, p);
++      
++      VecMulf(a, 0.999f);
++      VecMulf(b, 0.999f);
++      
++      VecAddf(v1, p, a);
++      VecAddf(v2, p, b);
++      
++      while (i < nvert) {
++              VECCOPY(vv1, projectverts[i]);
++              VECCOPY(vv2, projectverts[(i+1)%nvert]);
++              
++              if (linecrosses(vv1, vv2, v1, v2)) return 0;
++
++              VecAddf(mid, vv1, vv2);
++              VecMulf(mid, 0.5f);
++              
++              VecSubf(a, vv1, mid);
++              VecSubf(b, vv2, mid);
++              
++              VecMulf(a, 1.0001f);
++              VecMulf(b, 1.0001f);
++              
++              VecAddf(vv1, mid, a);
++              VecAddf(vv2, mid, b);
++                              
++              if (linecrosses(vv1, vv2, p, outv)) lcount += 1;
++
++              i += 1;
++      }
++      if ((lcount % 2) == 0) return 0;
++
++      return 1;
++}
++
 +/*
 + * FIND EAR
 + *
 + * Used by tesselator to find
 + * the next triangle to 'clip off'
 + * of a polygon while tesselating.
 + *
 +*/
 +
-       BMLoop *bestear = NULL, *l, *l2;
++static BMLoop *find_ear(BMFace *f, float (*verts)[3], int nvert)
 +{
 +      BMVert *v1, *v2, *v3;
-               if(isear && convexangle(verts[v1->head.eflag2], verts[v2->head.eflag2], verts[v3->head.eflag2])){
-                       for(l2 = ((BMLoop*)(l->head.next->next)); l2 != ((BMLoop*)(l->head.prev)); l2 = ((BMLoop*)(l2->head.next)) ){
-                               if(point_in_triangle(verts[v1->head.eflag2], verts[v2->head.eflag2],verts[v3->head.eflag2], l2->v->co)){
-                                       isear = 0;
-                                       break;
-                               }
-                       }
-               } else isear = 0;
++      BMLoop *bestear = NULL, *l;
 +      float angle, bestangle = 180.0f;
 +      int isear;
 +      
 +      l = f->loopbase;
 +      do{
 +              isear = 1;
 +              
 +              v1 = ((BMLoop*)(l->head.prev))->v;
 +              v2 = l->v;
 +              v3 = ((BMLoop*)(l->head.next))->v;
 +
 +              if (BM_Edge_Exist(v1, v3)) isear = 0;
 +
-       int i, done;
++              if (isear && !goodline(verts, v1->head.eflag2, v3->head.eflag2, nvert)) isear = 0;
 +              if(isear){
 +                      angle = VecAngle3(verts[v1->head.eflag2], verts[v2->head.eflag2], verts[v3->head.eflag2]);
 +                      if(!bestear || angle < bestangle){
 +                              bestear = l;
 +                              bestangle = angle;
 +                      }
 +                      if(angle < 90.0)
 +                              break;
 +              }
 +              l = (BMLoop*)(l->head.next);
 +      }
 +      while(l != f->loopbase);
 +
 +      return bestear;
 +}
 +
 +/*
 + * BMESH TRIANGULATE FACE
 + *
 + * Triangulates a face using a 
 + * simple 'ear clipping' algorithm
 + * that tries to favor non-skinny
 + * triangles (angles less than 
 + * 90 degrees). If the triangulator
 + * has bits left over (or cannot
 + * triangulate at all) it uses an 
 + * arbitrary triangulation.
 + *
 + * TODO:
 + * -Modify this to try and find ears that will not create a non-manifold face after conversion back to editmesh
 + *
 +*/
 +void BM_Triangulate_Face(BMesh *bm, BMFace *f, float (*projectverts)[3], int newedgeflag, int newfaceflag)
 +{
++      int i, done, nvert;
 +      BMLoop *l, *newl, *nextloop;
 +
 +      /*copy vertex coordinates to vertspace array*/
 +      i = 0;
 +      l = f->loopbase;
 +      do{
 +              VECCOPY(projectverts[i], l->v->co);
 +              l->v->head.eflag2 = i; /*warning, abuse! never duplicate in tools code! never you hear?*/ /*actually, get rid of this completely, use a new structure for this....*/
 +              i++;
 +              l = (BMLoop*)(l->head.next);
 +      }while(l != f->loopbase);
 +      
 +      bmesh_update_face_normal(bm, f, projectverts);
 +
 +      compute_poly_plane(projectverts, i);
 +      poly_rotate_plane(f->no, projectverts, i);
-               l = find_ear(f, projectverts);
++      
++      nvert = f->len;
++      
 +      done = 0;
 +      while(!done && f->len > 3){
 +              done = 1;
++              l = find_ear(f, projectverts, nvert);
 +              if(l) {
 +                      done = 0;
 +                      f = bmesh_sfme(bm, f, ((BMLoop*)(l->head.prev))->v, ((BMLoop*)(l->head.next))->v, &newl);
 +                      BMO_SetFlag(bm, newl->e, newedgeflag);
 +                      BMO_SetFlag(bm, f, newfaceflag);
 +              }
 +      }
 +
 +      if (f->len > 3){
 +              l = f->loopbase;
 +              while (l->f->len > 3){
 +                      nextloop = ((BMLoop*)(l->head.next->next));
 +                      bmesh_sfme(bm, l->f, l->v,nextloop->v, &newl);
 +                      BMO_SetFlag(bm, newl->e, newedgeflag);
 +                      BMO_SetFlag(bm, f, newfaceflag);
 +                      l = nextloop;
 +              }
 +      }
 +}
index e06a7f7dd27ec9a0cb5cc03a0920f9eaa51ad3a2,0000000000000000000000000000000000000000..c9e29c9f94a8cc8e5c1fe0ea29a8e644576d2491
mode 100644,000000..100644
--- /dev/null
@@@ -1,110 -1,0 +1,157 @@@
- void dissolvefaces_exec(BMesh *bmesh, BMOperator *op)
 +#include "MEM_guardedalloc.h"
 +
 +#include "BKE_utildefines.h"
 +
 +#include "bmesh.h"
++#include "mesh_intern.h"
 +#include "bmesh_private.h"
 +#include "BLI_arithb.h"
 +
 +#include <stdio.h>
 +
 +#define FACE_MARK     1
 +
 +#define VERT_MARK     1
 +
-       BMO_Flag_Buffer(bmesh, op, BMOP_DISFACES_FACEIN, FACE_MARK);
++void dissolvefaces_exec(BMesh *bm, BMOperator *op)
 +{
++      BMOIter iter;
++      BMIter liter;
++      BMLoop *l;
++      BMFace *f, *f2, *nf = NULL;
++
++      //BMO_Flag_Buffer(bm, op, BMOP_DISFACES_FACEIN, FACE_MARK);
 +
 +      /*TODO: need to discuss with Briggs how best to implement this, seems this would be
 +        a great time to use the walker api, get it up to snuff.  perhaps have a walker
 +        that goes over inner vertices of a contiguously-flagged region?  then you
 +        could just use dissolve disk on them.*/
++      if (BMO_GetSlot(op, BMOP_DISFACES_FACEIN)->len != 2) return;
++
++      /*HACK: for debugging purposes, handle cases of two adjacent faces*/
++      f = BMO_IterNew(&iter, bm, op, BMOP_DISFACES_FACEIN);
++      f2 = BMO_IterStep(&iter);
++
++      for (l=BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);l;l=BMIter_Step(&liter)) {
++              if (!l->radial.next) continue;
++              if (((BMLoop*)l->radial.next->data)->f == f2) {
++                      nf = BM_Join_Faces(bm, f, f2, l->e, 1, 0);
++                      break;
++              }
++      }
++
++      if (nf) {
++              BMO_SetFlag(bm, nf, 1);
++              BMO_Flag_To_Slot(bm, op, BMOP_DISFACES_REGIONOUT, 1, BM_FACE);
++      }
++
++}
++
++/*returns 1 if any faces were dissolved*/
++int BM_DissolveFaces(EditMesh *em, int flag) {
++      BMesh *bm = editmesh_to_bmesh(em);
++      EditMesh *em2;
++      BMOperator op;
++
++      BMO_Init_Op(&op, BMOP_DISSOLVE_FACES);
++      BMO_HeaderFlag_To_Slot(bm, &op, BMOP_DISFACES_FACEIN, flag, BM_FACE);
++      BMO_Exec_Op(bm, &op);
++      BMO_Finish_Op(bm, &op);
++      
++      em2 = bmesh_to_editmesh(bm);
++      set_editMesh(em, em2);
++      MEM_freeN(em2);
++
++      return BMO_GetSlot(&op, BMOP_DISFACES_REGIONOUT)->len > 0;
 +}
 +
 +void dissolveverts_exec(BMesh *bm, BMOperator *op)
 +{
 +      BMOpSlot *vinput;
 +      BMIter iter, liter, fiter;
 +      BMVert *v;
 +      BMFace *f, *f2;
 +      BMEdge *fe;
 +      BMLoop *l;
 +      int found, found2, found3, len, oldlen=0;
 +      
 +      vinput = BMO_GetSlot(op, BMOP_DISVERTS_VERTIN);
 +
 +      BMO_Flag_Buffer(bm, op, BMOP_DISVERTS_VERTIN, VERT_MARK);
 +      
 +      found = 1;
 +      while (found) {
 +              found = 0;
 +              len = 0;
 +              for (v=BMIter_New(&iter, bm, BM_VERTS, NULL); v; v=BMIter_Step(&iter)) {
 +                      if (BMO_TestFlag(bm, v, VERT_MARK)) {
 +                              BM_Dissolve_Disk(bm, v);
 +                              found = 1;
 +                              len++;
 +                      }
 +              }
 +
 +
 +              /*clean up two-edged faces*/
 +              /*basic idea is to keep joining 2-edged faces until their
 +                gone.  this however relies on joining two 2-edged faces
 +                together to work, which doesn't.*/
 +              found3 = 1;
 +              while (found3) {
 +                      found3 = 0;
 +                      for (f=BMIter_New(&iter, bm, BM_FACES, NULL); f; f=BMIter_Step(&iter)){
++                              if (BM_Validate_Face(bm, f, stderr)) {
++                                      printf("error.\n");
++                              }
++
 +                              if (f->len == 2) {
 +                                      //this design relies on join faces working
 +                                      //with two-edged faces properly.
 +                                      //commenting this line disables the
 +                                      //outermost loop.
 +                                      //found3 = 1;
 +                                      found2 = 0;
 +                                      l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
 +                                      fe = l->e;
 +                                      for (; l; l=BMIter_Step(&liter)) {
 +                                              f2 = BMIter_New(&fiter, bm,
 +                                                              BM_FACES_OF_EDGE, l->e);
 +                                              for (; f2; f2=BMIter_Step(&fiter)) {
 +                                                      if (f2 != f) {
 +                                                              BM_Join_Faces(bm, f, f2, l->e, 
 +                                                                            1, 0);
 +                                                              found2 = 1;
 +                                                              break;
 +                                                      }
 +                                              }
 +                                              if (found2) break;
 +                                      }
 +
 +                                      if (!found2) {
 +                                              bmesh_kf(bm, f);
 +                                              bmesh_ke(bm, fe);
 +                                      }
 +                              } /*else if (f->len == 3) {
 +                                      BMEdge *ed[3];
 +                                      BMVert *vt[3];
 +                                      BMLoop *lp[3];
 +                                      int i=0;
 +
 +                                      //check for duplicate edges
 +                                      l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
 +                                      for (; l; l=BMIter_Step(&liter)) {
 +                                              ed[i] = l->e;   
 +                                              lp[i] = l;
 +                                              vt[i++] = l->v;
 +                                      }
 +                                      if (vt[0] == vt[1] || vt[0] == vt[2]) {
 +                                              i += 1;
 +                                      }
 +                              }*/
 +                      }
 +              }
 +              if (oldlen == len) break;
 +              oldlen = len;
 +      }
 +
 +}
index 9759d0905b60241909622a81331dd200c65b4758,8dfb1c20bbe06e87bcc3a833530bf2cb7d4e8488..ca385333d7a05e3dbdee227d2f326d9cf0933b7d
@@@ -1170,11 -1240,9 +1208,12 @@@ static void mouse_anim_channels (bAnimC
                                        agrp->flag |= AGRP_SELECTED;
                                }
                                
 -                              /* if group is selected now, make group the 'active' one in the visible list */
 -                              if (agrp->flag & AGRP_SELECTED)
 -                                      ANIM_set_active_channel(ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
 +                              /* if group is selected now, and we're in Action Editor mode (so that we have pointer to active action),
 +                               * we can make this group the 'active' one in that action
 +                               */
++                              // TODO: we should be able to do this through dopesheet + f-curves editor too...
 +                              if ((agrp->flag & AGRP_SELECTED) && (ac->datatype == ANIMCONT_ACTION))
 +                                      action_set_active_agrp((bAction *)ac->data, agrp);
                        }
                }
                        break;
index 157609ed64055b08b43f774881db12d30b951a3f,328747c7c92d4e243dbbca839e179cb50b399297..9529eb840116183d75507662d669ae0e9b31ee64
@@@ -2085,8 -2224,150 +2224,123 @@@ static int commonkey_modifykey (ListBas
        return success;
  }
  
 -
 -/* Polling callback for use with ANIM_*_keyframe() operators
 - * This is based on the standard ED_operator_areaactive callback,
 - * except that it does special checks for a few spacetypes too...
 - */
 -static int modify_key_op_poll(bContext *C)
 -{
 -      ScrArea *sa= CTX_wm_area(C);
 -      Scene *scene= CTX_data_scene(C);
 -      
 -      /* if no area or active scene */
 -      if (ELEM(NULL, sa, scene)) 
 -              return 0;
 -      
 -      /* if Outliner, only allow in DataBlocks view */
 -      if (sa->spacetype == SPACE_OOPS) {
 -              SpaceOops *so= (SpaceOops *)CTX_wm_space_data(C);
 -              
 -              if ((so->type != SO_OUTLINER) || (so->outlinevis != SO_DATABLOCKS))
 -                      return 0;
 -      }
 -      
 -      /* TODO: checks for other space types can be added here */
 -      
 -      /* should be fine */
 -      return 1;
 -}
 -
  /* Insert Key Operator ------------------------ */
  
 - 
+ /* NOTE:
+  * This is one of the 'simpler new-style' Insert Keyframe operators which relies on Keying Sets.
+  * For now, these are absolute Keying Sets only, so there is very little context info involved.
+  *
+  *    -- Joshua Leung, Feb 2009
+  */
 -      ot->poll= modify_key_op_poll;
++
+ static int insert_key_exec (bContext *C, wmOperator *op)
+ {
+       ListBase dsources = {NULL, NULL};
+       Scene *scene= CTX_data_scene(C);
+       KeyingSet *ks= NULL;
+       float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
+       short success;
+       
+       /* try to get KeyingSet */
+       if (scene->active_keyingset > 0)
+               ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
+       /* report failure */
+       if (ks == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
+               return OPERATOR_CANCELLED;
+       }
+       
+       /* try to insert keyframes for the channels specified by KeyingSet */
+       success= commonkey_modifykey(&dsources, ks, COMMONKEY_MODE_INSERT, cfra);
+       printf("KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success);
+       
+       /* report failure? */
+       if (success == 0)
+               BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes");
+       
+       /* send updates */
+       ED_anim_dag_flush_update(C);    
+       
+       /* for now, only send ND_KEYS for KeyingSets */
+       WM_event_add_notifier(C, ND_KEYS, NULL);
+       
+       return OPERATOR_FINISHED;
+ }
+ void ANIM_OT_insert_keyframe (wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Insert Keyframe";
+       ot->idname= "ANIM_OT_insert_keyframe";
+       
+       /* callbacks */
+       ot->exec= insert_key_exec; 
 -      ot->poll= modify_key_op_poll;
++      ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ }
+ /* Delete Key Operator ------------------------ */
+ /* NOTE:
+  * This is one of the 'simpler new-style' Insert Keyframe operators which relies on Keying Sets.
+  * For now, these are absolute Keying Sets only, so there is very little context info involved.
+  *
+  *    -- Joshua Leung, Feb 2009
+  */
+  
+ static int delete_key_exec (bContext *C, wmOperator *op)
+ {
+       ListBase dsources = {NULL, NULL};
+       Scene *scene= CTX_data_scene(C);
+       KeyingSet *ks= NULL;
+       float cfra= (float)CFRA; // XXX for now, don't bother about all the yucky offset crap
+       short success;
+       
+       /* try to get KeyingSet */
+       if (scene->active_keyingset > 0)
+               ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1);
+       /* report failure */
+       if (ks == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
+               return OPERATOR_CANCELLED;
+       }
+       
+       /* try to insert keyframes for the channels specified by KeyingSet */
+       success= commonkey_modifykey(&dsources, ks, COMMONKEY_MODE_DELETE, cfra);
+       printf("KeyingSet '%s' - Successfully removed %d Keyframes \n", ks->name, success);
+       
+       /* report failure? */
+       if (success == 0)
+               BKE_report(op->reports, RPT_WARNING, "Keying Set failed to remove any keyframes");
+       
+       /* send updates */
+       ED_anim_dag_flush_update(C);    
+       
+       /* for now, only send ND_KEYS for KeyingSets */
+       WM_event_add_notifier(C, ND_KEYS, NULL);
+       
+       return OPERATOR_FINISHED;
+ }
+ void ANIM_OT_delete_keyframe (wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Delete Keyframe";
+       ot->idname= "ANIM_OT_delete_keyframe";
+       
+       /* callbacks */
+       ot->exec= delete_key_exec; 
++      
++      ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ }
+ /* Insert Key Operator ------------------------ */
  /* XXX WARNING:
   * This is currently just a basic operator, which work in 3d-view context on objects/bones only
   * and will insert keyframes for a few settings only. This is until it becomes clear how
index 9aacec7e44be149dc9888844cf5b2b8afd27b6b1,9f50bb3f044479f37c69115468c3716046bb5a33..6ca92f356446940d9a9350de4cd30eae53683b4d
@@@ -43,6 -43,12 +43,8 @@@ void ARMATURE_OT_parent_set(struct wmOp
  void ARMATURE_OT_parent_clear(struct wmOperatorType *ot);
  void ARMATURE_OT_de_select_all(struct wmOperatorType *ot);
  void ARMATURE_OT_selection_invert(struct wmOperatorType *ot);
 -void ARMATURE_OT_delete_selected(struct wmOperatorType *ot);
 -void ARMATURE_OT_duplicate_selected(struct wmOperatorType *ot);
 -void ARMATURE_OT_extrude(struct wmOperatorType *ot);
 -void ARMATURE_OT_click_extrude(struct wmOperatorType *ot);
+ void ARMATURE_OT_select_hierarchy(struct wmOperatorType *ot);
+ void ARMATURE_OT_select_connected(struct wmOperatorType *ot);
  
  void POSE_OT_hide(struct wmOperatorType *ot);
  void POSE_OT_reveal(struct wmOperatorType *ot);
index a8502aefcff07ac5fb46f9ee0ea4271efbd6a82d,e80d4d017d9c3c0d58c4f874c6673e0f9cebf743..12554c8492fba98ffc563dc8acee494433ac1844
@@@ -120,6 -122,13 +122,8 @@@ void ED_operatortypes_armature(void
        
        WM_operatortype_append(ARMATURE_OT_de_select_all);
        WM_operatortype_append(ARMATURE_OT_selection_invert);
 -
 -      WM_operatortype_append(ARMATURE_OT_delete_selected);
 -      WM_operatortype_append(ARMATURE_OT_duplicate_selected);
 -      WM_operatortype_append(ARMATURE_OT_extrude);
 -      WM_operatortype_append(ARMATURE_OT_click_extrude);
+       WM_operatortype_append(ARMATURE_OT_select_hierarchy);
+       WM_operatortype_append(ARMATURE_OT_select_connected);
        
        /* POSE */
        WM_operatortype_append(POSE_OT_hide);
@@@ -162,6 -174,28 +169,22 @@@ void ED_keymap_armature(wmWindowManage
        WM_keymap_add_item(keymap, "ARMATURE_OT_selection_invert", IKEY, KM_PRESS, KM_CTRL, 0);
        
        WM_keymap_add_item(keymap, "ARMATURE_OT_test", TKEY, KM_PRESS, 0, 0);  // XXX temp test for context iterators... to be removed
 -      WM_keymap_add_item(keymap, "ARMATURE_OT_delete_selected", XKEY, KM_PRESS, 0, 0);
 -      WM_keymap_add_item(keymap, "ARMATURE_OT_duplicate_selected", DKEY, KM_PRESS, KM_SHIFT, 0);
 -      WM_keymap_add_item(keymap, "ARMATURE_OT_extrude", EKEY, KM_PRESS, 0, 0);
 -      kmi= WM_keymap_add_item(keymap, "ARMATURE_OT_extrude", EKEY, KM_PRESS, KM_SHIFT, 0);
 -      RNA_boolean_set(kmi->ptr, "forked", 1);
 -      WM_keymap_add_item(keymap, "ARMATURE_OT_click_extrude", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
+       kmi= WM_keymap_add_item(keymap, "ARMATURE_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, 0, 0);
+       RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_PARENT);
+       RNA_boolean_set(kmi->ptr, "add_to_sel", 0);
+       kmi= WM_keymap_add_item(keymap, "ARMATURE_OT_select_hierarchy", LEFTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
+       RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_PARENT);
+       RNA_boolean_set(kmi->ptr, "add_to_sel", 1);
+       
+       kmi= WM_keymap_add_item(keymap, "ARMATURE_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, 0, 0);
+       RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_CHILD);
+       RNA_boolean_set(kmi->ptr, "add_to_sel", 0);
+       kmi= WM_keymap_add_item(keymap, "ARMATURE_OT_select_hierarchy", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
+       RNA_enum_set(kmi->ptr, "direction", BONE_SELECT_CHILD);
+       RNA_boolean_set(kmi->ptr, "add_to_sel", 1);
+       WM_keymap_add_item(keymap, "ARMATURE_OT_select_connected", LKEY, KM_PRESS, 0, 0);
        
        /* Pose ------------------------ */
        /* only set in posemode, by space_view3d listener */
index 15f8bcf9e29beb9685908528d107a0cb3b71da90,d3c59bf340cddbfde36b6d97d98133aaf58223be..3d8753d3ade2f6cdc3f7a14159e18ff20683e091
@@@ -3026,11 -3146,104 +3032,73 @@@ void extrude_armature(Scene *scene, in
        
        /* Transform the endpoints */
        armature_sync_selection(arm->edbo);
 -
 -      return OPERATOR_FINISHED;
 -}
 -
 -static int armature_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
 -{
 -      if (OPERATOR_CANCELLED == armature_extrude_exec(C, op))
 -              return OPERATOR_CANCELLED;
 -
 -      RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
 -      WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
 -
 -      return OPERATOR_FINISHED;
 -}
 -
 -void ARMATURE_OT_extrude(wmOperatorType *ot)
 -{
 -      /* identifiers */
 -      ot->name= "Extrude";
 -      ot->idname= "ARMATURE_OT_extrude";
 -      
 -      /* api callbacks */
 -      ot->invoke= armature_extrude_invoke;
 -      ot->exec= armature_extrude_exec;
 -      ot->poll= ED_operator_editarmature;
 -      
 -      /* flags */
 -      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +// XXX        BIF_TransformSetUndo("Extrude");
 +//    initTransform(TFM_TRANSLATION, CTX_NO_PET);
 +//    Transform();
        
 -      /* props */
 -      RNA_def_boolean(ot->srna, "forked", 0, "Forked", "");
 -      /* to give to transform */
 -      RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
  }
+ /* ********************** Bone Add ********************/
+ /*op makes a new bone and returns it with its tip selected */
+ static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) 
+ {
+       RegionView3D *rv3d= CTX_wm_region_view3d(C);
+       Object *obedit = CTX_data_edit_object(C);
+       EditBone *bone;
+       float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
+       char name[32];
+       
+       RNA_string_get(op->ptr, "name", name);
+       
+       VECCOPY(curs, give_cursor(CTX_data_scene(C),CTX_wm_view3d(C))); 
+       /* Get inverse point for head and orientation for tail */
+       Mat4Invert(obedit->imat, obedit->obmat);
+       Mat4MulVecfl(obedit->imat, curs);
+       if (U.flag & USER_ADD_VIEWALIGNED)
+               Mat3CpyMat4(obmat, rv3d->viewmat);
+       else Mat3One(obmat);
+       
+       Mat3CpyMat4(viewmat, obedit->obmat);
+       Mat3MulMat3(totmat, obmat, viewmat);
+       Mat3Inv(imat, totmat);
+       
+       deselectall_armature(obedit, 0, 0);
+       
+       /*      Create a bone   */
+       bone= add_editbone(obedit, name);
+       VECCOPY(bone->head, curs);
+       
+       if(U.flag & USER_ADD_VIEWALIGNED)
+               VecAddf(bone->tail, bone->head, imat[1]);       // bone with unit length 1
+       else
+               VecAddf(bone->tail, bone->head, imat[2]);       // bone with unit length 1, pointing up Z
+       WM_event_add_notifier(C, NC_OBJECT, obedit);
+       
+       return OPERATOR_FINISHED;
+ }
+ void ARMATURE_OT_bone_primitive_add(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Add Bone";
+       ot->idname= "ARMATURE_OT_bone_primitive_add";
+       
+       /* api callbacks */
+       ot->exec = armature_bone_primitive_add_exec;
+       ot->poll = ED_operator_editarmature;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_string(ot->srna, "name", "Bone", 32, "Name", "Name of the newly created bone");
+       
+ }
  
  /* ----------- */
  
index e16ec867e7c71c208386c081c1b5d8b2553b773d,aa4c132bf3ae8bd71ce41194e363efdd1954d3b0..d4780927b700cd8273be28b256025384fbb43a9e
@@@ -70,6 -71,6 +71,8 @@@
  #include "ED_view3d.h"
  #include "ED_screen.h"
  
++#include "bmesh.h"
++
  #include "mesh_intern.h"
  
  /* bpymenu removed XXX */
@@@ -688,6 -666,6 +668,12 @@@ static void addedgeface_mesh(EditMesh *
        EditEdge *eed;
        EditFace *efa;
        short amount=0;
++              
++      if (em->selectmode & SCE_SELECT_FACE) {
++              /*return if bmesh face dissolve finds stuff to
++                dissolve.*/
++              if (BM_DissolveFaces(em, BM_SELECT)) return;
++      }
  
        /* how many selected ? */
        if(em->selectmode & SCE_SELECT_EDGE) {
index db2f6d5f88684f372757978e463445aca9c72f51,af85a041b1b4679f15db7ea60458c1882fdd4b61..5fd0a2b698837beeb1a0726ecffcf987a4076b5d
@@@ -474,10 -474,10 +475,10 @@@ static float seg_intersect(EditEdge *e
        float  m1, b1, m2, b2, x21, x22, y21, y22, xi;
        float  yi, x1min, x1max, y1max, y1min, perc=0; 
        float  *scr;
 -      float  threshold;
 +      float  threshold = 0.0;
        int  i;
        
-       //threshold = 0.000001; /*tolerance for vertex intersection*/
+       threshold = 0.000001; /*tolerance for vertex intersection*/
        // XXX  threshold = scene->toolsettings->select_thresh / 100;
        
        /* Get screen coords of verts */
index 591854c2811e1fb43f620419031b42b725be7c3e,b48674a9bbabe3b967d946120d17c9a14f9d8614..3bc59fe90945b533cf8aefc90f912c154e6af64f
@@@ -635,15 -641,12 +642,15 @@@ void extrude_mesh(Object *obedit, EditM
        }
        else if(em->selectmode & SCE_SELECT_EDGE) {
                if (em->totedgesel==0) nr = 0;
 -              else if (em->totedgesel==1) nr = 3;
 +              
 +              nr = 1;
 +              /*else if (em->totedgesel==1) nr = 3;
                else if(em->totfacesel==0) nr = 3;
                else if(em->totfacesel==1)
-                       nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3");
+                       nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
                else
-                       nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
+                       nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
 +              */
        }
        else {
                if (em->totfacesel == 0) nr = 0;
@@@ -1025,24 -1115,8 +1119,24 @@@ void delete_mesh(Object *obedit, EditMe
                erase_faces(em, &em->faces);
                erase_vertices(em, &em->verts);
        } 
 +      else if(event==7) {
 +              BMesh *bm = editmesh_to_bmesh(em);
 +              BMOperator op;
 +              EditMesh *em2;
 +              
 +              BMO_Init_Op(&op, BMOP_DISSOLVE_VERTS);
 +              BMO_HeaderFlag_To_Slot(bm, &op, BMOP_DISVERTS_VERTIN, 
 +                                              BM_SELECT, BM_VERT);
 +              BMO_Exec_Op(bm, &op);
 +              
 +              BMO_Finish_Op(bm, &op);
 +              
 +              em2 = bmesh_to_editmesh(bm);
 +              set_editMesh(em, em2);
 +              MEM_freeN(em2);
 +      }
        else if(event==6) {
-               if(!EdgeLoopDelete(em))
+               if(!EdgeLoopDelete(em, op))
                        return;
  
                str= "Erase Edge Loop";
index 2036642776742b84729db743a2aea90faefdde14,e89db4fabca421e338f7a0c131c58ddbfbb29a0d..0a5b97eeabde6bf43c55477b05fb3dbc4f6ee594
@@@ -210,7 -200,7 +211,7 @@@ extern EditVert *findnearestvert(struc
  void join_triangles(EditMesh *em);
  int removedoublesflag(EditMesh *em, short flag, short automerge, float limit);                /* return amount */
  void esubdivideflag(Object *obedit, EditMesh *em, int flag, float rad, int beauty, int numcuts, int seltype);
- int EdgeSlide(EditMesh *em, short immediate, float imperc);
 -int EdgeSlide(EditMesh *em, wmOperator *op, short immediate, float imperc);
++int EdgeSlide(EditMesh *em, struct wmOperator *op, short immediate, float imperc);
  
  void MESH_OT_subdivs(struct wmOperatorType *ot);
  void MESH_OT_subdivide(struct wmOperatorType *ot);
index 06e07dc0026a0efe62c6ad5e72ce570fff4cb058,d0d7e834fcfabbb816c3a7e866669632c0146c11..05cc377c6f3eb69aeef600275959303c082aa66e
@@@ -176,8 -179,7 +179,9 @@@ void ED_operatortypes_mesh(void
        WM_operatortype_append(MESH_OT_smooth_vertex);
        WM_operatortype_append(MESH_OT_flip_editnormals);
        WM_operatortype_append(MESH_OT_knife_cut);
 +
+       WM_operatortype_append(MESH_OT_rip);
 +      WM_operatortype_append(MESH_OT_bmesh_test);
        
  }
  
index aeddff725397658b706f8d0b0bdc4ecd34ff9862,cc07c334aeccc747876e1439e95081015980290e..6e2b38acd8de0bd41afbd7f3d67e43daa825d37f
@@@ -489,10 -593,12 +591,10 @@@ static int object_add_armature_exec(bCo
        }
        else DAG_object_flush_update(CTX_data_scene(C), obedit, OB_RECALC_DATA);
        
-       //nu= addNurbprim(C, RNA_enum_get(op->ptr, "type"), newob);
 -      if(v3d) 
 -              rv3d= CTX_wm_region(C)->regiondata;
++      //nu= add_nurbs_primitive(C, RNA_enum_get(op->ptr, "type"), newob);
 +      //editnurb= curve_get_editcurve(CTX_data_edit_object(C));
 +      //BLI_addtail(editnurb, nu);
        
 -      /* v3d and rv3d are allowed to be NULL */
 -      add_primitive_bone(CTX_data_scene(C), v3d, rv3d);
 -
        /* userdef */
        if (newob && (U.flag & USER_ADD_EDITMODE)==0) {
                ED_object_exit_editmode(C, EM_FREEDATA);
index 89d4466d849ebe0a7bdba0fa04c6af76c2acbc7f,b3c7be688f276295fd1c8e61f79fabe3fded7d48..4751bd7bb3374f04887172004c16a1b5c212fd4c
  #include "BIF_gl.h"
  #include "BIF_glutil.h"
  
- #include "ED_editparticle.h"
 -#include "ED_mesh.h"
+ #include "ED_particle.h"
  #include "ED_view3d.h"
  
+ #include "UI_interface.h"
  #include "UI_resources.h"
  
+ #include "WM_api.h"
+ #include "WM_types.h"
+ #include "RNA_access.h"
+ #include "RNA_define.h"
  #include "physics_intern.h"
  
 -static void PE_create_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys);
  static void ParticleUndo_clear(ParticleSystem *psys);
  
 -#define LOOP_PARTICLES(i, pa) for(i=0, pa=psys->particles; i<totpart; i++, pa++)
 -#define LOOP_KEYS(k, key) if(psys->edit)for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++)
 +#define LOOP_PARTICLES(i,pa) for(i=0, pa=psys->particles; i<totpart; i++, pa++)
 +#define LOOP_KEYS(k,key) if(psys->edit)for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++)
 +
 +/* XXX */
- static void BIF_undo_push() {}
 +static void error() {}
- static int pupmenu() {return 0;}
 +static int lasso_inside() {return 0;}
 +static void *mesh_get_x_mirror_faces() {return NULL;}
- #define LEFTMOUSE 0
++
 +#define RADIALCONTROL_SIZE            0
 +#define RADIALCONTROL_STRENGTH        0
 +#define RADIALCONTROL_NONE            0
 +/* XXX */
 +
+ /**************************** utilities *******************************/
+ static int PE_poll(bContext *C)
+ {
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys;
+       if(!scene || !ob)
+               return 0;
+       
+       psys= PE_get_current(scene, ob);
+       return (psys && psys->edit && (G.f & G_PARTICLEEDIT));
+ }
+ static int PE_poll_3dview(bContext *C)
+ {
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys;
+       if(!scene || !ob || !CTX_wm_region_view3d(C))
+               return 0;
+       
+       psys= PE_get_current(scene, ob);
+       return (psys && psys->edit && (G.f & G_PARTICLEEDIT));
+ }
 -static void PE_free_particle_edit(ParticleSystem *psys)
 +void PE_free_particle_edit(ParticleSystem *psys)
  {
 -      ParticleEdit *edit= psys->edit;
 -      int i, totpart= psys->totpart;
 +      ParticleEdit *edit=psys->edit;
 +      int i, totpart=psys->totpart;
  
        if(edit==0) return;
  
  
        MEM_freeN(edit);
  
-       psys->edit=NULL;
+       psys->edit= NULL;
 -      psys->free_edit= NULL;
  }
  /************************************************/
  /*                    Edit Mode Helpers                                       */
  /************************************************/
@@@ -141,46 -172,8 +180,47 @@@ ParticleEditSettings *PE_settings(Scen
        return &scene->toolsettings->particle;
  }
  
-       Object *ob = ob_v;
 +void PE_change_act(void *ob_v, void *act_v)
 +{
-       short act = *((short*)act_v) - 1;
++      Scene *scene= NULL; // XXX
++      Object *ob= ob_v;
 +      ParticleSystem *psys;
-       if(act>=0){
++      short act= *((short*)act_v) - 1;
 +
 +      if((psys=psys_get_current(ob)))
 +              psys->flag &= ~PSYS_CURRENT;
 +
-                                       PE_create_particle_edit(ob, psys);
++      if(act>=0) {
 +              if((psys=BLI_findlink(&ob->particlesystem,act))) {
 +                      psys->flag |= PSYS_CURRENT;
 +
 +                      if(psys_check_enabled(ob, psys)) {
 +                              if(G.f & G_PARTICLEEDIT && !psys->edit)
- void PE_change_act_psys(Object *ob, ParticleSystem *psys)
++                                      PE_create_particle_edit(scene, ob, psys);
 +                              PE_recalc_world_cos(ob, psys);
 +                      }
 +              }
 +      }
 +}
 +
-                       PE_create_particle_edit(ob, psys);
++void PE_change_act_psys(Scene *scene, Object *ob, ParticleSystem *psys)
 +{
 +      ParticleSystem *p;
 +      
 +      if((p=psys_get_current(ob)))
 +              p->flag &= ~PSYS_CURRENT;
 +      
 +      psys->flag |= PSYS_CURRENT;
 +      
 +      if(psys_check_enabled(ob, psys)) {
 +              if(G.f & G_PARTICLEEDIT && !psys->edit)
++                      PE_create_particle_edit(scene, ob, psys);
 +              PE_recalc_world_cos(ob, psys);
 +      }
 +}
 +
  /* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set */
- ParticleSystem *PE_get_current(Object *ob)
+ ParticleSystem *PE_get_current(Scene *scene, Object *ob)
  {
        ParticleSystem *psys;
  
                psys->flag |= PSYS_CURRENT;
        }
  
-       if(psys && psys_check_enabled(ob, psys)) // XXX && ob == OBACT && (G.f & G_PARTICLEEDIT))
 -      /* this happens when Blender is started with particle
 -       * edit mode enabled XXX there's a draw error then? */
 -      if(psys && psys_check_enabled(ob, psys) && (ob == OBACT) && (G.f & G_PARTICLEEDIT))
++      if(psys && psys_check_enabled(ob, psys)) // XXX && (ob == scene->obact) && (G.f & G_PARTICLEEDIT))
                if(psys->part->type == PART_HAIR && psys->flag & PSYS_EDITED)
                        if(psys->edit == NULL)
-                               PE_create_particle_edit(ob, psys);
+                               PE_create_particle_edit(scene, ob, psys);
  
        return psys;
  }
@@@ -228,73 -223,86 +268,83 @@@ void PE_hide_keys_time(Scene *scene, Pa
        ParticleData *pa;
        ParticleEditKey *key;
        ParticleEditSettings *pset=PE_settings(scene);
-       int i,k,totpart=psys->totpart;
 -      int i, k, totpart= psys->totpart;
++      int i, k, totpart=psys->totpart;
  
-       if(pset->draw_timed && scene->selectmode==SCE_SELECT_POINT){
-               LOOP_PARTICLES(i,pa){
-                       LOOP_KEYS(k,key){
+       if(pset->draw_timed && scene->selectmode==SCE_SELECT_POINT) {
 -              LOOP_PARTICLES(i, pa) {
 -                      LOOP_KEYS(k, key) {
++              LOOP_PARTICLES(i,pa) {
++                      LOOP_KEYS(k,key) {
                                if(fabs(cfra-*key->time) < pset->draw_timed)
                                        key->flag &= ~PEK_HIDE;
-                               else{
+                               else {
                                        key->flag |= PEK_HIDE;
                                        key->flag &= ~PEK_SELECT;
                                }
                        }
                }
        }
-       else{
-               LOOP_PARTICLES(i,pa){
-                       LOOP_KEYS(k,key){
+       else {
 -              LOOP_PARTICLES(i, pa) {
 -                      LOOP_KEYS(k, key) {
++              LOOP_PARTICLES(i,pa) {
++                      LOOP_KEYS(k,key) {
                                key->flag &= ~PEK_HIDE;
                        }
                }
        }
  }
  
- static int key_inside_circle(short mco[2], float rad, float co[3], float *distance)
- {
-       ARegion *ar= NULL; // XXX
-       float dx,dy,dist;
-       short vertco[2];
+ /****************** common struct passed to callbacks ******************/
  
-       project_short(ar, co, vertco);
-       
-       if (vertco[0]==IS_CLIPPED)
-               return 0;
+ typedef struct PEData {
+       ViewContext vc;
+       bglMats mats;
        
-       dx=(float)(mco[0]-vertco[0]);
-       dy=(float)(mco[1]-vertco[1]);
-       dist=(float)sqrt((double)(dx*dx + dy*dy));
+       Scene *scene;
+       Object *ob;
+       DerivedMesh *dm;
+       ParticleSystem *psys;
  
-       if(dist<=rad){
-               if(distance) *distance=dist;
-               return 1;
-       }
-       else
-               return 0;
- }
- static int key_inside_rect(rcti *rect, float co[3])
+       short *mval;
+       rcti *rect;
+       float rad;
+       float dist;
+       float dval;
+       int select;
+       float *dvec;
+       float combfac;
+       float pufffac;
+       float cutfac;
+       float smoothfac;
+       float weightfac;
+       float growfac;
+       int invert;
+       int tot;
+       float vec[3];
+ } PEData;
+ static void PE_set_data(bContext *C, PEData *data)
  {
-       ARegion *ar= NULL; // XXX
-       short vertco[2];
+       memset(data, 0, sizeof(*data));
+       data->scene= CTX_data_scene(C);
+       data->ob= CTX_data_active_object(C);
+       data->psys= PE_get_current(data->scene, data->ob);
+ }
  
-       project_short(ar, co,vertco);
+ static void PE_set_view3d_data(bContext *C, PEData *data)
+ {
+       PE_set_data(C, data);
  
-       if (vertco[0]==IS_CLIPPED)
-               return 0;
-       
-       if(vertco[0] > rect->xmin && vertco[0] < rect->xmax &&
-                       vertco[1] > rect->ymin && vertco[1] < rect->ymax)
-               return 1;
-       else
-               return 0;
+       view3d_set_viewcontext(C, &data->vc);
+       view3d_get_transformation(&data->vc, data->ob, &data->mats);
 -
 -      if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT))
 -              view3d_validate_backbuf(&data->vc);
  }
  
- static int test_key_depth(float *co, bglMats *mats)
+ /*************************** selection utilities *******************************/
+ static int key_test_depth(PEData *data, float co[3])
  {
-       ARegion *ar= NULL; // XXX
-       View3D *v3d= NULL;
-       RegionView3D *rv3d= ar->regiondata;
+       View3D *v3d= data->vc.v3d;
+       RegionView3D *rv3d= data->vc.rv3d;
        double ux, uy, uz;
        float depth;
        short wco[3], x,y;
        }
  }
  
 -static int key_inside_circle(PEData *data, float rad, float co[3], float *distance)
++static int key_inside_circle(PEData *data, float co[3], float *distance)
+ {
+       float dx, dy, dist;
+       short sco[2];
+       project_short(data->vc.ar, co, sco);
+       
+       if(sco[0] == IS_CLIPPED)
+               return 0;
+       
+       dx= data->mval[0] - sco[0];
+       dy= data->mval[1] - sco[1];
+       dist= sqrt(dx*dx + dy*dy);
 -      if(dist > rad)
++      if(dist > data->rad)
+               return 0;
+       if(key_test_depth(data, co)) {
+               if(distance)
+                       *distance=dist;
+               return 1;
+       }
+       
+       return 0;
+ }
+ static int key_inside_rect(PEData *data, float co[3])
+ {
+       short sco[2];
+       project_short(data->vc.ar, co,sco);
+       if(sco[0] == IS_CLIPPED)
+               return 0;
+       
+       if(sco[0] > data->rect->xmin && sco[0] < data->rect->xmax &&
+          sco[1] > data->rect->ymin && sco[1] < data->rect->ymax)
+               return key_test_depth(data, co);
+       return 0;
+ }
+ static int key_inside_test(PEData *data, float co[3])
+ {
+       if(data->mval)
 -              return key_inside_circle(data, data->rad, co, NULL);
++              return key_inside_circle(data, co, NULL);
+       else
+               return key_inside_rect(data, co);
+ }
  static int particle_is_selected(ParticleSystem *psys, ParticleData *pa)
  {
        ParticleEditKey *key;
        int sel, i, k;
  
-       if(pa->flag&PARS_HIDE) return 0;
+       if(pa->flag & PARS_HIDE)
+               return 0;
  
-       sel=0;
+       sel= 0;
        i= pa - psys->particles;
 -      LOOP_KEYS(k, key)
-               if(key->flag&PEK_SELECT)
 +      LOOP_KEYS(k,key)
+               if(key->flag & PEK_SELECT)
                        return 1;
        
        return 0;
  }
  
- /*-----iterators over editable particles-----*/
- static void for_mouse_hit_keys(int nearest, ParticleSystem *psys, void (*func)(ParticleSystem *psys, 
-                                                                                                       int pa_index, int key_index, void *userData), void *userData)
+ /*************************** iterators *******************************/
+ typedef void (*ForParticleFunc)(PEData *data, int pa_index);
+ typedef void (*ForKeyFunc)(PEData *data, int pa_index, int key_index);
+ typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index);
+ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
  {
-       /* these are allways the first in this userData */
-       struct {Scene *scene; short *mval; float rad; rcti *rect;} *data = userData;
+       ParticleSystem *psys= data->psys;
+       ParticleEdit *edit= psys->edit;
        ParticleData *pa;
        ParticleEditKey *key;
-       bglMats mats;
-       int i,k, totpart, nearest_pa=-1, nearest_key=-1;
-       float dist=data->rad;
-       if(psys==0 || data->scene->selectmode==SCE_SELECT_PATH) return;
+       int i, k, totpart, nearest_pa, nearest_key;
+       float dist= data->rad;
  
-       totpart=psys->totpart;
+       /* in path select mode we have no keys */
+       if(data->scene->selectmode==SCE_SELECT_PATH)
+               return;
  
-       bgl_get_mats(&mats);
+       totpart= psys->totpart;
+       nearest_pa= -1;
+       nearest_key= -1;
  
-       LOOP_PARTICLES(i,pa){
+       LOOP_PARTICLES(i, pa) {
                if(pa->flag & PARS_HIDE) continue;
  
-               if(data->scene->selectmode==SCE_SELECT_END){
-                       key=psys->edit->keys[i]+pa->totkey-1;
+               if(data->scene->selectmode == SCE_SELECT_END) {
+                       /* only do end keys */
+                       key= edit->keys[i] + pa->totkey-1;
  
-                       if(nearest){
-                               if(key_inside_circle(data->mval,dist,key->world_co,&dist) && test_key_depth(key->world_co,&mats)){
-                                       nearest_pa=i;
-                                       nearest_key=pa->totkey-1;
+                       if(nearest) {
 -                              if(key_inside_circle(data, dist, key->world_co, &dist)) {
++                              if(key_inside_circle(data, key->world_co, &dist)) {
+                                       nearest_pa= i;
+                                       nearest_key= pa->totkey-1;
                                }
                        }
-                       else if(((data->mval)?
-                                               key_inside_circle(data->mval,data->rad,key->world_co,0):
-                                               key_inside_rect(data->rect,key->world_co)) && test_key_depth(key->world_co,&mats))
-                               func(psys,i,pa->totkey-1,userData);
+                       else if(key_inside_test(data, key->world_co))
+                               func(data, i, pa->totkey-1);
                }
-               else{
-                       key=psys->edit->keys[i];
+               else {
+                       /* do all keys */
+                       key= edit->keys[i];
  
-                       LOOP_KEYS(k,key){
-                               if(key->flag&PEK_HIDE) continue;
+                       LOOP_KEYS(k, key) {
+                               if(key->flag & PEK_HIDE) continue;
  
-                               if(nearest){
-                                       if(key_inside_circle(data->mval,dist,key->world_co,&dist) && test_key_depth(key->world_co,&mats)){
-                                               nearest_pa=i;
-                                               nearest_key=k;
+                               if(nearest) {
 -                                      if(key_inside_circle(data, dist, key->world_co, &dist)) {
++                                      if(key_inside_circle(data, key->world_co, &dist)) {
+                                               nearest_pa= i;
+                                               nearest_key= k;
                                        }
                                }
-                               else if(((data->mval)?
-                                                       key_inside_circle(data->mval,data->rad,key->world_co,0):
-                                                       key_inside_rect(data->rect,key->world_co)) && test_key_depth(key->world_co,&mats))
-                                       func(psys,i,k,userData);
+                               else if(key_inside_test(data, key->world_co))
+                                       func(data, i, k);
                        }
                }
        }
@@@ -425,21 -489,27 +531,27 @@@ static void foreach_mouse_hit_particle(
        if(data->scene->selectmode==SCE_SELECT_PATH)
                selected=0;
  
-       LOOP_PARTICLES(i,pa){
+       LOOP_PARTICLES(i, pa) {
                if(pa->flag & PARS_HIDE) continue;
  
-               if(data->scene->selectmode==SCE_SELECT_END){
-                       key=psys->edit->keys[i]+pa->totkey-1;
-                       if(key_inside_circle(data->mval,data->rad,key->world_co,&data->dist) && (selected==0 || key->flag&PEK_SELECT) && test_key_depth(key->world_co,&mats))
-                               func(psys,i,userData);
+               if(data->scene->selectmode==SCE_SELECT_END) {
+                       /* only do end keys */
+                       key= psys->edit->keys[i] + pa->totkey-1;
+                       if(selected==0 || key->flag & PEK_SELECT)
 -                              if(key_inside_circle(data, data->rad, key->world_co, &data->dist))
++                              if(key_inside_circle(data, key->world_co, &data->dist))
+                                       func(data, i);
                }
-               else{
-                       LOOP_KEYS(k,key){
-                               if(key->flag&PEK_HIDE) continue;
+               else {
+                       /* do all keys */
 -                      LOOP_KEYS(k, key) {
++                      LOOP_KEYS(k,key) {
+                               if(key->flag & PEK_HIDE) continue;
  
-                               if(key_inside_circle(data->mval,data->rad,key->world_co,&data->dist) && (selected==0 || key->flag&PEK_SELECT) && test_key_depth(key->world_co,&mats)){
-                                       func(psys,i,userData);
-                                       break;
+                               if(selected==0 || key->flag & PEK_SELECT) {
 -                                      if(key_inside_circle(data, data->rad, key->world_co, &data->dist)) {
++                                      if(key_inside_circle(data, key->world_co, &data->dist)) {
+                                               func(data, i);
+                                               break;
+                                       }
                                }
                        }
                }
@@@ -471,99 -535,99 +577,99 @@@ static void foreach_mouse_hit_key(PEDat
        Mat4One(imat);
        Mat4One(mat);
  
-       LOOP_PARTICLES(i,pa){
 -      LOOP_PARTICLES(i, pa) {
++      LOOP_PARTICLES(i,pa) {
                if(pa->flag & PARS_HIDE) continue;
  
                psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, pa, mat);
-               //psys_geometry_mat(psmd->dm,pa,tmat);
-               //Mat4MulMat4(mat,tmat,data->ob->obmat);
                Mat4Invert(imat,mat);
  
-               if(data->scene->selectmode==SCE_SELECT_END){
-                       key=psys->edit->keys[i]+pa->totkey-1;
-                       if(key_inside_circle(data->mval,data->rad,key->world_co,&data->dist) && (selected==0 || key->flag&PEK_SELECT) && test_key_depth(key->world_co,&mats))
-                               func(psys,mat,imat,i,pa->totkey-1,userData);
+               if(data->scene->selectmode==SCE_SELECT_END) {
+                       /* only do end keys */
+                       key= psys->edit->keys[i] + pa->totkey-1;
+                       if(selected==0 || key->flag & PEK_SELECT)
 -                              if(key_inside_circle(data, data->rad, key->world_co, &data->dist))
++                              if(key_inside_circle(data, key->world_co, &data->dist))
+                                       func(data, mat, imat, i, pa->totkey-1);
                }
-               else{
-                       LOOP_KEYS(k,key){
+               else {
+                       /* do all keys */
 -                      LOOP_KEYS(k, key) {
++                      LOOP_KEYS(k,key) {
                                if(key->flag&PEK_HIDE) continue;
  
-                               if(key_inside_circle(data->mval,data->rad,key->world_co,&data->dist) && (selected==0 || key->flag&PEK_SELECT) && test_key_depth(key->world_co,&mats)){
-                                       func(psys,mat,imat,i,k,userData);
-                               }
+                               if(selected==0 || key->flag & PEK_SELECT)
 -                                      if(key_inside_circle(data, data->rad, key->world_co, &data->dist))
++                                      if(key_inside_circle(data, key->world_co, &data->dist))
+                                               func(data, mat, imat, i, k);
                        }
                }
        }
  }
  
- static void foreach_selected_element(ParticleSystem *psys, void (*func)(ParticleSystem *psys, int index, void *userData), void *userData)
+ static void foreach_selected_particle(PEData *data, ForParticleFunc func)
  {
+       ParticleSystem *psys= data->psys;
        ParticleData *pa;
-       int i,totpart;
-       if(psys==0) return;
+       int i, totpart;
  
-       totpart=psys->totpart;
+       totpart= psys->totpart;
  
 -      LOOP_PARTICLES(i, pa)
 +      LOOP_PARTICLES(i,pa)
                if(particle_is_selected(psys, pa))
-                       func(psys,i,userData);
+                       func(data, i);
  }
  
- static void foreach_selected_key(ParticleSystem *psys, void (*func)(ParticleSystem *psys, int pa_index, int key_index, void *userData), void *userData)
+ static void foreach_selected_key(PEData *data, ForKeyFunc func)
  {
+       ParticleSystem *psys= data->psys;
        ParticleData *pa;
        ParticleEditKey *key;
-       int i,k,totpart;
+       int i, k, totpart;
  
-       if(psys==0) return;
+       totpart= psys->totpart;
  
-       totpart=psys->totpart;
 -      LOOP_PARTICLES(i, pa) {
++      LOOP_PARTICLES(i,pa) {
+               if(pa->flag & PARS_HIDE) continue;
  
-       LOOP_PARTICLES(i,pa){
-               if(pa->flag&PARS_HIDE) continue;
+               key= psys->edit->keys[i];
  
-               key=psys->edit->keys[i];
-               LOOP_KEYS(k,key){
-                       if(key->flag&PEK_SELECT)
-                               func(psys,i,k,userData);
-               }
 -              LOOP_KEYS(k, key)
++              LOOP_KEYS(k,key)
+                       if(key->flag & PEK_SELECT)
+                               func(data, i, k);
        }
  }
- void PE_foreach_element(ParticleSystem *psys, void (*func)(ParticleSystem *psys, int index, void *userData), void *userData)
- {
-       int i,totpart;
  
-       if(psys==0) return;
+ void PE_foreach_particle(PEData *data, ForParticleFunc func)
+ {
+       ParticleSystem *psys= data->psys;
+       int i, totpart;
  
-       totpart=psys->totpart;
+       totpart= psys->totpart;
  
        for(i=0; i<totpart; i++)
-               func(psys,i,userData);
+               func(data, i);
  }
  static int count_selected_keys(Scene *scene, ParticleSystem *psys)
  {
        ParticleData *pa;
        ParticleEditKey *key;
-       int i,k,totpart,sel=0;
+       int i, k, totpart, sel= 0;
  
-       if(psys==0) return 0;
+       totpart= psys->totpart;
  
-       totpart=psys->totpart;
 -      LOOP_PARTICLES(i, pa) {
++      LOOP_PARTICLES(i,pa) {
+               if(pa->flag & PARS_HIDE) continue;
  
-       LOOP_PARTICLES(i,pa){
-               if(pa->flag&PARS_HIDE) continue;
+               key= psys->edit->keys[i];
  
-               key=psys->edit->keys[i];
-               if(scene->selectmode==SCE_SELECT_POINT){
-                       for(k=0; k<pa->totkey; k++,key++){
-                               if(key->flag&PEK_SELECT)
+               if(scene->selectmode==SCE_SELECT_POINT) {
+                       for(k=0; k<pa->totkey; k++,key++)
+                               if(key->flag & PEK_SELECT)
                                        sel++;
-                       }
                }
-               else if(scene->selectmode==SCE_SELECT_END){
-                       key+=pa->totkey-1;
-                       if(key->flag&PEK_SELECT)
+               else if(scene->selectmode==SCE_SELECT_END) {
+                       key += pa->totkey-1;
+                       if(key->flag & PEK_SELECT)
                                sel++;
                }
        }
@@@ -749,21 -814,21 +856,21 @@@ static void pe_deflect_emitter(Scene *s
        if((pset->flag & PE_DEFLECT_EMITTER)==0)
                return;
  
 -      edit= psys->edit;
 -      totpart= psys->totpart;
 +      edit=psys->edit;
 +      totpart=psys->totpart;
  
-       LOOP_PARTICLES(i,pa){
 -      LOOP_PARTICLES(i, pa) {
++      LOOP_PARTICLES(i,pa) {
                if(!(pa->flag & PARS_EDIT_RECALC))
                        continue;
                
                psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat);
                
-               LOOP_KEYS(k,key){
 -              LOOP_KEYS(k, key) {
++              LOOP_KEYS(k,key) {
                        Mat4MulVecfl(hairmat, key->co);
                }
        //}
  
-       //LOOP_PARTICLES(i,pa){
 -      //LOOP_PARTICLES(i, pa) {
++      //LOOP_PARTICLES(i,pa) {
                key=psys->edit->keys[i]+1;
  
                dist_1st=VecLenf((key-1)->co,key->co);
                }
        //}
  
-       //LOOP_PARTICLES(i,pa){
 -      //LOOP_PARTICLES(i, pa) {
++      //LOOP_PARTICLES(i,pa) {
                
                Mat4Invert(hairimat,hairmat);
  
-               LOOP_KEYS(k,key){
 -              LOOP_KEYS(k, key) {
++              LOOP_KEYS(k,key) {
                        Mat4MulVecfl(hairimat, key->co);
                }
        }
@@@ -822,10 -887,10 +929,10 @@@ void PE_apply_lengths(Scene *scene, Par
        if((pset->flag & PE_KEEP_LENGTHS)==0)
                return;
  
 -      edit= psys->edit;
 -      totpart= psys->totpart;
 +      edit=psys->edit;
 +      totpart=psys->totpart;
  
-       LOOP_PARTICLES(i,pa){
 -      LOOP_PARTICLES(i, pa) {
++      LOOP_PARTICLES(i,pa) {
                if(!(pa->flag & PARS_EDIT_RECALC))
                        continue;
                
@@@ -856,10 -921,10 +963,10 @@@ static void pe_iterate_lengths(Scene *s
        if((pset->flag & PE_KEEP_LENGTHS)==0)
                return;
  
 -      edit= psys->edit;
 -      totpart= psys->totpart;
 +      edit=psys->edit;
 +      totpart=psys->totpart;
  
-       LOOP_PARTICLES(i,pa){
 -      LOOP_PARTICLES(i, pa) {
++      LOOP_PARTICLES(i,pa) {
                if(!(pa->flag & PARS_EDIT_RECALC))
                        continue;
  
@@@ -909,38 -974,16 +1016,38 @@@ static void recalc_lengths(ParticleSyst
        if(psys==0)
                return;
  
-       totpart = psys->totpart;
+       totpart= psys->totpart;
  
-       LOOP_PARTICLES(i,pa){
-               key = psys->edit->keys[i];
-               for(k=0; k<pa->totkey-1; k++, key++){
-                       key->length = VecLenf(key->co, (key + 1)->co);
 -      LOOP_PARTICLES(i, pa) {
++      LOOP_PARTICLES(i,pa) {
+               key= psys->edit->keys[i];
+               for(k=0; k<pa->totkey-1; k++, key++) {
+                       key->length= VecLenf(key->co, (key + 1)->co);
                }
        }
  }
-       ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
 +/* calculate and store key locations in world coordinates */
 +void PE_recalc_world_cos(Object *ob, ParticleSystem *psys)
 +{
++      ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
 +      ParticleData *pa;
 +      ParticleEditKey *key;
 +      int i, k, totpart;
 +      float hairmat[4][4];
  
-       totpart = psys->totpart;
 +      if(psys==0)
 +              return;
 +
-       LOOP_PARTICLES(i,pa){
++      totpart= psys->totpart;
 +
-               LOOP_KEYS(k,key){
++      LOOP_PARTICLES(i,pa) {
 +              psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
 +
++              LOOP_KEYS(k,key) {
 +                      VECCOPY(key->world_co,key->co);
 +                      Mat4MulVecfl(hairmat, key->world_co);
 +              }
 +      }
 +}
  /* calculate a tree for finding nearest emitter's vertice */
  static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
  {
        BLI_kdtree_balance(edit->emitter_field);
  }
  
 -static void PE_update_selection(Scene *scene, Object *ob, int useflag)
 +void PE_update_selection(Scene *scene, Object *ob, int useflag)
  {
-       ParticleSystem *psys= PE_get_current(ob);
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleEdit *edit= psys->edit;
        ParticleEditSettings *pset= PE_settings(scene);
        ParticleSettings *part= psys->part;
  
        /* flush edit key flag to hair key flag to preserve selection 
         * on save */
 -      LOOP_PARTICLES(i, pa) {
 +      LOOP_PARTICLES(i,pa) {
-               key = edit->keys[i];
+               key= edit->keys[i];
  
                for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++)
                        hkey->editflag= key->flag;
@@@ -1072,95 -1115,6 +1179,117 @@@ void PE_update_object(Scene *scene, Obj
                pa->flag &= ~PARS_EDIT_RECALC;
  }
  
- void PE_create_particle_edit(Object *ob, ParticleSystem *psys)
++/************************ particle edit toggle operator ************************/
++
 +/* initialize needed data for bake edit */
-       Scene *scene= NULL; // XXX
++void PE_create_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys)
 +{
-       int i,k, totpart=psys->totpart, alloc=1;
 +      ParticleEdit *edit=psys->edit;
 +      ParticleData *pa;
 +      ParticleEditKey *key;
 +      HairKey *hkey;
-       if(edit){
-               int newtotkeys = psys_count_keys(psys);
++      int i, k, totpart=psys->totpart, alloc=1;
 +
 +      if((psys->flag & PSYS_EDITED)==0)
 +              return;
 +
-       if(alloc){
-               if(edit){
++      if(edit) {
++              int newtotkeys= psys_count_keys(psys);
 +              if(newtotkeys == edit->totkeys)
 +                      alloc=0;
 +      }
 +
-               LOOP_PARTICLES(i,pa){
-                       key = edit->keys[i] = MEM_callocN(pa->totkey*sizeof(ParticleEditKey),"ParticleEditKeys");
-                       for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++){
-                               key->co = hkey->co;
-                               key->time = &hkey->time;
++      if(alloc) {
++              if(edit) {
 +                      error("ParticleEdit exists allready! Poke jahka!");
 +                      PE_free_particle_edit(psys);
 +              }
 +
 +              edit=psys->edit=MEM_callocN(sizeof(ParticleEdit), "PE_create_particle_edit");
 +
 +              edit->keys=MEM_callocN(totpart*sizeof(ParticleEditKey*),"ParticleEditKey array");
 +
-               edit->totkeys = psys_count_keys(psys);
++              LOOP_PARTICLES(i,pa) {
++                      key= edit->keys[i]= MEM_callocN(pa->totkey*sizeof(ParticleEditKey),"ParticleEditKeys");
++                      for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++) {
++                              key->co= hkey->co;
++                              key->time= &hkey->time;
 +                              key->flag= hkey->editflag;
 +                      }
 +              }
 +
- /* toggle particle mode on & off */
- void PE_set_particle_edit(Scene *scene)
++              edit->totkeys= psys_count_keys(psys);
 +      }
 +
 +      recalc_lengths(psys);
 +      recalc_emitter_field(ob, psys);
 +      PE_recalc_world_cos(ob, psys);
 +
 +      if(alloc) {
 +              ParticleUndo_clear(psys);
 +              PE_undo_push(scene, "Original");
 +      }
 +}
 +
-       Object *ob= OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
++static int particle_edit_toggle_poll(bContext *C)
 +{
-       //if(!ob || ob->id.lib) return; /* is the id.lib test needed? -jahka*/
-       if(ob==0 || psys==0) return;
++      Scene *scene= CTX_data_scene(C);
++      Object *ob= CTX_data_active_object(C);
 +
++      if(!scene || !ob || ob->id.lib)
++              return 0;
 +      
-       if(psys==0){
-               if(ob->particlesystem.first){
-                       psys=ob->particlesystem.first;
-                       psys->flag |= PSYS_CURRENT;
-               }
-               else
-                       return;
++      return (ob->particlesystem.first != NULL);
++}
++
++static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
++{
++      Scene *scene= CTX_data_scene(C);
++      Object *ob= CTX_data_active_object(C);
++      ParticleSystem *psys= PE_get_current(scene, ob);
 +      
-       if((G.f & G_PARTICLEEDIT)==0){
++      if(psys==NULL) {
++              psys= ob->particlesystem.first;
++              psys->flag |= PSYS_CURRENT;
 +      }
 +
-                               if(psys->edit==0)
-                                       PE_create_particle_edit(ob, psys);
++      if(!(G.f & G_PARTICLEEDIT)) {
 +              if(psys && psys->part->type == PART_HAIR && psys->flag & PSYS_EDITED) {
 +                      if(psys_check_enabled(ob, psys)) {
-       else{
++                              if(psys->edit==NULL)
++                                      PE_create_particle_edit(scene, ob, psys);
++
 +                              PE_recalc_world_cos(ob, psys);
 +                      }
 +              }
 +
 +              G.f |= G_PARTICLEEDIT;
++              WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_PARTICLE, NULL);
 +      }
-       DAG_object_flush_update(scene, OBACT, OB_RECALC_DATA);
++      else {
 +              G.f &= ~G_PARTICLEEDIT;
++              WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL);
 +      }
 +
++      DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
++
++      return OPERATOR_FINISHED;
++}
++
++void PARTICLE_OT_particle_edit_toggle(wmOperatorType *ot)
++{
++      /* identifiers */
++      ot->name= "Particle Edit Toggle";
++      ot->idname= "PARTICLE_OT_particle_edit_toggle";
++      
++      /* api callbacks */
++      ot->exec= particle_edit_toggle_exec;
++      ot->poll= particle_edit_toggle_poll;
 +
++      /* flags */
++      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +}
 +
  /************************************************/
  /*                    Edit Selections                                         */
  /************************************************/
@@@ -1208,112 -1165,36 +1340,36 @@@ static void toggle_key_select(PEData *d
        pa->flag |= PARS_EDIT_RECALC;
  }
  
- static void select_root(ParticleSystem *psys, int index, void *userData)
- {
-       psys->edit->keys[index]->flag |= PEK_SELECT;
- }
- static void select_tip(ParticleSystem *psys, int index, void *userData)
- {
-       ParticleData *pa = psys->particles + index;
-       ParticleEditKey *key = psys->edit->keys[index] + pa->totkey-1;
-       key->flag |= PEK_SELECT;
- }
- static void select_more_keys(ParticleSystem *psys, int index, void *userData)
- {
-       ParticleEdit *edit = psys->edit;
-       ParticleData *pa = psys->particles+index;
-       ParticleEditKey *key;
-       int k;
-       for(k=0,key=edit->keys[index]; k<pa->totkey; k++,key++){
-               if(key->flag&PEK_SELECT) continue;
-               if(k==0){
-                       if((key+1)->flag&PEK_SELECT)
-                               key->flag |= PEK_TO_SELECT;
-               }
-               else if(k==pa->totkey-1){
-                       if((key-1)->flag&PEK_SELECT)
-                               key->flag |= PEK_TO_SELECT;
-               }
-               else{
-                       if(((key-1)->flag | (key+1)->flag) & PEK_SELECT)
-                               key->flag |= PEK_TO_SELECT;
-               }
-       }
-       for(k=0,key=edit->keys[index]; k<pa->totkey; k++,key++){
-               if(key->flag&PEK_TO_SELECT){
-                       key->flag &= ~PEK_TO_SELECT;
-                       key->flag |= PEK_SELECT;
-               }
-       }
- }
- static void select_less_keys(ParticleSystem *psys, int index, void *userData)
- {
-       ParticleEdit *edit = psys->edit;
-       ParticleData *pa = psys->particles+index;
-       ParticleEditKey *key;
-       int k;
-       for(k=0,key=edit->keys[index]; k<pa->totkey; k++,key++){
-               if((key->flag&PEK_SELECT)==0) continue;
-               if(k==0){
-                       if(((key+1)->flag&PEK_SELECT)==0)
-                               key->flag |= PEK_TO_SELECT;
-               }
-               else if(k==pa->totkey-1){
-                       if(((key-1)->flag&PEK_SELECT)==0)
-                               key->flag |= PEK_TO_SELECT;
-               }
-               else{
-                       if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
-                               key->flag |= PEK_TO_SELECT;
-               }
-       }
-       for(k=0,key=edit->keys[index]; k<pa->totkey; k++,key++){
-               if(key->flag&PEK_TO_SELECT)
-                       key->flag &= ~(PEK_TO_SELECT|PEK_SELECT);
-       }
- }
+ /************************ de select all operator ************************/
  
- /*-----using above callbacks-----*/
- void PE_deselectall(void)
+ static int de_select_all_exec(bContext *C, wmOperator *op)
  {
-       Scene *scene= NULL;
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
-       ParticleEdit *edit = 0;
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       ParticleEdit *edit= 0;
        ParticleData *pa;
        ParticleEditKey *key;
-       int i,k,totpart, sel = 0;
-               
-       if(!PE_can_edit(psys)) return;
+       int i, k, totpart, sel= 0;
        
-       edit = psys->edit;
-       totpart = psys->totpart;
+       edit= psys->edit;
+       totpart= psys->totpart;
        
-       LOOP_PARTICLES(i,pa){
 -      LOOP_PARTICLES(i, pa) {
++      LOOP_PARTICLES(i,pa) {
                if(pa->flag & PARS_HIDE) continue;
-               LOOP_KEYS(k,key){
-                       if(key->flag&PEK_SELECT){
-                               sel = 1;
 -              LOOP_KEYS(k, key) {
++              LOOP_KEYS(k,key) {
+                       if(key->flag & PEK_SELECT) {
+                               sel= 1;
                                key->flag &= ~PEK_SELECT;
                                pa->flag |= PARS_EDIT_RECALC;
                        }
                }
        }
  
-       if(sel==0){
-               LOOP_PARTICLES(i,pa){
+       if(sel==0) {
 -              LOOP_PARTICLES(i, pa) {
++              LOOP_PARTICLES(i,pa) {
                        if(pa->flag & PARS_HIDE) continue;
-                       LOOP_KEYS(k,key){
 -                      LOOP_KEYS(k, key) {
++                      LOOP_KEYS(k,key) {
                                if(!(key->flag & PEK_SELECT)) {
                                        key->flag |= PEK_SELECT;
                                        pa->flag |= PARS_EDIT_RECALC;
        }
  
        PE_update_selection(scene, ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
  
-       BIF_undo_push("(De)select all keys");
+       return OPERATOR_FINISHED;
  }
  
- void PE_mouse_particles(void)
+ void PARTICLE_OT_de_select_all(wmOperatorType *ot)
  {
-       struct {Scene *scene;  short *mval; float rad; rcti* rect; int select; } data;
-       Scene *scene= NULL;
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
-       ParticleEdit *edit = 0;
-       ParticleData *pa;
-       ParticleEditKey *key;
-       short mval[2];
-       int i,k,totpart;
+       /* identifiers */
+       ot->name= "Select or Deselect All";
+       ot->idname= "PARTICLE_OT_de_select_all";
+       
+       /* api callbacks */
+       ot->exec= de_select_all_exec;
+       ot->poll= PE_poll;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ }
+ /************************ pick select operator ************************/
 -int PE_mouse_particles(bContext *C, short *mval, int extend)
++void PE_mouse_particles(void)
+ {
++      bContext *C= NULL; // XXX
+       PEData data;
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       ParticleEdit *edit= 0;
+       ParticleData *pa;
+       ParticleEditKey *key;
++      short mval[2];
+       int i, k, totpart;
 +      int shift= 0; // XXX
        
 -      if(!PE_can_edit(psys))
 -              return OPERATOR_CANCELLED;
 +      if(!PE_can_edit(psys)) return;
  
-       edit = psys->edit;
+       edit= psys->edit;
 +
-       totpart = psys->totpart;
+       totpart= psys->totpart;
  
 -      if(!extend) {
 -              LOOP_PARTICLES(i, pa) {
 +      bglFlush();
 +      glReadBuffer(GL_BACK);
 +      glDrawBuffer(GL_BACK);
 +//    persp(PERSP_VIEW);
 +
 +      if(shift)
-               LOOP_PARTICLES(i,pa){
++              LOOP_PARTICLES(i,pa) {
                        if(pa->flag & PARS_HIDE) continue;
-                       LOOP_KEYS(k,key){
 -                      LOOP_KEYS(k, key) {
++                      LOOP_KEYS(k,key) {
                                if(key->flag & PEK_SELECT) {
                                        key->flag &= ~PEK_SELECT;
                                        pa->flag |= PARS_EDIT_RECALC;
                                }
                        }
                }
 -      }
++      
++      // XXX mval
  
- //    getmouseco_areawin(mval);
-       data.scene= scene;
+       PE_set_view3d_data(C, &data);
        data.mval= mval;
        data.rad= 75.0f;
-       data.rect= 0;
-       data.select= 0;
  
-       for_mouse_hit_keys(1,psys,toggle_key_select,&data);
+       for_mouse_hit_keys(&data, toggle_key_select, 1);  /* nearest only */
  
        PE_update_selection(scene, ob, 1);
 -      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
  
 -      return OPERATOR_FINISHED;
  }
  
- void PE_select_root(void)
+ /************************ select first operator ************************/
+ static void select_root(PEData *data, int pa_index)
  {
-       Object *ob=NULL; // XXX
-       ParticleSystem *psys = PE_get_current(ob);
+       ParticleSystem *psys= data->psys;
  
-       if(!PE_can_edit(psys)) return;
+       psys->edit->keys[pa_index]->flag |= PEK_SELECT;
+ }
  
-       PE_foreach_element(psys,select_root,NULL);
-       BIF_undo_push("Select first");
+ static int select_first_exec(bContext *C, wmOperator *op)
+ {
+       PEData data;
+       PE_set_data(C, &data);
+       PE_foreach_particle(&data, select_root);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
+       return OPERATOR_FINISHED;
  }
  
- void PE_select_tip()
+ void PARTICLE_OT_select_first(wmOperatorType *ot)
  {
-       Object *ob=NULL; // XXX
-       ParticleSystem *psys = PE_get_current(ob);
+       /* identifiers */
+       ot->name= "Select First";
+       ot->idname= "PARTICLE_OT_select_first";
+       
+       /* api callbacks */
+       ot->exec= select_first_exec;
+       ot->poll= PE_poll;
  
-       if(!PE_can_edit(psys)) return;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ }
+ /************************ select last operator ************************/
+ static void select_tip(PEData *data, int pa_index)
+ {
+       ParticleSystem *psys= data->psys;
+       ParticleData *pa= psys->particles + pa_index;
+       ParticleEditKey *key= psys->edit->keys[pa_index] + pa->totkey-1;
  
-       PE_foreach_element(psys,select_tip,NULL);
-       BIF_undo_push("Select last");
+       key->flag |= PEK_SELECT;
  }
  
void PE_select_linked(void)
static int select_last_exec(bContext *C, wmOperator *op)
  {
-       struct {Scene *scene;  short *mval; float rad; rcti* rect; int select; } data;
-       Object *ob=NULL; // XXX
-       Scene *scene= NULL;
-       ParticleSystem *psys = PE_get_current(ob);
-       short mval[2];
-       int shift= 0; // XXX
+       PEData data;
+       PE_set_data(C, &data);
+       PE_foreach_particle(&data, select_tip);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
+       return OPERATOR_FINISHED;
+ }
+ void PARTICLE_OT_select_last(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Select Last";
+       ot->idname= "PARTICLE_OT_select_last";
        
-       if(!PE_can_edit(psys)) return;
+       /* api callbacks */
+       ot->exec= select_last_exec;
+       ot->poll= PE_poll;
  
- //    getmouseco_areawin(mval);
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ }
  
-       data.scene= NULL; // XXX
-       data.mval=mval;
+ /************************ select linked operator ************************/
+ static int select_linked_exec(bContext *C, wmOperator *op)
+ {
+       PEData data;
+       short mval[2];
+       int location[2];
+       RNA_int_get_array(op->ptr, "location", location);
+       mval[0]= location[0];
+       mval[1]= location[1];
 -      view3d_operator_needs_opengl(C);
 -
+       PE_set_view3d_data(C, &data);
+       data.mval= mval;
        data.rad=75.0f;
-       data.rect=0;
-       data.select=(shift);
+       data.select= !RNA_boolean_get(op->ptr, "deselect");
  
-       for_mouse_hit_keys(1,psys,select_keys,&data);
+       for_mouse_hit_keys(&data, select_keys, 1);  /* nearest only */
+       PE_update_selection(data.scene, data.ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
  
-       PE_update_selection(scene, ob, 1);
+       return OPERATOR_FINISHED;
+ }
  
-       BIF_undo_push("Select linked keys");
+ static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
+ {
+       ARegion *ar= CTX_wm_region(C);
+       int location[2];
+       location[0]= event->x - ar->winrct.xmin;
+       location[1]= event->y - ar->winrct.ymin;
+       RNA_int_set_array(op->ptr, "location", location);
+       return select_linked_exec(C, op);
+ }
+ void PARTICLE_OT_select_linked(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Select Linked";
+       ot->idname= "PARTICLE_OT_select_linked";
+       
+       /* api callbacks */
+       ot->exec= select_linked_exec;
+       ot->invoke= select_linked_invoke;
+       ot->poll= PE_poll_3dview;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
  
-       return;
+       /* properties */
+       RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them.");
+       RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
  }
  
- void PE_borderselect(ViewContext *vc, rcti *rect, int select)
+ /************************ border select operator ************************/
 -int PE_border_select(bContext *C, rcti *rect, int select)
++void PE_border_select(ViewContext *vc, rcti *rect, int select)
  {
-       struct {Scene *scene;  short *mval; float rad; rcti* rect; int select; } data;
 -      Scene *scene= CTX_data_scene(C);
 -      Object *ob= CTX_data_active_object(C);
 +      Scene *scene= vc->scene;
 +      Object *ob= vc->obact;
-       ParticleSystem *psys = PE_get_current(ob);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       PEData data;
  
 -      if(!PE_can_edit(psys))
 -              return OPERATOR_CANCELLED;
 +      if(!PE_can_edit(psys)) return;
  
 -      PE_set_view3d_data(C, &data);
++      memset(&data, 0, sizeof(data));
++      data.vc= *vc;
 +      data.scene= scene;
-       data.mval=0;
++      data.ob= ob;
++      data.psys= psys;
        data.rect= rect;
        data.select= select;
  
-       for_mouse_hit_keys(0, psys, select_key, &data);
+       for_mouse_hit_keys(&data, select_key, 0);
  
        PE_update_selection(scene, ob, 1);
 -      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
  
-       BIF_undo_push("Select keys");
-       return;
 -      return OPERATOR_FINISHED;
++      /* XXX undo, notifier */
++      PE_undo_push(scene, "Border Select");
  }
  
- void PE_selectionCB(short selecting, Object *editobj, short *mval, float rad)
+ /************************ circle select operator ************************/
 -int PE_circle_select(bContext *C, int selecting, short *mval, float rad)
++void PE_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
  {
-       struct {Scene *scene;  short *mval; float rad; rcti* rect; int select; } data;
-       Scene *scene= NULL;
-       ParticleSystem *psys = PE_get_current(OBACT);
 -      Scene *scene= CTX_data_scene(C);
 -      Object *ob= CTX_data_active_object(C);
++      Scene *scene= vc->scene;
++      Object *ob= vc->obact;
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       PEData data;
  
 -      if(!PE_can_edit(psys))
 -              return OPERATOR_FINISHED;
 +      if(!PE_can_edit(psys)) return;
  
 -      PE_set_view3d_data(C, &data);
 -      data.mval= mval;
 -      data.rad= rad;
++      memset(&data, 0, sizeof(data));
++      data.vc= *vc;
 +      data.scene= scene;
++      data.ob= ob;
++      data.psys= psys;
 +      data.mval=mval;
 +      data.rad=rad;
-       data.rect=0;
-       data.select=(selecting==LEFTMOUSE);
+       data.select= selecting;
  
-       for_mouse_hit_keys(0,psys,select_key,&data);
+       for_mouse_hit_keys(&data, select_key, 0);
  
- //    draw_sel_circle(0, 0, 0, 0, 0); /* signal */
 -      PE_update_selection(scene, ob, 1);
 -      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
 -
 -      return OPERATOR_FINISHED;
++      /* XXX undo, notifier */
++      PE_undo_push(scene, "Circle Select");
  }
  
- void PE_do_lasso_select(ViewContext *vc, short mcords[][2], short moves, short select)
+ /************************ lasso select operator ************************/
 -int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
++void PE_lasso_select(ViewContext *vc, short mcords[][2], short moves, short select)
  {
 -      Scene *scene= CTX_data_scene(C);
 -      Object *ob= CTX_data_active_object(C);
 -      ARegion *ar= CTX_wm_region(C);
 +      Scene *scene= vc->scene;
 +      ARegion *ar= vc->ar;
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
++      Object *ob= OBACT;
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleSystemModifierData *psmd;
        ParticleEdit *edit;
        ParticleData *pa;
        short vertco[2];
        int i, k, totpart;
  
 -      if(!PE_can_edit(psys))
 -              return OPERATOR_CANCELLED;
 +      if(!PE_can_edit(psys)) return;
  
        psmd= psys_get_modifier(ob, psys);
 -      edit= psys->edit;
 -      totpart= psys->totpart;
 +      edit=psys->edit;
 +      totpart=psys->totpart;
  
-       LOOP_PARTICLES(i,pa){
 -      LOOP_PARTICLES(i, pa) {
++      LOOP_PARTICLES(i,pa) {
                if(pa->flag & PARS_HIDE) continue;
  
                psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
  
-               if(scene->selectmode==SCE_SELECT_POINT){
-                       LOOP_KEYS(k,key){
+               if(scene->selectmode==SCE_SELECT_POINT) {
 -                      LOOP_KEYS(k, key) {
++                      LOOP_KEYS(k,key) {
                                VECCOPY(co, key->co);
                                Mat4MulVecfl(mat, co);
                                project_short(ar, co, vertco);
        }
  
        PE_update_selection(scene, ob, 1);
 -      WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
  
-       BIF_undo_push("Lasso select particles");
 -      return OPERATOR_FINISHED;
++      /* XXX undo, notifier */
++      PE_undo_push(scene, "Lasso select particles");
  }
  
- void PE_hide(int mode)
+ /*************************** hide operator **************************/
+ static int hide_exec(bContext *C, wmOperator *op)
  {
-       Scene *scene= NULL;
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
+       Object *ob= CTX_data_active_object(C);
+       Scene *scene= CTX_data_scene(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleEdit *edit;
        ParticleEditKey *key;
        ParticleData *pa;
@@@ -1746,10 -1885,10 +2068,10 @@@ static int remove_tagged_particles(Scen
  
        if(pset->flag & PE_X_MIRROR) {
                /* mirror tags */
-               psmd = psys_get_modifier(ob, psys);
-               totpart = psys->totpart;
+               psmd= psys_get_modifier(ob, psys);
+               totpart= psys->totpart;
  
 -              LOOP_PARTICLES(i, pa)
 +              LOOP_PARTICLES(i,pa)
                        if(pa->flag & PARS_TAG)
                                PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
        }
@@@ -1816,9 -1955,9 +2138,9 @@@ static void remove_tagged_keys(Scene *s
  
        if(pset->flag & PE_X_MIRROR) {
                /* mirror key tags */
-               psmd = psys_get_modifier(ob, psys);
+               psmd= psys_get_modifier(ob, psys);
  
 -              LOOP_PARTICLES(i, pa) {
 +              LOOP_PARTICLES(i,pa) {
                        LOOP_KEYS(k,ekey) {
                                if(ekey->flag & PEK_TAG) {
                                        PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
                }
        }
  
 -      LOOP_PARTICLES(i, pa) {
 +      LOOP_PARTICLES(i,pa) {
-               new_totkey = pa->totkey;
+               new_totkey= pa->totkey;
                LOOP_KEYS(k,ekey) {
                        if(ekey->flag & PEK_TAG)
                                new_totkey--;
                if(new_totkey < 2)
                        pa->flag |= PARS_TAG;
        }
-       remove_tagged_elements(scene, ob, psys);
+       remove_tagged_particles(scene, ob, psys);
  
-       totpart = psys->totpart;
+       totpart= psys->totpart;
  
 -      LOOP_PARTICLES(i, pa) {
 +      LOOP_PARTICLES(i,pa) {
-               new_totkey = pa->totkey;
+               new_totkey= pa->totkey;
                LOOP_KEYS(k,ekey) {
                        if(ekey->flag & PEK_TAG)
                                new_totkey--;
@@@ -1958,33 -2100,45 +2283,45 @@@ static void subdivide_particle(PEData *
        pa->flag &= ~PARS_REKEY;
  }
  
void PE_subdivide(Object *ob)
static int subdivide_exec(bContext *C, wmOperator *op)
  {
-       ParticleSystem *psys = PE_get_current(ob);
-       Scene *scene= NULL;
-       struct {Scene *scene; Object *ob; } data;
-       if(!PE_can_edit(psys)) return;
+       PEData data;
  
-       data.scene= scene;
-       data.ob= ob;
-       PE_foreach_element(psys,subdivide_element,&data);
+       PE_set_data(C, &data);
+       PE_foreach_particle(&data, subdivide_particle);
        
-       psys->edit->totkeys = psys_count_keys(psys);
+       data.psys->edit->totkeys= psys_count_keys(data.psys);
        
-       recalc_lengths(psys);
-       PE_recalc_world_cos(ob, psys);
+       recalc_lengths(data.psys);
 -      psys_update_world_cos(data.ob, data.psys);
++      PE_recalc_world_cos(data.ob, data.psys);
+       PE_update_object(data.scene, data.ob, 1);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
+       return OPERATOR_FINISHED;
+ }
  
-       PE_update_object(scene, ob, 1);
+ void PARTICLE_OT_subdivide(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Subdivide";
+       ot->idname= "PARTICLE_OT_subdivide";
        
-       BIF_undo_push("Subdivide hair(s)");
+       /* api callbacks */
+       ot->exec= subdivide_exec;
+       ot->poll= PE_poll;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
  }
  
- void PE_remove_doubles()
+ /************************ remove doubles opertor *********************/
+ static int remove_doubles_exec(bContext *C, wmOperator *op)
  {
-       Scene *scene= NULL; // XXX
-       Object *ob=OBACT;
-       ParticleSystem *psys=PE_get_current(ob);
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
        ParticleEditSettings *pset=PE_settings(scene);
        ParticleData *pa;
        ParticleEdit *edit;
                totremoved += removed;
        } while(removed);
  
- //    if(totremoved)
- // XXX                notice("Removed: %d", totremoved);
+       if(totremoved == 0)
+               return OPERATOR_CANCELLED;
+       BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved);
  
 -      psys_update_world_cos(ob, psys);
 +      PE_recalc_world_cos(ob, psys);
        DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-       BIF_undo_push("Remove double particles");
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
+       return OPERATOR_FINISHED;
+ }
+ void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Remove Doubles";
+       ot->idname= "PARTICLE_OT_remove_doubles";
+       
+       /* api callbacks */
+       ot->exec= remove_doubles_exec;
+       ot->poll= PE_poll;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       /* properties */
+       RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
  }
  
 -/************************ cursor drawing *******************************/
 -
 -static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
 -{
 -      ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
 -      ParticleBrushData *brush;
 -
 -      if(pset->brushtype < 0)
 -              return;
 -
 -      brush= &pset->brush[pset->brushtype];
 -
 -      if(brush) {
 -              glPushMatrix();
 -
 -              glTranslatef((float)x, (float)y, 0.0f);
 -
 -              glColor4ub(255, 255, 255, 128);
 -              glEnable(GL_LINE_SMOOTH );
 -              glEnable(GL_BLEND);
 -              glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
 -              glDisable(GL_BLEND);
 -              glDisable(GL_LINE_SMOOTH );
 -              
 -              glPopMatrix();
 -      }
 -}
 -
 -static void toggle_particle_cursor(bContext *C, int enable)
 -{
 -      ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
 -
 -      if(pset->paintcursor && !enable) {
 -              WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
 -              pset->paintcursor = NULL;
 -      }
 -      else if(enable)
 -              pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll, brush_drawcursor, NULL);
 -}
 -
+ /********************* radial control operator *********************/
 -static int brush_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
 +/* XXX static */
 +void PE_radialcontrol_callback(const int mode, const int val)
  {
-       ParticleEditSettings *pset = NULL; // XXX PE_settings(scene);
 -      ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
 -      ParticleBrushData *brush;
 -      int mode = RNA_enum_get(op->ptr, "mode");
 -      float original_value;
 -
 -      if(pset->brushtype < 0)
 -              return OPERATOR_CANCELLED;
 -
 -      brush= &pset->brush[pset->brushtype];
 -
 -      toggle_particle_cursor(C, 0);
++      ParticleEditSettings *pset= NULL; // XXX PE_settings(scene);
  
 -      if(mode == WM_RADIALCONTROL_SIZE)
 -              original_value = brush->size;
 -      else if(mode == WM_RADIALCONTROL_STRENGTH)
 -              original_value = brush->strength;
 +      if(pset->brushtype>=0) {
 +              ParticleBrushData *brush= &pset->brush[pset->brushtype];
  
 -      RNA_float_set(op->ptr, "initial_value", original_value);
 +              if(mode == RADIALCONTROL_SIZE)
-                       brush->size = val;
++                      brush->size= val;
 +              else if(mode == RADIALCONTROL_STRENGTH)
-                       brush->strength = val;
++                      brush->strength= val;
 +      }
  
-       (*PE_radialcontrol()) = NULL;
 -      return WM_radial_control_invoke(C, op, event);
++      (*PE_radialcontrol())= NULL;
  }
  
 -static int brush_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
 +struct RadialControl **PE_radialcontrol(void)
  {
-       static struct RadialControl *rc = NULL;
 -      int ret = WM_radial_control_modal(C, op, event);
 -
 -      if(ret != OPERATOR_RUNNING_MODAL)
 -              toggle_particle_cursor(C, 1);
 -
 -      return ret;
++      static struct RadialControl *rc= NULL;
 +      return &rc;
  }
  
 -static int brush_radial_control_exec(bContext *C, wmOperator *op)
 +void PE_radialcontrol_start(const int mode)
  {
-       ParticleEditSettings *pset = NULL; // XXX PE_settings(scene);
 -      ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
 -      ParticleBrushData *brush;
 -      int mode = RNA_enum_get(op->ptr, "mode");
 -      float new_value = RNA_float_get(op->ptr, "new_value");
 -      char str[256];
 -
 -      if(pset->brushtype < 0)
 -              return OPERATOR_CANCELLED;
 -
 -      brush= &pset->brush[pset->brushtype];
++      ParticleEditSettings *pset= NULL; // XXX PE_settings(scene);
 +      int orig= 1;
  
 -      if(mode == WM_RADIALCONTROL_SIZE)
 -              brush->size= new_value;
 -      else if(mode == WM_RADIALCONTROL_STRENGTH)
 -              brush->strength= new_value;
 -
 -      WM_radial_control_string(op, str, 256);
 -
 -      return OPERATOR_FINISHED;
 -}
 -
 -void PARTICLE_OT_brush_radial_control(wmOperatorType *ot)
 -{
 -      WM_OT_radial_control_partial(ot);
 -
 -      ot->name= "Brush Radial Control";
 -      ot->idname= "PARTICLE_OT_brush_radial_control";
 -
 -      ot->invoke= brush_radial_control_invoke;
 -      ot->modal= brush_radial_control_modal;
 -      ot->exec= brush_radial_control_exec;
 -      ot->poll= PE_poll;
 -      
 -      /* flags */
 -      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      if(pset->brushtype>=0) {
 +              ParticleBrushData *brush= &pset->brush[pset->brushtype];
 +              
 +              if(mode == RADIALCONTROL_SIZE)
-                       orig = brush->size;
++                      orig= brush->size;
 +              else if(mode == RADIALCONTROL_STRENGTH)
-                       orig = brush->strength;
++                      orig= brush->strength;
 +              
 +//            if(mode != RADIALCONTROL_NONE)
 +//                    (*PE_radialcontrol())= radialcontrol_start(mode, PE_radialcontrol_callback, orig, 100, 0);
 +      }
  }
  
- /************************************************/
- /*                    Edit Brushes                                            */
- /************************************************/
- static void brush_comb(ParticleSystem *psys, float mat[][4], float imat[][4], int pa_index, int key_index, void *userData)
- {
-       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float *dvec; float combfac;} *data = userData;
-       ParticleData *pa= &psys->particles[pa_index];
-       ParticleEditSettings *pset= PE_settings(data->scene);
-       HairKey *key = pa->hair + key_index;
-       float cvec[3], fac;
+ /*************************** delete operator **************************/
  
      if(pset->flag & PE_LOCK_FIRST && key_index == 0) return;
enum { DEL_PARTICLE, DEL_KEY };
  
-       fac = (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
+ static EnumPropertyItem delete_type_items[]= {
+       {DEL_PARTICLE, "PARTICLE", "Particle", ""},
+       {DEL_KEY, "KEY", "Key", ""},
+       {0, NULL, NULL}};
  
-       VECCOPY(cvec,data->dvec);
-       Mat4Mul3Vecfl(imat,cvec);
-       VecMulf(cvec, fac);
-       VECADD(key->co, key->co, cvec);
+ static void set_delete_particle(PEData *data, int pa_index)
+ {
+       ParticleSystem *psys= data->psys;
  
-       pa->flag |= PARS_EDIT_RECALC;
+       psys->particles[pa_index].flag |= PARS_TAG;
  }
  
- static void brush_cut(ParticleSystem *psys, int index, void *userData)
+ static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
  {
-       struct {Scene *scene; short *mval; float rad; rcti* rect; int selected; float cutfac; bglMats mats;} *data = userData;
-       ARegion *ar= NULL; // XXX
-       Object *ob= NULL; // XXX
-       ParticleData *pa= &psys->particles[index];
-       ParticleCacheKey *key = psys->pathcache[index];
-       float rad2, cut_time = 1.0;
-       float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
-       int k, cut, keys = (int)pow(2.0, (double)psys->part->draw_step);
-       short vertco[2];
+       ParticleSystem *psys= data->psys;
  
-       /* blunt scissors */
-       if(BLI_frand() > data->cutfac) return;
+       psys->edit->keys[pa_index][key_index].flag |= PEK_TAG;
+ }
  
-       rad2 = data->rad * data->rad;
+ static int delete_exec(bContext *C, wmOperator *op)
+ {
+       PEData data;
+       int type= RNA_enum_get(op->ptr, "type");
  
-       cut=0;
+       PE_set_data(C, &data);
  
-       project_short_noclip(ar, key->co, vertco);
-       x0 = (float)vertco[0];
-       x1 = (float)vertco[1];
+       if(type == DEL_KEY) {
+               foreach_selected_key(&data, set_delete_particle_key);
+               remove_tagged_keys(data.scene, data.ob, data.psys);
+               recalc_lengths(data.psys);
+       }
+       else if(type == DEL_PARTICLE) {
+               foreach_selected_particle(&data, set_delete_particle);
+               remove_tagged_particles(data.scene, data.ob, data.psys);
+               recalc_lengths(data.psys);
+       }
  
-       o0 = (float)data->mval[0];
-       o1 = (float)data->mval[1];
+       DAG_object_flush_update(data.scene, data.ob, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
+       return OPERATOR_FINISHED;
+ }
+ void PARTICLE_OT_delete(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Delete";
+       ot->idname= "PARTICLE_OT_delete";
        
-       xo0 = x0 - o0;
-       xo1 = x1 - o1;
+       /* api callbacks */
+       ot->exec= delete_exec;
+       ot->invoke= WM_menu_invoke;
+       ot->poll= PE_poll;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       /* properties */
+       RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys.");
+ }
+ /*************************** mirror operator **************************/
+ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
+ {
+       Mesh *me= (Mesh*)(ob->data);
+       ParticleSystemModifierData *psmd;
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       ParticleEdit *edit;
+       ParticleData *pa, *newpa, *new_pars;
+       ParticleEditKey *ekey, **newkey, **key, **new_keys;
+       HairKey *hkey;
+       int *mirrorfaces;
+       int i, k, rotation, totpart, newtotpart;
+       edit= psys->edit;
+       psmd= psys_get_modifier(ob, psys);
 -      mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
++      mirrorfaces= mesh_get_x_mirror_faces(ob);
+       if(!edit->mirror_cache)
+               PE_update_mirror_cache(ob, psys);
+       totpart= psys->totpart;
+       newtotpart= psys->totpart;
 -      LOOP_PARTICLES(i, pa) {
++      LOOP_PARTICLES(i,pa) {
+               if(pa->flag & PARS_HIDE) continue;
+               if(!tagged) {
+                       if(particle_is_selected(psys, pa)) {
+                               if(edit->mirror_cache[i] != -1) {
+                                       /* already has a mirror, don't need to duplicate */
+                                       PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
+                                       continue;
+                               }
+                               else
+                                       pa->flag |= PARS_TAG;
+                       }
+               }
+               if((pa->flag & PARS_TAG) && mirrorfaces[pa->num*2] != -1)
+                       newtotpart++;
+       }
+       if(newtotpart != psys->totpart) {
+               /* allocate new arrays and copy existing */
+               new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
+               new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey*), "ParticleEditKey new");
+               memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
+               memcpy(new_keys, edit->keys, totpart*sizeof(ParticleEditKey*));
+               if(psys->particles) MEM_freeN(psys->particles);
+               psys->particles= new_pars;
+               if(edit->keys) MEM_freeN(edit->keys);
+               edit->keys= new_keys;
+               if(edit->mirror_cache) {
+                       MEM_freeN(edit->mirror_cache);
+                       edit->mirror_cache= NULL;
+               }
+               psys->totpart= newtotpart;
+                       
+               /* create new elements */
+               pa= psys->particles;
+               newpa= psys->particles + totpart;
+               key= edit->keys;
+               newkey= edit->keys + totpart;
+               for(i=0; i<totpart; i++, pa++, key++) {
+                       if(pa->flag & PARS_HIDE) continue;
+                       if(!(pa->flag & PARS_TAG) || mirrorfaces[pa->num*2] == -1)
+                               continue;
+                       /* duplicate */
+                       *newpa= *pa;
+                       if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
+                       if(pa->keys) newpa->keys= MEM_dupallocN(pa->keys);
+                       if(*key) *newkey= MEM_dupallocN(*key);
+                       /* rotate weights according to vertex index rotation */
+                       rotation= mirrorfaces[pa->num*2+1];
+                       newpa->fuv[0]= pa->fuv[2];
+                       newpa->fuv[1]= pa->fuv[1];
+                       newpa->fuv[2]= pa->fuv[0];
+                       newpa->fuv[3]= pa->fuv[3];
+                       while(rotation-- > 0)
+                               if(me->mface[pa->num].v4)
+                                       SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
+                               else
+                                       SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
+                       /* assign face inddex */
+                       newpa->num= mirrorfaces[pa->num*2];
+                       newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
+                       /* update edit key pointers */
+                       ekey= *newkey;
+                       for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, ekey++) {
+                               ekey->co= hkey->co;
+                               ekey->time= &hkey->time;
+                       }
+                       /* map key positions as mirror over x axis */
+                       PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
+                       newpa++;
+                       newkey++;
+               }
+               edit->totkeys= psys_count_keys(psys);
+       }
+       for(pa=psys->particles, i=0; i<psys->totpart; i++, pa++)
+               pa->flag &= ~PARS_TAG;
+       MEM_freeN(mirrorfaces);
+ }
+ static int mirror_exec(bContext *C, wmOperator *op)
+ {
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       
+       PE_mirror_x(scene, ob, 0);
 -      psys_update_world_cos(ob, psys);
++      PE_recalc_world_cos(ob, psys);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
+       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+       return OPERATOR_FINISHED;
+ }
+ void PARTICLE_OT_mirror(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Mirror";
+       ot->idname= "PARTICLE_OT_mirror";
+       
+       /* api callbacks */
+       ot->exec= mirror_exec;
+       ot->poll= PE_poll;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+ }
+ /*********************** set brush operator **********************/
+ static EnumPropertyItem brush_type_items[]= {
+       {PE_BRUSH_NONE, "NONE", "None", ""},
+       {PE_BRUSH_COMB, "COMB", "Comb", ""},
+       {PE_BRUSH_SMOOTH, "SMOOTH", "Smooth", ""},
+       {PE_BRUSH_WEIGHT, "WEIGHT", "Weight", ""},
+       {PE_BRUSH_ADD, "ADD", "Add", ""},
+       {PE_BRUSH_LENGTH, "LENGTH", "Length", ""},
+       {PE_BRUSH_PUFF, "PUFF", "Puff", ""},
+       {PE_BRUSH_CUT, "CUT", "Cut", ""},
+       {0, NULL, NULL, NULL}
+ };
+ static int set_brush_exec(bContext *C, wmOperator *op)
+ {
+       Scene *scene= CTX_data_scene(C);
+       ParticleEditSettings *pset= PE_settings(scene);
+       pset->brushtype= RNA_enum_get(op->ptr, "type");
+       return OPERATOR_FINISHED;
+ }
+ void PARTICLE_OT_set_brush(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Set Brush";
+       ot->idname= "PARTICLE_OT_set_brush";
+       
+       /* api callbacks */
+       ot->exec= set_brush_exec;
+       ot->invoke= WM_menu_invoke;
+       ot->poll= PE_poll;
+       /* properties */
+       RNA_def_enum(ot->srna, "type", brush_type_items, PE_BRUSH_NONE, "Type", "Brush type to select for editing.");
+ }
+ /************************* brush edit callbacks ********************/
+ static void brush_comb(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
+ {
+       ParticleSystem *psys= data->psys;
+       ParticleData *pa= &psys->particles[pa_index];
+       ParticleEditSettings *pset= PE_settings(data->scene);
+       HairKey *key= pa->hair + key_index;
+       float cvec[3], fac;
+       if(pset->flag & PE_LOCK_FIRST && key_index == 0) return;
+       fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
+       VECCOPY(cvec,data->dvec);
+       Mat4Mul3Vecfl(imat,cvec);
+       VecMulf(cvec, fac);
+       VECADD(key->co, key->co, cvec);
+       pa->flag |= PARS_EDIT_RECALC;
+ }
+ static void brush_cut(PEData *data, int pa_index)
+ {
+       ParticleSystem *psys= data->psys;
+       ARegion *ar= data->vc.ar;
+       Object *ob= data->ob;
+       ParticleData *pa= &psys->particles[pa_index];
+       ParticleCacheKey *key= psys->pathcache[pa_index];
+       float rad2, cut_time= 1.0;
+       float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
+       int k, cut, keys= (int)pow(2.0, (double)psys->part->draw_step);
+       short vertco[2];
+       /* blunt scissors */
+       if(BLI_frand() > data->cutfac) return;
+       rad2= data->rad * data->rad;
+       cut=0;
+       project_short_noclip(ar, key->co, vertco);
+       x0= (float)vertco[0];
+       x1= (float)vertco[1];
+       o0= (float)data->mval[0];
+       o1= (float)data->mval[1];
+       
+       xo0= x0 - o0;
+       xo1= x1 - o1;
  
        /* check if root is inside circle */
-       if(xo0*xo0 + xo1*xo1 < rad2 && test_key_depth(key->co,&(data->mats))) {
-               cut_time = -1.0f;
-               cut = 1;
+       if(xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) {
+               cut_time= -1.0f;
+               cut= 1;
        }
        else {
                /* calculate path time closest to root that was inside the circle */
@@@ -2597,403 -3028,339 +3139,339 @@@ static void brush_weight(PEData *data, 
        }
  }
  
- /* returns 0 if no brush was used */
- int PE_brush_particles(void)
- {
-       Scene *scene= NULL; // XXX
-       ARegion *ar= NULL; // XXX
-       Object *ob = OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
-       ParticleEdit *edit;
-       ParticleEditSettings *pset = PE_settings(scene);
-       ParticleSystemModifierData *psmd;
-       ParticleBrushData *brush;
-       float vec1[3], vec2[3];
-       short mval[2], mvalo[2], firsttime = 1, dx, dy;
-       int selected = 0, flip, removed = 0;
+ /************************* brush edit operator ********************/
  
-       if(!PE_can_edit(psys)) return 0;
+ typedef struct BrushEdit {
+       Scene *scene;
+       Object *ob;
+       ParticleSystem *psys;
  
-       edit = psys->edit;
-       psmd= psys_get_modifier(ob, psys);
+       int first;
+       int lastmouse[2];
+ } BrushEdit;
  
- // XXX        flip= (get_qual() == LR_SHIFTKEY);
+ static int brush_edit_init(bContext *C, wmOperator *op)
+ {
+       Scene *scene= CTX_data_scene(C);
+       Object *ob= CTX_data_active_object(C);
+       ParticleSystem *psys= PE_get_current(scene, ob);
+       ParticleEditSettings *pset= PE_settings(scene);
+       ARegion *ar= CTX_wm_region(C);
+       BrushEdit *bedit;
  
-       if(pset->brushtype<0) return 0;
-       brush= &pset->brush[pset->brushtype];
+       if(pset->brushtype < 0)
+               return 0;
  
++      // XXX
        initgrabz(ar->regiondata, ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]);
  
- //    getmouseco_areawin(mvalo);
-       mval[0] = mvalo[0]; mval[1] = mvalo[1];
-       while(0){ // XXX get_mbut
-               bglFlush();
-               glReadBuffer(GL_BACK);
-               glDrawBuffer(GL_BACK);
- //            persp(PERSP_VIEW);
+       bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit");
+       bedit->first= 1;
+       op->customdata= bedit;
  
-               dx=mval[0]-mvalo[0];
-               dy=mval[1]-mvalo[1];
-               if(((pset->brushtype == PE_BRUSH_ADD) ?
-                       (sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0))
-                       || firsttime){
-                       firsttime = 0;
+       bedit->scene= scene;
+       bedit->ob= ob;
+       bedit->psys= psys;
  
-                       selected = (short)count_selected_keys(scene, psys);
+       return 1;
+ }
  
-                       switch(pset->brushtype){
-                               case PE_BRUSH_COMB:
-                               {
-                                       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float *dvec; float combfac;} data;
+ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
+ {
+       BrushEdit *bedit= op->customdata;
+       Scene *scene= bedit->scene;
+       Object *ob= bedit->ob;
+       ParticleSystem *psys= bedit->psys;
+       ParticleEditSettings *pset= PE_settings(scene);
+       ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
+       ParticleBrushData *brush= &pset->brush[pset->brushtype];
+       ARegion *ar= CTX_wm_region(C);
+       float vec1[3], vec2[3];
+       short mval[2], mvalo[2];
+       int flip, mouse[2], dx, dy, removed= 0, selected= 0;
  
-                                       data.scene = scene;
-                                       data.ob = ob;
-                                       data.mval = mval;
-                                       data.rad = (float)brush->size;
+       RNA_int_get_array(itemptr, "mouse", mouse);
+       flip= RNA_boolean_get(itemptr, "flip");
  
-                                       data.combfac = (float)(brush->strength - 50) / 50.0f;
-                                       if(data.combfac < 0.0f)
-                                               data.combfac = 1.0f - 9.0f * data.combfac;
-                                       else
-                                               data.combfac = 1.0f - data.combfac;
 -      if(bedit->first) {
 -              bedit->lastmouse[0]= mouse[0];
 -              bedit->lastmouse[1]= mouse[1];
 -      }
++      bglFlush();
++      glReadBuffer(GL_BACK);
++      glDrawBuffer(GL_BACK);
++//            persp(PERSP_VIEW);
  
-                                       Mat4Invert(ob->imat, ob->obmat);
+       dx= mouse[0] - bedit->lastmouse[0];
+       dy= mouse[1] - bedit->lastmouse[1];
  
-                                       window_to_3d(ar, vec1, mvalo[0], mvalo[1]);
-                                       window_to_3d(ar, vec2, mval[0], mval[1]);
-                                       VECSUB(vec1, vec2, vec1);
-                                       data.dvec = vec1;
+       mval[0]= mouse[0];
+       mval[1]= mouse[1];
  
-                                       foreach_mouse_hit_key(selected, psys,brush_comb, &data);
-                                       break;
-                               }
-                               case PE_BRUSH_CUT:
-                               {
-                                       struct {Scene *scene; short *mval; float rad; rcti* rect; int selected; float cutfac; bglMats mats;} data;
+       mvalo[0]= bedit->lastmouse[0];
+       mvalo[1]= bedit->lastmouse[1];
  
-                                       data.scene = scene;
-                                       data.mval = mval;
-                                       data.rad = (float)brush->size;
+       if(((pset->brushtype == PE_BRUSH_ADD) ?
+               (sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0))
+               || bedit->first) {
  
-                                       data.selected = selected;
 -              view3d_operator_needs_opengl(C);
+               selected= (short)count_selected_keys(scene, psys);
  
-                                       data.cutfac = (float)(brush->strength / 100.0f);
+               switch(pset->brushtype) {
+                       case PE_BRUSH_COMB:
+                       {
+                               PEData data;
  
-                                       bgl_get_mats(&(data.mats));
+                               PE_set_view3d_data(C, &data);
+                               data.mval= mval;
+                               data.rad= (float)brush->size;
  
-                                       if(selected)
-                                               foreach_selected_element(psys, brush_cut, &data);
-                                       else
-                                               PE_foreach_element(psys, brush_cut, &data);
+                               data.combfac= (float)(brush->strength - 50) / 50.0f;
+                               if(data.combfac < 0.0f)
+                                       data.combfac= 1.0f - 9.0f * data.combfac;
+                               else
+                                       data.combfac= 1.0f - data.combfac;
  
-                                       removed= remove_tagged_elements(scene, ob, psys);
-                                       if(pset->flag & PE_KEEP_LENGTHS)
-                                               recalc_lengths(psys);
-                                       break;
-                               }
-                               case PE_BRUSH_LENGTH:
-                               {
-                                       struct {Scene *scene; short *mval; float rad; rcti* rect; float dist; float growfac; } data;
-                                       
-                                       data.scene= scene;
-                                       data.mval = mval;
-                                       
-                                       data.rad = (float)brush->size;
-                                       data.growfac = (float)brush->strength / 5000.0f;
+                               Mat4Invert(ob->imat, ob->obmat);
  
-                                       if(brush->invert ^ flip)
-                                               data.growfac = 1.0f - data.growfac;
-                                       else
-                                               data.growfac = 1.0f + data.growfac;
+                               window_to_3d(ar, vec1, mvalo[0], mvalo[1]);
+                               window_to_3d(ar, vec2, mval[0], mval[1]);
+                               VECSUB(vec1, vec2, vec1);
+                               data.dvec= vec1;
  
-                                       foreach_mouse_hit_element(selected, psys, brush_length, &data);
+                               foreach_mouse_hit_key(&data, brush_comb, selected);
+                               break;
+                       }
+                       case PE_BRUSH_CUT:
+                       {
+                               PEData data;
  
-                                       if(pset->flag & PE_KEEP_LENGTHS)
-                                               recalc_lengths(psys);
-                                       break;
-                               }
-                               case PE_BRUSH_PUFF:
-                               {
-                                       struct {Scene *scene; short *mval; float rad; rcti* rect; float dist;
-                                               Object *ob; DerivedMesh *dm; float pufffac; int invert; } data;
-                                       data.scene= scene;
-                                       data.ob = ob;
-                                       data.dm = psmd->dm;
-                                       data.mval = mval;
-                                       data.rad = (float)brush->size;
-                                       data.pufffac = (float)(brush->strength - 50) / 50.0f;
-                                       if(data.pufffac < 0.0f)
-                                               data.pufffac = 1.0f - 9.0f * data.pufffac;
-                                       else
-                                               data.pufffac = 1.0f - data.pufffac;
-                                       data.invert= (brush->invert ^ flip);
-                                       Mat4Invert(ob->imat, ob->obmat);
-                                       foreach_mouse_hit_element(selected, psys, brush_puff, &data);
-                                       break;
-                               }
-                               case PE_BRUSH_ADD:
-                                       if(psys->part->from==PART_FROM_FACE){
-                                               brush_add(scene, ob, psys, mval, brush->strength);
-                                               if(pset->flag & PE_KEEP_LENGTHS)
-                                                       recalc_lengths(psys);
-                                       }
-                                       break;
-                               case PE_BRUSH_WEIGHT:
-                               {
-                                       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float weightfac;} data;
+                               PE_set_view3d_data(C, &data);
+                               data.mval= mval;
+                               data.rad= (float)brush->size;
+                               data.cutfac= (float)(brush->strength / 100.0f);
  
-                                       data.scene = scene;
-                                       data.ob = ob;
-                                       data.mval = mval;
-                                       data.rad = (float)brush->size;
+                               if(selected)
+                                       foreach_selected_particle(&data, brush_cut);
+                               else
+                                       PE_foreach_particle(&data, brush_cut);
  
-                                       data.weightfac = (float)(brush->strength / 100.0f);
+                               removed= remove_tagged_particles(scene, ob, psys);
+                               if(pset->flag & PE_KEEP_LENGTHS)
+                                       recalc_lengths(psys);
+                               break;
+                       }
+                       case PE_BRUSH_LENGTH:
+                       {
+                               PEData data;
+                               
+                               PE_set_view3d_data(C, &data);
+                               data.mval= mval;
+                               
+                               data.rad= (float)brush->size;
+                               data.growfac= (float)brush->strength / 5000.0f;
  
-                                       foreach_mouse_hit_key(selected, psys, brush_weight, &data);
-                                       break;
-                               }
-                               case PE_BRUSH_SMOOTH:
-                               {
-                                       struct {Scene *scene; Object *ob; short *mval; float rad; rcti* rect; float dist; float vec[3]; int tot; float smoothfac;} data;
+                               if(brush->invert ^ flip)
+                                       data.growfac= 1.0f - data.growfac;
+                               else
+                                       data.growfac= 1.0f + data.growfac;
  
-                                       data.scene = scene;
-                                       data.ob = ob;
-                                       data.mval = mval;
-                                       data.rad = (float)brush->size;
+                               foreach_mouse_hit_particle(&data, brush_length, selected);
  
-                                       data.vec[0] = data.vec[1] = data.vec[2] = 0.0f;
-                                       data.tot = 0;
+                               if(pset->flag & PE_KEEP_LENGTHS)
+                                       recalc_lengths(psys);
+                               break;
+                       }
+                       case PE_BRUSH_PUFF:
+                       {
+                               PEData data;
+                               PE_set_view3d_data(C, &data);
+                               data.dm= psmd->dm;
+                               data.mval= mval;
+                               data.rad= (float)brush->size;
+                               data.pufffac= (float)(brush->strength - 50) / 50.0f;
+                               if(data.pufffac < 0.0f)
+                                       data.pufffac= 1.0f - 9.0f * data.pufffac;
+                               else
+                                       data.pufffac= 1.0f - data.pufffac;
  
-                                       data.smoothfac = (float)(brush->strength / 100.0f);
+                               data.invert= (brush->invert ^ flip);
+                               Mat4Invert(ob->imat, ob->obmat);
  
-                                       Mat4Invert(ob->imat, ob->obmat);
+                               foreach_mouse_hit_particle(&data, brush_puff, selected);
+                               break;
+                       }
+                       case PE_BRUSH_ADD:
+                       {
+                               PEData data;
  
-                                       foreach_mouse_hit_key(selected, psys, brush_smooth_get, &data);
+                               if(psys->part->from==PART_FROM_FACE) {
+                                       PE_set_view3d_data(C, &data);
+                                       data.mval= mval;
  
-                                       if(data.tot){
-                                               VecMulf(data.vec, 1.0f / (float)data.tot);
-                                               foreach_mouse_hit_key(selected, psys, brush_smooth_do, &data);
-                                       }
+                                       brush_add(&data, brush->strength);
  
-                                       break;
+                                       if(pset->flag & PE_KEEP_LENGTHS)
+                                               recalc_lengths(psys);
                                }
+                               break;
                        }
-                       if((pset->flag & PE_KEEP_LENGTHS)==0)
-                               recalc_lengths(psys);
-                       if(pset->brushtype == PE_BRUSH_ADD || removed) {
-                               if(pset->brushtype == PE_BRUSH_ADD && (pset->flag & PE_X_MIRROR))
-                                       PE_mirror_x(scene, 1);
-                               PE_recalc_world_cos(ob,psys);
-                               psys_free_path_cache(psys);
-                               DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-                       }
-                       else
-                               PE_update_object(scene, ob, 1);
-                       
-                       mvalo[0] = mval[0];
-                       mvalo[1] = mval[1];
-               }
-               PIL_sleep_ms(10);
-               
- //            getmouseco_areawin(mval);
-       }
-       BIF_undo_push("Brush edit particles");
-       return 1;
- }
+                       case PE_BRUSH_WEIGHT:
+                       {
+                               PEData data;
  
- static void set_delete_particle(ParticleSystem *psys, int index, void *userData)
- {
-       psys->particles[index].flag |= PARS_TAG;
- }
+                               PE_set_view3d_data(C, &data);
+                               data.mval= mval;
+                               data.rad= (float)brush->size;
  
- static void set_delete_particle_key(ParticleSystem *psys, int pa_index, int key_index, void *userData)
- {
-       psys->edit->keys[pa_index][key_index].flag |= PEK_TAG;
- }
+                               data.weightfac= (float)(brush->strength / 100.0f);
  
- void PE_delete_particle(void)
- {
-       Scene *scene= NULL; // XXX
-       Object *ob=OBACT;
-       ParticleSystem *psys = PE_get_current(ob);
-       short event=0;
-       if(!PE_can_edit(psys)) return;
-       event= pupmenu("Erase %t|Particle%x2|Key%x1");
-       if(event<1) return;
+                               foreach_mouse_hit_key(&data, brush_weight, selected);
+                               break;
+                       }
+                       case PE_BRUSH_SMOOTH:
+                       {
+                               PEData data;
  
-       if(event==1){
-               foreach_selected_key(psys, set_delete_particle_key, 0);
-               remove_tagged_keys(scene, ob, psys);
-               recalc_lengths(psys);
-       }
-       else if(event==2){
-               foreach_selected_element(psys, set_delete_particle, 0);
-               remove_tagged_elements(scene, ob, psys);
-               recalc_lengths(psys);
-       }
+                               PE_set_view3d_data(C, &data);
+                               data.mval= mval;
+                               data.rad= (float)brush->size;
  
-       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-       BIF_undo_push("Delete particles/keys");
- }
+                               data.vec[0]= data.vec[1]= data.vec[2]= 0.0f;
+                               data.tot= 0;
  
- void PE_mirror_x(Scene *scene, int tagged)
- {
-       Object *ob=OBACT;
-       Mesh *me= (Mesh*)(ob->data);
-       ParticleSystemModifierData *psmd;
-       ParticleSystem *psys = PE_get_current(ob);
-       ParticleEdit *edit;
-       ParticleData *pa, *newpa, *new_pars;
-       ParticleEditKey *ekey, **newkey, **key, **new_keys;
-       HairKey *hkey;
-       int *mirrorfaces;
-       int i, k, rotation, totpart, newtotpart;
+                               data.smoothfac= (float)(brush->strength / 100.0f);
  
-       if(!PE_can_edit(psys)) return;
+                               Mat4Invert(ob->imat, ob->obmat);
  
-       edit= psys->edit;
-       psmd= psys_get_modifier(ob, psys);
+                               foreach_mouse_hit_key(&data, brush_smooth_get, selected);
  
-       mirrorfaces= mesh_get_x_mirror_faces(ob);
+                               if(data.tot) {
+                                       VecMulf(data.vec, 1.0f / (float)data.tot);
+                                       foreach_mouse_hit_key(&data, brush_smooth_do, selected);
+                               }
  
-       if(!edit->mirror_cache)
-               PE_update_mirror_cache(ob, psys);
+                               break;
+                       }
+               }
+               if((pset->flag & PE_KEEP_LENGTHS)==0)
+                       recalc_lengths(psys);
  
-       totpart= psys->totpart;
-       newtotpart= psys->totpart;
-       LOOP_PARTICLES(i,pa) {
-               if(pa->flag&PARS_HIDE) continue;
+               if(pset->brushtype == PE_BRUSH_ADD || removed) {
+                       if(pset->brushtype == PE_BRUSH_ADD && (pset->flag & PE_X_MIRROR))
+                               PE_mirror_x(scene, ob, 1);
  
-               if(!tagged) {
-                       if(particle_is_selected(psys, pa)) {
-                               if(edit->mirror_cache[i] != -1) {
-                                       /* already has a mirror, don't need to duplicate */
-                                       PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
-                                       continue;
-                               }
-                               else
-                                       pa->flag |= PARS_TAG;
-                       }
 -                      psys_update_world_cos(ob,psys);
++                      PE_recalc_world_cos(ob,psys);
+                       psys_free_path_cache(psys);
+                       DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
                }
+               else
+                       PE_update_object(scene, ob, 1);
  
-               if((pa->flag & PARS_TAG) && mirrorfaces[pa->num*2] != -1)
-                       newtotpart++;
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
+               
+               bedit->lastmouse[0]= mouse[0];
+               bedit->lastmouse[1]= mouse[1];
+               bedit->first= 0;
        }
+ }
  
-       if(newtotpart != psys->totpart) {
-               /* allocate new arrays and copy existing */
-               new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
-               new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey*), "ParticleEditKey new");
+ static void brush_edit_exit(bContext *C, wmOperator *op)
+ {
+       BrushEdit *bedit= op->customdata;
  
-               memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
-               memcpy(new_keys, edit->keys, totpart*sizeof(ParticleEditKey*));
+       MEM_freeN(bedit);
+ }
  
-               if(psys->particles) MEM_freeN(psys->particles);
-               psys->particles= new_pars;
+ static int brush_edit_exec(bContext *C, wmOperator *op)
+ {
+       if(!brush_edit_init(C, op))
+               return OPERATOR_CANCELLED;
  
-               if(edit->keys) MEM_freeN(edit->keys);
-               edit->keys= new_keys;
+       RNA_BEGIN(op->ptr, itemptr, "stroke") {
+               brush_edit_apply(C, op, &itemptr);
+       }
+       RNA_END;
  
-               if(edit->mirror_cache) {
-                       MEM_freeN(edit->mirror_cache);
-                       edit->mirror_cache= NULL;
-               }
+       brush_edit_exit(C, op);
  
-               psys->totpart= newtotpart;
-                       
-               /* create new elements */
-               pa= psys->particles;
-               newpa= psys->particles + totpart;
-               key= edit->keys;
-               newkey= edit->keys + totpart;
+       return OPERATOR_FINISHED;
+ }
  
-               for(i=0; i<totpart; i++, pa++, key++) {
-                       if(pa->flag&PARS_HIDE) continue;
+ static void brush_edit_apply_event(bContext *C, wmOperator *op, wmEvent *event)
+ {
+       ARegion *ar= CTX_wm_region(C);
+       PointerRNA itemptr;
+       int mouse[2];
  
-                       if(!(pa->flag & PARS_TAG) || mirrorfaces[pa->num*2] == -1)
-                               continue;
+       mouse[0]= event->x - ar->winrct.xmin;
+       mouse[1]= event->y - ar->winrct.ymin;
  
-                       /* duplicate */
-                       *newpa= *pa;
-                       if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
-                       if(pa->keys) newpa->keys= MEM_dupallocN(pa->keys);
-                       if(*key) *newkey= MEM_dupallocN(*key);
+       /* fill in stroke */
+       RNA_collection_add(op->ptr, "stroke", &itemptr);
  
-                       /* rotate weights according to vertex index rotation */
-                       rotation= mirrorfaces[pa->num*2+1];
-                       newpa->fuv[0]= pa->fuv[2];
-                       newpa->fuv[1]= pa->fuv[1];
-                       newpa->fuv[2]= pa->fuv[0];
-                       newpa->fuv[3]= pa->fuv[3];
-                       while(rotation-- > 0)
-                               if(me->mface[pa->num].v4)
-                                       SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
-                               else
-                                       SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
+       RNA_int_set_array(&itemptr, "mouse", mouse);
+       RNA_boolean_set(&itemptr, "flip", event->shift != 0); // XXX hardcoded
  
-                       /* assign face inddex */
-                       newpa->num= mirrorfaces[pa->num*2];
-                       newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
+       /* apply */
+       brush_edit_apply(C, op, &itemptr);
+ }
  
-                       /* update edit key pointers */
-                       ekey= *newkey;
-                       for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, ekey++) {
-                               ekey->co= hkey->co;
-                               ekey->time= &hkey->time;
-                       }
+ static int brush_edit_invoke(bContext *C, wmOperator *op, wmEvent *event)
+ {
+       if(!brush_edit_init(C, op))
+               return OPERATOR_CANCELLED;
+       
+       brush_edit_apply_event(C, op, event);
  
-                       /* map key positions as mirror over x axis */
-                       PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
+       WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
  
-                       newpa++;
-                       newkey++;
-               }
+       return OPERATOR_RUNNING_MODAL;
+ }
  
-               edit->totkeys = psys_count_keys(psys);
+ static int brush_edit_modal(bContext *C, wmOperator *op, wmEvent *event)
+ {
+       switch(event->type) {
+               case LEFTMOUSE:
+               case MIDDLEMOUSE:
+               case RIGHTMOUSE: // XXX hardcoded
+                       brush_edit_exit(C, op);
+                       return OPERATOR_FINISHED;
+               case MOUSEMOVE:
+                       brush_edit_apply_event(C, op, event);
+                       break;
        }
  
-       for(pa=psys->particles, i=0; i<psys->totpart; i++, pa++)
-               pa->flag &= ~PARS_TAG;
+       return OPERATOR_RUNNING_MODAL;
+ }
  
-       MEM_freeN(mirrorfaces);
+ static int brush_edit_cancel(bContext *C, wmOperator *op)
+ {
+       brush_edit_exit(C, op);
  
-       if(!tagged) {
-               PE_recalc_world_cos(ob,psys);
-               DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
-               BIF_undo_push("Mirror particles");
-       }
+       return OPERATOR_CANCELLED;
  }
  
- void PE_selectbrush_menu(Scene *scene)
+ void PARTICLE_OT_brush_edit(wmOperatorType *ot)
  {
-       ParticleEditSettings *pset= PE_settings(scene);
-       int val;
+       /* identifiers */
+       ot->name= "Brush Edit";
+       ot->idname= "PARTICLE_OT_brush_edit";
        
-       // XXX pupmenu_set_active(pset->brushtype);
-       
-       val= pupmenu("Select Brush%t|None %x0|Comb %x1|Smooth %x7|Weight %x6|Add %x5|Length %x3|Puff %x4|Cut %x2");
+       /* api callbacks */
+       ot->exec= brush_edit_exec;
+       ot->invoke= brush_edit_invoke;
+       ot->modal= brush_edit_modal;
+       ot->cancel= brush_edit_cancel;
+       ot->poll= PE_poll_3dview;
  
-       if(val>=0) {
-               pset->brushtype= val-1;
-       }
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       /* properties */
+       RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
  }
  
- /************************************************/
- /*                    Particle Edit Undo                                      */
- /************************************************/
+ /*********************** undo ***************************/
  static void free_ParticleUndo(ParticleUndo *undo)
  {
        ParticleData *pa;
@@@ -3036,9 -3405,9 +3516,9 @@@ static void get_ParticleUndo(ParticleSy
        ParticleData *pa, *upa;
        ParticleEditKey *key;
        HairKey *hkey;
-       int i, k, totpart = psys->totpart;
+       int i, k, totpart= psys->totpart;
  
 -      LOOP_PARTICLES(i, pa) {
 +      LOOP_PARTICLES(i,pa) {
                if(pa->hair)
                        MEM_freeN(pa->hair);
  
@@@ -3113,13 -3482,14 +3593,14 @@@ void PE_undo_push(Scene *scene, char *s
        /* copy  */
        make_ParticleUndo(psys,edit->curundo);
  }
  void PE_undo_step(Scene *scene, int step)
  {     
-       ParticleSystem *psys = PE_get_current(OBACT);
-       ParticleEdit *edit = 0;
+       ParticleSystem *psys= PE_get_current(scene, OBACT);
+       ParticleEdit *edit= 0;
  
        if(!PE_can_edit(psys)) return;
 -      edit= psys->edit;
 +      edit=psys->edit;
  
        if(step==0) {
                get_ParticleUndo(psys,edit->curundo);