merge with/from trunk at r35190
[blender.git] / source / blender / editors / physics / particle_edit.c
index 6ec744ad0274a8312d923885f3dffc1ebadd249b..b5d07025ca5e377bc443313a536042ad2e8fa16f 100644 (file)
@@ -30,6 +30,7 @@
 #include <stdlib.h>
 #include <math.h>
 #include <string.h>
+#include <assert.h>
 
 #include "MEM_guardedalloc.h"
 
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
 
+#include "BLI_math.h"
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+#include "BLI_kdtree.h"
+#include "BLI_rand.h"
+#include "BLI_utildefines.h"
+
 #include "BKE_DerivedMesh.h"
 #include "BKE_depsgraph.h"
 
 #include "BKE_particle.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
-#include "BKE_utildefines.h"
-#include "BKE_pointcache.h"
-
-#include "BLI_math.h"
-#include "BLI_blenlib.h"
-#include "BLI_dynstr.h"
-#include "BLI_kdtree.h"
-#include "BLI_rand.h"
 
+#include "BKE_pointcache.h"
 
 #include "BIF_gl.h"
 #include "BIF_glutil.h"
 
+#include "ED_physics.h"
 #include "ED_mesh.h"
 #include "ED_particle.h"
 #include "ED_view3d.h"
@@ -160,7 +162,7 @@ void PE_free_ptcache_edit(PTCacheEdit *edit)
                edit->emitter_field= 0;
        }
 
-       psys_free_path_cache(NULL, edit);
+       psys_free_path_cache(edit->psys, edit);
 
        MEM_freeN(edit);
 }
@@ -369,8 +371,18 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
        /* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather then (obmat * viewmat) */
        view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats);
 
-       if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT))
-               view3d_validate_backbuf(&data->vc);
+       if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT)) {
+               if(data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
+                       /* needed or else the draw matrix can be incorrect */
+                       view3d_operator_needs_opengl(C);
+
+                       view3d_validate_backbuf(&data->vc);
+                       /* we may need to force an update here by setting the rv3d as dirty
+                        * for now it seems ok, but take care!:
+                        * rv3d->depths->dirty = 1; */
+                       view3d_update_depths(data->vc.ar);
+               }
+       }
 }
 
 /*************************** selection utilities *******************************/
@@ -397,14 +409,23 @@ static int key_test_depth(PEData *data, float co[3])
        x=wco[0];
        y=wco[1];
 
+#if 0 /* works well but too slow on some systems [#23118] */
        x+= (short)data->vc.ar->winrct.xmin;
        y+= (short)data->vc.ar->winrct.ymin;
 
        /* PE_set_view3d_data calls this. no need to call here */
        /* view3d_validate_backbuf(&data->vc); */
        glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
+#else /* faster to use depths, these are calculated in PE_set_view3d_data */
+       {
+               ViewDepths *vd = data->vc.rv3d->depths;
+               assert(vd && vd->depths);
+               /* we know its not clipped */
+               depth= vd->depths[y * vd->w + x];
+       }
+#endif
 
-       if((float)uz - 0.0001 > depth)
+       if((float)uz - 0.00001 > depth)
                return 0;
        else
                return 1;
@@ -464,13 +485,10 @@ static int key_inside_test(PEData *data, float co[3])
 static int point_is_selected(PTCacheEditPoint *point)
 {
        KEY_K;
-       int sel;
 
        if(point->flag & PEP_HIDE)
                return 0;
 
-       sel= 0;
-
        LOOP_SELECTED_KEYS {
                return 1;
        }
@@ -573,7 +591,7 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
        ParticleSystemModifierData *psmd = NULL;
        ParticleEditSettings *pset= PE_settings(data->scene);
        POINT_P; KEY_K;
-       float mat[4][4], imat[4][4];
+       float mat[4][4]= MAT4_UNITY, imat[4][4]= MAT4_UNITY;
 
        if(edit->psys)
                psmd= psys_get_modifier(data->ob, edit->psys);
@@ -582,9 +600,6 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
        if(pset->selectmode==SCE_SELECT_PATH)
                selected= 0;
 
-       unit_m4(imat);
-       unit_m4(mat);
-
        LOOP_VISIBLE_POINTS {
                if(pset->selectmode==SCE_SELECT_END) {
                        /* only do end keys */
@@ -756,6 +771,9 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys
        if(!mpa) {
                if(!edit->mirror_cache)
                        PE_update_mirror_cache(ob, psys);
+               
+               if(!edit->mirror_cache)
+                       return; /* something went wrong! */
 
                mi= edit->mirror_cache[i];
                if(mi == -1)
@@ -774,6 +792,7 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys
                if(mpoint->keys) MEM_freeN(mpoint->keys);
 
                mpa->hair= MEM_dupallocN(pa->hair);
+               mpa->totkey= pa->totkey;
                mpoint->keys= MEM_dupallocN(point->keys);
                mpoint->totkey= point->totkey;
 
@@ -782,7 +801,7 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys
                for(k=0; k<mpa->totkey; k++, mkey++, mhkey++) {
                        mkey->co= mhkey->co;
                        mkey->time= &mhkey->time;
-                       mkey->flag &= PEK_SELECT;
+                       mkey->flag &= ~PEK_SELECT;
                }
        }
 
@@ -829,6 +848,9 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
        if(!edit->mirror_cache)
                PE_update_mirror_cache(ob, psys);
 
+       if(!edit->mirror_cache)
+               return; /* something went wrong */
+
        /* we delay settings the PARS_EDIT_RECALC for mirrored particles
         * to avoid doing mirror twice */
        LOOP_POINTS {
@@ -918,7 +940,7 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
        }
 }
 /* force set distances between neighbouring keys */
-void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
+static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
 {
        
        ParticleEditSettings *pset=PE_settings(scene);
@@ -1018,10 +1040,8 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
 {
        DerivedMesh *dm=psys_get_modifier(ob,psys)->dm;
        PTCacheEdit *edit= psys->edit;
-       MFace *mface;
-       MVert *mvert;
        float *vec, *nor;
-       int i, totface, totvert;
+       int i, totface /*, totvert*/;
 
        if(!dm)
                return;
@@ -1031,8 +1051,8 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
 
        BLI_kdtree_free(edit->emitter_field);
 
-       totface=dm->getNumFaces(dm);
-       totvert=dm->getNumVerts(dm);
+       totface=dm->getNumTessFaces(dm);
+       /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/
 
        edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos");
 
@@ -1041,9 +1061,9 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
        vec=edit->emitter_cosnos;
        nor=vec+3;
 
-       mvert=dm->getVertDataArray(dm,CD_MVERT);
        for(i=0; i<totface; i++, vec+=6, nor+=6) {
-               mface=dm->getFaceData(dm,i,CD_MFACE);
+               MFace *mface=dm->getTessFaceData(dm,i,CD_MFACE);
+               MVert *mvert;
 
                mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
                VECCOPY(vec,mvert->co);
@@ -1125,7 +1145,7 @@ static void update_world_cos(Object *ob, PTCacheEdit *edit)
                }
        }
 }
-static void update_velocities(Object *ob, PTCacheEdit *edit)
+static void update_velocities(PTCacheEdit *edit)
 {
        /*TODO: get frs_sec properly */
        float vec1[3], vec2[3], frs_sec, dfra;
@@ -1208,7 +1228,7 @@ void PE_update_object(Scene *scene, Object *ob, int useflag)
        if(edit->psys)
                update_world_cos(ob, edit);
        if(pset->flag & PE_AUTO_VELOCITY)
-               update_velocities(ob, edit);
+               update_velocities(edit);
        PE_hide_keys_time(scene, edit, CFRA);
 
        /* regenerate path caches */
@@ -1243,7 +1263,7 @@ static void select_key(PEData *data, int point_index, int key_index)
        point->flag |= PEP_EDIT_RECALC;
 }
 
-static void select_keys(PEData *data, int point_index, int key_index)
+static void select_keys(PEData *data, int point_index, int UNUSED(key_index))
 {
        PTCacheEdit *edit = data->edit;
        PTCacheEditPoint *point = edit->points + point_index;
@@ -1321,7 +1341,7 @@ static int select_all_exec(bContext *C, wmOperator *op)
        }
 
        PE_update_selection(scene, ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1371,7 +1391,7 @@ int PE_mouse_particles(bContext *C, short *mval, int extend)
        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_PARTICLE_SELECT, data.ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1387,7 +1407,7 @@ static void select_root(PEData *data, int point_index)
        data->edit->points[point_index].flag |= PEP_EDIT_RECALC; /* redraw selection only */
 }
 
-static int select_roots_exec(bContext *C, wmOperator *op)
+static int select_roots_exec(bContext *C, wmOperator *UNUSED(op))
 {
        PEData data;
 
@@ -1395,7 +1415,7 @@ static int select_roots_exec(bContext *C, wmOperator *op)
        foreach_point(&data, select_root);
 
        PE_update_selection(data.scene, data.ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1427,7 +1447,7 @@ static void select_tip(PEData *data, int point_index)
        point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
 }
 
-static int select_tips_exec(bContext *C, wmOperator *op)
+static int select_tips_exec(bContext *C, wmOperator *UNUSED(op))
 {
        PEData data;
 
@@ -1435,7 +1455,7 @@ static int select_tips_exec(bContext *C, wmOperator *op)
        foreach_point(&data, select_tip);
 
        PE_update_selection(data.scene, data.ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1466,8 +1486,6 @@ static int select_linked_exec(bContext *C, wmOperator *op)
        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;
@@ -1475,7 +1493,7 @@ static int select_linked_exec(bContext *C, wmOperator *op)
 
        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_PARTICLE_SELECT, data.ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1512,6 +1530,17 @@ void PARTICLE_OT_select_linked(wmOperatorType *ot)
 }
 
 /************************ border select operator ************************/
+void PE_deselect_all_visible(PTCacheEdit *edit)
+{
+       POINT_P; KEY_K;
+
+       LOOP_VISIBLE_POINTS {
+               LOOP_SELECTED_KEYS {
+                       key->flag &= ~PEK_SELECT;
+                       point->flag |= PEP_EDIT_RECALC;
+               }
+       }
+}
 
 int PE_border_select(bContext *C, rcti *rect, int select, int extend)
 {
@@ -1523,16 +1552,8 @@ int PE_border_select(bContext *C, rcti *rect, int select, int extend)
        if(!PE_start_edit(edit))
                return OPERATOR_CANCELLED;
 
-       if (extend == 0 && select) {
-               POINT_P; KEY_K;
-
-               LOOP_VISIBLE_POINTS {
-                       LOOP_SELECTED_KEYS {
-                               key->flag &= ~PEK_SELECT;
-                               point->flag |= PEP_EDIT_RECALC;
-                       }
-               }
-       }
+       if (extend == 0 && select)
+               PE_deselect_all_visible(edit);
 
        PE_set_view3d_data(C, &data);
        data.rect= rect;
@@ -1541,7 +1562,7 @@ int PE_border_select(bContext *C, rcti *rect, int select, int extend)
        for_mouse_hit_keys(&data, select_key, 0);
 
        PE_update_selection(scene, ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1566,14 +1587,14 @@ int PE_circle_select(bContext *C, int selecting, short *mval, float rad)
        for_mouse_hit_keys(&data, select_key, 0);
 
        PE_update_selection(scene, ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
 
        return OPERATOR_FINISHED;
 }
 
 /************************ lasso select operator ************************/
 
-int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
+int PE_lasso_select(bContext *C, short mcords[][2], short moves, short extend, short select)
 {
        Scene *scene= CTX_data_scene(C);
        Object *ob= CTX_data_active_object(C);
@@ -1583,13 +1604,19 @@ int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
        ParticleSystem *psys = edit->psys;
        ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
        POINT_P; KEY_K;
-       float co[3], mat[4][4];
+       float co[3], mat[4][4]= MAT4_UNITY;
        short vertco[2];
 
+       PEData data;
+
        if(!PE_start_edit(edit))
                return OPERATOR_CANCELLED;
 
-       unit_m4(mat);
+       if (extend == 0 && select)
+               PE_deselect_all_visible(edit);
+
+       /* only for depths */
+       PE_set_view3d_data(C, &data);
 
        LOOP_VISIBLE_POINTS {
                if(edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
@@ -1600,7 +1627,7 @@ int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
                                VECCOPY(co, key->co);
                                mul_m4_v3(mat, co);
                                project_short(ar, co, vertco);
-                               if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
+                               if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1]) && key_test_depth(&data, co)) {
                                        if(select && !(key->flag & PEK_SELECT)) {
                                                key->flag |= PEK_SELECT;
                                                point->flag |= PEP_EDIT_RECALC;
@@ -1618,7 +1645,7 @@ int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
                        VECCOPY(co, key->co);
                        mul_m4_v3(mat, co);
                        project_short(ar, co,vertco);
-                       if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
+                       if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1]) && key_test_depth(&data, co)) {
                                if(select && !(key->flag & PEK_SELECT)) {
                                        key->flag |= PEK_SELECT;
                                        point->flag |= PEP_EDIT_RECALC;
@@ -1632,7 +1659,7 @@ int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
        }
 
        PE_update_selection(scene, ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1666,7 +1693,7 @@ static int hide_exec(bContext *C, wmOperator *op)
        }
 
        PE_update_selection(scene, ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1690,7 +1717,7 @@ void PARTICLE_OT_hide(wmOperatorType *ot)
 
 /*************************** reveal operator **************************/
 
-static int reveal_exec(bContext *C, wmOperator *op)
+static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Object *ob= CTX_data_active_object(C);
        Scene *scene= CTX_data_scene(C);
@@ -1708,7 +1735,7 @@ static int reveal_exec(bContext *C, wmOperator *op)
        }
 
        PE_update_selection(scene, ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1758,7 +1785,7 @@ static void select_less_keys(PEData *data, int point_index)
        }
 }
 
-static int select_less_exec(bContext *C, wmOperator *op)
+static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
 {
        PEData data;
 
@@ -1766,7 +1793,7 @@ static int select_less_exec(bContext *C, wmOperator *op)
        foreach_point(&data, select_less_keys);
 
        PE_update_selection(data.scene, data.ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1819,7 +1846,7 @@ static void select_more_keys(PEData *data, int point_index)
        }
 }
 
-static int select_more_exec(bContext *C, wmOperator *op)
+static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
 {
        PEData data;
 
@@ -1827,7 +1854,7 @@ static int select_more_exec(bContext *C, wmOperator *op)
        foreach_point(&data, select_more_keys);
 
        PE_update_selection(data.scene, data.ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1846,7 +1873,7 @@ void PARTICLE_OT_select_more(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-static int select_inverse_exec(bContext *C, wmOperator *op)
+static int select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
 {
        PEData data;
        PTCacheEdit *edit;
@@ -1864,7 +1891,7 @@ static int select_inverse_exec(bContext *C, wmOperator *op)
        }
 
        PE_update_selection(data.scene, data.ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1889,7 +1916,7 @@ static void rekey_particle(PEData *data, int pa_index)
 {
        PTCacheEdit *edit= data->edit;
        ParticleSystem *psys= edit->psys;
-       ParticleSimulationData sim = {data->scene, data->ob, edit->psys, NULL};
+       ParticleSimulationData sim= {0};
        ParticleData *pa= psys->particles + pa_index;
        PTCacheEditPoint *point = edit->points + pa_index;
        ParticleKey state;
@@ -1898,6 +1925,10 @@ static void rekey_particle(PEData *data, int pa_index)
        float dval, sta, end;
        int k;
 
+       sim.scene= data->scene;
+       sim.ob= data->ob;
+       sim.psys= edit->psys;
+
        pa->flag |= PARS_REKEY;
 
        key= new_keys= MEM_callocN(data->totrekey * sizeof(HairKey),"Hair re-key keys");
@@ -1955,7 +1986,7 @@ static int rekey_exec(bContext *C, wmOperator *op)
        
        recalc_lengths(data.edit);
        PE_update_object(data.scene, data.ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
 
        return OPERATOR_FINISHED;
 }
@@ -1982,7 +2013,7 @@ static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float
 {
        PTCacheEdit *edit= PE_get_current(scene, ob);
        ParticleSystem *psys;
-       ParticleSimulationData sim = {scene, ob, edit ? edit->psys : NULL, NULL};
+       ParticleSimulationData sim= {0};
        ParticleData *pa;
        ParticleKey state;
        HairKey *new_keys, *key;
@@ -1993,6 +2024,10 @@ static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float
 
        psys = edit->psys;
 
+       sim.scene= scene;
+       sim.ob= ob;
+       sim.psys= psys;
+
        pa= psys->particles + pa_index;
 
        pa->flag |= PARS_REKEY;
@@ -2022,19 +2057,18 @@ static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float
 
 /************************* utilities **************************/
 
-static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psys, int mirror)
+static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
 {
        PTCacheEdit *edit = psys->edit;
        ParticleData *pa, *npa=0, *new_pars=0;
        POINT_P;
        PTCacheEditPoint *npoint=0, *new_points=0;
        ParticleSystemModifierData *psmd;
-       int i, totpart, new_totpart= psys->totpart, removed= 0;
+       int i, new_totpart= psys->totpart, removed= 0;
 
        if(mirror) {
                /* mirror tags */
                psmd= psys_get_modifier(ob, psys);
-               totpart= psys->totpart;
 
                LOOP_TAGGED_POINTS {
                        PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
@@ -2050,6 +2084,15 @@ static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psy
                if(new_totpart) {
                        npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
                        npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
+
+                       if(ELEM(NULL, new_pars, new_points)) {
+                                /* allocation error! */
+                               if(new_pars)
+                                       MEM_freeN(new_pars);
+                               if(new_points)
+                                       MEM_freeN(new_points);
+                               return 0;
+                       }
                }
 
                pa= psys->particles;
@@ -2092,12 +2135,13 @@ static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psy
        return removed;
 }
 
-static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
+static void remove_tagged_keys(Object *ob, ParticleSystem *psys)
 {
        PTCacheEdit *edit= psys->edit;
        ParticleData *pa;
        HairKey *hkey, *nhkey, *new_hkeys=0;
        POINT_P; KEY_K;
+       PTCacheEditKey *nkey, *new_keys;
        ParticleSystemModifierData *psmd;
        short new_totkey;
 
@@ -2122,7 +2166,7 @@ static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
                if(new_totkey < 2)
                        point->flag |= PEP_TAG;
        }
-       remove_tagged_particles(scene, ob, psys, pe_x_mirror(ob));
+       remove_tagged_particles(ob, psys, pe_x_mirror(ob));
 
        LOOP_POINTS {
                pa = psys->particles + p;
@@ -2133,9 +2177,10 @@ static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
                }
 
                if(new_totkey != pa->totkey) {
-                       hkey= pa->hair;
                        nhkey= new_hkeys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
+                       nkey= new_keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys");
 
+                       hkey= pa->hair;
                        LOOP_KEYS {
                                while(key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
                                        key++;
@@ -2144,29 +2189,36 @@ static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
 
                                if(hkey < pa->hair + pa->totkey) {
                                        VECCOPY(nhkey->co, hkey->co);
+                                       nhkey->editflag = hkey->editflag;
                                        nhkey->time= hkey->time;
                                        nhkey->weight= hkey->weight;
+                                       
+                                       nkey->co= nhkey->co;
+                                       nkey->time= &nhkey->time;
+                                       /* these can be copied from old edit keys */
+                                       nkey->flag = key->flag;
+                                       nkey->ftime = key->ftime;
+                                       nkey->length = key->length;
+                                       VECCOPY(nkey->world_co, key->world_co);
                                }
-                               hkey++;
+                               nkey++;
                                nhkey++;
+                               hkey++;
                        }
+
                        if(pa->hair)
                                MEM_freeN(pa->hair);
+
+                       if(point->keys)
+                               MEM_freeN(point->keys);
                        
                        pa->hair= new_hkeys;
+                       point->keys= new_keys;
 
                        point->totkey= pa->totkey= new_totkey;
 
-                       if(point->keys)
-                               MEM_freeN(point->keys);
-                       key= point->keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys");
-
-                       hkey = pa->hair;
-                       LOOP_KEYS {
-                               key->co= hkey->co;
-                               key->time= &hkey->time;
-                               hkey++;
-                       }
+                       /* flag for recalculating length */
+                       point->flag |= PEP_EDIT_RECALC;
                }
        }
 }
@@ -2178,7 +2230,7 @@ static void subdivide_particle(PEData *data, int pa_index)
 {
        PTCacheEdit *edit= data->edit;
        ParticleSystem *psys= edit->psys;
-       ParticleSimulationData sim = {data->scene, data->ob, edit->psys, NULL};
+       ParticleSimulationData sim= {0};
        ParticleData *pa= psys->particles + pa_index;
        PTCacheEditPoint *point = edit->points + pa_index;
        ParticleKey state;
@@ -2189,6 +2241,10 @@ static void subdivide_particle(PEData *data, int pa_index)
        short totnewkey=0;
        float endtime;
 
+       sim.scene= data->scene;
+       sim.ob= data->ob;
+       sim.psys= edit->psys;
+
        for(k=0, ekey=point->keys; k<pa->totkey-1; k++,ekey++) {
                if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
                        totnewkey++;
@@ -2251,7 +2307,7 @@ static void subdivide_particle(PEData *data, int pa_index)
        pa->flag &= ~PARS_REKEY;
 }
 
-static int subdivide_exec(bContext *C, wmOperator *op)
+static int subdivide_exec(bContext *C, wmOperator *UNUSED(op))
 {
        PEData data;
 
@@ -2260,7 +2316,7 @@ static int subdivide_exec(bContext *C, wmOperator *op)
        
        recalc_lengths(data.edit);
        PE_update_object(data.scene, data.ob, 1);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
 
        return OPERATOR_FINISHED;
 }
@@ -2338,7 +2394,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
                BLI_kdtree_free(tree);
 
                /* remove tagged particles - don't do mirror here! */
-               remove_tagged_particles(scene, ob, psys, 0);
+               remove_tagged_particles(ob, psys, 0);
                totremoved += removed;
        } while(removed);
 
@@ -2347,8 +2403,8 @@ static int remove_doubles_exec(bContext *C, wmOperator *op)
 
        BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved);
 
-       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
+       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
 
        return OPERATOR_FINISHED;
 }
@@ -2397,8 +2453,8 @@ static int weight_set_exec(bContext *C, wmOperator *op)
                }
        }
 
-       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
+       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
 
        return OPERATOR_FINISHED;
 }
@@ -2421,7 +2477,7 @@ void PARTICLE_OT_weight_set(wmOperatorType *ot)
 
 /************************ cursor drawing *******************************/
 
-static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
+static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
 {
        ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
        ParticleBrushData *brush;
@@ -2565,17 +2621,17 @@ static int delete_exec(bContext *C, wmOperator *op)
 
        if(type == DEL_KEY) {
                foreach_selected_key(&data, set_delete_particle_key);
-               remove_tagged_keys(data.scene, data.ob, data.edit->psys);
+               remove_tagged_keys(data.ob, data.edit->psys);
                recalc_lengths(data.edit);
        }
        else if(type == DEL_PARTICLE) {
                foreach_selected_point(&data, set_delete_particle);
-               remove_tagged_particles(data.scene, data.ob, data.edit->psys, pe_x_mirror(data.ob));
+               remove_tagged_particles(data.ob, data.edit->psys, pe_x_mirror(data.ob));
                recalc_lengths(data.edit);
        }
 
-       DAG_id_flush_update(&data.ob->id, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob);
+       DAG_id_tag_update(&data.ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
 
        return OPERATOR_FINISHED;
 }
@@ -2620,7 +2676,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
        if(!psmd->dm)
                return;
 
-       mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
+       //BMESH_TODO mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
 
        if(!edit->mirror_cache)
                PE_update_mirror_cache(ob, psys);
@@ -2725,7 +2781,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
        MEM_freeN(mirrorfaces);
 }
 
-static int mirror_exec(bContext *C, wmOperator *op)
+static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Scene *scene= CTX_data_scene(C);
        Object *ob= CTX_data_active_object(C);
@@ -2734,8 +2790,8 @@ static int mirror_exec(bContext *C, wmOperator *op)
        PE_mirror_x(scene, ob, 0);
 
        update_world_cos(ob, edit);
-       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
-       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
+       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 
        return OPERATOR_FINISHED;
 }
@@ -2756,7 +2812,7 @@ void PARTICLE_OT_mirror(wmOperatorType *ot)
 
 /************************* brush edit callbacks ********************/
 
-static void brush_comb(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
+static void brush_comb(PEData *data, float UNUSED(mat[][4]), float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
 {
        ParticleEditSettings *pset= PE_settings(data->scene);
        float cvec[3], fac;
@@ -3025,7 +3081,7 @@ static void brush_puff(PEData *data, int point_index)
 }
 
 
-static void brush_weight(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
+static void brush_weight(PEData *data, float UNUSED(mat[][4]), float UNUSED(imat[][4]), int point_index, int key_index, PTCacheEditKey *UNUSED(key))
 {
        /* roots have full weight allways */
        if(key_index) {
@@ -3039,7 +3095,7 @@ static void brush_weight(PEData *data, float mat[][4], float imat[][4], int poin
        }
 }
 
-static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
+static void brush_smooth_get(PEData *data, float mat[][4], float UNUSED(imat[][4]), int UNUSED(point_index), int key_index, PTCacheEditKey *key)
 {      
        if(key_index) {
                float dvec[3];
@@ -3051,7 +3107,7 @@ static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int
        }
 }
 
-static void brush_smooth_do(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
+static void brush_smooth_do(PEData *data, float UNUSED(mat[][4]), float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
 {
        float vec[3], dvec[3];
        
@@ -3078,13 +3134,13 @@ static int brush_add(PEData *data, short number)
        ParticleSystem *psys= edit->psys;
        ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add");
        ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
-       ParticleSimulationData sim = {scene, ob, psys, psmd};
+       ParticleSimulationData sim= {0};
        ParticleEditSettings *pset= PE_settings(scene);
        int i, k, n= 0, totpart= psys->totpart;
        float mco[2];
        short dmx= 0, dmy= 0;
        float co1[3], co2[3], min_d, imat[4][4];
-       float framestep, timestep= psys_get_timestep(&sim);
+       float framestep, timestep;
        short size= pset->brush[PE_BRUSH_ADD].size;
        short size2= size*size;
        DerivedMesh *dm=0;
@@ -3094,7 +3150,14 @@ static int brush_add(PEData *data, short number)
                return 0;
 
        BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
-       
+
+       sim.scene= scene;
+       sim.ob= ob;
+       sim.psys= psys;
+       sim.psmd= psmd;
+
+       timestep= psys_get_timestep(&sim);
+
        /* painting onto the deformed mesh, could be an option? */
        if(psmd->dm->deformedOnly)
                dm= psmd->dm;
@@ -3191,18 +3254,17 @@ static int brush_add(PEData *data, short number)
                        framestep= pa->lifetime/(float)(pset->totaddkey-1);
 
                        if(tree) {
-                               HairKey *hkey;
-                               ParticleKey key[3];
+                               ParticleData *ppa;
+                               HairKey *thkey;
+                               ParticleKey key3[3];
                                KDTreeNearest ptn[3];
                                int w, maxw;
-                               float maxd, mind, dd, totw=0.0, weight[3];
+                               float maxd, totw=0.0, weight[3];
 
                                psys_particle_on_dm(psmd->dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,0,0);
                                maxw= BLI_kdtree_find_n_nearest(tree,3,co1,NULL,ptn);
 
                                maxd= ptn[maxw-1].dist;
-                               mind= ptn[0].dist;
-                               dd= maxd - mind;
                                
                                for(w=0; w<maxw; w++) {
                                        weight[w]= (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
@@ -3215,40 +3277,46 @@ static int brush_add(PEData *data, short number)
                                for(w=0; w<maxw; w++)
                                        weight[w] /= totw;
 
+                               ppa= psys->particles+ptn[0].index;
+
                                for(k=0; k<pset->totaddkey; k++) {
-                                       hkey= (HairKey*)pa->hair + k;
-                                       hkey->time= pa->time + k * framestep;
+                                       thkey= (HairKey*)pa->hair + k;
+                                       thkey->time= pa->time + k * framestep;
 
-                                       key[0].time= hkey->time/ 100.0f;
-                                       psys_get_particle_on_path(&sim, ptn[0].index, key, 0);
-                                       mul_v3_fl(key[0].co, weight[0]);
+                                       key3[0].time= thkey->time/ 100.0f;
+                                       psys_get_particle_on_path(&sim, ptn[0].index, key3, 0);
+                                       mul_v3_fl(key3[0].co, weight[0]);
+                                       
+                                       /* TODO: interpolatint the weight would be nicer */
+                                       thkey->weight= (ppa->hair+MIN2(k, ppa->totkey-1))->weight;
                                        
                                        if(maxw>1) {
-                                               key[1].time= key[0].time;
-                                               psys_get_particle_on_path(&sim, ptn[1].index, key + 1, 0);
-                                               mul_v3_fl(key[1].co, weight[1]);
-                                               VECADD(key[0].co, key[0].co, key[1].co);
+                                               key3[1].time= key3[0].time;
+                                               psys_get_particle_on_path(&sim, ptn[1].index, &key3[1], 0);
+                                               mul_v3_fl(key3[1].co, weight[1]);
+                                               VECADD(key3[0].co, key3[0].co, key3[1].co);
 
                                                if(maxw>2) {                                            
-                                                       key[2].time= key[0].time;
-                                                       psys_get_particle_on_path(&sim, ptn[2].index, key + 2, 0);
-                                                       mul_v3_fl(key[2].co, weight[2]);
-                                                       VECADD(key[0].co, key[0].co, key[2].co);
+                                                       key3[2].time= key3[0].time;
+                                                       psys_get_particle_on_path(&sim, ptn[2].index, &key3[2], 0);
+                                                       mul_v3_fl(key3[2].co, weight[2]);
+                                                       VECADD(key3[0].co, key3[0].co, key3[2].co);
                                                }
                                        }
 
                                        if(k==0)
-                                               VECSUB(co1, pa->state.co, key[0].co);
+                                               VECSUB(co1, pa->state.co, key3[0].co);
 
-                                       VECADD(hkey->co, key[0].co, co1);
+                                       VECADD(thkey->co, key3[0].co, co1);
 
-                                       hkey->time= key[0].time;
+                                       thkey->time= key3[0].time;
                                }
                        }
                        else {
                                for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
                                        VECADDFAC(hkey->co, pa->state.co, pa->state.vel, k * framestep * timestep);
                                        hkey->time += k * framestep;
+                                       hkey->weight = 1.f - (float)k/(float)(pset->totaddkey-1);
                                }
                        }
                        for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
@@ -3279,6 +3347,9 @@ typedef struct BrushEdit {
 
        int first;
        int lastmouse[2];
+
+       /* optional cached view settings to avoid setting on every mousemove */
+       PEData data;
 } BrushEdit;
 
 static int brush_edit_init(bContext *C, wmOperator *op)
@@ -3303,6 +3374,9 @@ static int brush_edit_init(bContext *C, wmOperator *op)
        bedit->ob= ob;
        bedit->edit= edit;
 
+       /* cache view depths and settings for re-use */
+       PE_set_view3d_data(C, &bedit->data);
+
        return 1;
 }
 
@@ -3327,7 +3401,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
        RNA_float_get_array(itemptr, "mouse", mousef);
        mouse[0] = mousef[0];
        mouse[1] = mousef[1];
-       flip= RNA_boolean_get(itemptr, "flip");
+       flip= RNA_boolean_get(itemptr, "pen_flip");
 
        if(bedit->first) {
                bedit->lastmouse[0]= mouse[0];
@@ -3350,6 +3424,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
        if(((pset->brushtype == PE_BRUSH_ADD) ?
                (sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0))
                || bedit->first) {
+               PEData data= bedit->data;
 
                view3d_operator_needs_opengl(C);
                selected= (short)count_selected_keys(scene, edit);
@@ -3357,9 +3432,6 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
                switch(pset->brushtype) {
                        case PE_BRUSH_COMB:
                        {
-                               PEData data;
-
-                               PE_set_view3d_data(C, &data);
                                data.mval= mval;
                                data.rad= (float)brush->size;
 
@@ -3379,10 +3451,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
                        }
                        case PE_BRUSH_CUT:
                        {
-                               PEData data;
-                               
                                if(edit->psys && edit->pathcache) {
-                                       PE_set_view3d_data(C, &data);
                                        data.mval= mval;
                                        data.rad= (float)brush->size;
                                        data.cutfac= brush->strength;
@@ -3392,7 +3461,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
                                        else
                                                foreach_point(&data, brush_cut);
 
-                                       removed= remove_tagged_particles(scene, ob, edit->psys, pe_x_mirror(ob));
+                                       removed= remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob));
                                        if(pset->flag & PE_KEEP_LENGTHS)
                                                recalc_lengths(edit);
                                }
@@ -3403,9 +3472,6 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
                        }
                        case PE_BRUSH_LENGTH:
                        {
-                               PEData data;
-                               
-                               PE_set_view3d_data(C, &data);
                                data.mval= mval;
                                
                                data.rad= (float)brush->size;
@@ -3424,10 +3490,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
                        }
                        case PE_BRUSH_PUFF:
                        {
-                               PEData data;
-
                                if(edit->psys) {
-                                       PE_set_view3d_data(C, &data);
                                        data.dm= psmd->dm;
                                        data.mval= mval;
                                        data.rad= (float)brush->size;
@@ -3448,10 +3511,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
                        }
                        case PE_BRUSH_ADD:
                        {
-                               PEData data;
-
                                if(edit->psys && edit->psys->part->from==PART_FROM_FACE) {
-                                       PE_set_view3d_data(C, &data);
                                        data.mval= mval;
 
                                        added= brush_add(&data, brush->count);
@@ -3465,9 +3525,6 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
                        }
                        case PE_BRUSH_SMOOTH:
                        {
-                               PEData data;
-
-                               PE_set_view3d_data(C, &data);
                                data.mval= mval;
                                data.rad= (float)brush->size;
 
@@ -3489,9 +3546,6 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
                        }
                        case PE_BRUSH_WEIGHT:
                        {
-                               PEData data;
-                               PE_set_view3d_data(C, &data);
-
                                if(edit->psys) {
                                        data.dm= psmd->dm;
                                        data.mval= mval;
@@ -3514,12 +3568,12 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
 
                        update_world_cos(ob,edit);
                        psys_free_path_cache(NULL, edit);
-                       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+                       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
                }
                else
                        PE_update_object(scene, ob, 1);
 
-               WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
+               WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
                
                bedit->lastmouse[0]= mouse[0];
                bedit->lastmouse[1]= mouse[1];
@@ -3529,7 +3583,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
        pset->flag |= lock_root;
 }
 
-static void brush_edit_exit(bContext *C, wmOperator *op)
+static void brush_edit_exit(wmOperator *op)
 {
        BrushEdit *bedit= op->customdata;
 
@@ -3546,7 +3600,7 @@ static int brush_edit_exec(bContext *C, wmOperator *op)
        }
        RNA_END;
 
-       brush_edit_exit(C, op);
+       brush_edit_exit(op);
 
        return OPERATOR_FINISHED;
 }
@@ -3564,7 +3618,7 @@ static void brush_edit_apply_event(bContext *C, wmOperator *op, wmEvent *event)
        RNA_collection_add(op->ptr, "stroke", &itemptr);
 
        RNA_float_set_array(&itemptr, "mouse", mouse);
-       RNA_boolean_set(&itemptr, "flip", event->shift != 0); // XXX hardcoded
+       RNA_boolean_set(&itemptr, "pen_flip", event->shift != 0); // XXX hardcoded
 
        /* apply */
        brush_edit_apply(C, op, &itemptr);
@@ -3588,7 +3642,7 @@ static int brush_edit_modal(bContext *C, wmOperator *op, wmEvent *event)
                case LEFTMOUSE:
                case MIDDLEMOUSE:
                case RIGHTMOUSE: // XXX hardcoded
-                       brush_edit_exit(C, op);
+                       brush_edit_exit(op);
                        return OPERATOR_FINISHED;
                case MOUSEMOVE:
                        brush_edit_apply_event(C, op, event);
@@ -3598,9 +3652,9 @@ static int brush_edit_modal(bContext *C, wmOperator *op, wmEvent *event)
        return OPERATOR_RUNNING_MODAL;
 }
 
-static int brush_edit_cancel(bContext *C, wmOperator *op)
+static int brush_edit_cancel(bContext *UNUSED(C), wmOperator *op)
 {
-       brush_edit_exit(C, op);
+       brush_edit_exit(op);
 
        return OPERATOR_CANCELLED;
 }
@@ -3673,8 +3727,6 @@ static void make_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
                for(; pm; pm=pm->next) {
                        for(i=0; i<BPHYS_TOT_DATA; i++)
                                pm->data[i] = MEM_dupallocN(pm->data[i]);
-
-                       pm->index_array = MEM_dupallocN(pm->index_array);
                }
        }
 
@@ -3749,9 +3801,7 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
                        for(i=0; i<BPHYS_TOT_DATA; i++)
                                pm->data[i] = MEM_dupallocN(pm->data[i]);
 
-                       pm->index_array = MEM_dupallocN(pm->index_array);
-
-                       BKE_ptcache_mem_init_pointers(pm);
+                       BKE_ptcache_mem_pointers_init(pm);
 
                        LOOP_POINTS {
                                LOOP_KEYS {
@@ -3762,13 +3812,13 @@ static void get_PTCacheUndo(PTCacheEdit *edit, PTCacheUndo *undo)
                                                key->time = &key->ftime;
                                        }
                                }
-                               BKE_ptcache_mem_incr_pointers(pm);
+                               BKE_ptcache_mem_pointers_incr(pm);
                        }
                }
        }
 }
 
-void PE_undo_push(Scene *scene, char *str)
+void PE_undo_push(Scene *scene, const char *str)
 {
        PTCacheEdit *edit= PE_get_current(scene, OBACT);
        PTCacheUndo *undo;
@@ -3839,7 +3889,17 @@ void PE_undo_step(Scene *scene, int step)
                }
        }
 
-       DAG_id_flush_update(&OBACT->id, OB_RECALC_DATA);
+       DAG_id_tag_update(&OBACT->id, OB_RECALC_DATA);
+}
+
+int PE_undo_valid(Scene *scene)
+{
+       PTCacheEdit *edit= PE_get_current(scene, OBACT);
+       
+       if(edit) {
+               return (edit->undo.last != edit->undo.first);
+       }
+       return 0;
 }
 
 static void PTCacheUndo_number(Scene *scene, PTCacheEdit *edit, int nr)
@@ -3965,6 +4025,9 @@ static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache,
        if(cache && cache->flag & PTCACHE_DISK_CACHE)
                return;
 
+       if(psys == NULL && cache->mem_cache.first == NULL)
+               return;
+
        if(!edit) {
                totpoint = psys ? psys->totpart : ((PTCacheMem*)cache->mem_cache.first)->totpoint;
 
@@ -3992,12 +4055,16 @@ static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache,
                                        key->co= hkey->co;
                                        key->time= &hkey->time;
                                        key->flag= hkey->editflag;
-                                       if(!(psys->flag & PSYS_GLOBAL_HAIR))
+                                       if(!(psys->flag & PSYS_GLOBAL_HAIR)) {
                                                key->flag |= PEK_USE_WCO;
+                                               hkey->editflag |= PEK_USE_WCO;
+                                       }
+
                                        hkey++;
                                }
                                pa++;
                        }
+                       update_world_cos(ob, edit);
                }
                else {
                        PTCacheMem *pm;
@@ -4011,25 +4078,9 @@ static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache,
                                totframe++;
 
                        for(pm=cache->mem_cache.first; pm; pm=pm->next) {
-                               BKE_ptcache_mem_init_pointers(pm);
-
                                LOOP_POINTS {
-                                       if(psys) {
-                                               if(pm->index_array) {
-                                                       if(pm->index_array[p])
-                                                               BKE_ptcache_mem_seek_pointers(p, pm);
-                                                       else
-                                                               continue;
-                                               }
-                                               else {
-                                                       pa = psys->particles + p;
-                                                       if((pm->next && pm->next->frame < pa->time)
-                                                               || (pm->prev && pm->prev->frame >= pa->dietime)) {
-                                                                       BKE_ptcache_mem_incr_pointers(pm);
-                                                                       continue;
-                                                               }
-                                               }
-                                       }
+                                       if(BKE_ptcache_mem_pointers_seek(p, pm) == 0)
+                                               continue;
 
                                        if(!point->totkey) {
                                                key = point->keys = MEM_callocN(totframe*sizeof(PTCacheEditKey),"ParticleEditKeys");
@@ -4043,7 +4094,7 @@ static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache,
                                        key->rot = pm->cur[BPHYS_DATA_ROTATION];
                                        key->ftime = (float)pm->frame;
                                        key->time = &key->ftime;
-                                       BKE_ptcache_mem_incr_pointers(pm);
+                                       BKE_ptcache_mem_pointers_incr(pm);
 
                                        point->totkey++;
                                }
@@ -4075,7 +4126,7 @@ static int particle_edit_toggle_poll(bContext *C)
        return (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || modifiers_findByType(ob, eModifierType_Softbody));
 }
 
-static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
+static int particle_edit_toggle_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Scene *scene= CTX_data_scene(C);
        Object *ob= CTX_data_active_object(C);
@@ -4099,7 +4150,7 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
                WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL);
        }
 
-       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 
        return OPERATOR_FINISHED;
 }
@@ -4121,7 +4172,7 @@ void PARTICLE_OT_particle_edit_toggle(wmOperatorType *ot)
 
 /************************ set editable operator ************************/
 
-static int clear_edited_exec(bContext *C, wmOperator *op)
+static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Object *ob= CTX_data_active_object(C);
        ParticleSystem *psys = psys_get_current(ob);
@@ -4138,10 +4189,17 @@ static int clear_edited_exec(bContext *C, wmOperator *op)
                        psys->flag &= ~PSYS_EDITED;
 
                        psys_reset(psys, PSYS_RESET_DEPSGRAPH);
-                       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
-                       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+                       WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
+                       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
                }
        }
+       else { /* some operation might have protected hair from editing so let's clear the flag */
+               psys->recalc |= PSYS_RECALC_RESET;
+               psys->flag &= ~PSYS_GLOBAL_HAIR;
+               psys->flag &= ~PSYS_EDITED;
+               WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
+               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+       }
 
        return OPERATOR_FINISHED;
 }