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