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