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