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