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