style cleanup, brackets in else/if, some indentation.
[blender.git] / source / blender / editors / physics / particle_edit.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2007 by Janne Karhu.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/physics/particle_edit.c
29  *  \ingroup edphys
30  */
31
32
33 #include <stdlib.h>
34 #include <math.h>
35 #include <string.h>
36 #include <assert.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_scene_types.h"
41 #include "DNA_mesh_types.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_view3d_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_space_types.h"
46
47 #include "BLI_math.h"
48 #include "BLI_blenlib.h"
49 #include "BLI_dynstr.h"
50 #include "BLI_kdtree.h"
51 #include "BLI_rand.h"
52 #include "BLI_utildefines.h"
53
54 #include "BKE_DerivedMesh.h"
55 #include "BKE_depsgraph.h"
56
57 #include "BKE_context.h"
58 #include "BKE_global.h"
59 #include "BKE_object.h"
60 #include "BKE_mesh.h"
61 #include "BKE_modifier.h"
62 #include "BKE_particle.h"
63 #include "BKE_report.h"
64 #include "BKE_scene.h"
65
66 #include "BKE_pointcache.h"
67
68 #include "BIF_gl.h"
69 #include "BIF_glutil.h"
70
71 #include "ED_physics.h"
72 #include "ED_mesh.h"
73 #include "ED_particle.h"
74 #include "ED_view3d.h"
75
76 #include "UI_resources.h"
77
78 #include "WM_api.h"
79 #include "WM_types.h"
80
81 #include "RNA_access.h"
82 #include "RNA_define.h"
83
84 #include "physics_intern.h"
85
86 static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
87 static void PTCacheUndo_clear(PTCacheEdit *edit);
88 static void recalc_emitter_field(Object *ob, ParticleSystem *psys);
89
90 #define KEY_K                                   PTCacheEditKey *key; int k
91 #define POINT_P                                 PTCacheEditPoint *point; int p
92 #define LOOP_POINTS                             for(p=0, point=edit->points; p<edit->totpoint; p++, point++)
93 #define LOOP_VISIBLE_POINTS             for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!(point->flag & PEP_HIDE))
94 #define LOOP_SELECTED_POINTS    for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point_is_selected(point))
95 #define LOOP_UNSELECTED_POINTS  for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!point_is_selected(point))
96 #define LOOP_EDITED_POINTS              for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_EDIT_RECALC)
97 #define LOOP_TAGGED_POINTS              for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_TAG)
98 #define LOOP_KEYS                               for(k=0, key=point->keys; k<point->totkey; k++, key++)
99 #define LOOP_VISIBLE_KEYS               for(k=0, key=point->keys; k<point->totkey; k++, key++) if(!(key->flag & PEK_HIDE))
100 #define LOOP_SELECTED_KEYS              for(k=0, key=point->keys; k<point->totkey; k++, key++) if((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
101 #define LOOP_TAGGED_KEYS                for(k=0, key=point->keys; k<point->totkey; k++, key++) if(key->flag & PEK_TAG)
102
103 #define KEY_WCO                                 (key->flag & PEK_USE_WCO ? key->world_co : key->co)
104
105 /**************************** utilities *******************************/
106
107 int PE_poll(bContext *C)
108 {
109         Scene *scene= CTX_data_scene(C);
110         Object *ob= CTX_data_active_object(C);
111
112         if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
113                 return 0;
114         
115         return (PE_get_current(scene, ob) != NULL);
116 }
117
118 int PE_hair_poll(bContext *C)
119 {
120         Scene *scene= CTX_data_scene(C);
121         Object *ob= CTX_data_active_object(C);
122         PTCacheEdit *edit;
123
124         if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
125                 return 0;
126         
127         edit= PE_get_current(scene, ob);
128
129         return (edit && edit->psys);
130 }
131
132 int PE_poll_view3d(bContext *C)
133 {
134         return PE_poll(C) && CTX_wm_area(C)->spacetype == SPACE_VIEW3D &&
135                 CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW;
136 }
137
138 void PE_free_ptcache_edit(PTCacheEdit *edit)
139 {
140         POINT_P;
141
142         if(edit==0) return;
143
144         PTCacheUndo_clear(edit);
145
146         if(edit->points) {
147                 LOOP_POINTS {
148                         if(point->keys) 
149                                 MEM_freeN(point->keys);
150                 }
151
152                 MEM_freeN(edit->points);
153         }
154
155         if(edit->mirror_cache)
156                 MEM_freeN(edit->mirror_cache);
157
158         if(edit->emitter_cosnos) {
159                 MEM_freeN(edit->emitter_cosnos);
160                 edit->emitter_cosnos= 0;
161         }
162
163         if(edit->emitter_field) {
164                 BLI_kdtree_free(edit->emitter_field);
165                 edit->emitter_field= 0;
166         }
167
168         psys_free_path_cache(edit->psys, edit);
169
170         MEM_freeN(edit);
171 }
172
173 /************************************************/
174 /*                      Edit Mode Helpers                                       */
175 /************************************************/
176
177 int PE_start_edit(PTCacheEdit *edit)
178 {
179         if(edit) {
180                 edit->edited = 1;
181                 if(edit->psys)
182                         edit->psys->flag |= PSYS_EDITED;
183                 return 1;
184         }
185
186         return 0;
187 }
188
189 ParticleEditSettings *PE_settings(Scene *scene)
190 {
191         return scene->toolsettings ? &scene->toolsettings->particle : NULL;
192 }
193
194 /* always gets at least the first particlesystem even if PSYS_CURRENT flag is not set
195  *
196  * note: this function runs on poll, therefor it can runs many times a second
197  * keep it fast! */
198 static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
199 {
200         ParticleEditSettings *pset= PE_settings(scene);
201         PTCacheEdit *edit = NULL;
202         ListBase pidlist;
203         PTCacheID *pid;
204
205         if(pset==NULL || ob==NULL)
206                 return NULL;
207
208         pset->scene = scene;
209         pset->object = ob;
210
211         BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
212
213         /* in the case of only one editable thing, set pset->edittype accordingly */
214         if(pidlist.first && pidlist.first == pidlist.last) {
215                 pid = pidlist.first;
216                 switch(pid->type) {
217                         case PTCACHE_TYPE_PARTICLES:
218                                 pset->edittype = PE_TYPE_PARTICLES;
219                                 break;
220                         case PTCACHE_TYPE_SOFTBODY:
221                                 pset->edittype = PE_TYPE_SOFTBODY;
222                                 break;
223                         case PTCACHE_TYPE_CLOTH:
224                                 pset->edittype = PE_TYPE_CLOTH;
225                                 break;
226                 }
227         }
228
229         for(pid=pidlist.first; pid; pid=pid->next) {
230                 if(pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) {
231                         ParticleSystem *psys = pid->calldata;
232
233                         if(psys->flag & PSYS_CURRENT) {
234                                 if(psys->part && psys->part->type == PART_HAIR) {
235                                         if(psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
236                                                 if(create && !psys->pointcache->edit)
237                                                         PE_create_particle_edit(scene, ob, pid->cache, NULL);
238                                                 edit = pid->cache->edit;
239                                         }
240                                         else {
241                                                 if(create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
242                                                         PE_create_particle_edit(scene, ob, NULL, psys);
243                                                 edit = psys->edit;
244                                         }
245                                 }
246                                 else {
247                                         if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
248                                                 PE_create_particle_edit(scene, ob, pid->cache, psys);
249                                         edit = pid->cache->edit;
250                                 }
251
252                                 break;
253                         }
254                 }
255                 else if (pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
256                         if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
257                                 pset->flag |= PE_FADE_TIME;
258                                 // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
259                                 PE_create_particle_edit(scene, ob, pid->cache, NULL);
260                         }
261                         edit = pid->cache->edit;
262                         break;
263                 }
264                 else if (pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
265                         if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
266                                 pset->flag |= PE_FADE_TIME;
267                                 // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
268                                 PE_create_particle_edit(scene, ob, pid->cache, NULL);
269                         }
270                         edit = pid->cache->edit;
271                         break;
272                 }
273         }
274
275         if(edit)
276                 edit->pid = *pid;
277
278         BLI_freelistN(&pidlist);
279
280         return edit;
281 }
282
283 PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
284 {
285         return pe_get_current(scene, ob, 0);
286 }
287
288 PTCacheEdit *PE_create_current(Scene *scene, Object *ob)
289 {
290         return pe_get_current(scene, ob, 1);
291 }
292
293 void PE_current_changed(Scene *scene, Object *ob)
294 {
295         if(ob->mode == OB_MODE_PARTICLE_EDIT)
296                 PE_create_current(scene, ob);
297 }
298
299 void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
300 {
301         ParticleEditSettings *pset=PE_settings(scene);
302         POINT_P; KEY_K;
303
304
305         if(pset->flag & PE_FADE_TIME && pset->selectmode==SCE_SELECT_POINT) {
306                 LOOP_POINTS {
307                         LOOP_KEYS {
308                                 if(fabs(cfra-*key->time) < pset->fade_frames)
309                                         key->flag &= ~PEK_HIDE;
310                                 else {
311                                         key->flag |= PEK_HIDE;
312                                         //key->flag &= ~PEK_SELECT;
313                                 }
314                         }
315                 }
316         }
317         else {
318                 LOOP_POINTS {
319                         LOOP_KEYS {
320                                 key->flag &= ~PEK_HIDE;
321                         }
322                 }
323         }
324 }
325
326 static int pe_x_mirror(Object *ob)
327 {
328         if(ob->type == OB_MESH)
329                 return (((Mesh*)ob->data)->editflag & ME_EDIT_MIRROR_X);
330         
331         return 0;
332 }
333
334 /****************** common struct passed to callbacks ******************/
335
336 typedef struct PEData {
337         ViewContext vc;
338         bglMats mats;
339         
340         Scene *scene;
341         Object *ob;
342         DerivedMesh *dm;
343         PTCacheEdit *edit;
344
345         const int *mval;
346         rcti *rect;
347         float rad;
348         float dist;
349         float dval;
350         int select;
351
352         float *dvec;
353         float combfac;
354         float pufffac;
355         float cutfac;
356         float smoothfac;
357         float weightfac;
358         float growfac;
359         int totrekey;
360
361         int invert;
362         int tot;
363         float vec[3];
364 } PEData;
365
366 static void PE_set_data(bContext *C, PEData *data)
367 {
368         memset(data, 0, sizeof(*data));
369
370         data->scene= CTX_data_scene(C);
371         data->ob= CTX_data_active_object(C);
372         data->edit= PE_get_current(data->scene, data->ob);
373 }
374
375 static void PE_set_view3d_data(bContext *C, PEData *data)
376 {
377         PE_set_data(C, data);
378
379         view3d_set_viewcontext(C, &data->vc);
380         /* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather than (obmat * viewmat) */
381         view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats);
382
383         if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT)) {
384                 if(data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
385                         /* needed or else the draw matrix can be incorrect */
386                         view3d_operator_needs_opengl(C);
387
388                         view3d_validate_backbuf(&data->vc);
389                         /* we may need to force an update here by setting the rv3d as dirty
390                          * for now it seems ok, but take care!:
391                          * rv3d->depths->dirty = 1; */
392                         ED_view3d_depth_update(data->vc.ar);
393                 }
394         }
395 }
396
397 /*************************** selection utilities *******************************/
398
399 static int key_test_depth(PEData *data, const float co[3])
400 {
401         View3D *v3d= data->vc.v3d;
402         double ux, uy, uz;
403         float depth;
404         short wco[3], x,y;
405
406         /* nothing to do */
407         if((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
408                 return 1;
409
410         project_short(data->vc.ar, co, wco);
411         
412         if(wco[0] == IS_CLIPPED)
413                 return 0;
414
415         gluProject(co[0],co[1],co[2], data->mats.modelview, data->mats.projection,
416                    (GLint *)data->mats.viewport, &ux, &uy, &uz);
417
418         x=wco[0];
419         y=wco[1];
420
421 #if 0 /* works well but too slow on some systems [#23118] */
422         x+= (short)data->vc.ar->winrct.xmin;
423         y+= (short)data->vc.ar->winrct.ymin;
424
425         /* PE_set_view3d_data calls this. no need to call here */
426         /* view3d_validate_backbuf(&data->vc); */
427         glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
428 #else /* faster to use depths, these are calculated in PE_set_view3d_data */
429         {
430                 ViewDepths *vd = data->vc.rv3d->depths;
431                 assert(vd && vd->depths);
432                 /* we know its not clipped */
433                 depth= vd->depths[y * vd->w + x];
434         }
435 #endif
436
437         if((float)uz - 0.00001f > depth)
438                 return 0;
439         else
440                 return 1;
441 }
442
443 static int key_inside_circle(PEData *data, float rad, const float co[3], float *distance)
444 {
445         float dx, dy, dist;
446         int sco[2];
447
448         project_int(data->vc.ar, co, sco);
449         
450         if(sco[0] == IS_CLIPPED)
451                 return 0;
452         
453         dx= data->mval[0] - sco[0];
454         dy= data->mval[1] - sco[1];
455         dist= sqrt(dx*dx + dy*dy);
456
457         if(dist > rad)
458                 return 0;
459
460         if(key_test_depth(data, co)) {
461                 if(distance)
462                         *distance=dist;
463
464                 return 1;
465         }
466         
467         return 0;
468 }
469
470 static int key_inside_rect(PEData *data, const float co[3])
471 {
472         int sco[2];
473
474         project_int(data->vc.ar, co,sco);
475
476         if(sco[0] == IS_CLIPPED)
477                 return 0;
478         
479         if(sco[0] > data->rect->xmin && sco[0] < data->rect->xmax &&
480            sco[1] > data->rect->ymin && sco[1] < data->rect->ymax)
481                 return key_test_depth(data, co);
482
483         return 0;
484 }
485
486 static int key_inside_test(PEData *data, const float co[3])
487 {
488         if(data->mval)
489                 return key_inside_circle(data, data->rad, co, NULL);
490         else
491                 return key_inside_rect(data, co);
492 }
493
494 static int point_is_selected(PTCacheEditPoint *point)
495 {
496         KEY_K;
497
498         if(point->flag & PEP_HIDE)
499                 return 0;
500
501         LOOP_SELECTED_KEYS {
502                 return 1;
503         }
504         
505         return 0;
506 }
507
508 /*************************** iterators *******************************/
509
510 typedef void (*ForPointFunc)(PEData *data, int point_index);
511 typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index);
512 typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key);
513
514 static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
515 {
516         ParticleEditSettings *pset= PE_settings(data->scene);
517         PTCacheEdit *edit= data->edit;
518         POINT_P; KEY_K;
519         int nearest_point, nearest_key;
520         float dist= data->rad;
521
522         /* in path select mode we have no keys */
523         if(pset->selectmode==SCE_SELECT_PATH)
524                 return;
525
526         nearest_point= -1;
527         nearest_key= -1;
528
529         LOOP_VISIBLE_POINTS {
530                 if(pset->selectmode == SCE_SELECT_END) {
531                         /* only do end keys */
532                         key= point->keys + point->totkey-1;
533
534                         if(nearest) {
535                                 if(key_inside_circle(data, dist, KEY_WCO, &dist)) {
536                                         nearest_point= p;
537                                         nearest_key= point->totkey-1;
538                                 }
539                         }
540                         else if(key_inside_test(data, KEY_WCO))
541                                 func(data, p, point->totkey-1);
542                 }
543                 else {
544                         /* do all keys */
545                         LOOP_VISIBLE_KEYS {
546                                 if(nearest) {
547                                         if(key_inside_circle(data, dist, KEY_WCO, &dist)) {
548                                                 nearest_point= p;
549                                                 nearest_key= k;
550                                         }
551                                 }
552                                 else if(key_inside_test(data, KEY_WCO))
553                                         func(data, p, k);
554                         }
555                 }
556         }
557
558         /* do nearest only */
559         if(nearest && nearest_point > -1)
560                 func(data, nearest_point, nearest_key);
561 }
562
563 static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected)
564 {
565         ParticleEditSettings *pset= PE_settings(data->scene);
566         PTCacheEdit *edit= data->edit;
567         POINT_P; KEY_K;
568
569         /* all is selected in path mode */
570         if(pset->selectmode==SCE_SELECT_PATH)
571                 selected=0;
572
573         LOOP_VISIBLE_POINTS {
574                 if(pset->selectmode==SCE_SELECT_END) {
575                         /* only do end keys */
576                         key= point->keys + point->totkey - 1;
577
578                         if(selected==0 || key->flag & PEK_SELECT)
579                                 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
580                                         func(data, p);
581                 }
582                 else {
583                         /* do all keys */
584                         LOOP_VISIBLE_KEYS {
585                                 if(selected==0 || key->flag & PEK_SELECT) {
586                                         if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
587                                                 func(data, p);
588                                                 break;
589                                         }
590                                 }
591                         }
592                 }
593         }
594 }
595
596 static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
597 {
598         PTCacheEdit *edit = data->edit;
599         ParticleSystem *psys = edit->psys;
600         ParticleSystemModifierData *psmd = NULL;
601         ParticleEditSettings *pset= PE_settings(data->scene);
602         POINT_P; KEY_K;
603         float mat[4][4]= MAT4_UNITY, imat[4][4]= MAT4_UNITY;
604
605         if(edit->psys)
606                 psmd= psys_get_modifier(data->ob, edit->psys);
607
608         /* all is selected in path mode */
609         if(pset->selectmode==SCE_SELECT_PATH)
610                 selected= 0;
611
612         LOOP_VISIBLE_POINTS {
613                 if(pset->selectmode==SCE_SELECT_END) {
614                         /* only do end keys */
615                         key= point->keys + point->totkey-1;
616
617                         if(selected==0 || key->flag & PEK_SELECT) {
618                                 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
619                                         if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
620                                                 psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
621                                                 invert_m4_m4(imat,mat);
622                                         }
623
624                                         func(data, mat, imat, p, point->totkey-1, key);
625                                 }
626                         }
627                 }
628                 else {
629                         /* do all keys */
630                         LOOP_VISIBLE_KEYS {
631                                 if(selected==0 || key->flag & PEK_SELECT) {
632                                         if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
633                                                 if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
634                                                         psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
635                                                         invert_m4_m4(imat,mat);
636                                                 }
637
638                                                 func(data, mat, imat, p, k, key);
639                                         }
640                                 }
641                         }
642                 }
643         }
644 }
645
646 static void foreach_selected_point(PEData *data, ForPointFunc func)
647 {
648         PTCacheEdit *edit = data->edit;
649         POINT_P;
650
651         LOOP_SELECTED_POINTS {
652                 func(data, p);
653         }
654 }
655
656 static void foreach_selected_key(PEData *data, ForKeyFunc func)
657 {
658         PTCacheEdit *edit = data->edit;
659         POINT_P; KEY_K;
660
661         LOOP_VISIBLE_POINTS {
662                 LOOP_SELECTED_KEYS {
663                         func(data, p, k);
664                 }
665         }
666 }
667
668 static void foreach_point(PEData *data, ForPointFunc func)
669 {
670         PTCacheEdit *edit = data->edit;
671         POINT_P;
672
673         LOOP_POINTS { 
674                 func(data, p);
675         }
676 }
677
678 static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
679 {
680         ParticleEditSettings *pset= PE_settings(scene);
681         POINT_P; KEY_K;
682         int sel= 0;
683
684         LOOP_VISIBLE_POINTS {
685                 if(pset->selectmode==SCE_SELECT_POINT) {
686                         LOOP_SELECTED_KEYS {
687                                 sel++;
688                         }
689                 }
690                 else if(pset->selectmode==SCE_SELECT_END) {
691                         key = point->keys + point->totkey - 1;
692                         if(key->flag & PEK_SELECT)
693                                 sel++;
694                 }
695         }
696
697         return sel;
698 }
699
700 /************************************************/
701 /*                      Particle Edit Mirroring                         */
702 /************************************************/
703
704 static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
705 {
706         PTCacheEdit *edit;
707         ParticleSystemModifierData *psmd;
708         KDTree *tree;
709         KDTreeNearest nearest;
710         HairKey *key;
711         PARTICLE_P;
712         float mat[4][4], co[3];
713         int index, totpart;
714
715         edit= psys->edit;
716         psmd= psys_get_modifier(ob, psys);
717         totpart= psys->totpart;
718
719         if(!psmd->dm)
720                 return;
721
722         tree= BLI_kdtree_new(totpart);
723
724         /* insert particles into kd tree */
725         LOOP_PARTICLES {
726                 key = pa->hair;
727                 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
728                 copy_v3_v3(co, key->co);
729                 mul_m4_v3(mat, co);
730                 BLI_kdtree_insert(tree, p, co, NULL);
731         }
732
733         BLI_kdtree_balance(tree);
734
735         /* lookup particles and set in mirror cache */
736         if(!edit->mirror_cache)
737                 edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
738         
739         LOOP_PARTICLES {
740                 key = pa->hair;
741                 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
742                 copy_v3_v3(co, key->co);
743                 mul_m4_v3(mat, co);
744                 co[0]= -co[0];
745
746                 index= BLI_kdtree_find_nearest(tree, co, NULL, &nearest);
747
748                 /* this needs a custom threshold still, duplicated for editmode mirror */
749                 if(index != -1 && index != p && (nearest.dist <= 0.0002f))
750                         edit->mirror_cache[p]= index;
751                 else
752                         edit->mirror_cache[p]= -1;
753         }
754
755         /* make sure mirrors are in two directions */
756         LOOP_PARTICLES {
757                 if(edit->mirror_cache[p]) {
758                         index= edit->mirror_cache[p];
759                         if(edit->mirror_cache[index] != p)
760                                 edit->mirror_cache[p]= -1;
761                 }
762         }
763
764         BLI_kdtree_free(tree);
765 }
766
767 static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
768 {
769         HairKey *hkey, *mhkey;
770         PTCacheEditPoint *point, *mpoint;
771         PTCacheEditKey *key, *mkey;
772         PTCacheEdit *edit;
773         float mat[4][4], mmat[4][4], immat[4][4];
774         int i, mi, k;
775
776         edit= psys->edit;
777         i= pa - psys->particles;
778
779         /* find mirrored particle if needed */
780         if(!mpa) {
781                 if(!edit->mirror_cache)
782                         PE_update_mirror_cache(ob, psys);
783                 
784                 if(!edit->mirror_cache)
785                         return; /* something went wrong! */
786
787                 mi= edit->mirror_cache[i];
788                 if(mi == -1)
789                         return;
790                 mpa= psys->particles + mi;
791         }
792         else
793                 mi= mpa - psys->particles;
794
795         point = edit->points + i;
796         mpoint = edit->points + mi;
797
798         /* make sure they have the same amount of keys */
799         if(pa->totkey != mpa->totkey) {
800                 if(mpa->hair) MEM_freeN(mpa->hair);
801                 if(mpoint->keys) MEM_freeN(mpoint->keys);
802
803                 mpa->hair= MEM_dupallocN(pa->hair);
804                 mpa->totkey= pa->totkey;
805                 mpoint->keys= MEM_dupallocN(point->keys);
806                 mpoint->totkey= point->totkey;
807
808                 mhkey= mpa->hair;
809                 mkey= mpoint->keys;
810                 for(k=0; k<mpa->totkey; k++, mkey++, mhkey++) {
811                         mkey->co= mhkey->co;
812                         mkey->time= &mhkey->time;
813                         mkey->flag &= ~PEK_SELECT;
814                 }
815         }
816
817         /* mirror positions and tags */
818         psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
819         psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
820         invert_m4_m4(immat, mmat);
821
822         hkey=pa->hair;
823         mhkey=mpa->hair;
824         key= point->keys;
825         mkey= mpoint->keys;
826         for(k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
827                 copy_v3_v3(mhkey->co, hkey->co);
828                 mul_m4_v3(mat, mhkey->co);
829                 mhkey->co[0]= -mhkey->co[0];
830                 mul_m4_v3(immat, mhkey->co);
831
832                 if(key->flag & PEK_TAG)
833                         mkey->flag |= PEK_TAG;
834
835                 mkey->length = key->length;
836         }
837
838         if(point->flag & PEP_TAG)
839                 mpoint->flag |= PEP_TAG;
840         if(point->flag & PEP_EDIT_RECALC)
841                 mpoint->flag |= PEP_EDIT_RECALC;
842 }
843
844 static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
845 {
846         PTCacheEdit *edit;
847         ParticleSystemModifierData *psmd;
848         POINT_P;
849
850         if(!psys)
851                 return;
852
853         edit= psys->edit;
854         psmd= psys_get_modifier(ob, psys);
855
856         if(!psmd->dm)
857                 return;
858
859         if(!edit->mirror_cache)
860                 PE_update_mirror_cache(ob, psys);
861
862         if(!edit->mirror_cache)
863                 return; /* something went wrong */
864
865         /* we delay settings the PARS_EDIT_RECALC for mirrored particles
866          * to avoid doing mirror twice */
867         LOOP_POINTS {
868                 if(point->flag & PEP_EDIT_RECALC) {
869                         PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
870
871                         if(edit->mirror_cache[p] != -1)
872                                 edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
873                 }
874         }
875
876         LOOP_POINTS {
877                 if(point->flag & PEP_EDIT_RECALC)
878                         if(edit->mirror_cache[p] != -1)
879                                 edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
880         }
881 }
882
883 /************************************************/
884 /*                      Edit Calculation                                        */
885 /************************************************/
886 /* tries to stop edited particles from going through the emitter's surface */
887 static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
888 {
889         ParticleEditSettings *pset= PE_settings(scene);
890         ParticleSystem *psys;
891         ParticleSystemModifierData *psmd;
892         POINT_P; KEY_K;
893         int index;
894         float *vec, *nor, dvec[3], dot, dist_1st=0.0f;
895         float hairimat[4][4], hairmat[4][4];
896
897         if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0 || (edit->psys->flag & PSYS_GLOBAL_HAIR))
898                 return;
899
900         psys = edit->psys;
901         psmd = psys_get_modifier(ob,psys);
902
903         if(!psmd->dm)
904                 return;
905
906         LOOP_EDITED_POINTS {
907                 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles + p, hairmat);
908         
909                 LOOP_KEYS {
910                         mul_m4_v3(hairmat, key->co);
911                 }
912
913                 LOOP_KEYS {
914                         if(k==0) {
915                                 dist_1st = len_v3v3((key+1)->co, key->co);
916                                 dist_1st *= 0.75f * pset->emitterdist;
917                         }
918                         else {
919                                 index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL);
920                                 
921                                 vec=edit->emitter_cosnos +index*6;
922                                 nor=vec+3;
923
924                                 sub_v3_v3v3(dvec, key->co, vec);
925
926                                 dot=dot_v3v3(dvec,nor);
927                                 copy_v3_v3(dvec,nor);
928
929                                 if(dot>0.0f) {
930                                         if(dot<dist_1st) {
931                                                 normalize_v3(dvec);
932                                                 mul_v3_fl(dvec,dist_1st-dot);
933                                                 add_v3_v3(key->co, dvec);
934                                         }
935                                 }
936                                 else {
937                                         normalize_v3(dvec);
938                                         mul_v3_fl(dvec,dist_1st-dot);
939                                         add_v3_v3(key->co, dvec);
940                                 }
941                                 if(k==1)
942                                         dist_1st*=1.3333f;
943                         }
944                 }
945                 
946                 invert_m4_m4(hairimat,hairmat);
947
948                 LOOP_KEYS {
949                         mul_m4_v3(hairimat, key->co);
950                 }
951         }
952 }
953 /* force set distances between neighboring keys */
954 static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
955 {
956         
957         ParticleEditSettings *pset=PE_settings(scene);
958         POINT_P; KEY_K;
959         float dv1[3];
960
961         if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
962                 return;
963
964         if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
965                 return;
966
967         LOOP_EDITED_POINTS {
968                 LOOP_KEYS {
969                         if(k) {
970                                 sub_v3_v3v3(dv1, key->co, (key - 1)->co);
971                                 normalize_v3(dv1);
972                                 mul_v3_fl(dv1, (key - 1)->length);
973                                 add_v3_v3v3(key->co, (key - 1)->co, dv1);
974                         }
975                 }
976         }
977 }
978 /* try to find a nice solution to keep distances between neighboring keys */
979 static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
980 {
981         ParticleEditSettings *pset=PE_settings(scene);
982         POINT_P;
983         PTCacheEditKey *key;
984         int j, k;
985         float tlen;
986         float dv0[3]= {0.0f, 0.0f, 0.0f};
987         float dv1[3]= {0.0f, 0.0f, 0.0f};
988         float dv2[3]= {0.0f, 0.0f, 0.0f};
989
990         if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
991                 return;
992
993         if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
994                 return;
995
996         LOOP_EDITED_POINTS {
997                 for(j=1; j<point->totkey; j++) {
998                         float mul= 1.0f / (float)point->totkey;
999
1000                         if(pset->flag & PE_LOCK_FIRST) {
1001                                 key= point->keys + 1;
1002                                 k= 1;
1003                                 dv1[0]= dv1[1]= dv1[2]= 0.0;
1004                         }
1005                         else {
1006                                 key= point->keys;
1007                                 k= 0;
1008                                 dv0[0]= dv0[1]= dv0[2]= 0.0;
1009                         }
1010
1011                         for(; k<point->totkey; k++, key++) {
1012                                 if(k) {
1013                                         sub_v3_v3v3(dv0, (key - 1)->co, key->co);
1014                                         tlen= normalize_v3(dv0);
1015                                         mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
1016                                 }
1017
1018                                 if(k < point->totkey - 1) {
1019                                         sub_v3_v3v3(dv2, (key + 1)->co, key->co);
1020                                         tlen= normalize_v3(dv2);
1021                                         mul_v3_fl(dv2, mul * (tlen - key->length));
1022                                 }
1023
1024                                 if(k) {
1025                                         add_v3_v3((key-1)->co, dv1);
1026                                 }
1027
1028                                 add_v3_v3v3(dv1, dv0, dv2);
1029                         }
1030                 }
1031         }
1032 }
1033 /* set current distances to be kept between neighbouting keys */
1034 static void recalc_lengths(PTCacheEdit *edit)
1035 {
1036         POINT_P; KEY_K;
1037
1038         if(edit==0)
1039                 return;
1040
1041         LOOP_EDITED_POINTS {
1042                 key= point->keys;
1043                 for(k=0; k<point->totkey-1; k++, key++) {
1044                         key->length= len_v3v3(key->co, (key + 1)->co);
1045                 }
1046         }
1047 }
1048
1049 /* calculate a tree for finding nearest emitter's vertice */
1050 static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
1051 {
1052         DerivedMesh *dm=psys_get_modifier(ob,psys)->dm;
1053         PTCacheEdit *edit= psys->edit;
1054         float *vec, *nor;
1055         int i, totface /*, totvert*/;
1056
1057         if(!dm)
1058                 return;
1059
1060         if(edit->emitter_cosnos)
1061                 MEM_freeN(edit->emitter_cosnos);
1062
1063         BLI_kdtree_free(edit->emitter_field);
1064
1065         totface=dm->getNumTessFaces(dm);
1066         /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/
1067
1068         edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos");
1069
1070         edit->emitter_field= BLI_kdtree_new(totface);
1071
1072         vec=edit->emitter_cosnos;
1073         nor=vec+3;
1074
1075         for(i=0; i<totface; i++, vec+=6, nor+=6) {
1076                 MFace *mface=dm->getTessFaceData(dm,i,CD_MFACE);
1077                 MVert *mvert;
1078
1079                 mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
1080                 copy_v3_v3(vec,mvert->co);
1081                 VECCOPY(nor,mvert->no);
1082
1083                 mvert=dm->getVertData(dm,mface->v2,CD_MVERT);
1084                 add_v3_v3v3(vec,vec,mvert->co);
1085                 VECADD(nor,nor,mvert->no);
1086
1087                 mvert=dm->getVertData(dm,mface->v3,CD_MVERT);
1088                 add_v3_v3v3(vec,vec,mvert->co);
1089                 VECADD(nor,nor,mvert->no);
1090
1091                 if(mface->v4) {
1092                         mvert=dm->getVertData(dm,mface->v4,CD_MVERT);
1093                         add_v3_v3v3(vec,vec,mvert->co);
1094                         VECADD(nor,nor,mvert->no);
1095                         
1096                         mul_v3_fl(vec,0.25);
1097                 }
1098                 else
1099                         mul_v3_fl(vec,0.3333f);
1100
1101                 normalize_v3(nor);
1102
1103                 BLI_kdtree_insert(edit->emitter_field, i, vec, NULL);
1104         }
1105
1106         BLI_kdtree_balance(edit->emitter_field);
1107 }
1108
1109 static void PE_update_selection(Scene *scene, Object *ob, int useflag)
1110 {
1111         PTCacheEdit *edit= PE_get_current(scene, ob);
1112         HairKey *hkey;
1113         POINT_P; KEY_K;
1114
1115         /* flag all particles to be updated if not using flag */
1116         if(!useflag)
1117                 LOOP_POINTS
1118                         point->flag |= PEP_EDIT_RECALC;
1119
1120         /* flush edit key flag to hair key flag to preserve selection 
1121          * on save */
1122         if(edit->psys) LOOP_POINTS {
1123                 hkey = edit->psys->particles[p].hair;
1124                 LOOP_KEYS {
1125                         hkey->editflag= key->flag;
1126                         hkey++;
1127                 }
1128         }
1129
1130         psys_cache_edit_paths(scene, ob, edit, CFRA);
1131
1132
1133         /* disable update flag */
1134         LOOP_POINTS
1135                 point->flag &= ~PEP_EDIT_RECALC;
1136 }
1137
1138 static void update_world_cos(Object *ob, PTCacheEdit *edit)
1139 {
1140         ParticleSystem *psys = edit->psys;
1141         ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
1142         POINT_P; KEY_K;
1143         float hairmat[4][4];
1144
1145         if(psys==0 || psys->edit==0 || psmd->dm==NULL)
1146                 return;
1147
1148         LOOP_POINTS {
1149                 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1150                         psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat);
1151
1152                 LOOP_KEYS {
1153                         copy_v3_v3(key->world_co,key->co);
1154                         if(!(psys->flag & PSYS_GLOBAL_HAIR))
1155                                 mul_m4_v3(hairmat, key->world_co);
1156                 }
1157         }
1158 }
1159 static void update_velocities(PTCacheEdit *edit)
1160 {
1161         /*TODO: get frs_sec properly */
1162         float vec1[3], vec2[3], frs_sec, dfra;
1163         POINT_P; KEY_K;
1164
1165         /* hair doesn't use velocities */
1166         if(edit->psys || !edit->points || !edit->points->keys->vel)
1167                 return;
1168
1169         frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
1170
1171         LOOP_EDITED_POINTS {
1172                 LOOP_KEYS {
1173                         if(k==0) {
1174                                 dfra = *(key+1)->time - *key->time;
1175
1176                                 if(dfra <= 0.0f)
1177                                         continue;
1178
1179                                 sub_v3_v3v3(key->vel, (key+1)->co, key->co);
1180
1181                                 if(point->totkey>2) {
1182                                         sub_v3_v3v3(vec1, (key+1)->co, (key+2)->co);
1183                                         project_v3_v3v3(vec2, vec1, key->vel);
1184                                         sub_v3_v3v3(vec2, vec1, vec2);
1185                                         madd_v3_v3fl(key->vel, vec2, 0.5f);
1186                                 }
1187                         }
1188                         else if(k==point->totkey-1) {
1189                                 dfra = *key->time - *(key-1)->time;
1190
1191                                 if(dfra <= 0.0f)
1192                                         continue;
1193
1194                                 sub_v3_v3v3(key->vel, key->co, (key-1)->co);
1195
1196                                 if(point->totkey>2) {
1197                                         sub_v3_v3v3(vec1, (key-2)->co, (key-1)->co);
1198                                         project_v3_v3v3(vec2, vec1, key->vel);
1199                                         sub_v3_v3v3(vec2, vec1, vec2);
1200                                         madd_v3_v3fl(key->vel, vec2, 0.5f);
1201                                 }
1202                         }
1203                         else {
1204                                 dfra = *(key+1)->time - *(key-1)->time;
1205                                 
1206                                 if(dfra <= 0.0f)
1207                                         continue;
1208
1209                                 sub_v3_v3v3(key->vel, (key+1)->co, (key-1)->co);
1210                         }
1211                         mul_v3_fl(key->vel, frs_sec/dfra);
1212                 }
1213         }
1214 }
1215
1216 void PE_update_object(Scene *scene, Object *ob, int useflag)
1217 {
1218         /* use this to do partial particle updates, not usable when adding or
1219          * removing, then a full redo is necessary and calling this may crash */
1220         ParticleEditSettings *pset= PE_settings(scene);
1221         PTCacheEdit *edit = PE_get_current(scene, ob);
1222         POINT_P;
1223
1224         if(!edit)
1225                 return;
1226
1227         /* flag all particles to be updated if not using flag */
1228         if(!useflag)
1229                 LOOP_POINTS {
1230                         point->flag |= PEP_EDIT_RECALC;
1231                 }
1232
1233         /* do post process on particle edit keys */
1234         pe_iterate_lengths(scene, edit);
1235         pe_deflect_emitter(scene, ob, edit);
1236         PE_apply_lengths(scene, edit);
1237         if(pe_x_mirror(ob))
1238                 PE_apply_mirror(ob,edit->psys);
1239         if(edit->psys)
1240                 update_world_cos(ob, edit);
1241         if(pset->flag & PE_AUTO_VELOCITY)
1242                 update_velocities(edit);
1243         PE_hide_keys_time(scene, edit, CFRA);
1244
1245         /* regenerate path caches */
1246         psys_cache_edit_paths(scene, ob, edit, CFRA);
1247
1248         /* disable update flag */
1249         LOOP_POINTS {
1250                 point->flag &= ~PEP_EDIT_RECALC;
1251         }
1252
1253         if(edit->psys)
1254                 edit->psys->flag &= ~PSYS_HAIR_UPDATED;
1255 }
1256
1257 /************************************************/
1258 /*                      Edit Selections                                         */
1259 /************************************************/
1260
1261 /*-----selection callbacks-----*/
1262
1263 static void select_key(PEData *data, int point_index, int key_index)
1264 {
1265         PTCacheEdit *edit = data->edit;
1266         PTCacheEditPoint *point = edit->points + point_index;
1267         PTCacheEditKey *key = point->keys + key_index;
1268
1269         if(data->select)
1270                 key->flag |= PEK_SELECT;
1271         else
1272                 key->flag &= ~PEK_SELECT;
1273
1274         point->flag |= PEP_EDIT_RECALC;
1275 }
1276
1277 static void select_keys(PEData *data, int point_index, int UNUSED(key_index))
1278 {
1279         PTCacheEdit *edit = data->edit;
1280         PTCacheEditPoint *point = edit->points + point_index;
1281         KEY_K;
1282
1283         LOOP_KEYS {
1284                 if(data->select)
1285                         key->flag |= PEK_SELECT;
1286                 else
1287                         key->flag &= ~PEK_SELECT;
1288         }
1289
1290         point->flag |= PEP_EDIT_RECALC;
1291 }
1292
1293 static void toggle_key_select(PEData *data, int point_index, int key_index)
1294 {
1295         PTCacheEdit *edit = data->edit;
1296         PTCacheEditPoint *point = edit->points + point_index;
1297         PTCacheEditKey *key = point->keys + key_index;
1298
1299         key->flag ^= PEK_SELECT;
1300         point->flag |= PEP_EDIT_RECALC;
1301 }
1302
1303 /************************ de select all operator ************************/
1304
1305 static int pe_select_all_exec(bContext *C, wmOperator *op)
1306 {
1307         Scene *scene= CTX_data_scene(C);
1308         Object *ob= CTX_data_active_object(C);
1309         PTCacheEdit *edit= PE_get_current(scene, ob);
1310         POINT_P; KEY_K;
1311         int action = RNA_enum_get(op->ptr, "action");
1312
1313         if (action == SEL_TOGGLE) {
1314                 action = SEL_SELECT;
1315                 LOOP_VISIBLE_POINTS {
1316                         LOOP_SELECTED_KEYS {
1317                                 action = SEL_DESELECT;
1318                                 break;
1319                         }
1320
1321                         if (action == SEL_DESELECT)
1322                                 break;
1323                 }
1324         }
1325
1326         LOOP_VISIBLE_POINTS {
1327                 LOOP_VISIBLE_KEYS {
1328                         switch (action) {
1329                         case SEL_SELECT:
1330                                 if ((key->flag & PEK_SELECT) == 0) {
1331                                         key->flag |= PEK_SELECT;
1332                                         point->flag |= PEP_EDIT_RECALC;
1333                                 }
1334                                 break;
1335                         case SEL_DESELECT:
1336                                 if (key->flag & PEK_SELECT) {
1337                                         key->flag &= ~PEK_SELECT;
1338                                         point->flag |= PEP_EDIT_RECALC;
1339                                 }
1340                                 break;
1341                         case SEL_INVERT:
1342                                 if ((key->flag & PEK_SELECT) == 0) {
1343                                         key->flag |= PEK_SELECT;
1344                                         point->flag |= PEP_EDIT_RECALC;
1345                                 } else {
1346                                         key->flag &= ~PEK_SELECT;
1347                                         point->flag |= PEP_EDIT_RECALC;
1348                                 }
1349                                 break;
1350                         }
1351                 }
1352         }
1353
1354         PE_update_selection(scene, ob, 1);
1355         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1356
1357         return OPERATOR_FINISHED;
1358 }
1359
1360 void PARTICLE_OT_select_all(wmOperatorType *ot)
1361 {
1362         /* identifiers */
1363         ot->name= "Selection of all particles";
1364         ot->idname= "PARTICLE_OT_select_all";
1365         
1366         /* api callbacks */
1367         ot->exec= pe_select_all_exec;
1368         ot->poll= PE_poll;
1369
1370         /* flags */
1371         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1372
1373         WM_operator_properties_select_all(ot);
1374 }
1375
1376 /************************ pick select operator ************************/
1377
1378 int PE_mouse_particles(bContext *C, const int mval[2], int extend)
1379 {
1380         PEData data;
1381         Scene *scene= CTX_data_scene(C);
1382         Object *ob= CTX_data_active_object(C);
1383         PTCacheEdit *edit= PE_get_current(scene, ob);
1384         POINT_P; KEY_K;
1385         
1386         if(!PE_start_edit(edit))
1387                 return OPERATOR_CANCELLED;
1388
1389         if(!extend) {
1390                 LOOP_VISIBLE_POINTS {
1391                         LOOP_SELECTED_KEYS {
1392                                 key->flag &= ~PEK_SELECT;
1393                                 point->flag |= PEP_EDIT_RECALC;
1394                         }
1395                 }
1396         }
1397
1398         PE_set_view3d_data(C, &data);
1399         data.mval= mval;
1400         data.rad= 75.0f;
1401
1402         for_mouse_hit_keys(&data, toggle_key_select, 1);  /* nearest only */
1403
1404         PE_update_selection(scene, ob, 1);
1405         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1406
1407         return OPERATOR_FINISHED;
1408 }
1409
1410 /************************ select first operator ************************/
1411
1412 static void select_root(PEData *data, int point_index)
1413 {
1414         if (data->edit->points[point_index].flag & PEP_HIDE)
1415                 return;
1416         
1417         data->edit->points[point_index].keys->flag |= PEK_SELECT;
1418         data->edit->points[point_index].flag |= PEP_EDIT_RECALC; /* redraw selection only */
1419 }
1420
1421 static int select_roots_exec(bContext *C, wmOperator *UNUSED(op))
1422 {
1423         PEData data;
1424
1425         PE_set_data(C, &data);
1426         foreach_point(&data, select_root);
1427
1428         PE_update_selection(data.scene, data.ob, 1);
1429         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1430
1431         return OPERATOR_FINISHED;
1432 }
1433
1434 void PARTICLE_OT_select_roots(wmOperatorType *ot)
1435 {
1436         /* identifiers */
1437         ot->name= "Select Roots";
1438         ot->idname= "PARTICLE_OT_select_roots";
1439         
1440         /* api callbacks */
1441         ot->exec= select_roots_exec;
1442         ot->poll= PE_poll;
1443
1444         /* flags */
1445         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1446 }
1447
1448 /************************ select last operator ************************/
1449
1450 static void select_tip(PEData *data, int point_index)
1451 {
1452         PTCacheEditPoint *point = data->edit->points + point_index;
1453         
1454         if (point->flag & PEP_HIDE)
1455                 return;
1456         
1457         point->keys[point->totkey - 1].flag |= PEK_SELECT;
1458         point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1459 }
1460
1461 static int select_tips_exec(bContext *C, wmOperator *UNUSED(op))
1462 {
1463         PEData data;
1464
1465         PE_set_data(C, &data);
1466         foreach_point(&data, select_tip);
1467
1468         PE_update_selection(data.scene, data.ob, 1);
1469         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1470
1471         return OPERATOR_FINISHED;
1472 }
1473
1474 void PARTICLE_OT_select_tips(wmOperatorType *ot)
1475 {
1476         /* identifiers */
1477         ot->name= "Select Tips";
1478         ot->idname= "PARTICLE_OT_select_tips";
1479         
1480         /* api callbacks */
1481         ot->exec= select_tips_exec;
1482         ot->poll= PE_poll;
1483
1484         /* flags */
1485         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1486 }
1487
1488 /************************ select linked operator ************************/
1489
1490 static int select_linked_exec(bContext *C, wmOperator *op)
1491 {
1492         PEData data;
1493         int mval[2];
1494         int location[2];
1495
1496         RNA_int_get_array(op->ptr, "location", location);
1497         mval[0]= location[0];
1498         mval[1]= location[1];
1499
1500         PE_set_view3d_data(C, &data);
1501         data.mval= mval;
1502         data.rad=75.0f;
1503         data.select= !RNA_boolean_get(op->ptr, "deselect");
1504
1505         for_mouse_hit_keys(&data, select_keys, 1);  /* nearest only */
1506         PE_update_selection(data.scene, data.ob, 1);
1507         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1508
1509         return OPERATOR_FINISHED;
1510 }
1511
1512 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
1513 {
1514         RNA_int_set_array(op->ptr, "location", event->mval);
1515         return select_linked_exec(C, op);
1516 }
1517
1518 void PARTICLE_OT_select_linked(wmOperatorType *ot)
1519 {
1520         /* identifiers */
1521         ot->name= "Select Linked";
1522         ot->idname= "PARTICLE_OT_select_linked";
1523         
1524         /* api callbacks */
1525         ot->exec= select_linked_exec;
1526         ot->invoke= select_linked_invoke;
1527         ot->poll= PE_poll_view3d;
1528
1529         /* flags */
1530         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1531
1532         /* properties */
1533         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them");
1534         RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
1535 }
1536
1537 /************************ border select operator ************************/
1538 void PE_deselect_all_visible(PTCacheEdit *edit)
1539 {
1540         POINT_P; KEY_K;
1541
1542         LOOP_VISIBLE_POINTS {
1543                 LOOP_SELECTED_KEYS {
1544                         key->flag &= ~PEK_SELECT;
1545                         point->flag |= PEP_EDIT_RECALC;
1546                 }
1547         }
1548 }
1549
1550 int PE_border_select(bContext *C, rcti *rect, int select, int extend)
1551 {
1552         Scene *scene= CTX_data_scene(C);
1553         Object *ob= CTX_data_active_object(C);
1554         PTCacheEdit *edit= PE_get_current(scene, ob);
1555         PEData data;
1556
1557         if(!PE_start_edit(edit))
1558                 return OPERATOR_CANCELLED;
1559
1560         if (extend == 0 && select)
1561                 PE_deselect_all_visible(edit);
1562
1563         PE_set_view3d_data(C, &data);
1564         data.rect= rect;
1565         data.select= select;
1566
1567         for_mouse_hit_keys(&data, select_key, 0);
1568
1569         PE_update_selection(scene, ob, 1);
1570         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1571
1572         return OPERATOR_FINISHED;
1573 }
1574
1575 /************************ circle select operator ************************/
1576
1577 int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
1578 {
1579         Scene *scene= CTX_data_scene(C);
1580         Object *ob= CTX_data_active_object(C);
1581         PTCacheEdit *edit= PE_get_current(scene, ob);
1582         PEData data;
1583
1584         if(!PE_start_edit(edit))
1585                 return OPERATOR_FINISHED;
1586
1587         PE_set_view3d_data(C, &data);
1588         data.mval= mval;
1589         data.rad= rad;
1590         data.select= selecting;
1591
1592         for_mouse_hit_keys(&data, select_key, 0);
1593
1594         PE_update_selection(scene, ob, 1);
1595         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1596
1597         return OPERATOR_FINISHED;
1598 }
1599
1600 /************************ lasso select operator ************************/
1601
1602 int PE_lasso_select(bContext *C, int mcords[][2], short moves, short extend, short select)
1603 {
1604         Scene *scene= CTX_data_scene(C);
1605         Object *ob= CTX_data_active_object(C);
1606         ARegion *ar= CTX_wm_region(C);
1607         ParticleEditSettings *pset= PE_settings(scene);
1608         PTCacheEdit *edit = PE_get_current(scene, ob);
1609         ParticleSystem *psys = edit->psys;
1610         ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
1611         POINT_P; KEY_K;
1612         float co[3], mat[4][4]= MAT4_UNITY;
1613         int vertco[2];
1614
1615         PEData data;
1616
1617         if(!PE_start_edit(edit))
1618                 return OPERATOR_CANCELLED;
1619
1620         if (extend == 0 && select)
1621                 PE_deselect_all_visible(edit);
1622
1623         /* only for depths */
1624         PE_set_view3d_data(C, &data);
1625
1626         LOOP_VISIBLE_POINTS {
1627                 if(edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
1628                         psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + p, mat);
1629
1630                 if(pset->selectmode==SCE_SELECT_POINT) {
1631                         LOOP_KEYS {
1632                                 copy_v3_v3(co, key->co);
1633                                 mul_m4_v3(mat, co);
1634                                 project_int(ar, co, vertco);
1635                                 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1]) && key_test_depth(&data, co)) {
1636                                         if(select && !(key->flag & PEK_SELECT)) {
1637                                                 key->flag |= PEK_SELECT;
1638                                                 point->flag |= PEP_EDIT_RECALC;
1639                                         }
1640                                         else if(key->flag & PEK_SELECT) {
1641                                                 key->flag &= ~PEK_SELECT;
1642                                                 point->flag |= PEP_EDIT_RECALC;
1643                                         }
1644                                 }
1645                         }
1646                 }
1647                 else if(pset->selectmode==SCE_SELECT_END) {
1648                         key= point->keys + point->totkey - 1;
1649
1650                         copy_v3_v3(co, key->co);
1651                         mul_m4_v3(mat, co);
1652                         project_int(ar, co,vertco);
1653                         if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1]) && key_test_depth(&data, co)) {
1654                                 if(select && !(key->flag & PEK_SELECT)) {
1655                                         key->flag |= PEK_SELECT;
1656                                         point->flag |= PEP_EDIT_RECALC;
1657                                 }
1658                                 else if(key->flag & PEK_SELECT) {
1659                                         key->flag &= ~PEK_SELECT;
1660                                         point->flag |= PEP_EDIT_RECALC;
1661                                 }
1662                         }
1663                 }
1664         }
1665
1666         PE_update_selection(scene, ob, 1);
1667         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1668
1669         return OPERATOR_FINISHED;
1670 }
1671
1672 /*************************** hide operator **************************/
1673
1674 static int hide_exec(bContext *C, wmOperator *op)
1675 {
1676         Object *ob= CTX_data_active_object(C);
1677         Scene *scene= CTX_data_scene(C);
1678         PTCacheEdit *edit= PE_get_current(scene, ob);
1679         POINT_P; KEY_K;
1680         
1681         if(RNA_enum_get(op->ptr, "unselected")) {
1682                 LOOP_UNSELECTED_POINTS {
1683                         point->flag |= PEP_HIDE;
1684                         point->flag |= PEP_EDIT_RECALC;
1685
1686                         LOOP_KEYS
1687                                 key->flag &= ~PEK_SELECT;
1688                 }
1689         }
1690         else {
1691                 LOOP_SELECTED_POINTS {
1692                         point->flag |= PEP_HIDE;
1693                         point->flag |= PEP_EDIT_RECALC;
1694
1695                         LOOP_KEYS
1696                                 key->flag &= ~PEK_SELECT;
1697                 }
1698         }
1699
1700         PE_update_selection(scene, ob, 1);
1701         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1702
1703         return OPERATOR_FINISHED;
1704 }
1705
1706 void PARTICLE_OT_hide(wmOperatorType *ot)
1707 {
1708         /* identifiers */
1709         ot->name= "Hide Selected";
1710         ot->idname= "PARTICLE_OT_hide";
1711         
1712         /* api callbacks */
1713         ot->exec= hide_exec;
1714         ot->poll= PE_poll;
1715
1716         /* flags */
1717         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1718
1719         /* props */
1720         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
1721 }
1722
1723 /*************************** reveal operator **************************/
1724
1725 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
1726 {
1727         Object *ob= CTX_data_active_object(C);
1728         Scene *scene= CTX_data_scene(C);
1729         PTCacheEdit *edit= PE_get_current(scene, ob);
1730         POINT_P; KEY_K;
1731
1732         LOOP_POINTS {
1733                 if(point->flag & PEP_HIDE) {
1734                         point->flag &= ~PEP_HIDE;
1735                         point->flag |= PEP_EDIT_RECALC;
1736
1737                         LOOP_KEYS
1738                                 key->flag |= PEK_SELECT;
1739                 }
1740         }
1741
1742         PE_update_selection(scene, ob, 1);
1743         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1744
1745         return OPERATOR_FINISHED;
1746 }
1747
1748 void PARTICLE_OT_reveal(wmOperatorType *ot)
1749 {
1750         /* identifiers */
1751         ot->name= "Reveal";
1752         ot->idname= "PARTICLE_OT_reveal";
1753         
1754         /* api callbacks */
1755         ot->exec= reveal_exec;
1756         ot->poll= PE_poll;
1757
1758         /* flags */
1759         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1760 }
1761
1762 /************************ select less operator ************************/
1763
1764 static void select_less_keys(PEData *data, int point_index)
1765 {
1766         PTCacheEdit *edit= data->edit;
1767         PTCacheEditPoint *point = edit->points + point_index;
1768         KEY_K;
1769
1770         LOOP_SELECTED_KEYS {
1771                 if(k==0) {
1772                         if(((key+1)->flag&PEK_SELECT)==0)
1773                                 key->flag |= PEK_TAG;
1774                 }
1775                 else if(k==point->totkey-1) {
1776                         if(((key-1)->flag&PEK_SELECT)==0)
1777                                 key->flag |= PEK_TAG;
1778                 }
1779                 else {
1780                         if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
1781                                 key->flag |= PEK_TAG;
1782                 }
1783         }
1784
1785         LOOP_KEYS {
1786                 if(key->flag&PEK_TAG) {
1787                         key->flag &= ~(PEK_TAG|PEK_SELECT);
1788                         point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1789                 }
1790         }
1791 }
1792
1793 static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
1794 {
1795         PEData data;
1796
1797         PE_set_data(C, &data);
1798         foreach_point(&data, select_less_keys);
1799
1800         PE_update_selection(data.scene, data.ob, 1);
1801         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1802
1803         return OPERATOR_FINISHED;
1804 }
1805
1806 void PARTICLE_OT_select_less(wmOperatorType *ot)
1807 {
1808         /* identifiers */
1809         ot->name= "Select Less";
1810         ot->idname= "PARTICLE_OT_select_less";
1811         
1812         /* api callbacks */
1813         ot->exec= select_less_exec;
1814         ot->poll= PE_poll;
1815
1816         /* flags */
1817         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1818 }
1819
1820 /************************ select more operator ************************/
1821
1822 static void select_more_keys(PEData *data, int point_index)
1823 {
1824         PTCacheEdit *edit= data->edit;
1825         PTCacheEditPoint *point = edit->points + point_index;
1826         KEY_K;
1827
1828         LOOP_KEYS {
1829                 if(key->flag & PEK_SELECT) continue;
1830
1831                 if(k==0) {
1832                         if((key+1)->flag&PEK_SELECT)
1833                                 key->flag |= PEK_TAG;
1834                 }
1835                 else if(k==point->totkey-1) {
1836                         if((key-1)->flag&PEK_SELECT)
1837                                 key->flag |= PEK_TAG;
1838                 }
1839                 else {
1840                         if(((key-1)->flag | (key+1)->flag) & PEK_SELECT)
1841                                 key->flag |= PEK_TAG;
1842                 }
1843         }
1844
1845         LOOP_KEYS {
1846                 if(key->flag&PEK_TAG) {
1847                         key->flag &= ~PEK_TAG;
1848                         key->flag |= PEK_SELECT;
1849                         point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1850                 }
1851         }
1852 }
1853
1854 static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
1855 {
1856         PEData data;
1857
1858         PE_set_data(C, &data);
1859         foreach_point(&data, select_more_keys);
1860
1861         PE_update_selection(data.scene, data.ob, 1);
1862         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1863
1864         return OPERATOR_FINISHED;
1865 }
1866
1867 void PARTICLE_OT_select_more(wmOperatorType *ot)
1868 {
1869         /* identifiers */
1870         ot->name= "Select More";
1871         ot->idname= "PARTICLE_OT_select_more";
1872         
1873         /* api callbacks */
1874         ot->exec= select_more_exec;
1875         ot->poll= PE_poll;
1876
1877         /* flags */
1878         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1879 }
1880
1881 /************************ rekey operator ************************/
1882
1883 static void rekey_particle(PEData *data, int pa_index)
1884 {
1885         PTCacheEdit *edit= data->edit;
1886         ParticleSystem *psys= edit->psys;
1887         ParticleSimulationData sim= {0};
1888         ParticleData *pa= psys->particles + pa_index;
1889         PTCacheEditPoint *point = edit->points + pa_index;
1890         ParticleKey state;
1891         HairKey *key, *new_keys, *okey;
1892         PTCacheEditKey *ekey;
1893         float dval, sta, end;
1894         int k;
1895
1896         sim.scene= data->scene;
1897         sim.ob= data->ob;
1898         sim.psys= edit->psys;
1899
1900         pa->flag |= PARS_REKEY;
1901
1902         key= new_keys= MEM_callocN(data->totrekey * sizeof(HairKey),"Hair re-key keys");
1903
1904         okey = pa->hair;
1905         /* root and tip stay the same */
1906         copy_v3_v3(key->co, okey->co);
1907         copy_v3_v3((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co);
1908
1909         sta= key->time= okey->time;
1910         end= (key + data->totrekey - 1)->time= (okey + pa->totkey - 1)->time;
1911         dval= (end - sta) / (float)(data->totrekey - 1);
1912
1913         /* interpolate new keys from old ones */
1914         for(k=1,key++; k<data->totrekey-1; k++,key++) {
1915                 state.time= (float)k / (float)(data->totrekey-1);
1916                 psys_get_particle_on_path(&sim, pa_index, &state, 0);
1917                 copy_v3_v3(key->co, state.co);
1918                 key->time= sta + k * dval;
1919         }
1920
1921         /* replace keys */
1922         if(pa->hair)
1923                 MEM_freeN(pa->hair);
1924         pa->hair= new_keys;
1925
1926         point->totkey=pa->totkey=data->totrekey;
1927
1928
1929         if(point->keys)
1930                 MEM_freeN(point->keys);
1931         ekey= point->keys= MEM_callocN(pa->totkey * sizeof(PTCacheEditKey),"Hair re-key edit keys");
1932                 
1933         for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
1934                 ekey->co= key->co;
1935                 ekey->time= &key->time;
1936                 ekey->flag |= PEK_SELECT;
1937                 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1938                         ekey->flag |= PEK_USE_WCO;
1939         }
1940
1941         pa->flag &= ~PARS_REKEY;
1942         point->flag |= PEP_EDIT_RECALC;
1943 }
1944
1945 static int rekey_exec(bContext *C, wmOperator *op)
1946 {
1947         PEData data;
1948
1949         PE_set_data(C, &data);
1950
1951         data.dval= 1.0f / (float)(data.totrekey-1);
1952         data.totrekey= RNA_int_get(op->ptr, "keys");
1953
1954         foreach_selected_point(&data, rekey_particle);
1955         
1956         recalc_lengths(data.edit);
1957         PE_update_object(data.scene, data.ob, 1);
1958         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
1959
1960         return OPERATOR_FINISHED;
1961 }
1962
1963 void PARTICLE_OT_rekey(wmOperatorType *ot)
1964 {
1965         /* identifiers */
1966         ot->name= "Rekey";
1967         ot->idname= "PARTICLE_OT_rekey";
1968         
1969         /* api callbacks */
1970         ot->exec= rekey_exec;
1971         ot->invoke= WM_operator_props_popup;
1972         ot->poll= PE_poll;
1973
1974         /* flags */
1975         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1976
1977         /* properties */
1978         RNA_def_int(ot->srna, "keys", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
1979 }
1980
1981 static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time)
1982 {
1983         PTCacheEdit *edit= PE_get_current(scene, ob);
1984         ParticleSystem *psys;
1985         ParticleSimulationData sim= {0};
1986         ParticleData *pa;
1987         ParticleKey state;
1988         HairKey *new_keys, *key;
1989         PTCacheEditKey *ekey;
1990         int k;
1991
1992         if(!edit || !edit->psys) return;
1993
1994         psys = edit->psys;
1995
1996         sim.scene= scene;
1997         sim.ob= ob;
1998         sim.psys= psys;
1999
2000         pa= psys->particles + pa_index;
2001
2002         pa->flag |= PARS_REKEY;
2003
2004         key= new_keys= MEM_dupallocN(pa->hair);
2005         
2006         /* interpolate new keys from old ones (roots stay the same) */
2007         for(k=1, key++; k < pa->totkey; k++, key++) {
2008                 state.time= path_time * (float)k / (float)(pa->totkey-1);
2009                 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2010                 copy_v3_v3(key->co, state.co);
2011         }
2012
2013         /* replace hair keys */
2014         if(pa->hair)
2015                 MEM_freeN(pa->hair);
2016         pa->hair= new_keys;
2017
2018         /* update edit pointers */
2019         for(k=0, key=pa->hair, ekey=edit->points[pa_index].keys; k<pa->totkey; k++, key++, ekey++) {
2020                 ekey->co= key->co;
2021                 ekey->time= &key->time;
2022         }
2023
2024         pa->flag &= ~PARS_REKEY;
2025 }
2026
2027 /************************* utilities **************************/
2028
2029 static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
2030 {
2031         PTCacheEdit *edit = psys->edit;
2032         ParticleData *pa, *npa=0, *new_pars=0;
2033         POINT_P;
2034         PTCacheEditPoint *npoint=0, *new_points=0;
2035         ParticleSystemModifierData *psmd;
2036         int i, new_totpart= psys->totpart, removed= 0;
2037
2038         if(mirror) {
2039                 /* mirror tags */
2040                 psmd= psys_get_modifier(ob, psys);
2041
2042                 LOOP_TAGGED_POINTS {
2043                         PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
2044                 }
2045         }
2046
2047         LOOP_TAGGED_POINTS {
2048                 new_totpart--;
2049                 removed++;
2050         }
2051
2052         if(new_totpart != psys->totpart) {
2053                 if(new_totpart) {
2054                         npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
2055                         npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
2056
2057                         if(ELEM(NULL, new_pars, new_points)) {
2058                                  /* allocation error! */
2059                                 if(new_pars)
2060                                         MEM_freeN(new_pars);
2061                                 if(new_points)
2062                                         MEM_freeN(new_points);
2063                                 return 0;
2064                         }
2065                 }
2066
2067                 pa= psys->particles;
2068                 point= edit->points;
2069                 for(i=0; i<psys->totpart; i++, pa++, point++) {
2070                         if(point->flag & PEP_TAG) {
2071                                 if(point->keys)
2072                                         MEM_freeN(point->keys);
2073                                 if(pa->hair)
2074                                         MEM_freeN(pa->hair);
2075                         }
2076                         else {
2077                                 memcpy(npa, pa, sizeof(ParticleData));
2078                                 memcpy(npoint, point, sizeof(PTCacheEditPoint));
2079                                 npa++;
2080                                 npoint++;
2081                         }
2082                 }
2083
2084                 if(psys->particles) MEM_freeN(psys->particles);
2085                 psys->particles= new_pars;
2086
2087                 if(edit->points) MEM_freeN(edit->points);
2088                 edit->points= new_points;
2089
2090                 if(edit->mirror_cache) {
2091                         MEM_freeN(edit->mirror_cache);
2092                         edit->mirror_cache= NULL;
2093                 }
2094
2095                 if(psys->child) {
2096                         MEM_freeN(psys->child);
2097                         psys->child= NULL;
2098                         psys->totchild=0;
2099                 }
2100
2101                 edit->totpoint= psys->totpart= new_totpart;
2102         }
2103
2104         return removed;
2105 }
2106
2107 static void remove_tagged_keys(Object *ob, ParticleSystem *psys)
2108 {
2109         PTCacheEdit *edit= psys->edit;
2110         ParticleData *pa;
2111         HairKey *hkey, *nhkey, *new_hkeys=0;
2112         POINT_P; KEY_K;
2113         PTCacheEditKey *nkey, *new_keys;
2114         ParticleSystemModifierData *psmd;
2115         short new_totkey;
2116
2117         if(pe_x_mirror(ob)) {
2118                 /* mirror key tags */
2119                 psmd= psys_get_modifier(ob, psys);
2120
2121                 LOOP_POINTS {
2122                         LOOP_TAGGED_KEYS {
2123                                 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
2124                                 break;
2125                         }
2126                 }
2127         }
2128
2129         LOOP_POINTS {
2130                 new_totkey= point->totkey;
2131                 LOOP_TAGGED_KEYS {
2132                         new_totkey--;
2133                 }
2134                 /* we can't have elements with less than two keys*/
2135                 if(new_totkey < 2)
2136                         point->flag |= PEP_TAG;
2137         }
2138         remove_tagged_particles(ob, psys, pe_x_mirror(ob));
2139
2140         LOOP_POINTS {
2141                 pa = psys->particles + p;
2142                 new_totkey= pa->totkey;
2143
2144                 LOOP_TAGGED_KEYS {
2145                         new_totkey--;
2146                 }
2147
2148                 if(new_totkey != pa->totkey) {
2149                         nhkey= new_hkeys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
2150                         nkey= new_keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys");
2151
2152                         hkey= pa->hair;
2153                         LOOP_KEYS {
2154                                 while(key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
2155                                         key++;
2156                                         hkey++;
2157                                 }
2158
2159                                 if(hkey < pa->hair + pa->totkey) {
2160                                         copy_v3_v3(nhkey->co, hkey->co);
2161                                         nhkey->editflag = hkey->editflag;
2162                                         nhkey->time= hkey->time;
2163                                         nhkey->weight= hkey->weight;
2164                                         
2165                                         nkey->co= nhkey->co;
2166                                         nkey->time= &nhkey->time;
2167                                         /* these can be copied from old edit keys */
2168                                         nkey->flag = key->flag;
2169                                         nkey->ftime = key->ftime;
2170                                         nkey->length = key->length;
2171                                         copy_v3_v3(nkey->world_co, key->world_co);
2172                                 }
2173                                 nkey++;
2174                                 nhkey++;
2175                                 hkey++;
2176                         }
2177
2178                         if(pa->hair)
2179                                 MEM_freeN(pa->hair);
2180
2181                         if(point->keys)
2182                                 MEM_freeN(point->keys);
2183                         
2184                         pa->hair= new_hkeys;
2185                         point->keys= new_keys;
2186
2187                         point->totkey= pa->totkey= new_totkey;
2188
2189                         /* flag for recalculating length */
2190                         point->flag |= PEP_EDIT_RECALC;
2191                 }
2192         }
2193 }
2194
2195 /************************ subdivide opertor *********************/
2196
2197 /* works like normal edit mode subdivide, inserts keys between neighboring selected keys */
2198 static void subdivide_particle(PEData *data, int pa_index)
2199 {
2200         PTCacheEdit *edit= data->edit;
2201         ParticleSystem *psys= edit->psys;
2202         ParticleSimulationData sim= {0};
2203         ParticleData *pa= psys->particles + pa_index;
2204         PTCacheEditPoint *point = edit->points + pa_index;
2205         ParticleKey state;
2206         HairKey *key, *nkey, *new_keys;
2207         PTCacheEditKey *ekey, *nekey, *new_ekeys;
2208
2209         int k;
2210         short totnewkey=0;
2211         float endtime;
2212
2213         sim.scene= data->scene;
2214         sim.ob= data->ob;
2215         sim.psys= edit->psys;
2216
2217         for(k=0, ekey=point->keys; k<pa->totkey-1; k++,ekey++) {
2218                 if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
2219                         totnewkey++;
2220         }
2221
2222         if(totnewkey==0) return;
2223
2224         pa->flag |= PARS_REKEY;
2225
2226         nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys");
2227         nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(PTCacheEditKey)),"Hair subdivide edit keys");
2228         
2229         key = pa->hair;
2230         endtime= key[pa->totkey-1].time;
2231
2232         for(k=0, ekey=point->keys; k<pa->totkey-1; k++, key++, ekey++) {
2233
2234                 memcpy(nkey,key,sizeof(HairKey));
2235                 memcpy(nekey,ekey,sizeof(PTCacheEditKey));
2236
2237                 nekey->co= nkey->co;
2238                 nekey->time= &nkey->time;
2239
2240                 nkey++;
2241                 nekey++;
2242
2243                 if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) {
2244                         nkey->time= (key->time + (key+1)->time)*0.5f;
2245                         state.time= (endtime != 0.0f)? nkey->time/endtime: 0.0f;
2246                         psys_get_particle_on_path(&sim, pa_index, &state, 0);
2247                         copy_v3_v3(nkey->co, state.co);
2248
2249                         nekey->co= nkey->co;
2250                         nekey->time= &nkey->time;
2251                         nekey->flag |= PEK_SELECT;
2252                         if(!(psys->flag & PSYS_GLOBAL_HAIR))
2253                                 nekey->flag |= PEK_USE_WCO;
2254
2255                         nekey++;
2256                         nkey++;
2257                 }
2258         }
2259         /*tip still not copied*/
2260         memcpy(nkey,key,sizeof(HairKey));
2261         memcpy(nekey,ekey,sizeof(PTCacheEditKey));
2262
2263         nekey->co= nkey->co;
2264         nekey->time= &nkey->time;
2265
2266         if(pa->hair)
2267                 MEM_freeN(pa->hair);
2268         pa->hair= new_keys;
2269
2270         if(point->keys)
2271                 MEM_freeN(point->keys);
2272         point->keys= new_ekeys;
2273
2274         point->totkey = pa->totkey = pa->totkey + totnewkey;
2275         point->flag |= PEP_EDIT_RECALC;
2276         pa->flag &= ~PARS_REKEY;
2277 }
2278
2279 static int subdivide_exec(bContext *C, wmOperator *UNUSED(op))
2280 {
2281         PEData data;
2282
2283         PE_set_data(C, &data);
2284         foreach_point(&data, subdivide_particle);
2285         
2286         recalc_lengths(data.edit);
2287         PE_update_object(data.scene, data.ob, 1);
2288         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
2289
2290         return OPERATOR_FINISHED;
2291 }
2292
2293 void PARTICLE_OT_subdivide(wmOperatorType *ot)
2294 {
2295         /* identifiers */
2296         ot->name= "Subdivide";
2297         ot->idname= "PARTICLE_OT_subdivide";
2298         
2299         /* api callbacks */
2300         ot->exec= subdivide_exec;
2301         ot->poll= PE_poll;
2302
2303         /* flags */
2304         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2305 }
2306
2307 /************************ remove doubles opertor *********************/
2308
2309 static int remove_doubles_exec(bContext *C, wmOperator *op)
2310 {
2311         Scene *scene= CTX_data_scene(C);
2312         Object *ob= CTX_data_active_object(C);
2313         PTCacheEdit *edit= PE_get_current(scene, ob);
2314         ParticleSystem *psys = edit->psys;
2315         ParticleSystemModifierData *psmd;
2316         KDTree *tree;
2317         KDTreeNearest nearest[10];
2318         POINT_P;
2319         float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
2320         int n, totn, removed, totremoved;
2321
2322         if(psys->flag & PSYS_GLOBAL_HAIR)
2323                 return OPERATOR_CANCELLED;
2324
2325         edit= psys->edit;
2326         psmd= psys_get_modifier(ob, psys);
2327         totremoved= 0;
2328
2329         do {
2330                 removed= 0;
2331
2332                 tree=BLI_kdtree_new(psys->totpart);
2333                         
2334                 /* insert particles into kd tree */
2335                 LOOP_SELECTED_POINTS {
2336                         psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
2337                         copy_v3_v3(co, point->keys->co);
2338                         mul_m4_v3(mat, co);
2339                         BLI_kdtree_insert(tree, p, co, NULL);
2340                 }
2341
2342                 BLI_kdtree_balance(tree);
2343
2344                 /* tag particles to be removed */
2345                 LOOP_SELECTED_POINTS {
2346                         psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
2347                         copy_v3_v3(co, point->keys->co);
2348                         mul_m4_v3(mat, co);
2349
2350                         totn= BLI_kdtree_find_n_nearest(tree,10,co,NULL,nearest);
2351
2352                         for(n=0; n<totn; n++) {
2353                                 /* this needs a custom threshold still */
2354                                 if(nearest[n].index > p && nearest[n].dist < threshold) {
2355                                         if(!(point->flag & PEP_TAG)) {
2356                                                 point->flag |= PEP_TAG;
2357                                                 removed++;
2358                                         }
2359                                 }
2360                         }
2361                 }
2362
2363                 BLI_kdtree_free(tree);
2364
2365                 /* remove tagged particles - don't do mirror here! */
2366                 remove_tagged_particles(ob, psys, 0);
2367                 totremoved += removed;
2368         } while(removed);
2369
2370         if(totremoved == 0)
2371                 return OPERATOR_CANCELLED;
2372
2373         BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles", totremoved);
2374
2375         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2376         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2377
2378         return OPERATOR_FINISHED;
2379 }
2380
2381 void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
2382 {
2383         /* identifiers */
2384         ot->name= "Remove Doubles";
2385         ot->idname= "PARTICLE_OT_remove_doubles";
2386         
2387         /* api callbacks */
2388         ot->exec= remove_doubles_exec;
2389         ot->poll= PE_poll;
2390
2391         /* flags */
2392         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2393
2394         /* properties */
2395         RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
2396 }
2397
2398
2399 static int weight_set_exec(bContext *C, wmOperator *op)
2400 {
2401         Scene *scene= CTX_data_scene(C);
2402         ParticleEditSettings *pset= PE_settings(scene);
2403         Object *ob= CTX_data_active_object(C);
2404         PTCacheEdit *edit= PE_get_current(scene, ob);
2405         ParticleSystem *psys = edit->psys;
2406         POINT_P;
2407         KEY_K;
2408         HairKey *hkey;
2409         float weight;
2410         ParticleBrushData *brush= &pset->brush[pset->brushtype];
2411         float factor= RNA_float_get(op->ptr, "factor");
2412
2413         weight= brush->strength;
2414         edit= psys->edit;
2415
2416         LOOP_SELECTED_POINTS {
2417                 ParticleData *pa= psys->particles + p;
2418
2419                 LOOP_SELECTED_KEYS {
2420                         hkey= pa->hair + k;
2421                         hkey->weight= interpf(weight, hkey->weight, factor);
2422                 }
2423         }
2424
2425         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2426         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2427
2428         return OPERATOR_FINISHED;
2429 }
2430
2431 void PARTICLE_OT_weight_set(wmOperatorType *ot)
2432 {
2433         /* identifiers */
2434         ot->name= "Weight Set";
2435         ot->idname= "PARTICLE_OT_weight_set";
2436
2437         /* api callbacks */
2438         ot->exec= weight_set_exec;
2439         ot->poll= PE_poll;
2440
2441         /* flags */
2442         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2443
2444         RNA_def_float(ot->srna, "factor", 1, 0, 1, "Factor", "", 0, 1);
2445 }
2446
2447 /************************ cursor drawing *******************************/
2448
2449 static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
2450 {
2451         ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2452         ParticleBrushData *brush;
2453
2454         if(pset->brushtype < 0)
2455                 return;
2456
2457         brush= &pset->brush[pset->brushtype];
2458
2459         if(brush) {
2460                 glPushMatrix();
2461
2462                 glTranslatef((float)x, (float)y, 0.0f);
2463
2464                 glColor4ub(255, 255, 255, 128);
2465                 glEnable(GL_LINE_SMOOTH );
2466                 glEnable(GL_BLEND);
2467                 glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
2468                 glDisable(GL_BLEND);
2469                 glDisable(GL_LINE_SMOOTH );
2470                 
2471                 glPopMatrix();
2472         }
2473 }
2474
2475 static void toggle_particle_cursor(bContext *C, int enable)
2476 {
2477         ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2478
2479         if(pset->paintcursor && !enable) {
2480                 WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
2481                 pset->paintcursor = NULL;
2482         }
2483         else if(enable)
2484                 pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_view3d, brush_drawcursor, NULL);
2485 }
2486
2487 /*************************** delete operator **************************/
2488
2489 enum { DEL_PARTICLE, DEL_KEY };
2490
2491 static EnumPropertyItem delete_type_items[]= {
2492         {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
2493         {DEL_KEY, "KEY", 0, "Key", ""},
2494         {0, NULL, 0, NULL, NULL}};
2495
2496 static void set_delete_particle(PEData *data, int pa_index)
2497 {
2498         PTCacheEdit *edit= data->edit;
2499
2500         edit->points[pa_index].flag |= PEP_TAG;
2501 }
2502
2503 static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
2504 {
2505         PTCacheEdit *edit= data->edit;
2506
2507         edit->points[pa_index].keys[key_index].flag |= PEK_TAG;
2508 }
2509
2510 static int delete_exec(bContext *C, wmOperator *op)
2511 {
2512         PEData data;
2513         int type= RNA_enum_get(op->ptr, "type");
2514
2515         PE_set_data(C, &data);
2516
2517         if(type == DEL_KEY) {
2518                 foreach_selected_key(&data, set_delete_particle_key);
2519                 remove_tagged_keys(data.ob, data.edit->psys);
2520                 recalc_lengths(data.edit);
2521         }
2522         else if(type == DEL_PARTICLE) {
2523                 foreach_selected_point(&data, set_delete_particle);
2524                 remove_tagged_particles(data.ob, data.edit->psys, pe_x_mirror(data.ob));
2525                 recalc_lengths(data.edit);
2526         }
2527
2528         DAG_id_tag_update(&data.ob->id, OB_RECALC_DATA);
2529         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
2530
2531         return OPERATOR_FINISHED;
2532 }
2533
2534 void PARTICLE_OT_delete(wmOperatorType *ot)
2535 {
2536         /* identifiers */
2537         ot->name= "Delete";
2538         ot->idname= "PARTICLE_OT_delete";
2539         
2540         /* api callbacks */
2541         ot->exec= delete_exec;
2542         ot->invoke= WM_menu_invoke;
2543         ot->poll= PE_hair_poll;
2544
2545         /* flags */
2546         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2547
2548         /* properties */
2549         ot->prop= RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys");
2550 }
2551
2552 /*************************** mirror operator **************************/
2553
2554 static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
2555 {
2556         Mesh *me= (Mesh*)(ob->data);
2557         ParticleSystemModifierData *psmd;
2558         PTCacheEdit *edit= PE_get_current(scene, ob);
2559         ParticleSystem *psys = edit->psys;
2560         ParticleData *pa, *newpa, *new_pars;
2561         PTCacheEditPoint *newpoint, *new_points;
2562         POINT_P; KEY_K;
2563         HairKey *hkey;
2564         int *mirrorfaces = NULL;
2565         int rotation, totpart, newtotpart;
2566
2567         if(psys->flag & PSYS_GLOBAL_HAIR)
2568                 return;
2569
2570         psmd= psys_get_modifier(ob, psys);
2571         if(!psmd->dm)
2572                 return;
2573
2574         mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
2575
2576         if(!edit->mirror_cache)
2577                 PE_update_mirror_cache(ob, psys);
2578
2579         totpart= psys->totpart;
2580         newtotpart= psys->totpart;
2581         LOOP_VISIBLE_POINTS {
2582                 pa = psys->particles + p;
2583                 if(!tagged) {
2584                         if(point_is_selected(point)) {
2585                                 if(edit->mirror_cache[p] != -1) {
2586                                         /* already has a mirror, don't need to duplicate */
2587                                         PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
2588                                         continue;
2589                                 }
2590                                 else
2591                                         point->flag |= PEP_TAG;
2592                         }
2593                 }
2594
2595                 if((point->flag & PEP_TAG) && mirrorfaces[pa->num*2] != -1)
2596                         newtotpart++;
2597         }
2598
2599         if(newtotpart != psys->totpart) {
2600                 /* allocate new arrays and copy existing */
2601                 new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
2602                 new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
2603
2604                 if(psys->particles) {
2605                         memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
2606                         MEM_freeN(psys->particles);
2607                 }
2608                 psys->particles= new_pars;
2609
2610                 if(edit->points) {
2611                         memcpy(new_points, edit->points, totpart*sizeof(PTCacheEditPoint));
2612                         MEM_freeN(edit->points);
2613                 }
2614                 edit->points= new_points;
2615
2616                 if(edit->mirror_cache) {
2617                         MEM_freeN(edit->mirror_cache);
2618                         edit->mirror_cache= NULL;
2619                 }
2620
2621                 edit->totpoint= psys->totpart= newtotpart;
2622                         
2623                 /* create new elements */
2624                 newpa= psys->particles + totpart;
2625                 newpoint= edit->points + totpart;
2626
2627                 for(p=0, point=edit->points; p<totpart; p++, point++) {
2628                         pa = psys->particles + p;
2629
2630                         if(point->flag & PEP_HIDE)
2631                                 continue;
2632                         if(!(point->flag & PEP_TAG) || mirrorfaces[pa->num*2] == -1)
2633                                 continue;
2634
2635                         /* duplicate */
2636                         *newpa= *pa;
2637                         *newpoint= *point;
2638                         if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
2639                         if(point->keys) newpoint->keys= MEM_dupallocN(point->keys);
2640
2641                         /* rotate weights according to vertex index rotation */
2642                         rotation= mirrorfaces[pa->num*2+1];
2643                         newpa->fuv[0]= pa->fuv[2];
2644                         newpa->fuv[1]= pa->fuv[1];
2645                         newpa->fuv[2]= pa->fuv[0];
2646                         newpa->fuv[3]= pa->fuv[3];
2647                         while(rotation-- > 0)
2648                                 if(me->mface[pa->num].v4)
2649                                         SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
2650                                 else
2651                                         SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
2652
2653                         /* assign face inddex */
2654                         newpa->num= mirrorfaces[pa->num*2];
2655                         newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
2656
2657                         /* update edit key pointers */
2658                         key= newpoint->keys;
2659                         for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, key++) {
2660                                 key->co= hkey->co;
2661                                 key->time= &hkey->time;
2662                         }
2663
2664                         /* map key positions as mirror over x axis */
2665                         PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
2666
2667                         newpa++;
2668                         newpoint++;
2669                 }
2670         }
2671
2672         LOOP_POINTS {
2673                 point->flag &= ~PEP_TAG;
2674         }
2675
2676         MEM_freeN(mirrorfaces);
2677 }
2678
2679 static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
2680 {
2681         Scene *scene= CTX_data_scene(C);
2682         Object *ob= CTX_data_active_object(C);
2683         PTCacheEdit *edit= PE_get_current(scene, ob);
2684         
2685         PE_mirror_x(scene, ob, 0);
2686
2687         update_world_cos(ob, edit);
2688         WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2689         DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2690
2691         return OPERATOR_FINISHED;
2692 }
2693
2694 void PARTICLE_OT_mirror(wmOperatorType *ot)
2695 {
2696         /* identifiers */
2697         ot->name= "Mirror";
2698         ot->idname= "PARTICLE_OT_mirror";
2699         
2700         /* api callbacks */
2701         ot->exec= mirror_exec;
2702         ot->poll= PE_poll;
2703
2704         /* flags */
2705         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2706 }
2707
2708 /************************* brush edit callbacks ********************/
2709
2710 static void brush_comb(PEData *data, float UNUSED(mat[][4]), float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
2711 {
2712         ParticleEditSettings *pset= PE_settings(data->scene);
2713         float cvec[3], fac;
2714
2715         if(pset->flag & PE_LOCK_FIRST && key_index == 0) return;
2716
2717         fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
2718
2719         copy_v3_v3(cvec,data->dvec);
2720         mul_mat3_m4_v3(imat,cvec);
2721         mul_v3_fl(cvec, fac);
2722         add_v3_v3(key->co, cvec);
2723
2724         (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
2725 }
2726
2727 static void brush_cut(PEData *data, int pa_index)
2728 {
2729         PTCacheEdit *edit = data->edit;
2730         ARegion *ar= data->vc.ar;
2731         Object *ob= data->ob;
2732         ParticleEditSettings *pset= PE_settings(data->scene);
2733         ParticleCacheKey *key= edit->pathcache[pa_index];
2734         float rad2, cut_time= 1.0;
2735         float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
2736         int k, cut, keys= (int)pow(2.0, (double)pset->draw_step);
2737         int vertco[2];
2738
2739         /* blunt scissors */
2740         if(BLI_frand() > data->cutfac) return;
2741
2742         /* don't cut hidden */
2743         if(edit->points[pa_index].flag & PEP_HIDE)
2744                 return;
2745
2746         rad2= data->rad * data->rad;
2747
2748         cut=0;
2749
2750         project_int_noclip(ar, key->co, vertco);
2751         x0= (float)vertco[0];
2752         x1= (float)vertco[1];
2753
2754         o0= (float)data->mval[0];
2755         o1= (float)data->mval[1];
2756         
2757         xo0= x0 - o0;
2758         xo1= x1 - o1;
2759
2760         /* check if root is inside circle */
2761         if(xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) {
2762                 cut_time= -1.0f;
2763                 cut= 1;
2764         }
2765         else {
2766                 /* calculate path time closest to root that was inside the circle */
2767                 for(k=1, key++; k<=keys; k++, key++) {
2768                         project_int_noclip(ar, key->co, vertco);
2769
2770                         if(key_test_depth(data, key->co) == 0) {
2771                                 x0= (float)vertco[0];
2772                                 x1= (float)vertco[1];
2773
2774                                 xo0= x0 - o0;
2775                                 xo1= x1 - o1;
2776                                 continue;
2777                         }
2778
2779                         v0= (float)vertco[0] - x0;
2780                         v1= (float)vertco[1] - x1;
2781
2782                         dv= v0*v0 + v1*v1;
2783
2784                         d= (v0*xo1 - v1*xo0);
2785                         
2786                         d= dv * rad2 - d*d;
2787
2788                         if(d > 0.0f) {
2789                                 d= sqrt(d);
2790
2791                                 cut_time= -(v0*xo0 + v1*xo1 + d);
2792
2793                                 if(cut_time > 0.0f) {
2794                                         cut_time /= dv;
2795
2796                                         if(cut_time < 1.0f) {
2797                                                 cut_time += (float)(k-1);
2798                                                 cut_time /= (float)keys;
2799                                                 cut= 1;
2800                                                 break;
2801                                         }
2802                                 }
2803                         }
2804
2805                         x0= (float)vertco[0];
2806                         x1= (float)vertco[1];
2807
2808                         xo0= x0 - o0;
2809                         xo1= x1 - o1;
2810                 }
2811         }
2812
2813         if(cut) {
2814                 if(cut_time < 0.0f) {
2815                         edit->points[pa_index].flag |= PEP_TAG;
2816                 }
2817                 else {
2818                         rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
2819                         edit->points[pa_index].flag |= PEP_EDIT_RECALC;
2820                 }
2821         }
2822 }
2823
2824 static void brush_length(PEData *data, int point_index)
2825 {
2826         PTCacheEdit *edit= data->edit;
2827         PTCacheEditPoint *point = edit->points + point_index;
2828         KEY_K;
2829         float dvec[3],pvec[3] = {0.0f, 0.0f, 0.0f};
2830
2831         LOOP_KEYS {
2832                 if(k==0) {
2833                         copy_v3_v3(pvec,key->co);
2834                 }
2835                 else {
2836                         sub_v3_v3v3(dvec,key->co,pvec);
2837                         copy_v3_v3(pvec,key->co);
2838                         mul_v3_fl(dvec,data->growfac);
2839                         add_v3_v3v3(key->co,(key-1)->co,dvec);
2840                 }
2841         }
2842
2843         point->flag |= PEP_EDIT_RECALC;
2844 }
2845
2846 static void brush_puff(PEData *data, int point_index)
2847 {
2848         PTCacheEdit *edit = data->edit;
2849         ParticleSystem *psys = edit->psys;
2850         PTCacheEditPoint *point = edit->points + point_index;
2851         KEY_K;
2852         float mat[4][4], imat[4][4];
2853
2854         float lastco[3], rootco[3] = {0.0f, 0.0f, 0.0f}, co[3], nor[3], kco[3], dco[3], ofs[3] = {0.0f, 0.0f, 0.0f}, fac=0.0f, length=0.0f;
2855         int puff_volume = 0;
2856         int change= 0;
2857
2858         {
2859                 ParticleEditSettings *pset= PE_settings(data->scene);
2860                 ParticleBrushData *brush= &pset->brush[pset->brushtype];
2861                 puff_volume = brush->flag & PE_BRUSH_DATA_PUFF_VOLUME;
2862         }
2863
2864         if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
2865                 psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
2866                 invert_m4_m4(imat,mat);
2867         }
2868         else {
2869                 unit_m4(mat);
2870                 unit_m4(imat);
2871         }
2872
2873         LOOP_KEYS {
2874                 if(k==0) {
2875                         /* find root coordinate and normal on emitter */
2876                         copy_v3_v3(co, key->co);
2877                         mul_m4_v3(mat, co);
2878                         mul_v3_m4v3(kco, data->ob->imat, co); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
2879
2880                         point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL);
2881                         if(point_index == -1) return;
2882
2883                         copy_v3_v3(rootco, co);
2884                         copy_v3_v3(nor, &edit->emitter_cosnos[point_index*6+3]);
2885                         mul_mat3_m4_v3(data->ob->obmat, nor); /* normal into worldspace */
2886
2887                         normalize_v3(nor);
2888                         length= 0.0f;
2889
2890                         fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac);
2891                         fac *= 0.025f;
2892                         if(data->invert)
2893                                 fac= -fac;
2894                 }
2895                 else {
2896                         /* compute position as if hair was standing up straight.
2897                          * */
2898                         copy_v3_v3(lastco, co);
2899                         copy_v3_v3(co, key->co);
2900                         mul_m4_v3(mat, co);
2901                         length += len_v3v3(lastco, co);
2902                         if((data->select==0 || (key->flag & PEK_SELECT)) && !(key->flag & PEK_HIDE)) {
2903                                 madd_v3_v3v3fl(kco, rootco, nor, length);
2904
2905                                 /* blend between the current and straight position */
2906                                 sub_v3_v3v3(dco, kco, co);
2907                                 madd_v3_v3fl(co, dco, fac);
2908
2909                                 /* re-use dco to compare before and after translation and add to the offset  */
2910                                 copy_v3_v3(dco, key->co);
2911
2912                                 mul_v3_m4v3(key->co, imat, co);
2913
2914                                 if(puff_volume) {
2915                                         /* accumulate the total distance moved to apply to unselected
2916                                          * keys that come after */
2917                                         ofs[0] += key->co[0] - dco[0];
2918                                         ofs[1] += key->co[1] - dco[1];
2919                                         ofs[2] += key->co[2] - dco[2];
2920                                 }
2921                                 change = 1;
2922                         }
2923                         else {
2924
2925                                 if(puff_volume) {
2926 #if 0
2927                                         /* this is simple but looks bad, adds annoying kinks */
2928                                         add_v3_v3(key->co, ofs);
2929 #else
2930                                         /* translate (not rotate) the rest of the hair if its not selected  */
2931                                         if(ofs[0] || ofs[1] || ofs[2]) {
2932 #if 0                                   /* kindof works but looks worse then whats below */
2933
2934                                                 /* Move the unselected point on a vector based on the
2935                                                  * hair direction and the offset */
2936                                                 float c1[3], c2[3];
2937                                                 sub_v3_v3v3(dco, lastco, co);
2938                                                 mul_mat3_m4_v3(imat, dco); /* into particle space */
2939
2940                                                 /* move the point along a vector perpendicular to the
2941                                                  * hairs direction, reduces odd kinks, */
2942                                                 cross_v3_v3v3(c1, ofs, dco);
2943                                                 cross_v3_v3v3(c2, c1, dco);
2944                                                 normalize_v3(c2);
2945                                                 mul_v3_fl(c2, len_v3(ofs));
2946                                                 add_v3_v3(key->co, c2);
2947 #else
2948                                                 /* Move the unselected point on a vector based on the
2949                                                  * the normal of the closest geometry */
2950                                                 float oco[3], onor[3];
2951                                                 copy_v3_v3(oco, key->co);
2952                                                 mul_m4_v3(mat, oco);
2953                                                 mul_v3_m4v3(kco, data->ob->imat, oco); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
2954
2955                                                 point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL);
2956                                                 if(point_index != -1) {
2957                                                         copy_v3_v3(onor, &edit->emitter_cosnos[point_index*6+3]);
2958                                                         mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */
2959                                                         mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */
2960                                                         normalize_v3(onor);
2961
2962
2963                                                         mul_v3_fl(onor, len_v3(ofs));
2964                                                         add_v3_v3(key->co, onor);
2965                                                 }
2966 #endif
2967                                         }
2968 #endif
2969                                 }
2970                         }
2971                 }
2972         }
2973
2974         if(change)
2975                 point->flag |= PEP_EDIT_RECALC;
2976 }
2977
2978
2979 static void brush_weight(PEData *data, float UNUSED(mat[][4]), float UNUSED(imat[][4]), int point_index, int key_index, PTCacheEditKey *UNUSED(key))
2980 {
2981         /* roots have full weight allways */
2982         if(key_index) {
2983                 PTCacheEdit *edit = data->edit;
2984                 ParticleSystem *psys = edit->psys;
2985
2986                 ParticleData *pa= psys->particles + point_index;
2987                 pa->hair[key_index].weight = data->weightfac;
2988
2989                 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
2990         }
2991 }
2992
2993 static void brush_smooth_get(PEData *data, float mat[][4], float UNUSED(imat[][4]), int UNUSED(point_index), int key_index, PTCacheEditKey *key)
2994 {       
2995         if(key_index) {
2996                 float dvec[3];
2997
2998                 sub_v3_v3v3(dvec,key->co,(key-1)->co);
2999                 mul_mat3_m4_v3(mat,dvec);
3000                 add_v3_v3(data->vec, dvec);
3001                 data->tot++;
3002         }
3003 }
3004
3005 static void brush_smooth_do(PEData *data, float UNUSED(mat[][4]), float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
3006 {
3007         float vec[3], dvec[3];
3008         
3009         if(key_index) {
3010                 copy_v3_v3(vec, data->vec);
3011                 mul_mat3_m4_v3(imat,vec);
3012
3013                 sub_v3_v3v3(dvec,key->co,(key-1)->co);
3014
3015                 sub_v3_v3v3(dvec,vec,dvec);
3016                 mul_v3_fl(dvec,data->smoothfac);
3017                 
3018                 add_v3_v3(key->co, dvec);
3019         }
3020
3021         (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
3022 }
3023
3024 /* convert from triangle barycentric weights to quad mean value weights */
3025 static void intersect_dm_quad_weights(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float w[4])
3026 {
3027         float co[3], vert[4][3];
3028
3029         copy_v3_v3(vert[0], v1);
3030         copy_v3_v3(vert[1], v2);
3031         copy_v3_v3(vert[2], v3);
3032         copy_v3_v3(vert[3], v4);
3033
3034         co[0]= v1[0]*w[0] + v2[0]*w[1] + v3[0]*w[2] + v4[0]*w[3];
3035         co[1]= v1[1]*w[0] + v2[1]*w[1] + v3[1]*w[2] + v4[1]*w[3];
3036         co[2]= v1[2]*w[0] + v2[2]*w[1] + v3[2]*w[2] + v4[2]*w[3];
3037
3038         interp_weights_poly_v3(w, vert, 4, co);
3039 }
3040
3041 /* check intersection with a derivedmesh */
3042 static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm,
3043                                  float *vert_cos,
3044                                  const float co1[3], const float co2[3],
3045                                  float *min_d, int *min_face, float *min_w,
3046                                  float *face_minmax, float *pa_minmax,
3047                                  float radius, float *ipoint)
3048 {
3049         MFace *mface= NULL;
3050         MVert *mvert= NULL;
3051         int i, totface, intersect=0;
3052         float cur_d, cur_uv[2], v1[3], v2[3], v3[3], v4[3], min[3], max[3], p_min[3],p_max[3];
3053         float cur_ipoint[3];
3054         
3055         if(dm == NULL){
3056                 psys_disable_all(ob);
3057
3058                 dm=mesh_get_derived_final(scene, ob, 0);
3059                 if(dm == NULL)
3060                         dm=mesh_get_derived_deform(scene, ob, 0);
3061
3062                 psys_enable_all(ob);
3063
3064                 if(dm == NULL)
3065                         return 0;
3066         }
3067
3068         /* BMESH_ONLY, deform dm may not have tessface */
3069         DM_ensure_tessface(dm);
3070         
3071
3072         if(pa_minmax==0){
3073                 INIT_MINMAX(p_min,p_max);
3074                 DO_MINMAX(co1,p_min,p_max);
3075                 DO_MINMAX(co2,p_min,p_max);
3076         }
3077         else{
3078                 copy_v3_v3(p_min,pa_minmax);
3079                 copy_v3_v3(p_max,pa_minmax+3);
3080         }
3081
3082         totface=dm->getNumTessFaces(dm);
3083         mface=dm->getTessFaceDataArray(dm,CD_MFACE);
3084         mvert=dm->getVertDataArray(dm,CD_MVERT);
3085         
3086         /* lets intersect the faces */
3087         for(i=0; i<totface; i++,mface++){
3088                 if(vert_cos){
3089                         copy_v3_v3(v1,vert_cos+3*mface->v1);
3090                         copy_v3_v3(v2,vert_cos+3*mface->v2);
3091                         copy_v3_v3(v3,vert_cos+3*mface->v3);
3092                         if(mface->v4)
3093                                 copy_v3_v3(v4,vert_cos+3*mface->v4);
3094                 }
3095                 else{
3096                         copy_v3_v3(v1,mvert[mface->v1].co);
3097                         copy_v3_v3(v2,mvert[mface->v2].co);
3098                         copy_v3_v3(v3,mvert[mface->v3].co);
3099                         if(mface->v4)
3100                                 copy_v3_v3(v4,mvert[mface->v4].co);
3101                 }
3102
3103                 if(face_minmax==0){
3104                         INIT_MINMAX(min,max);
3105                         DO_MINMAX(v1,min,max);
3106                         DO_MINMAX(v2,min,max);
3107                         DO_MINMAX(v3,min,max);
3108                         if(mface->v4)
3109                                 DO_MINMAX(v4,min,max)
3110                         if(isect_aabb_aabb_v3(min,max,p_min,p_max)==0)
3111                                 continue;
3112                 }
3113                 else{
3114                         copy_v3_v3(min, face_minmax+6*i);
3115                         copy_v3_v3(max, face_minmax+6*i+3);
3116                         if(isect_aabb_aabb_v3(min,max,p_min,p_max)==0)
3117                                 continue;
3118                 }
3119
3120                 if(radius>0.0f){
3121                         if(isect_sweeping_sphere_tri_v3(co1, co2, radius, v2, v3, v1, &cur_d, cur_ipoint)){
3122                                 if(cur_d<*min_d){
3123                                         *min_d=cur_d;
3124                                         copy_v3_v3(ipoint,cur_ipoint);
3125                                         *min_face=i;
3126                                         intersect=1;
3127                                 }
3128                         }
3129                         if(mface->v4){
3130                                 if(isect_sweeping_sphere_tri_v3(co1, co2, radius, v4, v1, v3, &cur_d, cur_ipoint)){
3131                                         if(cur_d<*min_d){
3132                                                 *min_d=cur_d;
3133                                                 copy_v3_v3(ipoint,cur_ipoint);
3134                                                 *min_face=i;
3135                                                 intersect=1;
3136                                         }
3137                                 }
3138                         }
3139                 }
3140                 else{
3141                         if(isect_line_tri_v3(co1, co2, v1, v2, v3, &cur_d, cur_uv)){
3142                                 if(cur_d<*min_d){
3143                                         *min_d=cur_d;
3144                                         min_w[0]= 1.0f - cur_uv[0] - cur_uv[1];
3145                                         min_w[1]= cur_uv[0];
3146                                         min_w[2]= cur_uv[1];
3147                                         min_w[3]= 0.0f;
3148                                         if(mface->v4)
3149                                                 intersect_dm_quad_weights(v1, v2, v3, v4, min_w);
3150                                         *min_face=i;
3151                                         intersect=1;
3152                                 }
3153                         }
3154                         if(mface->v4){
3155                                 if(isect_line_tri_v3(co1, co2, v1, v3, v4, &cur_d, cur_uv)){
3156                                         if(cur_d<*min_d){
3157                                                 *min_d=cur_d;
3158                                                 min_w[0]= 1.0f - cur_uv[0] - cur_uv[1];
3159                                                 min_w[1]= 0.0f;
3160                                                 min_w[2]= cur_uv[0];
3161                                                 min_w[3]= cur_uv[1];
3162                                                 intersect_dm_quad_weights(v1, v2, v3, v4, min_w);
3163                                                 *min_face=i;
3164                                                 intersect=1;
3165                                         }
3166                                 }
3167                         }
3168                 }
3169         }
3170         return intersect;
3171 }
3172
3173 static int brush_add(PEData *data, short number)
3174 {
3175         Scene *scene= data->scene;
3176         Object *ob= data->ob;
3177         PTCacheEdit *edit = data->edit;
3178         ParticleSystem *psys= edit->psys;
3179         ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add");
3180         ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
3181         ParticleSimulationData sim= {0};
3182         ParticleEditSettings *pset= PE_settings(scene);
3183         int i, k, n= 0, totpart= psys->totpart;
3184         float mco[2];
3185         short dmx= 0, dmy= 0;
3186         float co1[3], co2[3], min_d, imat[4][4];
3187         float framestep, timestep;
3188         short size= pset->brush[PE_BRUSH_ADD].size;
3189         short size2= size*size;
3190         DerivedMesh *dm=0;
3191         invert_m4_m4(imat,ob->obmat);
3192
3193         if(psys->flag & PSYS_GLOBAL_HAIR)
3194                 return 0;
3195
3196         BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
3197
3198         sim.scene= scene;
3199         sim.ob= ob;
3200         sim.psys= psys;
3201         sim.psmd= psmd;
3202
3203         timestep= psys_get_timestep(&sim);
3204
3205         /* painting onto the deformed mesh, could be an option? */
3206         if(psmd->dm->deformedOnly)
3207                 dm= psmd->dm;
3208         else
3209                 dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
3210
3211         for(i=0; i<number; i++) {
3212                 if(number>1) {
3213                         dmx=dmy=size;
3214                         while(dmx*dmx+dmy*dmy>size2) {
3215                                 dmx=(short)((2.0f*BLI_frand()-1.0f)*size);
3216                                 dmy=(short)((2.0f*BLI_frand()-1.0f)*size);
3217