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