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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 *****
34 #include "MEM_guardedalloc.h"
36 #include "DNA_scene_types.h"
37 #include "DNA_mesh_types.h"
38 #include "DNA_meshdata_types.h"
39 #include "DNA_modifier_types.h"
40 #include "DNA_object_force.h"
41 #include "DNA_object_types.h"
42 #include "DNA_vec_types.h"
43 #include "DNA_userdef_types.h"
44 #include "DNA_view3d_types.h"
45 #include "DNA_screen_types.h"
46 #include "DNA_space_types.h"
47 #include "DNA_windowmanager_types.h"
49 #include "BKE_DerivedMesh.h"
50 #include "BKE_depsgraph.h"
52 #include "BKE_context.h"
53 #include "BKE_global.h"
54 #include "BKE_object.h"
56 #include "BKE_modifier.h"
57 #include "BKE_particle.h"
58 #include "BKE_report.h"
59 #include "BKE_scene.h"
60 #include "BKE_utildefines.h"
61 #include "BKE_pointcache.h"
64 #include "BLI_blenlib.h"
65 #include "BLI_dynstr.h"
66 #include "BLI_kdtree.h"
72 #include "BIF_glutil.h"
75 #include "ED_particle.h"
76 #include "ED_view3d.h"
78 #include "UI_interface.h"
79 #include "UI_resources.h"
84 #include "RNA_access.h"
85 #include "RNA_define.h"
87 #include "physics_intern.h"
89 static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
90 static void PTCacheUndo_clear(PTCacheEdit *edit);
92 #define KEY_K PTCacheEditKey *key; int k
93 #define POINT_P PTCacheEditPoint *point; int p
94 #define LOOP_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++)
95 #define LOOP_VISIBLE_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!(point->flag & PEP_HIDE))
96 #define LOOP_SELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point_is_selected(point))
97 #define LOOP_UNSELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!point_is_selected(point))
98 #define LOOP_EDITED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_EDIT_RECALC)
99 #define LOOP_TAGGED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_TAG)
100 #define LOOP_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++)
101 #define LOOP_VISIBLE_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(!(key->flag & PEK_HIDE))
102 #define LOOP_SELECTED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
103 #define LOOP_TAGGED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(key->flag & PEK_TAG)
105 #define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co)
107 /**************************** utilities *******************************/
109 int PE_poll(bContext *C)
111 Scene *scene= CTX_data_scene(C);
112 Object *ob= CTX_data_active_object(C);
114 if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
117 return (PE_get_current(scene, ob) != NULL);
120 int PE_hair_poll(bContext *C)
122 Scene *scene= CTX_data_scene(C);
123 Object *ob= CTX_data_active_object(C);
126 if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
129 edit= PE_get_current(scene, ob);
131 return (edit && edit->psys);
134 int PE_poll_3dview(bContext *C)
136 return PE_poll(C) && CTX_wm_area(C)->spacetype == SPACE_VIEW3D &&
137 CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW;
140 void PE_free_ptcache_edit(PTCacheEdit *edit)
146 PTCacheUndo_clear(edit);
151 MEM_freeN(point->keys);
154 MEM_freeN(edit->points);
157 if(edit->mirror_cache)
158 MEM_freeN(edit->mirror_cache);
160 if(edit->emitter_cosnos) {
161 MEM_freeN(edit->emitter_cosnos);
162 edit->emitter_cosnos= 0;
165 if(edit->emitter_field) {
166 BLI_kdtree_free(edit->emitter_field);
167 edit->emitter_field= 0;
170 psys_free_path_cache(NULL, edit);
175 /************************************************/
176 /* Edit Mode Helpers */
177 /************************************************/
179 int PE_start_edit(PTCacheEdit *edit)
184 edit->psys->flag |= PSYS_EDITED;
191 ParticleEditSettings *PE_settings(Scene *scene)
193 return &scene->toolsettings->particle;
196 /* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set */
197 static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
199 ParticleEditSettings *pset= PE_settings(scene);
200 PTCacheEdit *edit = NULL;
210 BKE_ptcache_ids_from_object(&pidlist, ob);
212 /* in the case of only one editable thing, set pset->edittype accordingly */
213 if(pidlist.first && pidlist.first == pidlist.last) {
216 case PTCACHE_TYPE_PARTICLES:
217 pset->edittype = PE_TYPE_PARTICLES;
219 case PTCACHE_TYPE_SOFTBODY:
220 pset->edittype = PE_TYPE_SOFTBODY;
222 case PTCACHE_TYPE_CLOTH:
223 pset->edittype = PE_TYPE_CLOTH;
228 for(pid=pidlist.first; pid; pid=pid->next) {
229 if(pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) {
230 ParticleSystem *psys = pid->calldata;
232 if(psys->flag & PSYS_CURRENT) {
233 if(psys->part && psys->part->type == PART_HAIR) {
234 if(psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
235 if(create && !psys->pointcache->edit)
236 PE_create_particle_edit(scene, ob, pid->cache, NULL);
237 edit = pid->cache->edit;
240 if(create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
241 PE_create_particle_edit(scene, ob, NULL, psys);
246 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
247 PE_create_particle_edit(scene, ob, pid->cache, psys);
248 edit = pid->cache->edit;
254 else if(pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
255 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
256 PE_create_particle_edit(scene, ob, pid->cache, NULL);
257 edit = pid->cache->edit;
260 else if(pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
261 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
262 PE_create_particle_edit(scene, ob, pid->cache, NULL);
263 edit = pid->cache->edit;
271 BLI_freelistN(&pidlist);
276 PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
278 return pe_get_current(scene, ob, 0);
281 PTCacheEdit *PE_create_current(Scene *scene, Object *ob)
283 return pe_get_current(scene, ob, 1);
286 void PE_current_changed(Scene *scene, Object *ob)
288 if(ob->mode == OB_MODE_PARTICLE_EDIT)
289 PE_create_current(scene, ob);
292 void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
294 ParticleEditSettings *pset=PE_settings(scene);
298 if(pset->flag & PE_FADE_TIME && pset->selectmode==SCE_SELECT_POINT) {
301 if(fabs(cfra-*key->time) < pset->fade_frames)
302 key->flag &= ~PEK_HIDE;
304 key->flag |= PEK_HIDE;
305 //key->flag &= ~PEK_SELECT;
313 key->flag &= ~PEK_HIDE;
319 /****************** common struct passed to callbacks ******************/
321 typedef struct PEData {
351 static void PE_set_data(bContext *C, PEData *data)
353 memset(data, 0, sizeof(*data));
355 data->scene= CTX_data_scene(C);
356 data->ob= CTX_data_active_object(C);
357 data->edit= PE_get_current(data->scene, data->ob);
360 static void PE_set_view3d_data(bContext *C, PEData *data)
362 PE_set_data(C, data);
364 view3d_set_viewcontext(C, &data->vc);
365 view3d_get_transformation(&data->vc, data->ob, &data->mats);
367 if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT))
368 view3d_validate_backbuf(&data->vc);
371 /*************************** selection utilities *******************************/
373 static int key_test_depth(PEData *data, float co[3])
375 View3D *v3d= data->vc.v3d;
376 RegionView3D *rv3d= data->vc.rv3d;
382 if((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
385 project_short(data->vc.ar, co, wco);
387 if(wco[0] == IS_CLIPPED)
390 gluProject(co[0],co[1],co[2], data->mats.modelview, data->mats.projection,
391 (GLint *)data->mats.viewport, &ux, &uy, &uz);
398 if(rv3d->depths && x<rv3d->depths->w && y<rv3d->depths->h) {
399 /* the 0.0001 is an experimental threshold to make selecting keys right next to a surface work better */
400 if((float)uz - 0.0001 > rv3d->depths->depths[y*rv3d->depths->w+x])
406 x+= (short)data->vc.ar->winrct.xmin;
407 y+= (short)data->vc.ar->winrct.ymin;
409 glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
411 if((float)uz - 0.0001 > depth)
418 static int key_inside_circle(PEData *data, float rad, float co[3], float *distance)
423 project_short(data->vc.ar, co, sco);
425 if(sco[0] == IS_CLIPPED)
428 dx= data->mval[0] - sco[0];
429 dy= data->mval[1] - sco[1];
430 dist= sqrt(dx*dx + dy*dy);
435 if(key_test_depth(data, co)) {
445 static int key_inside_rect(PEData *data, float co[3])
449 project_short(data->vc.ar, co,sco);
451 if(sco[0] == IS_CLIPPED)
454 if(sco[0] > data->rect->xmin && sco[0] < data->rect->xmax &&
455 sco[1] > data->rect->ymin && sco[1] < data->rect->ymax)
456 return key_test_depth(data, co);
461 static int key_inside_test(PEData *data, float co[3])
464 return key_inside_circle(data, data->rad, co, NULL);
466 return key_inside_rect(data, co);
469 static int point_is_selected(PTCacheEditPoint *point)
474 if(point->flag & PEP_HIDE)
486 /*************************** iterators *******************************/
488 typedef void (*ForPointFunc)(PEData *data, int point_index);
489 typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index);
490 typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key);
492 static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
494 ParticleEditSettings *pset= PE_settings(data->scene);
495 PTCacheEdit *edit= data->edit;
497 int nearest_point, nearest_key;
498 float dist= data->rad;
500 /* in path select mode we have no keys */
501 if(pset->selectmode==SCE_SELECT_PATH)
507 LOOP_VISIBLE_POINTS {
508 if(pset->selectmode == SCE_SELECT_END) {
509 /* only do end keys */
510 key= point->keys + point->totkey-1;
513 if(key_inside_circle(data, dist, KEY_WCO, &dist)) {
515 nearest_key= point->totkey-1;
518 else if(key_inside_test(data, KEY_WCO))
519 func(data, p, point->totkey-1);
525 if(key_inside_circle(data, dist, KEY_WCO, &dist)) {
530 else if(key_inside_test(data, KEY_WCO))
536 /* do nearest only */
537 if(nearest && nearest_point > -1)
538 func(data, nearest_point, nearest_key);
541 static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected)
543 ParticleEditSettings *pset= PE_settings(data->scene);
544 PTCacheEdit *edit= data->edit;
547 /* all is selected in path mode */
548 if(pset->selectmode==SCE_SELECT_PATH)
551 LOOP_VISIBLE_POINTS {
552 if(pset->selectmode==SCE_SELECT_END) {
553 /* only do end keys */
554 key= point->keys + point->totkey - 1;
556 if(selected==0 || key->flag & PEK_SELECT)
557 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
563 if(selected==0 || key->flag & PEK_SELECT) {
564 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
574 static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
576 PTCacheEdit *edit = data->edit;
577 ParticleSystem *psys = edit->psys;
578 ParticleSystemModifierData *psmd = NULL;
579 ParticleEditSettings *pset= PE_settings(data->scene);
581 float mat[4][4], imat[4][4];
584 psmd= psys_get_modifier(data->ob, edit->psys);
586 /* all is selected in path mode */
587 if(pset->selectmode==SCE_SELECT_PATH)
593 LOOP_VISIBLE_POINTS {
594 if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
595 psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
596 invert_m4_m4(imat,mat);
599 if(pset->selectmode==SCE_SELECT_END) {
600 /* only do end keys */
601 key= point->keys + point->totkey-1;
603 if(selected==0 || key->flag & PEK_SELECT)
604 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
605 func(data, mat, imat, p, point->totkey-1, key);
610 if(selected==0 || key->flag & PEK_SELECT)
611 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
612 func(data, mat, imat, p, k, key);
618 static void foreach_selected_point(PEData *data, ForPointFunc func)
620 PTCacheEdit *edit = data->edit;
623 LOOP_SELECTED_POINTS {
628 static void foreach_selected_key(PEData *data, ForKeyFunc func)
630 PTCacheEdit *edit = data->edit;
633 LOOP_VISIBLE_POINTS {
640 static void foreach_point(PEData *data, ForPointFunc func)
642 PTCacheEdit *edit = data->edit;
650 static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
652 ParticleEditSettings *pset= PE_settings(scene);
656 LOOP_VISIBLE_POINTS {
657 if(pset->selectmode==SCE_SELECT_POINT) {
662 else if(pset->selectmode==SCE_SELECT_END) {
663 key = point->keys + point->totkey - 1;
664 if(key->flag & PEK_SELECT)
672 /************************************************/
673 /* Particle Edit Mirroring */
674 /************************************************/
676 static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
679 ParticleSystemModifierData *psmd;
681 KDTreeNearest nearest;
684 float mat[4][4], co[3];
688 psmd= psys_get_modifier(ob, psys);
689 totpart= psys->totpart;
694 tree= BLI_kdtree_new(totpart);
696 /* insert particles into kd tree */
699 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
700 VECCOPY(co, key->co);
702 BLI_kdtree_insert(tree, p, co, NULL);
705 BLI_kdtree_balance(tree);
707 /* lookup particles and set in mirror cache */
708 if(!edit->mirror_cache)
709 edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
713 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
714 VECCOPY(co, key->co);
718 index= BLI_kdtree_find_nearest(tree, co, NULL, &nearest);
720 /* this needs a custom threshold still, duplicated for editmode mirror */
721 if(index != -1 && index != p && (nearest.dist <= 0.0002f))
722 edit->mirror_cache[p]= index;
724 edit->mirror_cache[p]= -1;
727 /* make sure mirrors are in two directions */
729 if(edit->mirror_cache[p]) {
730 index= edit->mirror_cache[p];
731 if(edit->mirror_cache[index] != p)
732 edit->mirror_cache[p]= -1;
736 BLI_kdtree_free(tree);
739 static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
741 HairKey *hkey, *mhkey;
742 PTCacheEditPoint *point, *mpoint;
743 PTCacheEditKey *key, *mkey;
745 float mat[4][4], mmat[4][4], immat[4][4];
749 i= pa - psys->particles;
751 /* find mirrored particle if needed */
753 if(!edit->mirror_cache)
754 PE_update_mirror_cache(ob, psys);
756 mi= edit->mirror_cache[i];
759 mpa= psys->particles + mi;
762 mi= mpa - psys->particles;
764 point = edit->points + i;
765 mpoint = edit->points + mi;
767 /* make sure they have the same amount of keys */
768 if(pa->totkey != mpa->totkey) {
769 if(mpa->hair) MEM_freeN(mpa->hair);
770 if(mpoint->keys) MEM_freeN(mpoint->keys);
772 mpa->hair= MEM_dupallocN(pa->hair);
773 mpoint->keys= MEM_dupallocN(point->keys);
774 mpoint->totkey= point->totkey;
778 for(k=0; k<mpa->totkey; k++, mkey++, mhkey++) {
780 mkey->time= &mhkey->time;
781 mkey->flag &= PEK_SELECT;
785 /* mirror positions and tags */
786 psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
787 psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
788 invert_m4_m4(immat, mmat);
794 for(k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
795 VECCOPY(mhkey->co, hkey->co);
796 mul_m4_v3(mat, mhkey->co);
797 mhkey->co[0]= -mhkey->co[0];
798 mul_m4_v3(immat, mhkey->co);
800 if(key->flag & PEK_TAG)
801 mkey->flag |= PEK_TAG;
804 if(point->flag & PEP_TAG)
805 mpoint->flag |= PEP_TAG;
806 if(point->flag & PEP_EDIT_RECALC)
807 mpoint->flag |= PEP_EDIT_RECALC;
810 static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
813 ParticleSystemModifierData *psmd;
820 psmd= psys_get_modifier(ob, psys);
822 if(!edit->mirror_cache || !psmd->dm)
825 /* we delay settings the PARS_EDIT_RECALC for mirrored particles
826 * to avoid doing mirror twice */
828 if(point->flag & PEP_EDIT_RECALC) {
829 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
831 if(edit->mirror_cache[p] != -1)
832 edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
837 if(point->flag & PEP_EDIT_RECALC)
838 if(edit->mirror_cache[p] != -1)
839 edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
843 /************************************************/
844 /* Edit Calculation */
845 /************************************************/
846 /* tries to stop edited particles from going through the emitter's surface */
847 static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
849 ParticleEditSettings *pset= PE_settings(scene);
850 ParticleSystem *psys;
851 ParticleSystemModifierData *psmd;
854 float *vec, *nor, dvec[3], dot, dist_1st=0.0f;
855 float hairimat[4][4], hairmat[4][4];
857 if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0 || (edit->psys->flag & PSYS_GLOBAL_HAIR))
861 psmd = psys_get_modifier(ob,psys);
867 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles + p, hairmat);
870 mul_m4_v3(hairmat, key->co);
875 dist_1st = len_v3v3((key+1)->co, key->co);
876 dist_1st *= 0.75f * pset->emitterdist;
879 index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL);
881 vec=edit->emitter_cosnos +index*6;
884 sub_v3_v3v3(dvec, key->co, vec);
886 dot=dot_v3v3(dvec,nor);
892 mul_v3_fl(dvec,dist_1st-dot);
893 add_v3_v3v3(key->co,key->co,dvec);
898 mul_v3_fl(dvec,dist_1st-dot);
899 add_v3_v3v3(key->co,key->co,dvec);
906 invert_m4_m4(hairimat,hairmat);
909 mul_m4_v3(hairimat, key->co);
913 /* force set distances between neighbouring keys */
914 void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
917 ParticleEditSettings *pset=PE_settings(scene);
921 if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
924 if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
930 sub_v3_v3v3(dv1, key->co, (key - 1)->co);
932 mul_v3_fl(dv1, (key - 1)->length);
933 add_v3_v3v3(key->co, (key - 1)->co, dv1);
938 /* try to find a nice solution to keep distances between neighbouring keys */
939 static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
941 ParticleEditSettings *pset=PE_settings(scene);
946 float dv0[3]= {0.0f, 0.0f, 0.0f};
947 float dv1[3]= {0.0f, 0.0f, 0.0f};
948 float dv2[3]= {0.0f, 0.0f, 0.0f};
950 if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
953 if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
957 for(j=1; j<point->totkey; j++) {
958 float mul= 1.0f / (float)point->totkey;
960 if(pset->flag & PE_LOCK_FIRST) {
961 key= point->keys + 1;
963 dv1[0]= dv1[1]= dv1[2]= 0.0;
968 dv0[0]= dv0[1]= dv0[2]= 0.0;
971 for(; k<point->totkey; k++, key++) {
973 sub_v3_v3v3(dv0, (key - 1)->co, key->co);
974 tlen= normalize_v3(dv0);
975 mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
978 if(k < point->totkey - 1) {
979 sub_v3_v3v3(dv2, (key + 1)->co, key->co);
980 tlen= normalize_v3(dv2);
981 mul_v3_fl(dv2, mul * (tlen - key->length));
985 add_v3_v3v3((key-1)->co,(key-1)->co,dv1);
993 /* set current distances to be kept between neighbouting keys */
994 static void recalc_lengths(PTCacheEdit *edit)
1001 LOOP_EDITED_POINTS {
1003 for(k=0; k<point->totkey-1; k++, key++) {
1004 key->length= len_v3v3(key->co, (key + 1)->co);
1009 /* calculate a tree for finding nearest emitter's vertice */
1010 static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
1012 DerivedMesh *dm=psys_get_modifier(ob,psys)->dm;
1013 PTCacheEdit *edit= psys->edit;
1017 int i, totface, totvert;
1022 if(edit->emitter_cosnos)
1023 MEM_freeN(edit->emitter_cosnos);
1025 BLI_kdtree_free(edit->emitter_field);
1027 totface=dm->getNumFaces(dm);
1028 totvert=dm->getNumVerts(dm);
1030 edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos");
1032 edit->emitter_field= BLI_kdtree_new(totface);
1034 vec=edit->emitter_cosnos;
1037 mvert=dm->getVertDataArray(dm,CD_MVERT);
1038 for(i=0; i<totface; i++, vec+=6, nor+=6) {
1039 mface=dm->getFaceData(dm,i,CD_MFACE);
1041 mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
1042 VECCOPY(vec,mvert->co);
1043 VECCOPY(nor,mvert->no);
1045 mvert=dm->getVertData(dm,mface->v2,CD_MVERT);
1046 VECADD(vec,vec,mvert->co);
1047 VECADD(nor,nor,mvert->no);
1049 mvert=dm->getVertData(dm,mface->v3,CD_MVERT);
1050 VECADD(vec,vec,mvert->co);
1051 VECADD(nor,nor,mvert->no);
1054 mvert=dm->getVertData(dm,mface->v4,CD_MVERT);
1055 VECADD(vec,vec,mvert->co);
1056 VECADD(nor,nor,mvert->no);
1058 mul_v3_fl(vec,0.25);
1061 mul_v3_fl(vec,0.3333f);
1065 BLI_kdtree_insert(edit->emitter_field, i, vec, NULL);
1068 BLI_kdtree_balance(edit->emitter_field);
1071 static void PE_update_selection(Scene *scene, Object *ob, int useflag)
1073 PTCacheEdit *edit= PE_get_current(scene, ob);
1077 /* flag all particles to be updated if not using flag */
1080 point->flag |= PEP_EDIT_RECALC;
1082 /* flush edit key flag to hair key flag to preserve selection
1084 if(edit->psys) LOOP_POINTS {
1085 hkey = edit->psys->particles[p].hair;
1087 hkey->editflag= key->flag;
1092 psys_cache_edit_paths(scene, ob, edit, CFRA);
1095 /* disable update flag */
1097 point->flag &= ~PEP_EDIT_RECALC;
1100 static void update_world_cos(Object *ob, PTCacheEdit *edit)
1102 ParticleSystem *psys = edit->psys;
1103 ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
1105 float hairmat[4][4];
1107 if(psys==0 || psys->edit==0 || psmd->dm==NULL)
1111 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1112 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat);
1115 VECCOPY(key->world_co,key->co);
1116 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1117 mul_m4_v3(hairmat, key->world_co);
1121 static void update_velocities(Object *ob, PTCacheEdit *edit)
1123 /*TODO: get frs_sec properly */
1124 float vec1[3], vec2[3], frs_sec, dfra;
1127 /* hair doesn't use velocities */
1128 if(edit->psys || !edit->points || !edit->points->keys->vel)
1131 frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
1133 LOOP_EDITED_POINTS {
1136 dfra = *(key+1)->time - *key->time;
1141 VECSUB(key->vel, (key+1)->co, key->co);
1143 if(point->totkey>2) {
1144 VECSUB(vec1, (key+1)->co, (key+2)->co);
1145 project_v3_v3v3(vec2, vec1, key->vel);
1146 VECSUB(vec2, vec1, vec2);
1147 VECADDFAC(key->vel, key->vel, vec2, 0.5f);
1150 else if(k==point->totkey-1) {
1151 dfra = *key->time - *(key-1)->time;
1156 VECSUB(key->vel, key->co, (key-1)->co);
1158 if(point->totkey>2) {
1159 VECSUB(vec1, (key-2)->co, (key-1)->co);
1160 project_v3_v3v3(vec2, vec1, key->vel);
1161 VECSUB(vec2, vec1, vec2);
1162 VECADDFAC(key->vel, key->vel, vec2, 0.5f);
1166 dfra = *(key+1)->time - *(key-1)->time;
1171 VECSUB(key->vel, (key+1)->co, (key-1)->co);
1173 mul_v3_fl(key->vel, frs_sec/dfra);
1178 void PE_update_object(Scene *scene, Object *ob, int useflag)
1180 /* use this to do partial particle updates, not usable when adding or
1181 removing, then a full redo is necessary and calling this may crash */
1182 ParticleEditSettings *pset= PE_settings(scene);
1183 PTCacheEdit *edit = PE_get_current(scene, ob);
1189 /* flag all particles to be updated if not using flag */
1192 point->flag |= PEP_EDIT_RECALC;
1195 /* do post process on particle edit keys */
1196 pe_iterate_lengths(scene, edit);
1197 pe_deflect_emitter(scene, ob, edit);
1198 PE_apply_lengths(scene, edit);
1199 if(pset->flag & PE_X_MIRROR)
1200 PE_apply_mirror(ob,edit->psys);
1202 update_world_cos(ob, edit);
1203 if(pset->flag & PE_AUTO_VELOCITY)
1204 update_velocities(ob, edit);
1205 PE_hide_keys_time(scene, edit, CFRA);
1207 /* regenerate path caches */
1208 psys_cache_edit_paths(scene, ob, edit, CFRA);
1210 /* disable update flag */
1212 point->flag &= ~PEP_EDIT_RECALC;
1216 edit->psys->flag &= ~PSYS_HAIR_UPDATED;
1219 /************************************************/
1220 /* Edit Selections */
1221 /************************************************/
1223 /*-----selection callbacks-----*/
1225 static void select_key(PEData *data, int point_index, int key_index)
1227 PTCacheEdit *edit = data->edit;
1228 PTCacheEditPoint *point = edit->points + point_index;
1229 PTCacheEditKey *key = point->keys + key_index;
1232 key->flag |= PEK_SELECT;
1234 key->flag &= ~PEK_SELECT;
1236 point->flag |= PEP_EDIT_RECALC;
1239 static void select_keys(PEData *data, int point_index, int key_index)
1241 PTCacheEdit *edit = data->edit;
1242 PTCacheEditPoint *point = edit->points + point_index;
1247 key->flag |= PEK_SELECT;
1249 key->flag &= ~PEK_SELECT;
1252 point->flag |= PEP_EDIT_RECALC;
1255 static void toggle_key_select(PEData *data, int point_index, int key_index)
1257 PTCacheEdit *edit = data->edit;
1258 PTCacheEditPoint *point = edit->points + point_index;
1259 PTCacheEditKey *key = point->keys + key_index;
1261 key->flag ^= PEK_SELECT;
1262 point->flag |= PEP_EDIT_RECALC;
1265 /************************ de select all operator ************************/
1267 static int select_all_exec(bContext *C, wmOperator *op)
1269 Scene *scene= CTX_data_scene(C);
1270 Object *ob= CTX_data_active_object(C);
1271 PTCacheEdit *edit= PE_get_current(scene, ob);
1273 int action = RNA_enum_get(op->ptr, "action");
1275 if (action == SEL_TOGGLE) {
1276 action = SEL_SELECT;
1277 LOOP_VISIBLE_POINTS {
1278 LOOP_SELECTED_KEYS {
1279 action = SEL_DESELECT;
1283 if (action == SEL_DESELECT)
1288 LOOP_VISIBLE_POINTS {
1292 if ((key->flag & PEK_SELECT) == 0) {
1293 key->flag |= PEK_SELECT;
1294 point->flag |= PEP_EDIT_RECALC;
1298 if (key->flag & PEK_SELECT) {
1299 key->flag &= ~PEK_SELECT;
1300 point->flag |= PEP_EDIT_RECALC;
1304 if ((key->flag & PEK_SELECT) == 0) {
1305 key->flag |= PEK_SELECT;
1306 point->flag |= PEP_EDIT_RECALC;
1308 key->flag &= ~PEK_SELECT;
1309 point->flag |= PEP_EDIT_RECALC;
1316 PE_update_selection(scene, ob, 1);
1317 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1319 return OPERATOR_FINISHED;
1322 void PARTICLE_OT_select_all(wmOperatorType *ot)
1325 ot->name= "Selection of all particles";
1326 ot->idname= "PARTICLE_OT_select_all";
1329 ot->exec= select_all_exec;
1333 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1335 WM_operator_properties_select_all(ot);
1338 /************************ pick select operator ************************/
1340 int PE_mouse_particles(bContext *C, short *mval, int extend)
1343 Scene *scene= CTX_data_scene(C);
1344 Object *ob= CTX_data_active_object(C);
1345 PTCacheEdit *edit= PE_get_current(scene, ob);
1348 if(!PE_start_edit(edit))
1349 return OPERATOR_CANCELLED;
1352 LOOP_VISIBLE_POINTS {
1353 LOOP_SELECTED_KEYS {
1354 key->flag &= ~PEK_SELECT;
1355 point->flag |= PEP_EDIT_RECALC;
1360 PE_set_view3d_data(C, &data);
1364 for_mouse_hit_keys(&data, toggle_key_select, 1); /* nearest only */
1366 PE_update_selection(scene, ob, 1);
1367 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1369 return OPERATOR_FINISHED;
1372 /************************ select first operator ************************/
1374 static void select_root(PEData *data, int point_index)
1376 data->edit->points[point_index].keys->flag |= PEK_SELECT;
1377 data->edit->points[point_index].flag |= PEP_EDIT_RECALC; /* redraw selection only */
1380 static int select_first_exec(bContext *C, wmOperator *op)
1384 PE_set_data(C, &data);
1385 foreach_point(&data, select_root);
1387 PE_update_selection(data.scene, data.ob, 1);
1388 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1390 return OPERATOR_FINISHED;
1393 void PARTICLE_OT_select_first(wmOperatorType *ot)
1396 ot->name= "Select First";
1397 ot->idname= "PARTICLE_OT_select_first";
1400 ot->exec= select_first_exec;
1404 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1407 /************************ select last operator ************************/
1409 static void select_tip(PEData *data, int point_index)
1411 PTCacheEditPoint *point = data->edit->points + point_index;
1412 point->keys[point->totkey - 1].flag |= PEK_SELECT;
1413 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1416 static int select_last_exec(bContext *C, wmOperator *op)
1420 PE_set_data(C, &data);
1421 foreach_point(&data, select_tip);
1423 PE_update_selection(data.scene, data.ob, 1);
1424 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1426 return OPERATOR_FINISHED;
1429 void PARTICLE_OT_select_last(wmOperatorType *ot)
1432 ot->name= "Select Last";
1433 ot->idname= "PARTICLE_OT_select_last";
1436 ot->exec= select_last_exec;
1440 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1443 /************************ select linked operator ************************/
1445 static int select_linked_exec(bContext *C, wmOperator *op)
1451 RNA_int_get_array(op->ptr, "location", location);
1452 mval[0]= location[0];
1453 mval[1]= location[1];
1455 view3d_operator_needs_opengl(C);
1457 PE_set_view3d_data(C, &data);
1460 data.select= !RNA_boolean_get(op->ptr, "deselect");
1462 for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */
1463 PE_update_selection(data.scene, data.ob, 1);
1464 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1466 return OPERATOR_FINISHED;
1469 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
1471 ARegion *ar= CTX_wm_region(C);
1474 location[0]= event->x - ar->winrct.xmin;
1475 location[1]= event->y - ar->winrct.ymin;
1476 RNA_int_set_array(op->ptr, "location", location);
1478 return select_linked_exec(C, op);
1481 void PARTICLE_OT_select_linked(wmOperatorType *ot)
1484 ot->name= "Select Linked";
1485 ot->idname= "PARTICLE_OT_select_linked";
1488 ot->exec= select_linked_exec;
1489 ot->invoke= select_linked_invoke;
1490 ot->poll= PE_poll_3dview;
1493 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1496 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them.");
1497 RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
1500 /************************ border select operator ************************/
1502 int PE_border_select(bContext *C, rcti *rect, int select, int extend)
1504 Scene *scene= CTX_data_scene(C);
1505 Object *ob= CTX_data_active_object(C);
1506 PTCacheEdit *edit= PE_get_current(scene, ob);
1509 if(!PE_start_edit(edit))
1510 return OPERATOR_CANCELLED;
1512 if (extend == 0 && select) {
1515 LOOP_VISIBLE_POINTS {
1516 LOOP_SELECTED_KEYS {
1517 key->flag &= ~PEK_SELECT;
1518 point->flag |= PEP_EDIT_RECALC;
1523 PE_set_view3d_data(C, &data);
1525 data.select= select;
1527 for_mouse_hit_keys(&data, select_key, 0);
1529 PE_update_selection(scene, ob, 1);
1530 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1532 return OPERATOR_FINISHED;
1535 /************************ circle select operator ************************/
1537 int PE_circle_select(bContext *C, int selecting, short *mval, float rad)
1539 Scene *scene= CTX_data_scene(C);
1540 Object *ob= CTX_data_active_object(C);
1541 PTCacheEdit *edit= PE_get_current(scene, ob);
1544 if(!PE_start_edit(edit))
1545 return OPERATOR_FINISHED;
1547 PE_set_view3d_data(C, &data);
1550 data.select= selecting;
1552 for_mouse_hit_keys(&data, select_key, 0);
1554 PE_update_selection(scene, ob, 1);
1555 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1557 return OPERATOR_FINISHED;
1560 /************************ lasso select operator ************************/
1562 int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
1564 Scene *scene= CTX_data_scene(C);
1565 Object *ob= CTX_data_active_object(C);
1566 ARegion *ar= CTX_wm_region(C);
1567 ParticleEditSettings *pset= PE_settings(scene);
1568 PTCacheEdit *edit = PE_get_current(scene, ob);
1569 ParticleSystem *psys = edit->psys;
1570 ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
1572 float co[3], mat[4][4];
1575 if(!PE_start_edit(edit))
1576 return OPERATOR_CANCELLED;
1580 LOOP_VISIBLE_POINTS {
1581 if(edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
1582 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + p, mat);
1584 if(pset->selectmode==SCE_SELECT_POINT) {
1586 VECCOPY(co, key->co);
1588 project_short(ar, co, vertco);
1589 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
1590 if(select && !(key->flag & PEK_SELECT)) {
1591 key->flag |= PEK_SELECT;
1592 point->flag |= PEP_EDIT_RECALC;
1594 else if(key->flag & PEK_SELECT) {
1595 key->flag &= ~PEK_SELECT;
1596 point->flag |= PEP_EDIT_RECALC;
1601 else if(pset->selectmode==SCE_SELECT_END) {
1602 key= point->keys + point->totkey - 1;
1604 VECCOPY(co, key->co);
1606 project_short(ar, co,vertco);
1607 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
1608 if(select && !(key->flag & PEK_SELECT)) {
1609 key->flag |= PEK_SELECT;
1610 point->flag |= PEP_EDIT_RECALC;
1612 else if(key->flag & PEK_SELECT) {
1613 key->flag &= ~PEK_SELECT;
1614 point->flag |= PEP_EDIT_RECALC;
1620 PE_update_selection(scene, ob, 1);
1621 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1623 return OPERATOR_FINISHED;
1626 /*************************** hide operator **************************/
1628 static int hide_exec(bContext *C, wmOperator *op)
1630 Object *ob= CTX_data_active_object(C);
1631 Scene *scene= CTX_data_scene(C);
1632 PTCacheEdit *edit= PE_get_current(scene, ob);
1635 if(RNA_enum_get(op->ptr, "unselected")) {
1636 LOOP_UNSELECTED_POINTS {
1637 point->flag |= PEP_HIDE;
1638 point->flag |= PEP_EDIT_RECALC;
1641 key->flag &= ~PEK_SELECT;
1645 LOOP_SELECTED_POINTS {
1646 point->flag |= PEP_HIDE;
1647 point->flag |= PEP_EDIT_RECALC;
1650 key->flag &= ~PEK_SELECT;
1654 PE_update_selection(scene, ob, 1);
1655 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1657 return OPERATOR_FINISHED;
1660 void PARTICLE_OT_hide(wmOperatorType *ot)
1663 ot->name= "Hide Selected";
1664 ot->idname= "PARTICLE_OT_hide";
1667 ot->exec= hide_exec;
1671 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1674 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1677 /*************************** reveal operator **************************/
1679 static int reveal_exec(bContext *C, wmOperator *op)
1681 Object *ob= CTX_data_active_object(C);
1682 Scene *scene= CTX_data_scene(C);
1683 PTCacheEdit *edit= PE_get_current(scene, ob);
1687 if(point->flag & PEP_HIDE) {
1688 point->flag &= ~PEP_HIDE;
1689 point->flag |= PEP_EDIT_RECALC;
1692 key->flag |= PEK_SELECT;
1696 PE_update_selection(scene, ob, 1);
1697 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1699 return OPERATOR_FINISHED;
1702 void PARTICLE_OT_reveal(wmOperatorType *ot)
1706 ot->idname= "PARTICLE_OT_reveal";
1709 ot->exec= reveal_exec;
1713 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1716 /************************ select less operator ************************/
1718 static void select_less_keys(PEData *data, int point_index)
1720 PTCacheEdit *edit= data->edit;
1721 PTCacheEditPoint *point = edit->points + point_index;
1724 LOOP_SELECTED_KEYS {
1726 if(((key+1)->flag&PEK_SELECT)==0)
1727 key->flag |= PEK_TAG;
1729 else if(k==point->totkey-1) {
1730 if(((key-1)->flag&PEK_SELECT)==0)
1731 key->flag |= PEK_TAG;
1734 if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
1735 key->flag |= PEK_TAG;
1740 if(key->flag&PEK_TAG) {
1741 key->flag &= ~(PEK_TAG|PEK_SELECT);
1742 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1747 static int select_less_exec(bContext *C, wmOperator *op)
1751 PE_set_data(C, &data);
1752 foreach_point(&data, select_less_keys);
1754 PE_update_selection(data.scene, data.ob, 1);
1755 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1757 return OPERATOR_FINISHED;
1760 void PARTICLE_OT_select_less(wmOperatorType *ot)
1763 ot->name= "Select Less";
1764 ot->idname= "PARTICLE_OT_select_less";
1767 ot->exec= select_less_exec;
1771 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1774 /************************ select more operator ************************/
1776 static void select_more_keys(PEData *data, int point_index)
1778 PTCacheEdit *edit= data->edit;
1779 PTCacheEditPoint *point = edit->points + point_index;
1783 if(key->flag & PEK_SELECT) continue;
1786 if((key+1)->flag&PEK_SELECT)
1787 key->flag |= PEK_TAG;
1789 else if(k==point->totkey-1) {
1790 if((key-1)->flag&PEK_SELECT)
1791 key->flag |= PEK_TAG;
1794 if(((key-1)->flag | (key+1)->flag) & PEK_SELECT)
1795 key->flag |= PEK_TAG;
1800 if(key->flag&PEK_TAG) {
1801 key->flag &= ~PEK_TAG;
1802 key->flag |= PEK_SELECT;
1803 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1808 static int select_more_exec(bContext *C, wmOperator *op)
1812 PE_set_data(C, &data);
1813 foreach_point(&data, select_more_keys);
1815 PE_update_selection(data.scene, data.ob, 1);
1816 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1818 return OPERATOR_FINISHED;
1821 void PARTICLE_OT_select_more(wmOperatorType *ot)
1824 ot->name= "Select More";
1825 ot->idname= "PARTICLE_OT_select_more";
1828 ot->exec= select_more_exec;
1832 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1835 static int select_inverse_exec(bContext *C, wmOperator *op)
1841 PE_set_data(C, &data);
1843 edit= PE_get_current(data.scene, data.ob);
1845 LOOP_VISIBLE_POINTS {
1847 key->flag ^= PEK_SELECT;
1848 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1852 PE_update_selection(data.scene, data.ob, 1);
1853 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1855 return OPERATOR_FINISHED;
1858 void PARTICLE_OT_select_inverse(wmOperatorType *ot)
1861 ot->name= "Select Inverse";
1862 ot->idname= "PARTICLE_OT_select_inverse";
1865 ot->exec= select_inverse_exec;
1869 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1872 /************************ rekey operator ************************/
1874 static void rekey_particle(PEData *data, int pa_index)
1876 PTCacheEdit *edit= data->edit;
1877 ParticleSystem *psys= edit->psys;
1878 ParticleSimulationData sim = {data->scene, data->ob, edit->psys, NULL};
1879 ParticleData *pa= psys->particles + pa_index;
1880 PTCacheEditPoint *point = edit->points + pa_index;
1882 HairKey *key, *new_keys, *okey;
1883 PTCacheEditKey *ekey;
1884 float dval, sta, end;
1887 pa->flag |= PARS_REKEY;
1889 key= new_keys= MEM_callocN(data->totrekey * sizeof(HairKey),"Hair re-key keys");
1892 /* root and tip stay the same */
1893 VECCOPY(key->co, okey->co);
1894 VECCOPY((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co);
1896 sta= key->time= okey->time;
1897 end= (key + data->totrekey - 1)->time= (okey + pa->totkey - 1)->time;
1898 dval= (end - sta) / (float)(data->totrekey - 1);
1900 /* interpolate new keys from old ones */
1901 for(k=1,key++; k<data->totrekey-1; k++,key++) {
1902 state.time= (float)k / (float)(data->totrekey-1);
1903 psys_get_particle_on_path(&sim, pa_index, &state, 0);
1904 VECCOPY(key->co, state.co);
1905 key->time= sta + k * dval;
1910 MEM_freeN(pa->hair);
1913 point->totkey=pa->totkey=data->totrekey;
1917 MEM_freeN(point->keys);
1918 ekey= point->keys= MEM_callocN(pa->totkey * sizeof(PTCacheEditKey),"Hair re-key edit keys");
1920 for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
1922 ekey->time= &key->time;
1923 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1924 ekey->flag |= PEK_USE_WCO;
1927 pa->flag &= ~PARS_REKEY;
1928 point->flag |= PEP_EDIT_RECALC;
1931 static int rekey_exec(bContext *C, wmOperator *op)
1935 PE_set_data(C, &data);
1937 data.dval= 1.0f / (float)(data.totrekey-1);
1938 data.totrekey= RNA_int_get(op->ptr, "keys");
1940 foreach_selected_point(&data, rekey_particle);
1942 recalc_lengths(data.edit);
1943 PE_update_object(data.scene, data.ob, 1);
1944 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob);
1946 return OPERATOR_FINISHED;
1949 void PARTICLE_OT_rekey(wmOperatorType *ot)
1953 ot->idname= "PARTICLE_OT_rekey";
1956 ot->exec= rekey_exec;
1957 ot->invoke= WM_operator_props_popup;
1961 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1964 RNA_def_int(ot->srna, "keys", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
1967 static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time)
1969 PTCacheEdit *edit= PE_get_current(scene, ob);
1970 ParticleSystem *psys;
1971 ParticleSimulationData sim = {scene, ob, edit ? edit->psys : NULL, NULL};
1974 HairKey *new_keys, *key;
1975 PTCacheEditKey *ekey;
1978 if(!edit || !edit->psys) return;
1982 pa= psys->particles + pa_index;
1984 pa->flag |= PARS_REKEY;
1986 key= new_keys= MEM_dupallocN(pa->hair);
1988 /* interpolate new keys from old ones (roots stay the same) */
1989 for(k=1, key++; k < pa->totkey; k++, key++) {
1990 state.time= path_time * (float)k / (float)(pa->totkey-1);
1991 psys_get_particle_on_path(&sim, pa_index, &state, 0);
1992 VECCOPY(key->co, state.co);
1995 /* replace hair keys */
1997 MEM_freeN(pa->hair);
2000 /* update edit pointers */
2001 for(k=0, key=pa->hair, ekey=edit->points[pa_index].keys; k<pa->totkey; k++, key++, ekey++) {
2003 ekey->time= &key->time;
2006 pa->flag &= ~PARS_REKEY;
2009 /************************* utilities **************************/
2011 static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psys)
2013 PTCacheEdit *edit = psys->edit;
2014 ParticleEditSettings *pset= PE_settings(scene);
2015 ParticleData *pa, *npa=0, *new_pars=0;
2017 PTCacheEditPoint *npoint=0, *new_points=0;
2018 ParticleSystemModifierData *psmd;
2019 int i, totpart, new_totpart= psys->totpart, removed= 0;
2021 if(pset->flag & PE_X_MIRROR) {
2023 psmd= psys_get_modifier(ob, psys);
2024 totpart= psys->totpart;
2026 LOOP_TAGGED_POINTS {
2027 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
2031 LOOP_TAGGED_POINTS {
2036 if(new_totpart != psys->totpart) {
2038 npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
2039 npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
2042 pa= psys->particles;
2043 point= edit->points;
2044 for(i=0; i<psys->totpart; i++, pa++, point++) {
2045 if(point->flag & PEP_TAG) {
2047 MEM_freeN(point->keys);
2049 MEM_freeN(pa->hair);
2052 memcpy(npa, pa, sizeof(ParticleData));
2053 memcpy(npoint, point, sizeof(PTCacheEditPoint));
2059 if(psys->particles) MEM_freeN(psys->particles);
2060 psys->particles= new_pars;
2062 if(edit->points) MEM_freeN(edit->points);
2063 edit->points= new_points;
2065 if(edit->mirror_cache) {
2066 MEM_freeN(edit->mirror_cache);
2067 edit->mirror_cache= NULL;
2071 MEM_freeN(psys->child);
2076 edit->totpoint= psys->totpart= new_totpart;
2082 static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
2084 PTCacheEdit *edit= psys->edit;
2085 ParticleEditSettings *pset= PE_settings(scene);
2087 HairKey *hkey, *nhkey, *new_hkeys=0;
2089 ParticleSystemModifierData *psmd;
2092 if(pset->flag & PE_X_MIRROR) {
2093 /* mirror key tags */
2094 psmd= psys_get_modifier(ob, psys);
2098 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
2105 new_totkey= point->totkey;
2109 /* we can't have elements with less than two keys*/
2111 point->flag |= PEP_TAG;
2113 remove_tagged_particles(scene, ob, psys);
2116 pa = psys->particles + p;
2117 new_totkey= pa->totkey;
2123 if(new_totkey != pa->totkey) {
2125 nhkey= new_hkeys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
2128 while(key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
2133 if(hkey < pa->hair + pa->totkey) {
2134 VECCOPY(nhkey->co, hkey->co);
2135 nhkey->time= hkey->time;
2136 nhkey->weight= hkey->weight;
2142 MEM_freeN(pa->hair);
2144 pa->hair= new_hkeys;
2146 point->totkey= pa->totkey= new_totkey;
2149 MEM_freeN(point->keys);
2150 key= point->keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys");
2155 key->time= &hkey->time;
2162 /************************ subdivide opertor *********************/
2164 /* works like normal edit mode subdivide, inserts keys between neighbouring selected keys */
2165 static void subdivide_particle(PEData *data, int pa_index)
2167 PTCacheEdit *edit= data->edit;
2168 ParticleSystem *psys= edit->psys;
2169 ParticleSimulationData sim = {data->scene, data->ob, edit->psys, NULL};
2170 ParticleData *pa= psys->particles + pa_index;
2171 PTCacheEditPoint *point = edit->points + pa_index;
2173 HairKey *key, *nkey, *new_keys;
2174 PTCacheEditKey *ekey, *nekey, *new_ekeys;
2180 for(k=0, ekey=point->keys; k<pa->totkey-1; k++,ekey++) {
2181 if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
2185 if(totnewkey==0) return;
2187 pa->flag |= PARS_REKEY;
2189 nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys");
2190 nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(PTCacheEditKey)),"Hair subdivide edit keys");
2193 endtime= key[pa->totkey-1].time;
2195 for(k=0, ekey=point->keys; k<pa->totkey-1; k++, key++, ekey++) {
2197 memcpy(nkey,key,sizeof(HairKey));
2198 memcpy(nekey,ekey,sizeof(PTCacheEditKey));
2200 nekey->co= nkey->co;
2201 nekey->time= &nkey->time;
2206 if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) {
2207 nkey->time= (key->time + (key+1)->time)*0.5f;
2208 state.time= (endtime != 0.0f)? nkey->time/endtime: 0.0f;
2209 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2210 VECCOPY(nkey->co, state.co);
2212 nekey->co= nkey->co;
2213 nekey->time= &nkey->time;
2214 nekey->flag |= PEK_SELECT;
2215 if(!(psys->flag & PSYS_GLOBAL_HAIR))
2216 nekey->flag |= PEK_USE_WCO;
2222 /*tip still not copied*/
2223 memcpy(nkey,key,sizeof(HairKey));
2224 memcpy(nekey,ekey,sizeof(PTCacheEditKey));
2226 nekey->co= nkey->co;
2227 nekey->time= &nkey->time;
2230 MEM_freeN(pa->hair);
2234 MEM_freeN(point->keys);
2235 point->keys= new_ekeys;
2237 point->totkey = pa->totkey = pa->totkey + totnewkey;
2238 point->flag |= PEP_EDIT_RECALC;
2239 pa->flag &= ~PARS_REKEY;
2242 static int subdivide_exec(bContext *C, wmOperator *op)
2246 PE_set_data(C, &data);
2247 foreach_point(&data, subdivide_particle);
2249 recalc_lengths(data.edit);
2250 PE_update_object(data.scene, data.ob, 1);
2251 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob);
2253 return OPERATOR_FINISHED;
2256 void PARTICLE_OT_subdivide(wmOperatorType *ot)
2259 ot->name= "Subdivide";
2260 ot->idname= "PARTICLE_OT_subdivide";
2263 ot->exec= subdivide_exec;
2267 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2270 /************************ remove doubles opertor *********************/
2272 static int remove_doubles_exec(bContext *C, wmOperator *op)
2274 Scene *scene= CTX_data_scene(C);
2275 Object *ob= CTX_data_active_object(C);
2276 ParticleEditSettings *pset=PE_settings(scene);
2277 PTCacheEdit *edit= PE_get_current(scene, ob);
2278 ParticleSystem *psys = edit->psys;
2279 ParticleSystemModifierData *psmd;
2281 KDTreeNearest nearest[10];
2283 float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
2284 int n, totn, removed, flag, totremoved;
2286 if(psys->flag & PSYS_GLOBAL_HAIR)
2287 return OPERATOR_CANCELLED;
2290 psmd= psys_get_modifier(ob, psys);
2296 tree=BLI_kdtree_new(psys->totpart);
2298 /* insert particles into kd tree */
2299 LOOP_SELECTED_POINTS {
2300 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
2301 VECCOPY(co, point->keys->co);
2303 BLI_kdtree_insert(tree, p, co, NULL);
2306 BLI_kdtree_balance(tree);
2308 /* tag particles to be removed */
2309 LOOP_SELECTED_POINTS {
2310 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
2311 VECCOPY(co, point->keys->co);
2314 totn= BLI_kdtree_find_n_nearest(tree,10,co,NULL,nearest);
2316 for(n=0; n<totn; n++) {
2317 /* this needs a custom threshold still */
2318 if(nearest[n].index > p && nearest[n].dist < threshold) {
2319 if(!(point->flag & PEP_TAG)) {
2320 point->flag |= PEP_TAG;
2327 BLI_kdtree_free(tree);
2329 /* remove tagged particles - don't do mirror here! */
2331 pset->flag &= ~PE_X_MIRROR;
2332 remove_tagged_particles(scene, ob, psys);
2334 totremoved += removed;
2338 return OPERATOR_CANCELLED;
2340 BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved);
2342 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
2343 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
2345 return OPERATOR_FINISHED;
2348 void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
2351 ot->name= "Remove Doubles";
2352 ot->idname= "PARTICLE_OT_remove_doubles";
2355 ot->exec= remove_doubles_exec;
2359 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2362 RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
2365 /************************ cursor drawing *******************************/
2367 static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
2369 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2370 ParticleBrushData *brush;
2372 if(pset->brushtype < 0)
2375 brush= &pset->brush[pset->brushtype];
2380 glTranslatef((float)x, (float)y, 0.0f);
2382 glColor4ub(255, 255, 255, 128);
2383 glEnable(GL_LINE_SMOOTH );
2385 glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
2386 glDisable(GL_BLEND);
2387 glDisable(GL_LINE_SMOOTH );
2393 static void toggle_particle_cursor(bContext *C, int enable)
2395 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2397 if(pset->paintcursor && !enable) {
2398 WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
2399 pset->paintcursor = NULL;
2402 pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_3dview, brush_drawcursor, NULL);
2405 /********************* radial control operator *********************/
2407 static int brush_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
2409 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2410 ParticleBrushData *brush;
2411 int mode = RNA_enum_get(op->ptr, "mode");
2412 float original_value=1.0f;
2414 if(pset->brushtype < 0)
2415 return OPERATOR_CANCELLED;
2417 brush= &pset->brush[pset->brushtype];
2419 toggle_particle_cursor(C, 0);
2421 if(mode == WM_RADIALCONTROL_SIZE)
2422 original_value = brush->size;
2423 else if(mode == WM_RADIALCONTROL_STRENGTH)
2424 original_value = brush->strength;
2426 RNA_float_set(op->ptr, "initial_value", original_value);
2428 return WM_radial_control_invoke(C, op, event);
2431 static int brush_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
2433 int ret = WM_radial_control_modal(C, op, event);
2435 if(ret != OPERATOR_RUNNING_MODAL)
2436 toggle_particle_cursor(C, 1);
2441 static int brush_radial_control_exec(bContext *C, wmOperator *op)
2443 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2444 ParticleBrushData *brush;
2445 int mode = RNA_enum_get(op->ptr, "mode");
2446 float new_value = RNA_float_get(op->ptr, "new_value");
2448 if(pset->brushtype < 0)
2449 return OPERATOR_CANCELLED;
2451 brush= &pset->brush[pset->brushtype];
2453 if(mode == WM_RADIALCONTROL_SIZE)
2454 brush->size= new_value;
2455 else if(mode == WM_RADIALCONTROL_STRENGTH)
2456 brush->strength= new_value;
2458 return OPERATOR_FINISHED;
2461 void PARTICLE_OT_brush_radial_control(wmOperatorType *ot)
2463 WM_OT_radial_control_partial(ot);
2465 ot->name= "Brush Radial Control";
2466 ot->idname= "PARTICLE_OT_brush_radial_control";
2468 ot->invoke= brush_radial_control_invoke;
2469 ot->modal= brush_radial_control_modal;
2470 ot->exec= brush_radial_control_exec;
2474 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
2477 /*************************** delete operator **************************/
2479 enum { DEL_PARTICLE, DEL_KEY };
2481 static EnumPropertyItem delete_type_items[]= {
2482 {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
2483 {DEL_KEY, "KEY", 0, "Key", ""},
2484 {0, NULL, 0, NULL, NULL}};
2486 static void set_delete_particle(PEData *data, int pa_index)
2488 PTCacheEdit *edit= data->edit;
2490 edit->points[pa_index].flag |= PEP_TAG;
2493 static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
2495 PTCacheEdit *edit= data->edit;
2497 edit->points[pa_index].keys[key_index].flag |= PEK_TAG;
2500 static int delete_exec(bContext *C, wmOperator *op)
2503 int type= RNA_enum_get(op->ptr, "type");
2505 PE_set_data(C, &data);
2507 if(type == DEL_KEY) {
2508 foreach_selected_key(&data, set_delete_particle_key);
2509 remove_tagged_keys(data.scene, data.ob, data.edit->psys);
2510 recalc_lengths(data.edit);
2512 else if(type == DEL_PARTICLE) {
2513 foreach_selected_point(&data, set_delete_particle);
2514 remove_tagged_particles(data.scene, data.ob, data.edit->psys);
2515 recalc_lengths(data.edit);
2518 DAG_id_flush_update(&data.ob->id, OB_RECALC_DATA);
2519 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob);
2521 return OPERATOR_FINISHED;
2524 void PARTICLE_OT_delete(wmOperatorType *ot)
2528 ot->idname= "PARTICLE_OT_delete";
2531 ot->exec= delete_exec;
2532 ot->invoke= WM_menu_invoke;
2533 ot->poll= PE_hair_poll;
2536 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2539 RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys.");
2542 /*************************** mirror operator **************************/
2544 static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
2546 Mesh *me= (Mesh*)(ob->data);
2547 ParticleSystemModifierData *psmd;
2548 PTCacheEdit *edit= PE_get_current(scene, ob);
2549 ParticleSystem *psys = edit->psys;
2550 ParticleData *pa, *newpa, *new_pars;
2551 PTCacheEditPoint *newpoint, *new_points;
2555 int rotation, totpart, newtotpart;
2557 if(psys->flag & PSYS_GLOBAL_HAIR)
2560 psmd= psys_get_modifier(ob, psys);
2564 mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
2566 if(!edit->mirror_cache)
2567 PE_update_mirror_cache(ob, psys);
2569 totpart= psys->totpart;
2570 newtotpart= psys->totpart;
2571 LOOP_VISIBLE_POINTS {
2572 pa = psys->particles + p;
2574 if(point_is_selected(point)) {
2575 if(edit->mirror_cache[p] != -1) {
2576 /* already has a mirror, don't need to duplicate */
2577 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
2581 point->flag |= PEP_TAG;
2585 if((point->flag & PEP_TAG) && mirrorfaces[pa->num*2] != -1)
2589 if(newtotpart != psys->totpart) {
2590 /* allocate new arrays and copy existing */
2591 new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
2592 new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
2594 if(psys->particles) {
2595 memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
2596 MEM_freeN(psys->particles);
2598 psys->particles= new_pars;
2601 memcpy(new_points, edit->points, totpart*sizeof(PTCacheEditPoint));
2602 MEM_freeN(edit->points);
2604 edit->points= new_points;
2606 if(edit->mirror_cache) {
2607 MEM_freeN(edit->mirror_cache);
2608 edit->mirror_cache= NULL;
2611 edit->totpoint= psys->totpart= newtotpart;
2613 /* create new elements */
2614 newpa= psys->particles + totpart;
2615 newpoint= edit->points + totpart;
2617 LOOP_VISIBLE_POINTS {
2618 pa = psys->particles + p;
2620 if(!(point->flag & PEP_TAG) || mirrorfaces[pa->num*2] == -1)
2626 if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
2627 if(point->keys) newpoint->keys= MEM_dupallocN(point->keys);
2629 /* rotate weights according to vertex index rotation */
2630 rotation= mirrorfaces[pa->num*2+1];
2631 newpa->fuv[0]= pa->fuv[2];
2632 newpa->fuv[1]= pa->fuv[1];
2633 newpa->fuv[2]= pa->fuv[0];
2634 newpa->fuv[3]= pa->fuv[3];
2635 while(rotation-- > 0)
2636 if(me->mface[pa->num].v4)
2637 SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
2639 SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
2641 /* assign face inddex */
2642 newpa->num= mirrorfaces[pa->num*2];
2643 newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
2645 /* update edit key pointers */
2646 key= newpoint->keys;
2647 for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, key++) {
2649 key->time= &hkey->time;
2652 /* map key positions as mirror over x axis */
2653 PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
2661 point->flag &= ~PEP_TAG;
2664 MEM_freeN(mirrorfaces);
2667 static int mirror_exec(bContext *C, wmOperator *op)
2669 Scene *scene= CTX_data_scene(C);
2670 Object *ob= CTX_data_active_object(C);
2671 PTCacheEdit *edit= PE_get_current(scene, ob);
2673 PE_mirror_x(scene, ob, 0);
2675 update_world_cos(ob, edit);
2676 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
2677 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
2679 return OPERATOR_FINISHED;
2682 void PARTICLE_OT_mirror(wmOperatorType *ot)
2686 ot->idname= "PARTICLE_OT_mirror";
2689 ot->exec= mirror_exec;
2693 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2696 /*********************** set brush operator **********************/
2698 static EnumPropertyItem brush_type_items[]= {
2699 {PE_BRUSH_NONE, "NONE", 0, "None", ""},
2700 {PE_BRUSH_COMB, "COMB", 0, "Comb", ""},
2701 {PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", ""},
2702 {PE_BRUSH_ADD, "ADD", 0, "Add", ""},
2703 {PE_BRUSH_LENGTH, "LENGTH", 0, "Length", ""},
2704 {PE_BRUSH_PUFF, "PUFF", 0, "Puff", ""},
2705 {PE_BRUSH_CUT, "CUT", 0, "Cut", ""},
2706 {0, NULL, 0, NULL, NULL}
2709 static int set_brush_exec(bContext *C, wmOperator *op)
2711 Scene *scene= CTX_data_scene(C);
2712 ParticleEditSettings *pset= PE_settings(scene);
2714 pset->brushtype= RNA_enum_get(op->ptr, "type");
2716 return OPERATOR_FINISHED;
2719 void PARTICLE_OT_brush_set(wmOperatorType *ot)
2722 ot->name= "Set Brush";
2723 ot->idname= "PARTICLE_OT_brush_set";
2726 ot->exec= set_brush_exec;
2727 ot->invoke= WM_menu_invoke;
2731 RNA_def_enum(ot->srna, "type", brush_type_items, PE_BRUSH_NONE, "Type", "Brush type to select for editing.");
2735 /*********************** set mode operator **********************/
2737 static EnumPropertyItem edit_type_items[]= {
2738 {PE_TYPE_PARTICLES, "PARTICLES", 0, "Particles", ""},
2739 {PE_TYPE_SOFTBODY, "SOFTBODY", 0, "Soft body", ""},
2740 {PE_TYPE_CLOTH, "CLOTH", 0, "Cloth", ""},
2741 {0, NULL, 0, NULL, NULL}
2744 static int set_edit_mode_exec(bContext *C, wmOperator *op)
2746 Scene *scene= CTX_data_scene(C);
2747 ParticleEditSettings *pset= PE_settings(scene);
2749 pset->edittype= RNA_enum_get(op->ptr, "type");
2751 return OPERATOR_FINISHED;
2754 void PARTICLE_OT_edit_type_set(wmOperatorType *ot)
2757 ot->name= "Set Edit Type";
2758 ot->idname= "PARTICLE_OT_edit_type_set";
2761 ot->exec= set_edit_mode_exec;
2762 ot->invoke= WM_menu_invoke;
2766 RNA_def_enum(ot->srna, "type", edit_type_items, PE_TYPE_PARTICLES, "Type", "Edit type to select for editing.");
2769 /************************* brush edit callbacks ********************/
2771 static void brush_comb(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
2773 ParticleEditSettings *pset= PE_settings(data->scene);
2776 if(pset->flag & PE_LOCK_FIRST && key_index == 0) return;
2778 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
2780 VECCOPY(cvec,data->dvec);
2781 mul_mat3_m4_v3(imat,cvec);
2782 mul_v3_fl(cvec, fac);
2783 VECADD(key->co, key->co, cvec);
2785 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
2788 static void brush_cut(PEData *data, int pa_index)
2790 PTCacheEdit *edit = data->edit;
2791 ARegion *ar= data->vc.ar;
2792 Object *ob= data->ob;
2793 ParticleEditSettings *pset= PE_settings(data->scene);
2794 ParticleCacheKey *key= edit->pathcache[pa_index];
2795 float rad2, cut_time= 1.0;
2796 float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
2797 int k, cut, keys= (int)pow(2.0, (double)pset->draw_step);
2800 /* blunt scissors */
2801 if(BLI_frand() > data->cutfac) return;
2803 /* don't cut hidden */
2804 if(edit->points[pa_index].flag & PEP_HIDE)
2807 rad2= data->rad * data->rad;
2811 project_short_noclip(ar, key->co, vertco);
2812 x0= (float)vertco[0];
2813 x1= (float)vertco[1];
2815 o0= (float)data->mval[0];
2816 o1= (float)data->mval[1];
2821 /* check if root is inside circle */
2822 if(xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) {
2827 /* calculate path time closest to root that was inside the circle */
2828 for(k=1, key++; k<=keys; k++, key++) {
2829 project_short_noclip(ar, key->co, vertco);
2831 if(key_test_depth(data, key->co) == 0) {
2832 x0= (float)vertco[0];
2833 x1= (float)vertco[1];
2840 v0= (float)vertco[0] - x0;
2841 v1= (float)vertco[1] - x1;
2845 d= (v0*xo1 - v1*xo0);
2852 cut_time= -(v0*xo0 + v1*xo1 + d);
2854 if(cut_time > 0.0f) {
2857 if(cut_time < 1.0f) {
2858 cut_time += (float)(k-1);
2859 cut_time /= (float)keys;
2866 x0= (float)vertco[0];
2867 x1= (float)vertco[1];
2875 if(cut_time < 0.0f) {
2876 edit->points[pa_index].flag |= PEP_TAG;
2879 rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
2880 edit->points[pa_index].flag |= PEP_EDIT_RECALC;
2885 static void brush_length(PEData *data, int point_index)
2887 PTCacheEdit *edit= data->edit;
2888 PTCacheEditPoint *point = edit->points + point_index;
2890 float dvec[3],pvec[3] = {0.0f, 0.0f, 0.0f};
2894 VECCOPY(pvec,key->co);
2897 VECSUB(dvec,key->co,pvec);
2898 VECCOPY(pvec,key->co);
2899 mul_v3_fl(dvec,data->growfac);
2900 VECADD(key->co,(key-1)->co,dvec);
2904 point->flag |= PEP_EDIT_RECALC;
2907 static void brush_puff(PEData *data, int point_index)
2909 PTCacheEdit *edit = data->edit;
2910 ParticleSystem *psys = edit->psys;
2911 PTCacheEditPoint *point = edit->points + point_index;
2913 float mat[4][4], imat[4][4];
2914 float lastco[3], rootco[3] = {0.0f, 0.0f, 0.0f}, co[3], nor[3], kco[3], dco[3], fac=0.0f, length=0.0f;
2916 if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
2917 psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
2918 invert_m4_m4(imat,mat);
2927 /* find root coordinate and normal on emitter */
2928 VECCOPY(co, key->co);
2931 point_index= BLI_kdtree_find_nearest(edit->emitter_field, co, NULL, NULL);
2932 if(point_index == -1) return;
2934 VECCOPY(rootco, co);
2935 copy_v3_v3(nor, &edit->emitter_cosnos[point_index*6+3]);
2939 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac);
2945 /* compute position as if hair was standing up straight */
2946 VECCOPY(lastco, co);
2947 VECCOPY(co, key->co);
2949 length += len_v3v3(lastco, co);
2951 VECADDFAC(kco, rootco, nor, length);
2953 /* blend between the current and straight position */
2954 VECSUB(dco, kco, co);
2955 VECADDFAC(co, co, dco, fac);
2957 VECCOPY(key->co, co);
2958 mul_m4_v3(imat, key->co);
2962 point->flag |= PEP_EDIT_RECALC;
2965 static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
2970 sub_v3_v3v3(dvec,key->co,(key-1)->co);
2971 mul_mat3_m4_v3(mat,dvec);
2972 VECADD(data->vec,data->vec,dvec);
2977 static void brush_smooth_do(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
2979 float vec[3], dvec[3];
2982 VECCOPY(vec,data->vec);
2983 mul_mat3_m4_v3(imat,vec);
2985 sub_v3_v3v3(dvec,key->co,(key-1)->co);
2987 VECSUB(dvec,vec,dvec);
2988 mul_v3_fl(dvec,data->smoothfac);
2990 VECADD(key->co,key->co,dvec);
2993 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
2996 static int brush_add(PEData *data, short number)
2998 Scene *scene= data->scene;
2999 Object *ob= data->ob;
3000 PTCacheEdit *edit = data->edit;
3001 ParticleSystem *psys= edit->psys;
3002 ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add");
3003 ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
3004 ParticleSimulationData sim = {scene, ob, psys, psmd};
3005 ParticleEditSettings *pset= PE_settings(scene);
3006 int i, k, n= 0, totpart= psys->totpart;
3008 short dmx= 0, dmy= 0;
3009 float co1[3], co2[3], min_d, imat[4][4];
3010 float framestep, timestep= psys_get_timestep(&sim);
3011 short size= pset->brush[PE_BRUSH_ADD].size;
3012 short size2= size*size;
3014 invert_m4_m4(imat,ob->obmat);
3016 if(psys->flag & PSYS_GLOBAL_HAIR)
3019 BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
3021 /* painting onto the deformed mesh, could be an option? */
3022 if(psmd->dm->deformedOnly)
3025 dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
3027 for(i=0; i<number; i++) {
3030 while(dmx*dmx+dmy*dmy>size2) {
3031 dmx=(short)((2.0f*BLI_frand()-1.0f)*size);
3032 dmy=(short)((2.0f*BLI_frand()-1.0f)*size);
3036 mco[0]= data->mval[0] + dmx;
3037 mco[1]= data->mval[1] + dmy;
3038 viewline(data->vc.ar, data->vc.v3d, mco, co1, co2);
3040 mul_m4_v3(imat,co1);
3041 mul_m4_v3(imat,co2);
3044 /* warning, returns the derived mesh face */
3045 if(psys_intersect_dm(scene, ob,dm,0,co1,co2,&min_d,&add_pars[n].num,add_pars[n].fuv,0,0,0,0)) {
3046 add_pars[n].num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,add_pars[n].num,add_pars[n].fuv,NULL);
3051 int newtotpart=totpart+n;
3052 float hairmat[4][4], cur_co[3];
3054 ParticleData *pa, *new_pars= MEM_callocN(newtotpart*sizeof(ParticleData),"ParticleData new");
3055 PTCacheEditPoint *point, *new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint),"PTCacheEditPoint array new");
3056 PTCacheEditKey *key;
3059 /* save existing elements */
3060 memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
3061 memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint));
3063 /* change old arrays to new ones */
3064 if(psys->particles) MEM_freeN(psys->particles);
3065 psys->particles= new_pars;
3067 if(edit->points) MEM_freeN(edit->points);
3068 edit->points= new_points;
3070 if(edit->mirror_cache) {
3071 MEM_freeN(edit->mirror_cache);
3072 edit->mirror_cache= NULL;
3075 /* create tree for interpolation */
3076 if(pset->flag & PE_INTERPOLATE_ADDED && psys->totpart) {
3077 tree=BLI_kdtree_new(psys->totpart);
3079 for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
3080 psys_particle_on_dm(psmd->dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,cur_co,0,0,0,0,0);
3081 BLI_kdtree_insert(tree, i, cur_co, NULL);
3084 BLI_kdtree_balance(tree);
3087 edit->totpoint= psys->totpart= newtotpart;
3089 /* create new elements */
3090 pa= psys->particles + totpart;
3091 point= edit->points + totpart;
3093 for(i=totpart; i<newtotpart; i++, pa++, point++) {
3094 memcpy(pa, add_pars + i - totpart, sizeof(ParticleData));
3095 pa->hair= MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add");
3096 key= point->keys= MEM_callocN(pset->totaddkey * sizeof(PTCacheEditKey), "PTCacheEditKey add");
3097 point->totkey= pa->totkey= pset->totaddkey;
3099 for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++) {
3101 key->time= &hkey->time;
3103 if(!(psys->flag & PSYS_GLOBAL_HAIR))
3104 key->flag |= PEK_USE_WCO;
3108 initialize_particle(&sim, pa,i);
3109 reset_particle(&sim, pa, 0.0, 1.0);
3110 point->flag |= PEP_EDIT_RECALC;
3111 if(pset->flag & PE_X_MIRROR)
3112 point->flag |= PEP_TAG; /* signal for duplicate */
3114 framestep= pa->lifetime/(float)(pset->totaddkey-1);
3119 KDTreeNearest ptn[3];
3121 float maxd, mind, dd, totw=0.0, weight[3];
3123 psys_particle_on_dm(psmd->dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,0,0);
3124 maxw= BLI_kdtree_find_n_nearest(tree,3,co1,NULL,ptn);
3126 maxd= ptn[maxw-1].dist;
3130 for(w=0; w<maxw; w++) {
3131 weight[w]= (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
3138 for(w=0; w<maxw; w++)
3141 for(k=0; k<pset->totaddkey; k++) {
3142 hkey= (HairKey*)pa->hair + k;
3143 hkey->time= pa->time + k * framestep;
3145 key[0].time= hkey->time/ 100.0f;
3146 psys_get_particle_on_path(&sim, ptn[0].index, key, 0);
3147 mul_v3_fl(key[0].co, weight[0]);
3150 key[1].time= key[0].time;
3151 psys_get_particle_on_path(&sim, ptn[1].index, key + 1, 0);
3152 mul_v3_fl(key[1].co, weight[1]);
3153 VECADD(key[0].co, key[0].co, key[1].co);
3156 key[2].time= key[0].time;
3157 psys_get_particle_on_path(&sim, ptn[2].index, key + 2, 0);
3158 mul_v3_fl(key[2].co, weight[2]);
3159 VECADD(key[0].co, key[0].co, key[2].co);
3164 VECSUB(co1, pa->state.co, key[0].co);
3166 VECADD(hkey->co, key[0].co, co1);
3168 hkey->time= key[0].time;
3172 for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
3173 VECADDFAC(hkey->co, pa->state.co, pa->state.vel, k * framestep * timestep);
3174 hkey->time += k * framestep;
3177 for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
3178 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
3179 invert_m4_m4(imat,hairmat);
3180 mul_m4_v3(imat, hkey->co);
3185 BLI_kdtree_free(tree);
3188 MEM_freeN(add_pars);
3190 if(!psmd->dm->deformedOnly)
3196 /************************* brush edit operator ********************/
3198 typedef struct BrushEdit {
3207 static int brush_edit_init(bContext *C, wmOperator *op)
3209 Scene *scene= CTX_data_scene(C);
3210 Object *ob= CTX_data_active_object(C);
3211 ParticleEditSettings *pset= PE_settings(scene);
3212 PTCacheEdit *edit= PE_get_current(scene, ob);
3213 ARegion *ar= CTX_wm_region(C);
3216 if(pset->brushtype < 0)
3219 initgrabz(ar->regiondata, ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]);
3221 bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit");
3223 op->customdata= bedit;
3225 bedit->scene= scene;
3232 static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
3234 BrushEdit *bedit= op->customdata;
3235 Scene *scene= bedit->scene;
3236 Object *ob= bedit->ob;
3237 PTCacheEdit *edit= bedit->edit;
3238 ParticleEditSettings *pset= PE_settings(scene);
3239 ParticleSystemModifierData *psmd= edit->psys ? psys_get_modifier(ob, edit->psys) : NULL;
3240 ParticleBrushData *brush= &pset->brush[pset->brushtype];
3241 ARegion *ar= CTX_wm_region(C);
3242 float vec[3], mousef[2];
3243 short mval[2], mvalo[2];
3244 int flip, mouse[2], dx, dy, removed= 0, added=0, selected= 0;
3245 int lock_root = pset->flag & PE_LOCK_FIRST;
3247 if(!PE_start_edit(edit))
3250 RNA_float_get_array(itemptr, "mouse", mousef);
3251 mouse[0] = mousef[0];
3252 mouse[1] = mousef[1];
3253 flip= RNA_boolean_get(itemptr, "flip");
3256 bedit->lastmouse[0]= mouse[0];
3257 bedit->lastmouse[1]= mouse[1];
3260 dx= mouse[0] - bedit->lastmouse[0];
3261 dy= mouse[1] - bedit->lastmouse[1];
3266 mvalo[0]= bedit->lastmouse[0];
3267 mvalo[1]= bedit->lastmouse[1];
3269 /* disable locking temporatily for disconnected hair */
3270 if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
3271 pset->flag &= ~PE_LOCK_FIRST;