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