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