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