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