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