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