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