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