4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2007 by Janne Karhu.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
35 #include "MEM_guardedalloc.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_meshdata_types.h"
40 #include "DNA_view3d_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_space_types.h"
45 #include "BLI_blenlib.h"
46 #include "BLI_dynstr.h"
47 #include "BLI_kdtree.h"
49 #include "BLI_utildefines.h"
51 #include "BKE_DerivedMesh.h"
52 #include "BKE_depsgraph.h"
54 #include "BKE_context.h"
55 #include "BKE_global.h"
56 #include "BKE_object.h"
58 #include "BKE_modifier.h"
59 #include "BKE_particle.h"
60 #include "BKE_report.h"
61 #include "BKE_scene.h"
63 #include "BKE_pointcache.h"
66 #include "BIF_glutil.h"
69 #include "ED_particle.h"
70 #include "ED_view3d.h"
72 #include "UI_resources.h"
77 #include "RNA_access.h"
78 #include "RNA_define.h"
80 #include "physics_intern.h"
82 static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
83 static void PTCacheUndo_clear(PTCacheEdit *edit);
84 static void recalc_emitter_field(Object *ob, ParticleSystem *psys);
86 #define KEY_K PTCacheEditKey *key; int k
87 #define POINT_P PTCacheEditPoint *point; int p
88 #define LOOP_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++)
89 #define LOOP_VISIBLE_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!(point->flag & PEP_HIDE))
90 #define LOOP_SELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point_is_selected(point))
91 #define LOOP_UNSELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!point_is_selected(point))
92 #define LOOP_EDITED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_EDIT_RECALC)
93 #define LOOP_TAGGED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_TAG)
94 #define LOOP_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++)
95 #define LOOP_VISIBLE_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(!(key->flag & PEK_HIDE))
96 #define LOOP_SELECTED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
97 #define LOOP_TAGGED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(key->flag & PEK_TAG)
99 #define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co)
101 /**************************** utilities *******************************/
103 int PE_poll(bContext *C)
105 Scene *scene= CTX_data_scene(C);
106 Object *ob= CTX_data_active_object(C);
108 if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
111 return (PE_get_current(scene, ob) != NULL);
114 int PE_hair_poll(bContext *C)
116 Scene *scene= CTX_data_scene(C);
117 Object *ob= CTX_data_active_object(C);
120 if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
123 edit= PE_get_current(scene, ob);
125 return (edit && edit->psys);
128 int PE_poll_view3d(bContext *C)
130 return PE_poll(C) && CTX_wm_area(C)->spacetype == SPACE_VIEW3D &&
131 CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW;
134 void PE_free_ptcache_edit(PTCacheEdit *edit)
140 PTCacheUndo_clear(edit);
145 MEM_freeN(point->keys);
148 MEM_freeN(edit->points);
151 if(edit->mirror_cache)
152 MEM_freeN(edit->mirror_cache);
154 if(edit->emitter_cosnos) {
155 MEM_freeN(edit->emitter_cosnos);
156 edit->emitter_cosnos= 0;
159 if(edit->emitter_field) {
160 BLI_kdtree_free(edit->emitter_field);
161 edit->emitter_field= 0;
164 psys_free_path_cache(edit->psys, edit);
169 /************************************************/
170 /* Edit Mode Helpers */
171 /************************************************/
173 int PE_start_edit(PTCacheEdit *edit)
178 edit->psys->flag |= PSYS_EDITED;
185 ParticleEditSettings *PE_settings(Scene *scene)
187 return scene->toolsettings ? &scene->toolsettings->particle : NULL;
190 /* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set
192 * note: this function runs on poll, therefor it can runs many times a second
194 static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
196 ParticleEditSettings *pset= PE_settings(scene);
197 PTCacheEdit *edit = NULL;
201 if(pset==NULL || ob==NULL)
207 BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
209 /* in the case of only one editable thing, set pset->edittype accordingly */
210 if(pidlist.first && pidlist.first == pidlist.last) {
213 case PTCACHE_TYPE_PARTICLES:
214 pset->edittype = PE_TYPE_PARTICLES;
216 case PTCACHE_TYPE_SOFTBODY:
217 pset->edittype = PE_TYPE_SOFTBODY;
219 case PTCACHE_TYPE_CLOTH:
220 pset->edittype = PE_TYPE_CLOTH;
225 for(pid=pidlist.first; pid; pid=pid->next) {
226 if(pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) {
227 ParticleSystem *psys = pid->calldata;
229 if(psys->flag & PSYS_CURRENT) {
230 if(psys->part && psys->part->type == PART_HAIR) {
231 if(psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
232 if(create && !psys->pointcache->edit)
233 PE_create_particle_edit(scene, ob, pid->cache, NULL);
234 edit = pid->cache->edit;
237 if(create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
238 PE_create_particle_edit(scene, ob, NULL, psys);
243 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
244 PE_create_particle_edit(scene, ob, pid->cache, psys);
245 edit = pid->cache->edit;
251 else if(pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
252 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
253 PE_create_particle_edit(scene, ob, pid->cache, NULL);
254 edit = pid->cache->edit;
257 else if(pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
258 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
259 PE_create_particle_edit(scene, ob, pid->cache, NULL);
260 edit = pid->cache->edit;
268 BLI_freelistN(&pidlist);
273 PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
275 return pe_get_current(scene, ob, 0);
278 PTCacheEdit *PE_create_current(Scene *scene, Object *ob)
280 return pe_get_current(scene, ob, 1);
283 void PE_current_changed(Scene *scene, Object *ob)
285 if(ob->mode == OB_MODE_PARTICLE_EDIT)
286 PE_create_current(scene, ob);
289 void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
291 ParticleEditSettings *pset=PE_settings(scene);
295 if(pset->flag & PE_FADE_TIME && pset->selectmode==SCE_SELECT_POINT) {
298 if(fabs(cfra-*key->time) < pset->fade_frames)
299 key->flag &= ~PEK_HIDE;
301 key->flag |= PEK_HIDE;
302 //key->flag &= ~PEK_SELECT;
310 key->flag &= ~PEK_HIDE;
316 static int pe_x_mirror(Object *ob)
318 if(ob->type == OB_MESH)
319 return (((Mesh*)ob->data)->editflag & ME_EDIT_MIRROR_X);
324 /****************** common struct passed to callbacks ******************/
326 typedef struct PEData {
356 static void PE_set_data(bContext *C, PEData *data)
358 memset(data, 0, sizeof(*data));
360 data->scene= CTX_data_scene(C);
361 data->ob= CTX_data_active_object(C);
362 data->edit= PE_get_current(data->scene, data->ob);
365 static void PE_set_view3d_data(bContext *C, PEData *data)
367 PE_set_data(C, data);
369 view3d_set_viewcontext(C, &data->vc);
370 /* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather then (obmat * viewmat) */
371 view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats);
373 if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT)) {
374 if(data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
375 /* needed or else the draw matrix can be incorrect */
376 view3d_operator_needs_opengl(C);
378 view3d_validate_backbuf(&data->vc);
379 /* we may need to force an update here by setting the rv3d as dirty
380 * for now it seems ok, but take care!:
381 * rv3d->depths->dirty = 1; */
382 view3d_update_depths(data->vc.ar);
387 /*************************** selection utilities *******************************/
389 static int key_test_depth(PEData *data, float co[3])
391 View3D *v3d= data->vc.v3d;
397 if((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
400 project_short(data->vc.ar, co, wco);
402 if(wco[0] == IS_CLIPPED)
405 gluProject(co[0],co[1],co[2], data->mats.modelview, data->mats.projection,
406 (GLint *)data->mats.viewport, &ux, &uy, &uz);
411 #if 0 /* works well but too slow on some systems [#23118] */
412 x+= (short)data->vc.ar->winrct.xmin;
413 y+= (short)data->vc.ar->winrct.ymin;
415 /* PE_set_view3d_data calls this. no need to call here */
416 /* view3d_validate_backbuf(&data->vc); */
417 glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
418 #else /* faster to use depths, these are calculated in PE_set_view3d_data */
420 ViewDepths *vd = data->vc.rv3d->depths;
421 assert(vd && vd->depths);
422 /* we know its not clipped */
423 depth= vd->depths[y * vd->w + x];
427 if((float)uz - 0.00001 > depth)
433 static int key_inside_circle(PEData *data, float rad, float co[3], float *distance)
438 project_short(data->vc.ar, co, sco);
440 if(sco[0] == IS_CLIPPED)
443 dx= data->mval[0] - sco[0];
444 dy= data->mval[1] - sco[1];
445 dist= sqrt(dx*dx + dy*dy);
450 if(key_test_depth(data, co)) {
460 static int key_inside_rect(PEData *data, float co[3])
464 project_short(data->vc.ar, co,sco);
466 if(sco[0] == IS_CLIPPED)
469 if(sco[0] > data->rect->xmin && sco[0] < data->rect->xmax &&
470 sco[1] > data->rect->ymin && sco[1] < data->rect->ymax)
471 return key_test_depth(data, co);
476 static int key_inside_test(PEData *data, float co[3])
479 return key_inside_circle(data, data->rad, co, NULL);
481 return key_inside_rect(data, co);
484 static int point_is_selected(PTCacheEditPoint *point)
489 if(point->flag & PEP_HIDE)
501 /*************************** iterators *******************************/
503 typedef void (*ForPointFunc)(PEData *data, int point_index);
504 typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index);
505 typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key);
507 static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
509 ParticleEditSettings *pset= PE_settings(data->scene);
510 PTCacheEdit *edit= data->edit;
512 int nearest_point, nearest_key;
513 float dist= data->rad;
515 /* in path select mode we have no keys */
516 if(pset->selectmode==SCE_SELECT_PATH)
522 LOOP_VISIBLE_POINTS {
523 if(pset->selectmode == SCE_SELECT_END) {
524 /* only do end keys */
525 key= point->keys + point->totkey-1;
528 if(key_inside_circle(data, dist, KEY_WCO, &dist)) {
530 nearest_key= point->totkey-1;
533 else if(key_inside_test(data, KEY_WCO))
534 func(data, p, point->totkey-1);
540 if(key_inside_circle(data, dist, KEY_WCO, &dist)) {
545 else if(key_inside_test(data, KEY_WCO))
551 /* do nearest only */
552 if(nearest && nearest_point > -1)
553 func(data, nearest_point, nearest_key);
556 static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected)
558 ParticleEditSettings *pset= PE_settings(data->scene);
559 PTCacheEdit *edit= data->edit;
562 /* all is selected in path mode */
563 if(pset->selectmode==SCE_SELECT_PATH)
566 LOOP_VISIBLE_POINTS {
567 if(pset->selectmode==SCE_SELECT_END) {
568 /* only do end keys */
569 key= point->keys + point->totkey - 1;
571 if(selected==0 || key->flag & PEK_SELECT)
572 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
578 if(selected==0 || key->flag & PEK_SELECT) {
579 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
589 static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
591 PTCacheEdit *edit = data->edit;
592 ParticleSystem *psys = edit->psys;
593 ParticleSystemModifierData *psmd = NULL;
594 ParticleEditSettings *pset= PE_settings(data->scene);
596 float mat[4][4]= MAT4_UNITY, imat[4][4]= MAT4_UNITY;
599 psmd= psys_get_modifier(data->ob, edit->psys);
601 /* all is selected in path mode */
602 if(pset->selectmode==SCE_SELECT_PATH)
605 LOOP_VISIBLE_POINTS {
606 if(pset->selectmode==SCE_SELECT_END) {
607 /* only do end keys */
608 key= point->keys + point->totkey-1;
610 if(selected==0 || key->flag & PEK_SELECT) {
611 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
612 if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
613 psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
614 invert_m4_m4(imat,mat);
617 func(data, mat, imat, p, point->totkey-1, key);
624 if(selected==0 || key->flag & PEK_SELECT) {
625 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
626 if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
627 psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
628 invert_m4_m4(imat,mat);
631 func(data, mat, imat, p, k, key);
639 static void foreach_selected_point(PEData *data, ForPointFunc func)
641 PTCacheEdit *edit = data->edit;
644 LOOP_SELECTED_POINTS {
649 static void foreach_selected_key(PEData *data, ForKeyFunc func)
651 PTCacheEdit *edit = data->edit;
654 LOOP_VISIBLE_POINTS {
661 static void foreach_point(PEData *data, ForPointFunc func)
663 PTCacheEdit *edit = data->edit;
671 static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
673 ParticleEditSettings *pset= PE_settings(scene);
677 LOOP_VISIBLE_POINTS {
678 if(pset->selectmode==SCE_SELECT_POINT) {
683 else if(pset->selectmode==SCE_SELECT_END) {
684 key = point->keys + point->totkey - 1;
685 if(key->flag & PEK_SELECT)
693 /************************************************/
694 /* Particle Edit Mirroring */
695 /************************************************/
697 static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
700 ParticleSystemModifierData *psmd;
702 KDTreeNearest nearest;
705 float mat[4][4], co[3];
709 psmd= psys_get_modifier(ob, psys);
710 totpart= psys->totpart;
715 tree= BLI_kdtree_new(totpart);
717 /* insert particles into kd tree */
720 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
721 VECCOPY(co, key->co);
723 BLI_kdtree_insert(tree, p, co, NULL);
726 BLI_kdtree_balance(tree);
728 /* lookup particles and set in mirror cache */
729 if(!edit->mirror_cache)
730 edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
734 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
735 VECCOPY(co, key->co);
739 index= BLI_kdtree_find_nearest(tree, co, NULL, &nearest);
741 /* this needs a custom threshold still, duplicated for editmode mirror */
742 if(index != -1 && index != p && (nearest.dist <= 0.0002f))
743 edit->mirror_cache[p]= index;
745 edit->mirror_cache[p]= -1;
748 /* make sure mirrors are in two directions */
750 if(edit->mirror_cache[p]) {
751 index= edit->mirror_cache[p];
752 if(edit->mirror_cache[index] != p)
753 edit->mirror_cache[p]= -1;
757 BLI_kdtree_free(tree);
760 static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
762 HairKey *hkey, *mhkey;
763 PTCacheEditPoint *point, *mpoint;
764 PTCacheEditKey *key, *mkey;
766 float mat[4][4], mmat[4][4], immat[4][4];
770 i= pa - psys->particles;
772 /* find mirrored particle if needed */
774 if(!edit->mirror_cache)
775 PE_update_mirror_cache(ob, psys);
777 mi= edit->mirror_cache[i];
780 mpa= psys->particles + mi;
783 mi= mpa - psys->particles;
785 point = edit->points + i;
786 mpoint = edit->points + mi;
788 /* make sure they have the same amount of keys */
789 if(pa->totkey != mpa->totkey) {
790 if(mpa->hair) MEM_freeN(mpa->hair);
791 if(mpoint->keys) MEM_freeN(mpoint->keys);
793 mpa->hair= MEM_dupallocN(pa->hair);
794 mpa->totkey= pa->totkey;
795 mpoint->keys= MEM_dupallocN(point->keys);
796 mpoint->totkey= point->totkey;
800 for(k=0; k<mpa->totkey; k++, mkey++, mhkey++) {
802 mkey->time= &mhkey->time;
803 mkey->flag &= ~PEK_SELECT;
807 /* mirror positions and tags */
808 psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
809 psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
810 invert_m4_m4(immat, mmat);
816 for(k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
817 VECCOPY(mhkey->co, hkey->co);
818 mul_m4_v3(mat, mhkey->co);
819 mhkey->co[0]= -mhkey->co[0];
820 mul_m4_v3(immat, mhkey->co);
822 if(key->flag & PEK_TAG)
823 mkey->flag |= PEK_TAG;
826 if(point->flag & PEP_TAG)
827 mpoint->flag |= PEP_TAG;
828 if(point->flag & PEP_EDIT_RECALC)
829 mpoint->flag |= PEP_EDIT_RECALC;
832 static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
835 ParticleSystemModifierData *psmd;
842 psmd= psys_get_modifier(ob, psys);
847 if(!edit->mirror_cache)
848 PE_update_mirror_cache(ob, psys);
850 /* we delay settings the PARS_EDIT_RECALC for mirrored particles
851 * to avoid doing mirror twice */
853 if(point->flag & PEP_EDIT_RECALC) {
854 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
856 if(edit->mirror_cache[p] != -1)
857 edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
862 if(point->flag & PEP_EDIT_RECALC)
863 if(edit->mirror_cache[p] != -1)
864 edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
868 /************************************************/
869 /* Edit Calculation */
870 /************************************************/
871 /* tries to stop edited particles from going through the emitter's surface */
872 static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
874 ParticleEditSettings *pset= PE_settings(scene);
875 ParticleSystem *psys;
876 ParticleSystemModifierData *psmd;
879 float *vec, *nor, dvec[3], dot, dist_1st=0.0f;
880 float hairimat[4][4], hairmat[4][4];
882 if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0 || (edit->psys->flag & PSYS_GLOBAL_HAIR))
886 psmd = psys_get_modifier(ob,psys);
892 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles + p, hairmat);
895 mul_m4_v3(hairmat, key->co);
900 dist_1st = len_v3v3((key+1)->co, key->co);
901 dist_1st *= 0.75f * pset->emitterdist;
904 index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL);
906 vec=edit->emitter_cosnos +index*6;
909 sub_v3_v3v3(dvec, key->co, vec);
911 dot=dot_v3v3(dvec,nor);
917 mul_v3_fl(dvec,dist_1st-dot);
918 add_v3_v3(key->co, dvec);
923 mul_v3_fl(dvec,dist_1st-dot);
924 add_v3_v3(key->co, dvec);
931 invert_m4_m4(hairimat,hairmat);
934 mul_m4_v3(hairimat, key->co);
938 /* force set distances between neighbouring keys */
939 void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
942 ParticleEditSettings *pset=PE_settings(scene);
946 if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
949 if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
955 sub_v3_v3v3(dv1, key->co, (key - 1)->co);
957 mul_v3_fl(dv1, (key - 1)->length);
958 add_v3_v3v3(key->co, (key - 1)->co, dv1);
963 /* try to find a nice solution to keep distances between neighbouring keys */
964 static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
966 ParticleEditSettings *pset=PE_settings(scene);
971 float dv0[3]= {0.0f, 0.0f, 0.0f};
972 float dv1[3]= {0.0f, 0.0f, 0.0f};
973 float dv2[3]= {0.0f, 0.0f, 0.0f};
975 if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
978 if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
982 for(j=1; j<point->totkey; j++) {
983 float mul= 1.0f / (float)point->totkey;
985 if(pset->flag & PE_LOCK_FIRST) {
986 key= point->keys + 1;
988 dv1[0]= dv1[1]= dv1[2]= 0.0;
993 dv0[0]= dv0[1]= dv0[2]= 0.0;
996 for(; k<point->totkey; k++, key++) {
998 sub_v3_v3v3(dv0, (key - 1)->co, key->co);
999 tlen= normalize_v3(dv0);
1000 mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
1003 if(k < point->totkey - 1) {
1004 sub_v3_v3v3(dv2, (key + 1)->co, key->co);
1005 tlen= normalize_v3(dv2);
1006 mul_v3_fl(dv2, mul * (tlen - key->length));
1010 add_v3_v3((key-1)->co, dv1);
1013 VECADD(dv1,dv0,dv2);
1018 /* set current distances to be kept between neighbouting keys */
1019 static void recalc_lengths(PTCacheEdit *edit)
1026 LOOP_EDITED_POINTS {
1028 for(k=0; k<point->totkey-1; k++, key++) {
1029 key->length= len_v3v3(key->co, (key + 1)->co);
1034 /* calculate a tree for finding nearest emitter's vertice */
1035 static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
1037 DerivedMesh *dm=psys_get_modifier(ob,psys)->dm;
1038 PTCacheEdit *edit= psys->edit;
1040 int i, totface /*, totvert*/;
1045 if(edit->emitter_cosnos)
1046 MEM_freeN(edit->emitter_cosnos);
1048 BLI_kdtree_free(edit->emitter_field);
1050 totface=dm->getNumFaces(dm);
1051 /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/
1053 edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos");
1055 edit->emitter_field= BLI_kdtree_new(totface);
1057 vec=edit->emitter_cosnos;
1060 for(i=0; i<totface; i++, vec+=6, nor+=6) {
1061 MFace *mface=dm->getFaceData(dm,i,CD_MFACE);
1064 mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
1065 VECCOPY(vec,mvert->co);
1066 VECCOPY(nor,mvert->no);
1068 mvert=dm->getVertData(dm,mface->v2,CD_MVERT);
1069 VECADD(vec,vec,mvert->co);
1070 VECADD(nor,nor,mvert->no);
1072 mvert=dm->getVertData(dm,mface->v3,CD_MVERT);
1073 VECADD(vec,vec,mvert->co);
1074 VECADD(nor,nor,mvert->no);
1077 mvert=dm->getVertData(dm,mface->v4,CD_MVERT);
1078 VECADD(vec,vec,mvert->co);
1079 VECADD(nor,nor,mvert->no);
1081 mul_v3_fl(vec,0.25);
1084 mul_v3_fl(vec,0.3333f);
1088 BLI_kdtree_insert(edit->emitter_field, i, vec, NULL);
1091 BLI_kdtree_balance(edit->emitter_field);
1094 static void PE_update_selection(Scene *scene, Object *ob, int useflag)
1096 PTCacheEdit *edit= PE_get_current(scene, ob);
1100 /* flag all particles to be updated if not using flag */
1103 point->flag |= PEP_EDIT_RECALC;
1105 /* flush edit key flag to hair key flag to preserve selection
1107 if(edit->psys) LOOP_POINTS {
1108 hkey = edit->psys->particles[p].hair;
1110 hkey->editflag= key->flag;
1115 psys_cache_edit_paths(scene, ob, edit, CFRA);
1118 /* disable update flag */
1120 point->flag &= ~PEP_EDIT_RECALC;
1123 static void update_world_cos(Object *ob, PTCacheEdit *edit)
1125 ParticleSystem *psys = edit->psys;
1126 ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
1128 float hairmat[4][4];
1130 if(psys==0 || psys->edit==0 || psmd->dm==NULL)
1134 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1135 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat);
1138 VECCOPY(key->world_co,key->co);
1139 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1140 mul_m4_v3(hairmat, key->world_co);
1144 static void update_velocities(PTCacheEdit *edit)
1146 /*TODO: get frs_sec properly */
1147 float vec1[3], vec2[3], frs_sec, dfra;
1150 /* hair doesn't use velocities */
1151 if(edit->psys || !edit->points || !edit->points->keys->vel)
1154 frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
1156 LOOP_EDITED_POINTS {
1159 dfra = *(key+1)->time - *key->time;
1164 VECSUB(key->vel, (key+1)->co, key->co);
1166 if(point->totkey>2) {
1167 VECSUB(vec1, (key+1)->co, (key+2)->co);
1168 project_v3_v3v3(vec2, vec1, key->vel);
1169 VECSUB(vec2, vec1, vec2);
1170 VECADDFAC(key->vel, key->vel, vec2, 0.5f);
1173 else if(k==point->totkey-1) {
1174 dfra = *key->time - *(key-1)->time;
1179 VECSUB(key->vel, key->co, (key-1)->co);
1181 if(point->totkey>2) {
1182 VECSUB(vec1, (key-2)->co, (key-1)->co);
1183 project_v3_v3v3(vec2, vec1, key->vel);
1184 VECSUB(vec2, vec1, vec2);
1185 VECADDFAC(key->vel, key->vel, vec2, 0.5f);
1189 dfra = *(key+1)->time - *(key-1)->time;
1194 VECSUB(key->vel, (key+1)->co, (key-1)->co);
1196 mul_v3_fl(key->vel, frs_sec/dfra);
1201 void PE_update_object(Scene *scene, Object *ob, int useflag)
1203 /* use this to do partial particle updates, not usable when adding or
1204 removing, then a full redo is necessary and calling this may crash */
1205 ParticleEditSettings *pset= PE_settings(scene);
1206 PTCacheEdit *edit = PE_get_current(scene, ob);
1212 /* flag all particles to be updated if not using flag */
1215 point->flag |= PEP_EDIT_RECALC;
1218 /* do post process on particle edit keys */
1219 pe_iterate_lengths(scene, edit);
1220 pe_deflect_emitter(scene, ob, edit);
1221 PE_apply_lengths(scene, edit);
1223 PE_apply_mirror(ob,edit->psys);
1225 update_world_cos(ob, edit);
1226 if(pset->flag & PE_AUTO_VELOCITY)
1227 update_velocities(edit);
1228 PE_hide_keys_time(scene, edit, CFRA);
1230 /* regenerate path caches */
1231 psys_cache_edit_paths(scene, ob, edit, CFRA);
1233 /* disable update flag */
1235 point->flag &= ~PEP_EDIT_RECALC;
1239 edit->psys->flag &= ~PSYS_HAIR_UPDATED;
1242 /************************************************/
1243 /* Edit Selections */
1244 /************************************************/
1246 /*-----selection callbacks-----*/
1248 static void select_key(PEData *data, int point_index, int key_index)
1250 PTCacheEdit *edit = data->edit;
1251 PTCacheEditPoint *point = edit->points + point_index;
1252 PTCacheEditKey *key = point->keys + key_index;
1255 key->flag |= PEK_SELECT;
1257 key->flag &= ~PEK_SELECT;
1259 point->flag |= PEP_EDIT_RECALC;
1262 static void select_keys(PEData *data, int point_index, int UNUSED(key_index))
1264 PTCacheEdit *edit = data->edit;
1265 PTCacheEditPoint *point = edit->points + point_index;
1270 key->flag |= PEK_SELECT;
1272 key->flag &= ~PEK_SELECT;
1275 point->flag |= PEP_EDIT_RECALC;
1278 static void toggle_key_select(PEData *data, int point_index, int key_index)
1280 PTCacheEdit *edit = data->edit;
1281 PTCacheEditPoint *point = edit->points + point_index;
1282 PTCacheEditKey *key = point->keys + key_index;
1284 key->flag ^= PEK_SELECT;
1285 point->flag |= PEP_EDIT_RECALC;
1288 /************************ de select all operator ************************/
1290 static int select_all_exec(bContext *C, wmOperator *op)
1292 Scene *scene= CTX_data_scene(C);
1293 Object *ob= CTX_data_active_object(C);
1294 PTCacheEdit *edit= PE_get_current(scene, ob);
1296 int action = RNA_enum_get(op->ptr, "action");
1298 if (action == SEL_TOGGLE) {
1299 action = SEL_SELECT;
1300 LOOP_VISIBLE_POINTS {
1301 LOOP_SELECTED_KEYS {
1302 action = SEL_DESELECT;
1306 if (action == SEL_DESELECT)
1311 LOOP_VISIBLE_POINTS {
1315 if ((key->flag & PEK_SELECT) == 0) {
1316 key->flag |= PEK_SELECT;
1317 point->flag |= PEP_EDIT_RECALC;
1321 if (key->flag & PEK_SELECT) {
1322 key->flag &= ~PEK_SELECT;
1323 point->flag |= PEP_EDIT_RECALC;
1327 if ((key->flag & PEK_SELECT) == 0) {
1328 key->flag |= PEK_SELECT;
1329 point->flag |= PEP_EDIT_RECALC;
1331 key->flag &= ~PEK_SELECT;
1332 point->flag |= PEP_EDIT_RECALC;
1339 PE_update_selection(scene, ob, 1);
1340 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1342 return OPERATOR_FINISHED;
1345 void PARTICLE_OT_select_all(wmOperatorType *ot)
1348 ot->name= "Selection of all particles";
1349 ot->idname= "PARTICLE_OT_select_all";
1352 ot->exec= select_all_exec;
1356 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1358 WM_operator_properties_select_all(ot);
1361 /************************ pick select operator ************************/
1363 int PE_mouse_particles(bContext *C, short *mval, int extend)
1366 Scene *scene= CTX_data_scene(C);
1367 Object *ob= CTX_data_active_object(C);
1368 PTCacheEdit *edit= PE_get_current(scene, ob);
1371 if(!PE_start_edit(edit))
1372 return OPERATOR_CANCELLED;
1375 LOOP_VISIBLE_POINTS {
1376 LOOP_SELECTED_KEYS {
1377 key->flag &= ~PEK_SELECT;
1378 point->flag |= PEP_EDIT_RECALC;
1383 PE_set_view3d_data(C, &data);
1387 for_mouse_hit_keys(&data, toggle_key_select, 1); /* nearest only */
1389 PE_update_selection(scene, ob, 1);
1390 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1392 return OPERATOR_FINISHED;
1395 /************************ select first operator ************************/
1397 static void select_root(PEData *data, int point_index)
1399 if (data->edit->points[point_index].flag & PEP_HIDE)
1402 data->edit->points[point_index].keys->flag |= PEK_SELECT;
1403 data->edit->points[point_index].flag |= PEP_EDIT_RECALC; /* redraw selection only */
1406 static int select_roots_exec(bContext *C, wmOperator *UNUSED(op))
1410 PE_set_data(C, &data);
1411 foreach_point(&data, select_root);
1413 PE_update_selection(data.scene, data.ob, 1);
1414 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1416 return OPERATOR_FINISHED;
1419 void PARTICLE_OT_select_roots(wmOperatorType *ot)
1422 ot->name= "Select Roots";
1423 ot->idname= "PARTICLE_OT_select_roots";
1426 ot->exec= select_roots_exec;
1430 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1433 /************************ select last operator ************************/
1435 static void select_tip(PEData *data, int point_index)
1437 PTCacheEditPoint *point = data->edit->points + point_index;
1439 if (point->flag & PEP_HIDE)
1442 point->keys[point->totkey - 1].flag |= PEK_SELECT;
1443 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1446 static int select_tips_exec(bContext *C, wmOperator *UNUSED(op))
1450 PE_set_data(C, &data);
1451 foreach_point(&data, select_tip);
1453 PE_update_selection(data.scene, data.ob, 1);
1454 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1456 return OPERATOR_FINISHED;
1459 void PARTICLE_OT_select_tips(wmOperatorType *ot)
1462 ot->name= "Select Tips";
1463 ot->idname= "PARTICLE_OT_select_tips";
1466 ot->exec= select_tips_exec;
1470 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1473 /************************ select linked operator ************************/
1475 static int select_linked_exec(bContext *C, wmOperator *op)
1481 RNA_int_get_array(op->ptr, "location", location);
1482 mval[0]= location[0];
1483 mval[1]= location[1];
1485 PE_set_view3d_data(C, &data);
1488 data.select= !RNA_boolean_get(op->ptr, "deselect");
1490 for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */
1491 PE_update_selection(data.scene, data.ob, 1);
1492 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1494 return OPERATOR_FINISHED;
1497 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
1499 ARegion *ar= CTX_wm_region(C);
1502 location[0]= event->x - ar->winrct.xmin;
1503 location[1]= event->y - ar->winrct.ymin;
1504 RNA_int_set_array(op->ptr, "location", location);
1506 return select_linked_exec(C, op);
1509 void PARTICLE_OT_select_linked(wmOperatorType *ot)
1512 ot->name= "Select Linked";
1513 ot->idname= "PARTICLE_OT_select_linked";
1516 ot->exec= select_linked_exec;
1517 ot->invoke= select_linked_invoke;
1518 ot->poll= PE_poll_view3d;
1521 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1524 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them.");
1525 RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
1528 /************************ border select operator ************************/
1529 void PE_deselect_all_visible(PTCacheEdit *edit)
1533 LOOP_VISIBLE_POINTS {
1534 LOOP_SELECTED_KEYS {
1535 key->flag &= ~PEK_SELECT;
1536 point->flag |= PEP_EDIT_RECALC;
1541 int PE_border_select(bContext *C, rcti *rect, int select, int extend)
1543 Scene *scene= CTX_data_scene(C);
1544 Object *ob= CTX_data_active_object(C);
1545 PTCacheEdit *edit= PE_get_current(scene, ob);
1548 if(!PE_start_edit(edit))
1549 return OPERATOR_CANCELLED;
1551 if (extend == 0 && select)
1552 PE_deselect_all_visible(edit);
1554 PE_set_view3d_data(C, &data);
1556 data.select= select;
1558 for_mouse_hit_keys(&data, select_key, 0);
1560 PE_update_selection(scene, ob, 1);
1561 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1563 return OPERATOR_FINISHED;
1566 /************************ circle select operator ************************/
1568 int PE_circle_select(bContext *C, int selecting, short *mval, float rad)
1570 Scene *scene= CTX_data_scene(C);
1571 Object *ob= CTX_data_active_object(C);
1572 PTCacheEdit *edit= PE_get_current(scene, ob);
1575 if(!PE_start_edit(edit))
1576 return OPERATOR_FINISHED;
1578 PE_set_view3d_data(C, &data);
1581 data.select= selecting;
1583 for_mouse_hit_keys(&data, select_key, 0);
1585 PE_update_selection(scene, ob, 1);
1586 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1588 return OPERATOR_FINISHED;
1591 /************************ lasso select operator ************************/
1593 int PE_lasso_select(bContext *C, short mcords[][2], short moves, short extend, short select)
1595 Scene *scene= CTX_data_scene(C);
1596 Object *ob= CTX_data_active_object(C);
1597 ARegion *ar= CTX_wm_region(C);
1598 ParticleEditSettings *pset= PE_settings(scene);
1599 PTCacheEdit *edit = PE_get_current(scene, ob);
1600 ParticleSystem *psys = edit->psys;
1601 ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
1603 float co[3], mat[4][4]= MAT4_UNITY;
1608 if(!PE_start_edit(edit))
1609 return OPERATOR_CANCELLED;
1611 if (extend == 0 && select)
1612 PE_deselect_all_visible(edit);
1614 /* only for depths */
1615 PE_set_view3d_data(C, &data);
1617 LOOP_VISIBLE_POINTS {
1618 if(edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
1619 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + p, mat);
1621 if(pset->selectmode==SCE_SELECT_POINT) {
1623 VECCOPY(co, key->co);
1625 project_short(ar, co, vertco);
1626 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1]) && key_test_depth(&data, co)) {
1627 if(select && !(key->flag & PEK_SELECT)) {
1628 key->flag |= PEK_SELECT;
1629 point->flag |= PEP_EDIT_RECALC;
1631 else if(key->flag & PEK_SELECT) {
1632 key->flag &= ~PEK_SELECT;
1633 point->flag |= PEP_EDIT_RECALC;
1638 else if(pset->selectmode==SCE_SELECT_END) {
1639 key= point->keys + point->totkey - 1;
1641 VECCOPY(co, key->co);
1643 project_short(ar, co,vertco);
1644 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1]) && key_test_depth(&data, co)) {
1645 if(select && !(key->flag & PEK_SELECT)) {
1646 key->flag |= PEK_SELECT;
1647 point->flag |= PEP_EDIT_RECALC;
1649 else if(key->flag & PEK_SELECT) {
1650 key->flag &= ~PEK_SELECT;
1651 point->flag |= PEP_EDIT_RECALC;
1657 PE_update_selection(scene, ob, 1);
1658 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1660 return OPERATOR_FINISHED;
1663 /*************************** hide operator **************************/
1665 static int hide_exec(bContext *C, wmOperator *op)
1667 Object *ob= CTX_data_active_object(C);
1668 Scene *scene= CTX_data_scene(C);
1669 PTCacheEdit *edit= PE_get_current(scene, ob);
1672 if(RNA_enum_get(op->ptr, "unselected")) {
1673 LOOP_UNSELECTED_POINTS {
1674 point->flag |= PEP_HIDE;
1675 point->flag |= PEP_EDIT_RECALC;
1678 key->flag &= ~PEK_SELECT;
1682 LOOP_SELECTED_POINTS {
1683 point->flag |= PEP_HIDE;
1684 point->flag |= PEP_EDIT_RECALC;
1687 key->flag &= ~PEK_SELECT;
1691 PE_update_selection(scene, ob, 1);
1692 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1694 return OPERATOR_FINISHED;
1697 void PARTICLE_OT_hide(wmOperatorType *ot)
1700 ot->name= "Hide Selected";
1701 ot->idname= "PARTICLE_OT_hide";
1704 ot->exec= hide_exec;
1708 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1711 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1714 /*************************** reveal operator **************************/
1716 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
1718 Object *ob= CTX_data_active_object(C);
1719 Scene *scene= CTX_data_scene(C);
1720 PTCacheEdit *edit= PE_get_current(scene, ob);
1724 if(point->flag & PEP_HIDE) {
1725 point->flag &= ~PEP_HIDE;
1726 point->flag |= PEP_EDIT_RECALC;
1729 key->flag |= PEK_SELECT;
1733 PE_update_selection(scene, ob, 1);
1734 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1736 return OPERATOR_FINISHED;
1739 void PARTICLE_OT_reveal(wmOperatorType *ot)
1743 ot->idname= "PARTICLE_OT_reveal";
1746 ot->exec= reveal_exec;
1750 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1753 /************************ select less operator ************************/
1755 static void select_less_keys(PEData *data, int point_index)
1757 PTCacheEdit *edit= data->edit;
1758 PTCacheEditPoint *point = edit->points + point_index;
1761 LOOP_SELECTED_KEYS {
1763 if(((key+1)->flag&PEK_SELECT)==0)
1764 key->flag |= PEK_TAG;
1766 else if(k==point->totkey-1) {
1767 if(((key-1)->flag&PEK_SELECT)==0)
1768 key->flag |= PEK_TAG;
1771 if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
1772 key->flag |= PEK_TAG;
1777 if(key->flag&PEK_TAG) {
1778 key->flag &= ~(PEK_TAG|PEK_SELECT);
1779 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1784 static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
1788 PE_set_data(C, &data);
1789 foreach_point(&data, select_less_keys);
1791 PE_update_selection(data.scene, data.ob, 1);
1792 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1794 return OPERATOR_FINISHED;
1797 void PARTICLE_OT_select_less(wmOperatorType *ot)
1800 ot->name= "Select Less";
1801 ot->idname= "PARTICLE_OT_select_less";
1804 ot->exec= select_less_exec;
1808 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1811 /************************ select more operator ************************/
1813 static void select_more_keys(PEData *data, int point_index)
1815 PTCacheEdit *edit= data->edit;
1816 PTCacheEditPoint *point = edit->points + point_index;
1820 if(key->flag & PEK_SELECT) continue;
1823 if((key+1)->flag&PEK_SELECT)
1824 key->flag |= PEK_TAG;
1826 else if(k==point->totkey-1) {
1827 if((key-1)->flag&PEK_SELECT)
1828 key->flag |= PEK_TAG;
1831 if(((key-1)->flag | (key+1)->flag) & PEK_SELECT)
1832 key->flag |= PEK_TAG;
1837 if(key->flag&PEK_TAG) {
1838 key->flag &= ~PEK_TAG;
1839 key->flag |= PEK_SELECT;
1840 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1845 static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
1849 PE_set_data(C, &data);
1850 foreach_point(&data, select_more_keys);
1852 PE_update_selection(data.scene, data.ob, 1);
1853 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1855 return OPERATOR_FINISHED;
1858 void PARTICLE_OT_select_more(wmOperatorType *ot)
1861 ot->name= "Select More";
1862 ot->idname= "PARTICLE_OT_select_more";
1865 ot->exec= select_more_exec;
1869 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1872 static int select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
1878 PE_set_data(C, &data);
1880 edit= PE_get_current(data.scene, data.ob);
1882 LOOP_VISIBLE_POINTS {
1884 key->flag ^= PEK_SELECT;
1885 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1889 PE_update_selection(data.scene, data.ob, 1);
1890 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1892 return OPERATOR_FINISHED;
1895 void PARTICLE_OT_select_inverse(wmOperatorType *ot)
1898 ot->name= "Select Inverse";
1899 ot->idname= "PARTICLE_OT_select_inverse";
1902 ot->exec= select_inverse_exec;
1906 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1909 /************************ rekey operator ************************/
1911 static void rekey_particle(PEData *data, int pa_index)
1913 PTCacheEdit *edit= data->edit;
1914 ParticleSystem *psys= edit->psys;
1915 ParticleSimulationData sim= {0};
1916 ParticleData *pa= psys->particles + pa_index;
1917 PTCacheEditPoint *point = edit->points + pa_index;
1919 HairKey *key, *new_keys, *okey;
1920 PTCacheEditKey *ekey;
1921 float dval, sta, end;
1924 sim.scene= data->scene;
1926 sim.psys= edit->psys;
1928 pa->flag |= PARS_REKEY;
1930 key= new_keys= MEM_callocN(data->totrekey * sizeof(HairKey),"Hair re-key keys");
1933 /* root and tip stay the same */
1934 VECCOPY(key->co, okey->co);
1935 VECCOPY((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co);
1937 sta= key->time= okey->time;
1938 end= (key + data->totrekey - 1)->time= (okey + pa->totkey - 1)->time;
1939 dval= (end - sta) / (float)(data->totrekey - 1);
1941 /* interpolate new keys from old ones */
1942 for(k=1,key++; k<data->totrekey-1; k++,key++) {
1943 state.time= (float)k / (float)(data->totrekey-1);
1944 psys_get_particle_on_path(&sim, pa_index, &state, 0);
1945 VECCOPY(key->co, state.co);
1946 key->time= sta + k * dval;
1951 MEM_freeN(pa->hair);
1954 point->totkey=pa->totkey=data->totrekey;
1958 MEM_freeN(point->keys);
1959 ekey= point->keys= MEM_callocN(pa->totkey * sizeof(PTCacheEditKey),"Hair re-key edit keys");
1961 for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
1963 ekey->time= &key->time;
1964 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1965 ekey->flag |= PEK_USE_WCO;
1968 pa->flag &= ~PARS_REKEY;
1969 point->flag |= PEP_EDIT_RECALC;
1972 static int rekey_exec(bContext *C, wmOperator *op)
1976 PE_set_data(C, &data);
1978 data.dval= 1.0f / (float)(data.totrekey-1);
1979 data.totrekey= RNA_int_get(op->ptr, "keys");
1981 foreach_selected_point(&data, rekey_particle);
1983 recalc_lengths(data.edit);
1984 PE_update_object(data.scene, data.ob, 1);
1985 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
1987 return OPERATOR_FINISHED;
1990 void PARTICLE_OT_rekey(wmOperatorType *ot)
1994 ot->idname= "PARTICLE_OT_rekey";
1997 ot->exec= rekey_exec;
1998 ot->invoke= WM_operator_props_popup;
2002 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2005 RNA_def_int(ot->srna, "keys", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
2008 static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time)
2010 PTCacheEdit *edit= PE_get_current(scene, ob);
2011 ParticleSystem *psys;
2012 ParticleSimulationData sim= {0};
2015 HairKey *new_keys, *key;
2016 PTCacheEditKey *ekey;
2019 if(!edit || !edit->psys) return;
2027 pa= psys->particles + pa_index;
2029 pa->flag |= PARS_REKEY;
2031 key= new_keys= MEM_dupallocN(pa->hair);
2033 /* interpolate new keys from old ones (roots stay the same) */
2034 for(k=1, key++; k < pa->totkey; k++, key++) {
2035 state.time= path_time * (float)k / (float)(pa->totkey-1);
2036 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2037 VECCOPY(key->co, state.co);
2040 /* replace hair keys */
2042 MEM_freeN(pa->hair);
2045 /* update edit pointers */
2046 for(k=0, key=pa->hair, ekey=edit->points[pa_index].keys; k<pa->totkey; k++, key++, ekey++) {
2048 ekey->time= &key->time;
2051 pa->flag &= ~PARS_REKEY;
2054 /************************* utilities **************************/
2056 static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
2058 PTCacheEdit *edit = psys->edit;
2059 ParticleData *pa, *npa=0, *new_pars=0;
2061 PTCacheEditPoint *npoint=0, *new_points=0;
2062 ParticleSystemModifierData *psmd;
2063 int i, new_totpart= psys->totpart, removed= 0;
2067 psmd= psys_get_modifier(ob, psys);
2069 LOOP_TAGGED_POINTS {
2070 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
2074 LOOP_TAGGED_POINTS {
2079 if(new_totpart != psys->totpart) {
2081 npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
2082 npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
2085 pa= psys->particles;
2086 point= edit->points;
2087 for(i=0; i<psys->totpart; i++, pa++, point++) {
2088 if(point->flag & PEP_TAG) {
2090 MEM_freeN(point->keys);
2092 MEM_freeN(pa->hair);
2095 memcpy(npa, pa, sizeof(ParticleData));
2096 memcpy(npoint, point, sizeof(PTCacheEditPoint));
2102 if(psys->particles) MEM_freeN(psys->particles);
2103 psys->particles= new_pars;
2105 if(edit->points) MEM_freeN(edit->points);
2106 edit->points= new_points;
2108 if(edit->mirror_cache) {
2109 MEM_freeN(edit->mirror_cache);
2110 edit->mirror_cache= NULL;
2114 MEM_freeN(psys->child);
2119 edit->totpoint= psys->totpart= new_totpart;
2125 static void remove_tagged_keys(Object *ob, ParticleSystem *psys)
2127 PTCacheEdit *edit= psys->edit;
2129 HairKey *hkey, *nhkey, *new_hkeys=0;
2131 PTCacheEditKey *nkey, *new_keys;
2132 ParticleSystemModifierData *psmd;
2135 if(pe_x_mirror(ob)) {
2136 /* mirror key tags */
2137 psmd= psys_get_modifier(ob, psys);
2141 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
2148 new_totkey= point->totkey;
2152 /* we can't have elements with less than two keys*/
2154 point->flag |= PEP_TAG;
2156 remove_tagged_particles(ob, psys, pe_x_mirror(ob));
2159 pa = psys->particles + p;
2160 new_totkey= pa->totkey;
2166 if(new_totkey != pa->totkey) {
2167 nhkey= new_hkeys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
2168 nkey= new_keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys");
2172 while(key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
2177 if(hkey < pa->hair + pa->totkey) {
2178 VECCOPY(nhkey->co, hkey->co);
2179 nhkey->editflag = hkey->editflag;
2180 nhkey->time= hkey->time;
2181 nhkey->weight= hkey->weight;
2183 nkey->co= nhkey->co;
2184 nkey->time= &nhkey->time;
2185 /* these can be copied from old edit keys */
2186 nkey->flag = key->flag;
2187 nkey->ftime = key->ftime;
2188 nkey->length = key->length;
2189 VECCOPY(nkey->world_co, key->world_co);
2197 MEM_freeN(pa->hair);
2200 MEM_freeN(point->keys);
2202 pa->hair= new_hkeys;
2203 point->keys= new_keys;
2205 point->totkey= pa->totkey= new_totkey;
2207 /* flag for recalculating length */
2208 point->flag |= PEP_EDIT_RECALC;
2213 /************************ subdivide opertor *********************/
2215 /* works like normal edit mode subdivide, inserts keys between neighbouring selected keys */
2216 static void subdivide_particle(PEData *data, int pa_index)
2218 PTCacheEdit *edit= data->edit;
2219 ParticleSystem *psys= edit->psys;
2220 ParticleSimulationData sim= {0};
2221 ParticleData *pa= psys->particles + pa_index;
2222 PTCacheEditPoint *point = edit->points + pa_index;
2224 HairKey *key, *nkey, *new_keys;
2225 PTCacheEditKey *ekey, *nekey, *new_ekeys;
2231 sim.scene= data->scene;
2233 sim.psys= edit->psys;
2235 for(k=0, ekey=point->keys; k<pa->totkey-1; k++,ekey++) {
2236 if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
2240 if(totnewkey==0) return;
2242 pa->flag |= PARS_REKEY;
2244 nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys");
2245 nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(PTCacheEditKey)),"Hair subdivide edit keys");
2248 endtime= key[pa->totkey-1].time;
2250 for(k=0, ekey=point->keys; k<pa->totkey-1; k++, key++, ekey++) {
2252 memcpy(nkey,key,sizeof(HairKey));
2253 memcpy(nekey,ekey,sizeof(PTCacheEditKey));
2255 nekey->co= nkey->co;
2256 nekey->time= &nkey->time;
2261 if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) {
2262 nkey->time= (key->time + (key+1)->time)*0.5f;
2263 state.time= (endtime != 0.0f)? nkey->time/endtime: 0.0f;
2264 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2265 VECCOPY(nkey->co, state.co);
2267 nekey->co= nkey->co;
2268 nekey->time= &nkey->time;
2269 nekey->flag |= PEK_SELECT;
2270 if(!(psys->flag & PSYS_GLOBAL_HAIR))
2271 nekey->flag |= PEK_USE_WCO;
2277 /*tip still not copied*/
2278 memcpy(nkey,key,sizeof(HairKey));
2279 memcpy(nekey,ekey,sizeof(PTCacheEditKey));
2281 nekey->co= nkey->co;
2282 nekey->time= &nkey->time;
2285 MEM_freeN(pa->hair);
2289 MEM_freeN(point->keys);
2290 point->keys= new_ekeys;
2292 point->totkey = pa->totkey = pa->totkey + totnewkey;
2293 point->flag |= PEP_EDIT_RECALC;
2294 pa->flag &= ~PARS_REKEY;
2297 static int subdivide_exec(bContext *C, wmOperator *UNUSED(op))
2301 PE_set_data(C, &data);
2302 foreach_point(&data, subdivide_particle);
2304 recalc_lengths(data.edit);
2305 PE_update_object(data.scene, data.ob, 1);
2306 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
2308 return OPERATOR_FINISHED;
2311 void PARTICLE_OT_subdivide(wmOperatorType *ot)
2314 ot->name= "Subdivide";
2315 ot->idname= "PARTICLE_OT_subdivide";
2318 ot->exec= subdivide_exec;
2322 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2325 /************************ remove doubles opertor *********************/
2327 static int remove_doubles_exec(bContext *C, wmOperator *op)
2329 Scene *scene= CTX_data_scene(C);
2330 Object *ob= CTX_data_active_object(C);
2331 PTCacheEdit *edit= PE_get_current(scene, ob);
2332 ParticleSystem *psys = edit->psys;
2333 ParticleSystemModifierData *psmd;
2335 KDTreeNearest nearest[10];
2337 float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
2338 int n, totn, removed, totremoved;
2340 if(psys->flag & PSYS_GLOBAL_HAIR)
2341 return OPERATOR_CANCELLED;
2344 psmd= psys_get_modifier(ob, psys);
2350 tree=BLI_kdtree_new(psys->totpart);
2352 /* insert particles into kd tree */
2353 LOOP_SELECTED_POINTS {
2354 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
2355 VECCOPY(co, point->keys->co);
2357 BLI_kdtree_insert(tree, p, co, NULL);
2360 BLI_kdtree_balance(tree);
2362 /* tag particles to be removed */
2363 LOOP_SELECTED_POINTS {
2364 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
2365 VECCOPY(co, point->keys->co);
2368 totn= BLI_kdtree_find_n_nearest(tree,10,co,NULL,nearest);
2370 for(n=0; n<totn; n++) {
2371 /* this needs a custom threshold still */
2372 if(nearest[n].index > p && nearest[n].dist < threshold) {
2373 if(!(point->flag & PEP_TAG)) {
2374 point->flag |= PEP_TAG;
2381 BLI_kdtree_free(tree);
2383 /* remove tagged particles - don't do mirror here! */
2384 remove_tagged_particles(ob, psys, 0);
2385 totremoved += removed;
2389 return OPERATOR_CANCELLED;
2391 BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved);
2393 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2394 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2396 return OPERATOR_FINISHED;
2399 void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
2402 ot->name= "Remove Doubles";
2403 ot->idname= "PARTICLE_OT_remove_doubles";
2406 ot->exec= remove_doubles_exec;
2410 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2413 RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
2417 static int weight_set_exec(bContext *C, wmOperator *op)
2419 Scene *scene= CTX_data_scene(C);
2420 ParticleEditSettings *pset= PE_settings(scene);
2421 Object *ob= CTX_data_active_object(C);
2422 PTCacheEdit *edit= PE_get_current(scene, ob);
2423 ParticleSystem *psys = edit->psys;
2428 ParticleBrushData *brush= &pset->brush[pset->brushtype];
2429 float factor= RNA_float_get(op->ptr, "factor");
2431 weight= brush->strength;
2434 LOOP_SELECTED_POINTS {
2435 ParticleData *pa= psys->particles + p;
2437 LOOP_SELECTED_KEYS {
2439 hkey->weight= interpf(weight, hkey->weight, factor);
2443 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2444 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2446 return OPERATOR_FINISHED;
2449 void PARTICLE_OT_weight_set(wmOperatorType *ot)
2452 ot->name= "Weight Set";
2453 ot->idname= "PARTICLE_OT_weight_set";
2456 ot->exec= weight_set_exec;
2460 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2462 RNA_def_float(ot->srna, "factor", 1, 0, 1, "Factor", "", 0, 1);
2465 /************************ cursor drawing *******************************/
2467 static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
2469 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2470 ParticleBrushData *brush;
2472 if(pset->brushtype < 0)
2475 brush= &pset->brush[pset->brushtype];
2480 glTranslatef((float)x, (float)y, 0.0f);
2482 glColor4ub(255, 255, 255, 128);
2483 glEnable(GL_LINE_SMOOTH );
2485 glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
2486 glDisable(GL_BLEND);
2487 glDisable(GL_LINE_SMOOTH );
2493 static void toggle_particle_cursor(bContext *C, int enable)
2495 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2497 if(pset->paintcursor && !enable) {
2498 WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
2499 pset->paintcursor = NULL;
2502 pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_view3d, brush_drawcursor, NULL);
2505 /********************* radial control operator *********************/
2507 static int brush_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
2509 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2510 ParticleBrushData *brush;
2511 int mode = RNA_enum_get(op->ptr, "mode");
2512 float original_value=1.0f;
2514 if(pset->brushtype < 0)
2515 return OPERATOR_CANCELLED;
2517 brush= &pset->brush[pset->brushtype];
2519 toggle_particle_cursor(C, 0);
2521 if(mode == WM_RADIALCONTROL_SIZE)
2522 original_value = brush->size;
2523 else if(mode == WM_RADIALCONTROL_STRENGTH)
2524 original_value = brush->strength;
2526 RNA_float_set(op->ptr, "initial_value", original_value);
2528 return WM_radial_control_invoke(C, op, event);
2531 static int brush_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
2533 int ret = WM_radial_control_modal(C, op, event);
2535 if(ret != OPERATOR_RUNNING_MODAL)
2536 toggle_particle_cursor(C, 1);
2541 static int brush_radial_control_exec(bContext *C, wmOperator *op)
2543 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2544 ParticleBrushData *brush;
2545 int mode = RNA_enum_get(op->ptr, "mode");
2546 float new_value = RNA_float_get(op->ptr, "new_value");
2548 if(pset->brushtype < 0)
2549 return OPERATOR_CANCELLED;
2551 brush= &pset->brush[pset->brushtype];
2553 if(mode == WM_RADIALCONTROL_SIZE)
2554 brush->size= new_value;
2555 else if(mode == WM_RADIALCONTROL_STRENGTH)
2556 brush->strength= new_value;
2558 WM_event_add_notifier(C, NC_WINDOW, NULL);
2560 return OPERATOR_FINISHED;
2563 void PARTICLE_OT_brush_radial_control(wmOperatorType *ot)
2565 WM_OT_radial_control_partial(ot);
2567 ot->name= "Brush Radial Control";
2568 ot->idname= "PARTICLE_OT_brush_radial_control";
2570 ot->invoke= brush_radial_control_invoke;
2571 ot->modal= brush_radial_control_modal;
2572 ot->exec= brush_radial_control_exec;
2576 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
2579 /*************************** delete operator **************************/
2581 enum { DEL_PARTICLE, DEL_KEY };
2583 static EnumPropertyItem delete_type_items[]= {
2584 {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
2585 {DEL_KEY, "KEY", 0, "Key", ""},
2586 {0, NULL, 0, NULL, NULL}};
2588 static void set_delete_particle(PEData *data, int pa_index)
2590 PTCacheEdit *edit= data->edit;
2592 edit->points[pa_index].flag |= PEP_TAG;
2595 static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
2597 PTCacheEdit *edit= data->edit;
2599 edit->points[pa_index].keys[key_index].flag |= PEK_TAG;
2602 static int delete_exec(bContext *C, wmOperator *op)
2605 int type= RNA_enum_get(op->ptr, "type");
2607 PE_set_data(C, &data);
2609 if(type == DEL_KEY) {
2610 foreach_selected_key(&data, set_delete_particle_key);
2611 remove_tagged_keys(data.ob, data.edit->psys);
2612 recalc_lengths(data.edit);
2614 else if(type == DEL_PARTICLE) {
2615 foreach_selected_point(&data, set_delete_particle);
2616 remove_tagged_particles(data.ob, data.edit->psys, pe_x_mirror(data.ob));
2617 recalc_lengths(data.edit);
2620 DAG_id_tag_update(&data.ob->id, OB_RECALC_DATA);
2621 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
2623 return OPERATOR_FINISHED;
2626 void PARTICLE_OT_delete(wmOperatorType *ot)
2630 ot->idname= "PARTICLE_OT_delete";
2633 ot->exec= delete_exec;
2634 ot->invoke= WM_menu_invoke;
2635 ot->poll= PE_hair_poll;
2638 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2641 ot->prop= RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys.");
2644 /*************************** mirror operator **************************/
2646 static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
2648 Mesh *me= (Mesh*)(ob->data);
2649 ParticleSystemModifierData *psmd;
2650 PTCacheEdit *edit= PE_get_current(scene, ob);
2651 ParticleSystem *psys = edit->psys;
2652 ParticleData *pa, *newpa, *new_pars;
2653 PTCacheEditPoint *newpoint, *new_points;
2657 int rotation, totpart, newtotpart;
2659 if(psys->flag & PSYS_GLOBAL_HAIR)
2662 psmd= psys_get_modifier(ob, psys);
2666 mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
2668 if(!edit->mirror_cache)
2669 PE_update_mirror_cache(ob, psys);
2671 totpart= psys->totpart;
2672 newtotpart= psys->totpart;
2673 LOOP_VISIBLE_POINTS {
2674 pa = psys->particles + p;
2676 if(point_is_selected(point)) {
2677 if(edit->mirror_cache[p] != -1) {
2678 /* already has a mirror, don't need to duplicate */
2679 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
2683 point->flag |= PEP_TAG;
2687 if((point->flag & PEP_TAG) && mirrorfaces[pa->num*2] != -1)
2691 if(newtotpart != psys->totpart) {
2692 /* allocate new arrays and copy existing */
2693 new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
2694 new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
2696 if(psys->particles) {
2697 memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
2698 MEM_freeN(psys->particles);
2700 psys->particles= new_pars;
2703 memcpy(new_points, edit->points, totpart*sizeof(PTCacheEditPoint));
2704 MEM_freeN(edit->points);
2706 edit->points= new_points;
2708 if(edit->mirror_cache) {
2709 MEM_freeN(edit->mirror_cache);
2710 edit->mirror_cache= NULL;
2713 edit->totpoint= psys->totpart= newtotpart;
2715 /* create new elements */
2716 newpa= psys->particles + totpart;
2717 newpoint= edit->points + totpart;
2719 for(p=0, point=edit->points; p<totpart; p++, point++) {
2720 pa = psys->particles + p;
2722 if(point->flag & PEP_HIDE)
2724 if(!(point->flag & PEP_TAG) || mirrorfaces[pa->num*2] == -1)
2730 if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
2731 if(point->keys) newpoint->keys= MEM_dupallocN(point->keys);
2733 /* rotate weights according to vertex index rotation */
2734 rotation= mirrorfaces[pa->num*2+1];
2735 newpa->fuv[0]= pa->fuv[2];
2736 newpa->fuv[1]= pa->fuv[1];
2737 newpa->fuv[2]= pa->fuv[0];
2738 newpa->fuv[3]= pa->fuv[3];
2739 while(rotation-- > 0)
2740 if(me->mface[pa->num].v4)
2741 SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
2743 SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
2745 /* assign face inddex */
2746 newpa->num= mirrorfaces[pa->num*2];
2747 newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
2749 /* update edit key pointers */
2750 key= newpoint->keys;
2751 for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, key++) {
2753 key->time= &hkey->time;
2756 /* map key positions as mirror over x axis */
2757 PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
2765 point->flag &= ~PEP_TAG;
2768 MEM_freeN(mirrorfaces);
2771 static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
2773 Scene *scene= CTX_data_scene(C);
2774 Object *ob= CTX_data_active_object(C);
2775 PTCacheEdit *edit= PE_get_current(scene, ob);
2777 PE_mirror_x(scene, ob, 0);
2779 update_world_cos(ob, edit);
2780 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2781 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2783 return OPERATOR_FINISHED;
2786 void PARTICLE_OT_mirror(wmOperatorType *ot)
2790 ot->idname= "PARTICLE_OT_mirror";
2793 ot->exec= mirror_exec;
2797 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2800 /************************* brush edit callbacks ********************/
2802 static void brush_comb(PEData *data, float UNUSED(mat[][4]), float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
2804 ParticleEditSettings *pset= PE_settings(data->scene);
2807 if(pset->flag & PE_LOCK_FIRST && key_index == 0) return;
2809 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
2811 VECCOPY(cvec,data->dvec);
2812 mul_mat3_m4_v3(imat,cvec);
2813 mul_v3_fl(cvec, fac);
2814 VECADD(key->co, key->co, cvec);
2816 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
2819 static void brush_cut(PEData *data, int pa_index)
2821 PTCacheEdit *edit = data->edit;
2822 ARegion *ar= data->vc.ar;
2823 Object *ob= data->ob;
2824 ParticleEditSettings *pset= PE_settings(data->scene);
2825 ParticleCacheKey *key= edit->pathcache[pa_index];
2826 float rad2, cut_time= 1.0;
2827 float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
2828 int k, cut, keys= (int)pow(2.0, (double)pset->draw_step);
2831 /* blunt scissors */
2832 if(BLI_frand() > data->cutfac) return;
2834 /* don't cut hidden */
2835 if(edit->points[pa_index].flag & PEP_HIDE)
2838 rad2= data->rad * data->rad;
2842 project_short_noclip(ar, key->co, vertco);
2843 x0= (float)vertco[0];
2844 x1= (float)vertco[1];
2846 o0= (float)data->mval[0];
2847 o1= (float)data->mval[1];
2852 /* check if root is inside circle */
2853 if(xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) {
2858 /* calculate path time closest to root that was inside the circle */
2859 for(k=1, key++; k<=keys; k++, key++) {
2860 project_short_noclip(ar, key->co, vertco);
2862 if(key_test_depth(data, key->co) == 0) {
2863 x0= (float)vertco[0];
2864 x1= (float)vertco[1];
2871 v0= (float)vertco[0] - x0;
2872 v1= (float)vertco[1] - x1;
2876 d= (v0*xo1 - v1*xo0);
2883 cut_time= -(v0*xo0 + v1*xo1 + d);
2885 if(cut_time > 0.0f) {
2888 if(cut_time < 1.0f) {
2889 cut_time += (float)(k-1);
2890 cut_time /= (float)keys;
2897 x0= (float)vertco[0];
2898 x1= (float)vertco[1];
2906 if(cut_time < 0.0f) {
2907 edit->points[pa_index].flag |= PEP_TAG;
2910 rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
2911 edit->points[pa_index].flag |= PEP_EDIT_RECALC;
2916 static void brush_length(PEData *data, int point_index)
2918 PTCacheEdit *edit= data->edit;
2919 PTCacheEditPoint *point = edit->points + point_index;
2921 float dvec[3],pvec[3] = {0.0f, 0.0f, 0.0f};
2925 VECCOPY(pvec,key->co);
2928 VECSUB(dvec,key->co,pvec);
2929 VECCOPY(pvec,key->co);
2930 mul_v3_fl(dvec,data->growfac);
2931 VECADD(key->co,(key-1)->co,dvec);
2935 point->flag |= PEP_EDIT_RECALC;
2938 static void brush_puff(PEData *data, int point_index)
2940 PTCacheEdit *edit = data->edit;
2941 ParticleSystem *psys = edit->psys;
2942 PTCacheEditPoint *point = edit->points + point_index;
2944 float mat[4][4], imat[4][4];
2946 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;
2947 int puff_volume = 0;
2951 ParticleEditSettings *pset= PE_settings(data->scene);
2952 ParticleBrushData *brush= &pset->brush[pset->brushtype];
2953 puff_volume = brush->flag & PE_BRUSH_DATA_PUFF_VOLUME;
2956 if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
2957 psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
2958 invert_m4_m4(imat,mat);
2967 /* find root coordinate and normal on emitter */
2968 VECCOPY(co, key->co);
2970 mul_v3_m4v3(kco, data->ob->imat, co); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
2972 point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL);
2973 if(point_index == -1) return;
2975 VECCOPY(rootco, co);
2976 copy_v3_v3(nor, &edit->emitter_cosnos[point_index*6+3]);
2977 mul_mat3_m4_v3(data->ob->obmat, nor); /* normal into worldspace */
2982 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac);
2988 /* compute position as if hair was standing up straight.
2990 VECCOPY(lastco, co);
2991 VECCOPY(co, key->co);
2993 length += len_v3v3(lastco, co);
2994 if((data->select==0 || (key->flag & PEK_SELECT)) && !(key->flag & PEK_HIDE)) {
2995 VECADDFAC(kco, rootco, nor, length);
2997 /* blend between the current and straight position */
2998 VECSUB(dco, kco, co);
2999 VECADDFAC(co, co, dco, fac);
3001 /* re-use dco to compare before and after translation and add to the offset */
3002 VECCOPY(dco, key->co);
3004 mul_v3_m4v3(key->co, imat, co);
3007 /* accumulate the total distance moved to apply to unselected
3008 * keys that come after */
3009 ofs[0] += key->co[0] - dco[0];
3010 ofs[1] += key->co[1] - dco[1];
3011 ofs[2] += key->co[2] - dco[2];
3019 /* this is simple but looks bad, adds annoying kinks */
3020 add_v3_v3(key->co, ofs);
3022 /* translate (not rotate) the rest of the hair if its not selected */
3023 if(ofs[0] || ofs[1] || ofs[2]) {
3024 #if 0 /* kindof works but looks worse then whats below */
3026 /* Move the unselected point on a vector based on the
3027 * hair direction and the offset */
3029 VECSUB(dco, lastco, co);
3030 mul_mat3_m4_v3(imat, dco); /* into particle space */
3032 /* move the point allong a vector perpendicular to the
3033 * hairs direction, reduces odd kinks, */
3034 cross_v3_v3v3(c1, ofs, dco);
3035 cross_v3_v3v3(c2, c1, dco);
3037 mul_v3_fl(c2, len_v3(ofs));
3038 add_v3_v3(key->co, c2);
3040 /* Move the unselected point on a vector based on the
3041 * the normal of the closest geometry */
3042 float oco[3], onor[3];
3043 VECCOPY(oco, key->co);
3044 mul_m4_v3(mat, oco);
3045 mul_v3_m4v3(kco, data->ob->imat, oco); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
3047 point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL);
3048 if(point_index != -1) {
3049 copy_v3_v3(onor, &edit->emitter_cosnos[point_index*6+3]);
3050 mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */
3051 mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */
3055 mul_v3_fl(onor, len_v3(ofs));
3056 add_v3_v3(key->co, onor);
3067 point->flag |= PEP_EDIT_RECALC;
3071 static void brush_weight(PEData *data, float UNUSED(mat[][4]), float UNUSED(imat[][4]), int point_index, int key_index, PTCacheEditKey *UNUSED(key))
3073 /* roots have full weight allways */
3075 PTCacheEdit *edit = data->edit;
3076 ParticleSystem *psys = edit->psys;
3078 ParticleData *pa= psys->particles + point_index;
3079 pa->hair[key_index].weight = data->weightfac;
3081 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
3085 static void brush_smooth_get(PEData *data, float mat[][4], float UNUSED(imat[][4]), int UNUSED(point_index), int key_index, PTCacheEditKey *key)
3090 sub_v3_v3v3(dvec,key->co,(key-1)->co);
3091 mul_mat3_m4_v3(mat,dvec);
3092 VECADD(data->vec,data->vec,dvec);
3097 static void brush_smooth_do(PEData *data, float UNUSED(mat[][4]), float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
3099 float vec[3], dvec[3];
3102 VECCOPY(vec,data->vec);
3103 mul_mat3_m4_v3(imat,vec);
3105 sub_v3_v3v3(dvec,key->co,(key-1)->co);
3107 VECSUB(dvec,vec,dvec);
3108 mul_v3_fl(dvec,data->smoothfac);
3110 VECADD(key->co,key->co,dvec);
3113 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
3116 static int brush_add(PEData *data, short number)
3118 Scene *scene= data->scene;
3119 Object *ob= data->ob;
3120 PTCacheEdit *edit = data->edit;
3121 ParticleSystem *psys= edit->psys;
3122 ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add");
3123 ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
3124 ParticleSimulationData sim= {0};
3125 ParticleEditSettings *pset= PE_settings(scene);
3126 int i, k, n= 0, totpart= psys->totpart;
3128 short dmx= 0, dmy= 0;
3129 float co1[3], co2[3], min_d, imat[4][4];
3130 float framestep, timestep;
3131 short size= pset->brush[PE_BRUSH_ADD].size;
3132 short size2= size*size;
3134 invert_m4_m4(imat,ob->obmat);
3136 if(psys->flag & PSYS_GLOBAL_HAIR)
3139 BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
3146 timestep= psys_get_timestep(&sim);
3148 /* painting onto the deformed mesh, could be an option? */
3149 if(psmd->dm->deformedOnly)
3152 dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
3154 for(i=0; i<number; i++) {
3157 while(dmx*dmx+dmy*dmy>size2) {
3158 dmx=(short)((2.0f*BLI_frand()-1.0f)*size);
3159 dmy=(short)((2.0f*BLI_frand()-1.0f)*size);
3163 mco[0]= data->mval[0] + dmx;
3164 mco[1]= data->mval[1] + dmy;
3165 viewline(data->vc.ar, data->vc.v3d, mco, co1, co2);
3167 mul_m4_v3(imat,co1);
3168 mul_m4_v3(imat,co2);
3171 /* warning, returns the derived mesh face */
3172 if(psys_intersect_dm(scene, ob,dm,0,co1,co2,&min_d,&add_pars[n].num,add_pars[n].fuv,0,0,0,0)) {
3173 add_pars[n].num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,add_pars[n].num,add_pars[n].fuv,NULL);
3178 int newtotpart=totpart+n;
3179 float hairmat[4][4], cur_co[3];