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