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