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