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