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