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