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