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