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