doxygen: blender/editors tagged.
[blender-staging.git] / source / blender / editors / physics / particle_edit.c
index 57867fdc4410bcbf733e84bb77130a5deb0b1ce0..8a304765a7a10702d7931bf6caca49a2f3c0cc8d 100644 (file)
  * ***** END GPL LICENSE BLOCK *****
  */
 
+/** \file blender/editors/physics/particle_edit.c
+ *  \ingroup edphys
+ */
+
+
 #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"
@@ -369,8 +376,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 +414,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 +490,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 +596,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 +605,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 +776,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 +797,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 +806,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 +853,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 +945,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 +1045,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;
@@ -1032,7 +1057,7 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
        BLI_kdtree_free(edit->emitter_field);
 
        totface=dm->getNumFaces(dm);
-       totvert=dm->getNumVerts(dm);
+       /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/
 
        edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos");
 
@@ -1041,9 +1066,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->getFaceData(dm,i,CD_MFACE);
+               MVert *mvert;
 
                mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
                VECCOPY(vec,mvert->co);
@@ -1466,8 +1491,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;
@@ -1512,6 +1535,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 +1557,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;
@@ -1573,7 +1599,7 @@ int PE_circle_select(bContext *C, int selecting, short *mval, float rad)
 
 /************************ 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 +1609,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 +1632,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 +1650,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;
@@ -1889,7 +1921,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 +1930,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");
@@ -1982,7 +2018,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 +2029,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;
@@ -2029,12 +2069,11 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
        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 +2089,15 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
                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;
@@ -2187,7 +2235,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;
@@ -2198,6 +2246,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++;
@@ -2356,7 +2408,7 @@ 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);
+       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
        WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
 
        return OPERATOR_FINISHED;
@@ -2406,7 +2458,7 @@ static int weight_set_exec(bContext *C, wmOperator *op)
                }
        }
 
-       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
        WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
 
        return OPERATOR_FINISHED;
@@ -2583,7 +2635,7 @@ static int delete_exec(bContext *C, wmOperator *op)
                recalc_lengths(data.edit);
        }
 
-       DAG_id_flush_update(&data.ob->id, OB_RECALC_DATA);
+       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;
@@ -2744,7 +2796,7 @@ static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
 
        update_world_cos(ob, edit);
        WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
-       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 
        return OPERATOR_FINISHED;
 }
@@ -3087,13 +3139,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;
@@ -3103,7 +3155,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;
@@ -3200,18 +3259,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));
@@ -3224,40 +3282,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++) {
@@ -3288,6 +3352,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)
@@ -3312,6 +3379,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;
 }
 
@@ -3359,6 +3429,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);
@@ -3366,9 +3437,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;
 
@@ -3388,10 +3456,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;
@@ -3412,9 +3477,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;
@@ -3433,10 +3495,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;
@@ -3457,10 +3516,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);
@@ -3474,9 +3530,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;
 
@@ -3498,9 +3551,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;
@@ -3523,7 +3573,7 @@ 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);
@@ -3682,8 +3732,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);
                }
        }
 
@@ -3758,26 +3806,24 @@ 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 {
-                                       if((int)key->ftime == pm->frame) {
+                                       if((int)key->ftime == (int)pm->frame) {
                                                key->co = pm->cur[BPHYS_DATA_LOCATION];
                                                key->vel = pm->cur[BPHYS_DATA_VELOCITY];
                                                key->rot = pm->cur[BPHYS_DATA_ROTATION];
                                                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;
@@ -3848,7 +3894,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)
@@ -3974,8 +4030,11 @@ 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;
+               totpoint = psys ? psys->totpart : (int)((PTCacheMem*)cache->mem_cache.first)->totpoint;
 
                edit= MEM_callocN(sizeof(PTCacheEdit), "PE_create_particle_edit");
                edit->points=MEM_callocN(totpoint*sizeof(PTCacheEditPoint),"PTCacheEditPoints");
@@ -4001,12 +4060,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;
@@ -4020,25 +4083,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");
@@ -4052,7 +4099,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++;
                                }
@@ -4108,7 +4155,7 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *UNUSED(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;
 }
@@ -4148,7 +4195,7 @@ static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op))
 
                        psys_reset(psys, PSYS_RESET_DEPSGRAPH);
                        WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
-                       DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+                       DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
                }
        }
        else { /* some operation might have protected hair from editing so let's clear the flag */
@@ -4156,7 +4203,7 @@ static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op))
                psys->flag &= ~PSYS_GLOBAL_HAIR;
                psys->flag &= ~PSYS_EDITED;
                WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
-               DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
+               DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
        }
 
        return OPERATOR_FINISHED;