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