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);
91 static void recalc_emitter_field(Object *ob, ParticleSystem *psys);
93 #define KEY_K PTCacheEditKey *key; int k
94 #define POINT_P PTCacheEditPoint *point; int p
95 #define LOOP_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++)
96 #define LOOP_VISIBLE_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!(point->flag & PEP_HIDE))
97 #define LOOP_SELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point_is_selected(point))
98 #define LOOP_UNSELECTED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(!point_is_selected(point))
99 #define LOOP_EDITED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_EDIT_RECALC)
100 #define LOOP_TAGGED_POINTS for(p=0, point=edit->points; p<edit->totpoint; p++, point++) if(point->flag & PEP_TAG)
101 #define LOOP_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++)
102 #define LOOP_VISIBLE_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(!(key->flag & PEK_HIDE))
103 #define LOOP_SELECTED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
104 #define LOOP_TAGGED_KEYS for(k=0, key=point->keys; k<point->totkey; k++, key++) if(key->flag & PEK_TAG)
106 #define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co)
108 /**************************** utilities *******************************/
110 int PE_poll(bContext *C)
112 Scene *scene= CTX_data_scene(C);
113 Object *ob= CTX_data_active_object(C);
115 if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
118 return (PE_get_current(scene, ob) != NULL);
121 int PE_hair_poll(bContext *C)
123 Scene *scene= CTX_data_scene(C);
124 Object *ob= CTX_data_active_object(C);
127 if(!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
130 edit= PE_get_current(scene, ob);
132 return (edit && edit->psys);
135 int PE_poll_3dview(bContext *C)
137 return PE_poll(C) && CTX_wm_area(C)->spacetype == SPACE_VIEW3D &&
138 CTX_wm_region(C)->regiontype == RGN_TYPE_WINDOW;
141 void PE_free_ptcache_edit(PTCacheEdit *edit)
147 PTCacheUndo_clear(edit);
152 MEM_freeN(point->keys);
155 MEM_freeN(edit->points);
158 if(edit->mirror_cache)
159 MEM_freeN(edit->mirror_cache);
161 if(edit->emitter_cosnos) {
162 MEM_freeN(edit->emitter_cosnos);
163 edit->emitter_cosnos= 0;
166 if(edit->emitter_field) {
167 BLI_kdtree_free(edit->emitter_field);
168 edit->emitter_field= 0;
171 psys_free_path_cache(NULL, edit);
176 /************************************************/
177 /* Edit Mode Helpers */
178 /************************************************/
180 int PE_start_edit(PTCacheEdit *edit)
185 edit->psys->flag |= PSYS_EDITED;
192 ParticleEditSettings *PE_settings(Scene *scene)
194 return &scene->toolsettings->particle;
197 /* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set
199 * note: this function runs on poll, therefor it can runs many times a second
201 static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
203 ParticleEditSettings *pset= PE_settings(scene);
204 PTCacheEdit *edit = NULL;
214 BKE_ptcache_ids_from_object(&pidlist, ob);
216 /* in the case of only one editable thing, set pset->edittype accordingly */
217 if(pidlist.first && pidlist.first == pidlist.last) {
220 case PTCACHE_TYPE_PARTICLES:
221 pset->edittype = PE_TYPE_PARTICLES;
223 case PTCACHE_TYPE_SOFTBODY:
224 pset->edittype = PE_TYPE_SOFTBODY;
226 case PTCACHE_TYPE_CLOTH:
227 pset->edittype = PE_TYPE_CLOTH;
232 for(pid=pidlist.first; pid; pid=pid->next) {
233 if(pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) {
234 ParticleSystem *psys = pid->calldata;
236 if(psys->flag & PSYS_CURRENT) {
237 if(psys->part && psys->part->type == PART_HAIR) {
238 if(psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
239 if(create && !psys->pointcache->edit)
240 PE_create_particle_edit(scene, ob, pid->cache, NULL);
241 edit = pid->cache->edit;
244 if(create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
245 PE_create_particle_edit(scene, ob, NULL, psys);
250 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
251 PE_create_particle_edit(scene, ob, pid->cache, psys);
252 edit = pid->cache->edit;
258 else if(pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
259 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
260 PE_create_particle_edit(scene, ob, pid->cache, NULL);
261 edit = pid->cache->edit;
264 else if(pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
265 if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
266 PE_create_particle_edit(scene, ob, pid->cache, NULL);
267 edit = pid->cache->edit;
275 BLI_freelistN(&pidlist);
280 PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
282 return pe_get_current(scene, ob, 0);
285 PTCacheEdit *PE_create_current(Scene *scene, Object *ob)
287 return pe_get_current(scene, ob, 1);
290 void PE_current_changed(Scene *scene, Object *ob)
292 if(ob->mode == OB_MODE_PARTICLE_EDIT)
293 PE_create_current(scene, ob);
296 void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
298 ParticleEditSettings *pset=PE_settings(scene);
302 if(pset->flag & PE_FADE_TIME && pset->selectmode==SCE_SELECT_POINT) {
305 if(fabs(cfra-*key->time) < pset->fade_frames)
306 key->flag &= ~PEK_HIDE;
308 key->flag |= PEK_HIDE;
309 //key->flag &= ~PEK_SELECT;
317 key->flag &= ~PEK_HIDE;
323 static int pe_x_mirror(Object *ob)
325 if(ob->type == OB_MESH)
326 return (((Mesh*)ob->data)->editflag & ME_EDIT_MIRROR_X);
331 /****************** common struct passed to callbacks ******************/
333 typedef struct PEData {
363 static void PE_set_data(bContext *C, PEData *data)
365 memset(data, 0, sizeof(*data));
367 data->scene= CTX_data_scene(C);
368 data->ob= CTX_data_active_object(C);
369 data->edit= PE_get_current(data->scene, data->ob);
372 static void PE_set_view3d_data(bContext *C, PEData *data)
374 PE_set_data(C, data);
376 view3d_set_viewcontext(C, &data->vc);
377 view3d_get_transformation(data->vc.ar, data->vc.rv3d, data->ob, &data->mats);
379 if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT))
380 view3d_validate_backbuf(&data->vc);
383 /*************************** selection utilities *******************************/
385 static int key_test_depth(PEData *data, float co[3])
387 View3D *v3d= data->vc.v3d;
393 if((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
396 project_short(data->vc.ar, co, wco);
398 if(wco[0] == IS_CLIPPED)
401 gluProject(co[0],co[1],co[2], data->mats.modelview, data->mats.projection,
402 (GLint *)data->mats.viewport, &ux, &uy, &uz);
407 x+= (short)data->vc.ar->winrct.xmin;
408 y+= (short)data->vc.ar->winrct.ymin;
410 view3d_validate_backbuf(&data->vc);
411 glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
413 if((float)uz - 0.0001 > depth)
419 static int key_inside_circle(PEData *data, float rad, float co[3], float *distance)
424 project_short(data->vc.ar, co, sco);
426 if(sco[0] == IS_CLIPPED)
429 dx= data->mval[0] - sco[0];
430 dy= data->mval[1] - sco[1];
431 dist= sqrt(dx*dx + dy*dy);
436 if(key_test_depth(data, co)) {
446 static int key_inside_rect(PEData *data, float co[3])
450 project_short(data->vc.ar, co,sco);
452 if(sco[0] == IS_CLIPPED)
455 if(sco[0] > data->rect->xmin && sco[0] < data->rect->xmax &&
456 sco[1] > data->rect->ymin && sco[1] < data->rect->ymax)
457 return key_test_depth(data, co);
462 static int key_inside_test(PEData *data, float co[3])
465 return key_inside_circle(data, data->rad, co, NULL);
467 return key_inside_rect(data, co);
470 static int point_is_selected(PTCacheEditPoint *point)
475 if(point->flag & PEP_HIDE)
487 /*************************** iterators *******************************/
489 typedef void (*ForPointFunc)(PEData *data, int point_index);
490 typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index);
491 typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key);
493 static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
495 ParticleEditSettings *pset= PE_settings(data->scene);
496 PTCacheEdit *edit= data->edit;
498 int nearest_point, nearest_key;
499 float dist= data->rad;
501 /* in path select mode we have no keys */
502 if(pset->selectmode==SCE_SELECT_PATH)
508 LOOP_VISIBLE_POINTS {
509 if(pset->selectmode == SCE_SELECT_END) {
510 /* only do end keys */
511 key= point->keys + point->totkey-1;
514 if(key_inside_circle(data, dist, KEY_WCO, &dist)) {
516 nearest_key= point->totkey-1;
519 else if(key_inside_test(data, KEY_WCO))
520 func(data, p, point->totkey-1);
526 if(key_inside_circle(data, dist, KEY_WCO, &dist)) {
531 else if(key_inside_test(data, KEY_WCO))
537 /* do nearest only */
538 if(nearest && nearest_point > -1)
539 func(data, nearest_point, nearest_key);
542 static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected)
544 ParticleEditSettings *pset= PE_settings(data->scene);
545 PTCacheEdit *edit= data->edit;
548 /* all is selected in path mode */
549 if(pset->selectmode==SCE_SELECT_PATH)
552 LOOP_VISIBLE_POINTS {
553 if(pset->selectmode==SCE_SELECT_END) {
554 /* only do end keys */
555 key= point->keys + point->totkey - 1;
557 if(selected==0 || key->flag & PEK_SELECT)
558 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
564 if(selected==0 || key->flag & PEK_SELECT) {
565 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
575 static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
577 PTCacheEdit *edit = data->edit;
578 ParticleSystem *psys = edit->psys;
579 ParticleSystemModifierData *psmd = NULL;
580 ParticleEditSettings *pset= PE_settings(data->scene);
582 float mat[4][4], imat[4][4];
585 psmd= psys_get_modifier(data->ob, edit->psys);
587 /* all is selected in path mode */
588 if(pset->selectmode==SCE_SELECT_PATH)
594 LOOP_VISIBLE_POINTS {
595 if(pset->selectmode==SCE_SELECT_END) {
596 /* only do end keys */
597 key= point->keys + point->totkey-1;
599 if(selected==0 || key->flag & PEK_SELECT) {
600 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
601 if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
602 psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
603 invert_m4_m4(imat,mat);
606 func(data, mat, imat, p, point->totkey-1, key);
613 if(selected==0 || key->flag & PEK_SELECT) {
614 if(key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
615 if(edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
616 psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, psys->particles + p, mat);
617 invert_m4_m4(imat,mat);
620 func(data, mat, imat, p, k, key);
628 static void foreach_selected_point(PEData *data, ForPointFunc func)
630 PTCacheEdit *edit = data->edit;
633 LOOP_SELECTED_POINTS {
638 static void foreach_selected_key(PEData *data, ForKeyFunc func)
640 PTCacheEdit *edit = data->edit;
643 LOOP_VISIBLE_POINTS {
650 static void foreach_point(PEData *data, ForPointFunc func)
652 PTCacheEdit *edit = data->edit;
660 static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
662 ParticleEditSettings *pset= PE_settings(scene);
666 LOOP_VISIBLE_POINTS {
667 if(pset->selectmode==SCE_SELECT_POINT) {
672 else if(pset->selectmode==SCE_SELECT_END) {
673 key = point->keys + point->totkey - 1;
674 if(key->flag & PEK_SELECT)
682 /************************************************/
683 /* Particle Edit Mirroring */
684 /************************************************/
686 static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
689 ParticleSystemModifierData *psmd;
691 KDTreeNearest nearest;
694 float mat[4][4], co[3];
698 psmd= psys_get_modifier(ob, psys);
699 totpart= psys->totpart;
704 tree= BLI_kdtree_new(totpart);
706 /* insert particles into kd tree */
709 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
710 VECCOPY(co, key->co);
712 BLI_kdtree_insert(tree, p, co, NULL);
715 BLI_kdtree_balance(tree);
717 /* lookup particles and set in mirror cache */
718 if(!edit->mirror_cache)
719 edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
723 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
724 VECCOPY(co, key->co);
728 index= BLI_kdtree_find_nearest(tree, co, NULL, &nearest);
730 /* this needs a custom threshold still, duplicated for editmode mirror */
731 if(index != -1 && index != p && (nearest.dist <= 0.0002f))
732 edit->mirror_cache[p]= index;
734 edit->mirror_cache[p]= -1;
737 /* make sure mirrors are in two directions */
739 if(edit->mirror_cache[p]) {
740 index= edit->mirror_cache[p];
741 if(edit->mirror_cache[index] != p)
742 edit->mirror_cache[p]= -1;
746 BLI_kdtree_free(tree);
749 static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
751 HairKey *hkey, *mhkey;
752 PTCacheEditPoint *point, *mpoint;
753 PTCacheEditKey *key, *mkey;
755 float mat[4][4], mmat[4][4], immat[4][4];
759 i= pa - psys->particles;
761 /* find mirrored particle if needed */
763 if(!edit->mirror_cache)
764 PE_update_mirror_cache(ob, psys);
766 mi= edit->mirror_cache[i];
769 mpa= psys->particles + mi;
772 mi= mpa - psys->particles;
774 point = edit->points + i;
775 mpoint = edit->points + mi;
777 /* make sure they have the same amount of keys */
778 if(pa->totkey != mpa->totkey) {
779 if(mpa->hair) MEM_freeN(mpa->hair);
780 if(mpoint->keys) MEM_freeN(mpoint->keys);
782 mpa->hair= MEM_dupallocN(pa->hair);
783 mpoint->keys= MEM_dupallocN(point->keys);
784 mpoint->totkey= point->totkey;
788 for(k=0; k<mpa->totkey; k++, mkey++, mhkey++) {
790 mkey->time= &mhkey->time;
791 mkey->flag &= PEK_SELECT;
795 /* mirror positions and tags */
796 psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
797 psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
798 invert_m4_m4(immat, mmat);
804 for(k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
805 VECCOPY(mhkey->co, hkey->co);
806 mul_m4_v3(mat, mhkey->co);
807 mhkey->co[0]= -mhkey->co[0];
808 mul_m4_v3(immat, mhkey->co);
810 if(key->flag & PEK_TAG)
811 mkey->flag |= PEK_TAG;
814 if(point->flag & PEP_TAG)
815 mpoint->flag |= PEP_TAG;
816 if(point->flag & PEP_EDIT_RECALC)
817 mpoint->flag |= PEP_EDIT_RECALC;
820 static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
823 ParticleSystemModifierData *psmd;
830 psmd= psys_get_modifier(ob, psys);
832 if(!edit->mirror_cache || !psmd->dm)
835 /* we delay settings the PARS_EDIT_RECALC for mirrored particles
836 * to avoid doing mirror twice */
838 if(point->flag & PEP_EDIT_RECALC) {
839 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
841 if(edit->mirror_cache[p] != -1)
842 edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
847 if(point->flag & PEP_EDIT_RECALC)
848 if(edit->mirror_cache[p] != -1)
849 edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
853 /************************************************/
854 /* Edit Calculation */
855 /************************************************/
856 /* tries to stop edited particles from going through the emitter's surface */
857 static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
859 ParticleEditSettings *pset= PE_settings(scene);
860 ParticleSystem *psys;
861 ParticleSystemModifierData *psmd;
864 float *vec, *nor, dvec[3], dot, dist_1st=0.0f;
865 float hairimat[4][4], hairmat[4][4];
867 if(edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0 || (edit->psys->flag & PSYS_GLOBAL_HAIR))
871 psmd = psys_get_modifier(ob,psys);
877 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles + p, hairmat);
880 mul_m4_v3(hairmat, key->co);
885 dist_1st = len_v3v3((key+1)->co, key->co);
886 dist_1st *= 0.75f * pset->emitterdist;
889 index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL);
891 vec=edit->emitter_cosnos +index*6;
894 sub_v3_v3v3(dvec, key->co, vec);
896 dot=dot_v3v3(dvec,nor);
902 mul_v3_fl(dvec,dist_1st-dot);
903 add_v3_v3v3(key->co,key->co,dvec);
908 mul_v3_fl(dvec,dist_1st-dot);
909 add_v3_v3v3(key->co,key->co,dvec);
916 invert_m4_m4(hairimat,hairmat);
919 mul_m4_v3(hairimat, key->co);
923 /* force set distances between neighbouring keys */
924 void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
927 ParticleEditSettings *pset=PE_settings(scene);
931 if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
934 if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
940 sub_v3_v3v3(dv1, key->co, (key - 1)->co);
942 mul_v3_fl(dv1, (key - 1)->length);
943 add_v3_v3v3(key->co, (key - 1)->co, dv1);
948 /* try to find a nice solution to keep distances between neighbouring keys */
949 static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
951 ParticleEditSettings *pset=PE_settings(scene);
956 float dv0[3]= {0.0f, 0.0f, 0.0f};
957 float dv1[3]= {0.0f, 0.0f, 0.0f};
958 float dv2[3]= {0.0f, 0.0f, 0.0f};
960 if(edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
963 if(edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
967 for(j=1; j<point->totkey; j++) {
968 float mul= 1.0f / (float)point->totkey;
970 if(pset->flag & PE_LOCK_FIRST) {
971 key= point->keys + 1;
973 dv1[0]= dv1[1]= dv1[2]= 0.0;
978 dv0[0]= dv0[1]= dv0[2]= 0.0;
981 for(; k<point->totkey; k++, key++) {
983 sub_v3_v3v3(dv0, (key - 1)->co, key->co);
984 tlen= normalize_v3(dv0);
985 mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
988 if(k < point->totkey - 1) {
989 sub_v3_v3v3(dv2, (key + 1)->co, key->co);
990 tlen= normalize_v3(dv2);
991 mul_v3_fl(dv2, mul * (tlen - key->length));
995 add_v3_v3v3((key-1)->co,(key-1)->co,dv1);
1003 /* set current distances to be kept between neighbouting keys */
1004 static void recalc_lengths(PTCacheEdit *edit)
1011 LOOP_EDITED_POINTS {
1013 for(k=0; k<point->totkey-1; k++, key++) {
1014 key->length= len_v3v3(key->co, (key + 1)->co);
1019 /* calculate a tree for finding nearest emitter's vertice */
1020 static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
1022 DerivedMesh *dm=psys_get_modifier(ob,psys)->dm;
1023 PTCacheEdit *edit= psys->edit;
1027 int i, totface, totvert;
1032 if(edit->emitter_cosnos)
1033 MEM_freeN(edit->emitter_cosnos);
1035 BLI_kdtree_free(edit->emitter_field);
1037 totface=dm->getNumFaces(dm);
1038 totvert=dm->getNumVerts(dm);
1040 edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos");
1042 edit->emitter_field= BLI_kdtree_new(totface);
1044 vec=edit->emitter_cosnos;
1047 mvert=dm->getVertDataArray(dm,CD_MVERT);
1048 for(i=0; i<totface; i++, vec+=6, nor+=6) {
1049 mface=dm->getFaceData(dm,i,CD_MFACE);
1051 mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
1052 VECCOPY(vec,mvert->co);
1053 VECCOPY(nor,mvert->no);
1055 mvert=dm->getVertData(dm,mface->v2,CD_MVERT);
1056 VECADD(vec,vec,mvert->co);
1057 VECADD(nor,nor,mvert->no);
1059 mvert=dm->getVertData(dm,mface->v3,CD_MVERT);
1060 VECADD(vec,vec,mvert->co);
1061 VECADD(nor,nor,mvert->no);
1064 mvert=dm->getVertData(dm,mface->v4,CD_MVERT);
1065 VECADD(vec,vec,mvert->co);
1066 VECADD(nor,nor,mvert->no);
1068 mul_v3_fl(vec,0.25);
1071 mul_v3_fl(vec,0.3333f);
1075 BLI_kdtree_insert(edit->emitter_field, i, vec, NULL);
1078 BLI_kdtree_balance(edit->emitter_field);
1081 static void PE_update_selection(Scene *scene, Object *ob, int useflag)
1083 PTCacheEdit *edit= PE_get_current(scene, ob);
1087 /* flag all particles to be updated if not using flag */
1090 point->flag |= PEP_EDIT_RECALC;
1092 /* flush edit key flag to hair key flag to preserve selection
1094 if(edit->psys) LOOP_POINTS {
1095 hkey = edit->psys->particles[p].hair;
1097 hkey->editflag= key->flag;
1102 psys_cache_edit_paths(scene, ob, edit, CFRA);
1105 /* disable update flag */
1107 point->flag &= ~PEP_EDIT_RECALC;
1110 static void update_world_cos(Object *ob, PTCacheEdit *edit)
1112 ParticleSystem *psys = edit->psys;
1113 ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
1115 float hairmat[4][4];
1117 if(psys==0 || psys->edit==0 || psmd->dm==NULL)
1121 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1122 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles+p, hairmat);
1125 VECCOPY(key->world_co,key->co);
1126 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1127 mul_m4_v3(hairmat, key->world_co);
1131 static void update_velocities(Object *ob, PTCacheEdit *edit)
1133 /*TODO: get frs_sec properly */
1134 float vec1[3], vec2[3], frs_sec, dfra;
1137 /* hair doesn't use velocities */
1138 if(edit->psys || !edit->points || !edit->points->keys->vel)
1141 frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
1143 LOOP_EDITED_POINTS {
1146 dfra = *(key+1)->time - *key->time;
1151 VECSUB(key->vel, (key+1)->co, key->co);
1153 if(point->totkey>2) {
1154 VECSUB(vec1, (key+1)->co, (key+2)->co);
1155 project_v3_v3v3(vec2, vec1, key->vel);
1156 VECSUB(vec2, vec1, vec2);
1157 VECADDFAC(key->vel, key->vel, vec2, 0.5f);
1160 else if(k==point->totkey-1) {
1161 dfra = *key->time - *(key-1)->time;
1166 VECSUB(key->vel, key->co, (key-1)->co);
1168 if(point->totkey>2) {
1169 VECSUB(vec1, (key-2)->co, (key-1)->co);
1170 project_v3_v3v3(vec2, vec1, key->vel);
1171 VECSUB(vec2, vec1, vec2);
1172 VECADDFAC(key->vel, key->vel, vec2, 0.5f);
1176 dfra = *(key+1)->time - *(key-1)->time;
1181 VECSUB(key->vel, (key+1)->co, (key-1)->co);
1183 mul_v3_fl(key->vel, frs_sec/dfra);
1188 void PE_update_object(Scene *scene, Object *ob, int useflag)
1190 /* use this to do partial particle updates, not usable when adding or
1191 removing, then a full redo is necessary and calling this may crash */
1192 ParticleEditSettings *pset= PE_settings(scene);
1193 PTCacheEdit *edit = PE_get_current(scene, ob);
1199 /* flag all particles to be updated if not using flag */
1202 point->flag |= PEP_EDIT_RECALC;
1205 /* do post process on particle edit keys */
1206 pe_iterate_lengths(scene, edit);
1207 pe_deflect_emitter(scene, ob, edit);
1208 PE_apply_lengths(scene, edit);
1210 PE_apply_mirror(ob,edit->psys);
1212 update_world_cos(ob, edit);
1213 if(pset->flag & PE_AUTO_VELOCITY)
1214 update_velocities(ob, edit);
1215 PE_hide_keys_time(scene, edit, CFRA);
1217 /* regenerate path caches */
1218 psys_cache_edit_paths(scene, ob, edit, CFRA);
1220 /* disable update flag */
1222 point->flag &= ~PEP_EDIT_RECALC;
1226 edit->psys->flag &= ~PSYS_HAIR_UPDATED;
1229 /************************************************/
1230 /* Edit Selections */
1231 /************************************************/
1233 /*-----selection callbacks-----*/
1235 static void select_key(PEData *data, int point_index, int key_index)
1237 PTCacheEdit *edit = data->edit;
1238 PTCacheEditPoint *point = edit->points + point_index;
1239 PTCacheEditKey *key = point->keys + key_index;
1242 key->flag |= PEK_SELECT;
1244 key->flag &= ~PEK_SELECT;
1246 point->flag |= PEP_EDIT_RECALC;
1249 static void select_keys(PEData *data, int point_index, int key_index)
1251 PTCacheEdit *edit = data->edit;
1252 PTCacheEditPoint *point = edit->points + point_index;
1257 key->flag |= PEK_SELECT;
1259 key->flag &= ~PEK_SELECT;
1262 point->flag |= PEP_EDIT_RECALC;
1265 static void toggle_key_select(PEData *data, int point_index, int key_index)
1267 PTCacheEdit *edit = data->edit;
1268 PTCacheEditPoint *point = edit->points + point_index;
1269 PTCacheEditKey *key = point->keys + key_index;
1271 key->flag ^= PEK_SELECT;
1272 point->flag |= PEP_EDIT_RECALC;
1275 /************************ de select all operator ************************/
1277 static int select_all_exec(bContext *C, wmOperator *op)
1279 Scene *scene= CTX_data_scene(C);
1280 Object *ob= CTX_data_active_object(C);
1281 PTCacheEdit *edit= PE_get_current(scene, ob);
1283 int action = RNA_enum_get(op->ptr, "action");
1285 if (action == SEL_TOGGLE) {
1286 action = SEL_SELECT;
1287 LOOP_VISIBLE_POINTS {
1288 LOOP_SELECTED_KEYS {
1289 action = SEL_DESELECT;
1293 if (action == SEL_DESELECT)
1298 LOOP_VISIBLE_POINTS {
1302 if ((key->flag & PEK_SELECT) == 0) {
1303 key->flag |= PEK_SELECT;
1304 point->flag |= PEP_EDIT_RECALC;
1308 if (key->flag & PEK_SELECT) {
1309 key->flag &= ~PEK_SELECT;
1310 point->flag |= PEP_EDIT_RECALC;
1314 if ((key->flag & PEK_SELECT) == 0) {
1315 key->flag |= PEK_SELECT;
1316 point->flag |= PEP_EDIT_RECALC;
1318 key->flag &= ~PEK_SELECT;
1319 point->flag |= PEP_EDIT_RECALC;
1326 PE_update_selection(scene, ob, 1);
1327 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1329 return OPERATOR_FINISHED;
1332 void PARTICLE_OT_select_all(wmOperatorType *ot)
1335 ot->name= "Selection of all particles";
1336 ot->idname= "PARTICLE_OT_select_all";
1339 ot->exec= select_all_exec;
1343 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1345 WM_operator_properties_select_all(ot);
1348 /************************ pick select operator ************************/
1350 int PE_mouse_particles(bContext *C, short *mval, int extend)
1353 Scene *scene= CTX_data_scene(C);
1354 Object *ob= CTX_data_active_object(C);
1355 PTCacheEdit *edit= PE_get_current(scene, ob);
1358 if(!PE_start_edit(edit))
1359 return OPERATOR_CANCELLED;
1362 LOOP_VISIBLE_POINTS {
1363 LOOP_SELECTED_KEYS {
1364 key->flag &= ~PEK_SELECT;
1365 point->flag |= PEP_EDIT_RECALC;
1370 PE_set_view3d_data(C, &data);
1374 for_mouse_hit_keys(&data, toggle_key_select, 1); /* nearest only */
1376 PE_update_selection(scene, ob, 1);
1377 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1379 return OPERATOR_FINISHED;
1382 /************************ select first operator ************************/
1384 static void select_root(PEData *data, int point_index)
1386 data->edit->points[point_index].keys->flag |= PEK_SELECT;
1387 data->edit->points[point_index].flag |= PEP_EDIT_RECALC; /* redraw selection only */
1390 static int select_first_exec(bContext *C, wmOperator *op)
1394 PE_set_data(C, &data);
1395 foreach_point(&data, select_root);
1397 PE_update_selection(data.scene, data.ob, 1);
1398 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1400 return OPERATOR_FINISHED;
1403 void PARTICLE_OT_select_first(wmOperatorType *ot)
1406 ot->name= "Select First";
1407 ot->idname= "PARTICLE_OT_select_first";
1410 ot->exec= select_first_exec;
1414 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1417 /************************ select last operator ************************/
1419 static void select_tip(PEData *data, int point_index)
1421 PTCacheEditPoint *point = data->edit->points + point_index;
1422 point->keys[point->totkey - 1].flag |= PEK_SELECT;
1423 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1426 static int select_last_exec(bContext *C, wmOperator *op)
1430 PE_set_data(C, &data);
1431 foreach_point(&data, select_tip);
1433 PE_update_selection(data.scene, data.ob, 1);
1434 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1436 return OPERATOR_FINISHED;
1439 void PARTICLE_OT_select_last(wmOperatorType *ot)
1442 ot->name= "Select Last";
1443 ot->idname= "PARTICLE_OT_select_last";
1446 ot->exec= select_last_exec;
1450 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1453 /************************ select linked operator ************************/
1455 static int select_linked_exec(bContext *C, wmOperator *op)
1461 RNA_int_get_array(op->ptr, "location", location);
1462 mval[0]= location[0];
1463 mval[1]= location[1];
1465 view3d_operator_needs_opengl(C);
1467 PE_set_view3d_data(C, &data);
1470 data.select= !RNA_boolean_get(op->ptr, "deselect");
1472 for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */
1473 PE_update_selection(data.scene, data.ob, 1);
1474 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1476 return OPERATOR_FINISHED;
1479 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
1481 ARegion *ar= CTX_wm_region(C);
1484 location[0]= event->x - ar->winrct.xmin;
1485 location[1]= event->y - ar->winrct.ymin;
1486 RNA_int_set_array(op->ptr, "location", location);
1488 return select_linked_exec(C, op);
1491 void PARTICLE_OT_select_linked(wmOperatorType *ot)
1494 ot->name= "Select Linked";
1495 ot->idname= "PARTICLE_OT_select_linked";
1498 ot->exec= select_linked_exec;
1499 ot->invoke= select_linked_invoke;
1500 ot->poll= PE_poll_3dview;
1503 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1506 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them.");
1507 RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
1510 /************************ border select operator ************************/
1512 int PE_border_select(bContext *C, rcti *rect, int select, int extend)
1514 Scene *scene= CTX_data_scene(C);
1515 Object *ob= CTX_data_active_object(C);
1516 PTCacheEdit *edit= PE_get_current(scene, ob);
1519 if(!PE_start_edit(edit))
1520 return OPERATOR_CANCELLED;
1522 if (extend == 0 && select) {
1525 LOOP_VISIBLE_POINTS {
1526 LOOP_SELECTED_KEYS {
1527 key->flag &= ~PEK_SELECT;
1528 point->flag |= PEP_EDIT_RECALC;
1533 PE_set_view3d_data(C, &data);
1535 data.select= select;
1537 for_mouse_hit_keys(&data, select_key, 0);
1539 PE_update_selection(scene, ob, 1);
1540 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1542 return OPERATOR_FINISHED;
1545 /************************ circle select operator ************************/
1547 int PE_circle_select(bContext *C, int selecting, short *mval, float rad)
1549 Scene *scene= CTX_data_scene(C);
1550 Object *ob= CTX_data_active_object(C);
1551 PTCacheEdit *edit= PE_get_current(scene, ob);
1554 if(!PE_start_edit(edit))
1555 return OPERATOR_FINISHED;
1557 PE_set_view3d_data(C, &data);
1560 data.select= selecting;
1562 for_mouse_hit_keys(&data, select_key, 0);
1564 PE_update_selection(scene, ob, 1);
1565 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1567 return OPERATOR_FINISHED;
1570 /************************ lasso select operator ************************/
1572 int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
1574 Scene *scene= CTX_data_scene(C);
1575 Object *ob= CTX_data_active_object(C);
1576 ARegion *ar= CTX_wm_region(C);
1577 ParticleEditSettings *pset= PE_settings(scene);
1578 PTCacheEdit *edit = PE_get_current(scene, ob);
1579 ParticleSystem *psys = edit->psys;
1580 ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
1582 float co[3], mat[4][4];
1585 if(!PE_start_edit(edit))
1586 return OPERATOR_CANCELLED;
1590 LOOP_VISIBLE_POINTS {
1591 if(edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
1592 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, psys->particles + p, mat);
1594 if(pset->selectmode==SCE_SELECT_POINT) {
1596 VECCOPY(co, key->co);
1598 project_short(ar, co, vertco);
1599 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
1600 if(select && !(key->flag & PEK_SELECT)) {
1601 key->flag |= PEK_SELECT;
1602 point->flag |= PEP_EDIT_RECALC;
1604 else if(key->flag & PEK_SELECT) {
1605 key->flag &= ~PEK_SELECT;
1606 point->flag |= PEP_EDIT_RECALC;
1611 else if(pset->selectmode==SCE_SELECT_END) {
1612 key= point->keys + point->totkey - 1;
1614 VECCOPY(co, key->co);
1616 project_short(ar, co,vertco);
1617 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
1618 if(select && !(key->flag & PEK_SELECT)) {
1619 key->flag |= PEK_SELECT;
1620 point->flag |= PEP_EDIT_RECALC;
1622 else if(key->flag & PEK_SELECT) {
1623 key->flag &= ~PEK_SELECT;
1624 point->flag |= PEP_EDIT_RECALC;
1630 PE_update_selection(scene, ob, 1);
1631 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1633 return OPERATOR_FINISHED;
1636 /*************************** hide operator **************************/
1638 static int hide_exec(bContext *C, wmOperator *op)
1640 Object *ob= CTX_data_active_object(C);
1641 Scene *scene= CTX_data_scene(C);
1642 PTCacheEdit *edit= PE_get_current(scene, ob);
1645 if(RNA_enum_get(op->ptr, "unselected")) {
1646 LOOP_UNSELECTED_POINTS {
1647 point->flag |= PEP_HIDE;
1648 point->flag |= PEP_EDIT_RECALC;
1651 key->flag &= ~PEK_SELECT;
1655 LOOP_SELECTED_POINTS {
1656 point->flag |= PEP_HIDE;
1657 point->flag |= PEP_EDIT_RECALC;
1660 key->flag &= ~PEK_SELECT;
1664 PE_update_selection(scene, ob, 1);
1665 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1667 return OPERATOR_FINISHED;
1670 void PARTICLE_OT_hide(wmOperatorType *ot)
1673 ot->name= "Hide Selected";
1674 ot->idname= "PARTICLE_OT_hide";
1677 ot->exec= hide_exec;
1681 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1684 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1687 /*************************** reveal operator **************************/
1689 static int reveal_exec(bContext *C, wmOperator *op)
1691 Object *ob= CTX_data_active_object(C);
1692 Scene *scene= CTX_data_scene(C);
1693 PTCacheEdit *edit= PE_get_current(scene, ob);
1697 if(point->flag & PEP_HIDE) {
1698 point->flag &= ~PEP_HIDE;
1699 point->flag |= PEP_EDIT_RECALC;
1702 key->flag |= PEK_SELECT;
1706 PE_update_selection(scene, ob, 1);
1707 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, ob);
1709 return OPERATOR_FINISHED;
1712 void PARTICLE_OT_reveal(wmOperatorType *ot)
1716 ot->idname= "PARTICLE_OT_reveal";
1719 ot->exec= reveal_exec;
1723 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1726 /************************ select less operator ************************/
1728 static void select_less_keys(PEData *data, int point_index)
1730 PTCacheEdit *edit= data->edit;
1731 PTCacheEditPoint *point = edit->points + point_index;
1734 LOOP_SELECTED_KEYS {
1736 if(((key+1)->flag&PEK_SELECT)==0)
1737 key->flag |= PEK_TAG;
1739 else if(k==point->totkey-1) {
1740 if(((key-1)->flag&PEK_SELECT)==0)
1741 key->flag |= PEK_TAG;
1744 if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
1745 key->flag |= PEK_TAG;
1750 if(key->flag&PEK_TAG) {
1751 key->flag &= ~(PEK_TAG|PEK_SELECT);
1752 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1757 static int select_less_exec(bContext *C, wmOperator *op)
1761 PE_set_data(C, &data);
1762 foreach_point(&data, select_less_keys);
1764 PE_update_selection(data.scene, data.ob, 1);
1765 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1767 return OPERATOR_FINISHED;
1770 void PARTICLE_OT_select_less(wmOperatorType *ot)
1773 ot->name= "Select Less";
1774 ot->idname= "PARTICLE_OT_select_less";
1777 ot->exec= select_less_exec;
1781 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1784 /************************ select more operator ************************/
1786 static void select_more_keys(PEData *data, int point_index)
1788 PTCacheEdit *edit= data->edit;
1789 PTCacheEditPoint *point = edit->points + point_index;
1793 if(key->flag & PEK_SELECT) continue;
1796 if((key+1)->flag&PEK_SELECT)
1797 key->flag |= PEK_TAG;
1799 else if(k==point->totkey-1) {
1800 if((key-1)->flag&PEK_SELECT)
1801 key->flag |= PEK_TAG;
1804 if(((key-1)->flag | (key+1)->flag) & PEK_SELECT)
1805 key->flag |= PEK_TAG;
1810 if(key->flag&PEK_TAG) {
1811 key->flag &= ~PEK_TAG;
1812 key->flag |= PEK_SELECT;
1813 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1818 static int select_more_exec(bContext *C, wmOperator *op)
1822 PE_set_data(C, &data);
1823 foreach_point(&data, select_more_keys);
1825 PE_update_selection(data.scene, data.ob, 1);
1826 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1828 return OPERATOR_FINISHED;
1831 void PARTICLE_OT_select_more(wmOperatorType *ot)
1834 ot->name= "Select More";
1835 ot->idname= "PARTICLE_OT_select_more";
1838 ot->exec= select_more_exec;
1842 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1845 static int select_inverse_exec(bContext *C, wmOperator *op)
1851 PE_set_data(C, &data);
1853 edit= PE_get_current(data.scene, data.ob);
1855 LOOP_VISIBLE_POINTS {
1857 key->flag ^= PEK_SELECT;
1858 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
1862 PE_update_selection(data.scene, data.ob, 1);
1863 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_SELECT, data.ob);
1865 return OPERATOR_FINISHED;
1868 void PARTICLE_OT_select_inverse(wmOperatorType *ot)
1871 ot->name= "Select Inverse";
1872 ot->idname= "PARTICLE_OT_select_inverse";
1875 ot->exec= select_inverse_exec;
1879 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1882 /************************ rekey operator ************************/
1884 static void rekey_particle(PEData *data, int pa_index)
1886 PTCacheEdit *edit= data->edit;
1887 ParticleSystem *psys= edit->psys;
1888 ParticleSimulationData sim = {data->scene, data->ob, edit->psys, NULL};
1889 ParticleData *pa= psys->particles + pa_index;
1890 PTCacheEditPoint *point = edit->points + pa_index;
1892 HairKey *key, *new_keys, *okey;
1893 PTCacheEditKey *ekey;
1894 float dval, sta, end;
1897 pa->flag |= PARS_REKEY;
1899 key= new_keys= MEM_callocN(data->totrekey * sizeof(HairKey),"Hair re-key keys");
1902 /* root and tip stay the same */
1903 VECCOPY(key->co, okey->co);
1904 VECCOPY((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co);
1906 sta= key->time= okey->time;
1907 end= (key + data->totrekey - 1)->time= (okey + pa->totkey - 1)->time;
1908 dval= (end - sta) / (float)(data->totrekey - 1);
1910 /* interpolate new keys from old ones */
1911 for(k=1,key++; k<data->totrekey-1; k++,key++) {
1912 state.time= (float)k / (float)(data->totrekey-1);
1913 psys_get_particle_on_path(&sim, pa_index, &state, 0);
1914 VECCOPY(key->co, state.co);
1915 key->time= sta + k * dval;
1920 MEM_freeN(pa->hair);
1923 point->totkey=pa->totkey=data->totrekey;
1927 MEM_freeN(point->keys);
1928 ekey= point->keys= MEM_callocN(pa->totkey * sizeof(PTCacheEditKey),"Hair re-key edit keys");
1930 for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
1932 ekey->time= &key->time;
1933 if(!(psys->flag & PSYS_GLOBAL_HAIR))
1934 ekey->flag |= PEK_USE_WCO;
1937 pa->flag &= ~PARS_REKEY;
1938 point->flag |= PEP_EDIT_RECALC;
1941 static int rekey_exec(bContext *C, wmOperator *op)
1945 PE_set_data(C, &data);
1947 data.dval= 1.0f / (float)(data.totrekey-1);
1948 data.totrekey= RNA_int_get(op->ptr, "keys");
1950 foreach_selected_point(&data, rekey_particle);
1952 recalc_lengths(data.edit);
1953 PE_update_object(data.scene, data.ob, 1);
1954 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob);
1956 return OPERATOR_FINISHED;
1959 void PARTICLE_OT_rekey(wmOperatorType *ot)
1963 ot->idname= "PARTICLE_OT_rekey";
1966 ot->exec= rekey_exec;
1967 ot->invoke= WM_operator_props_popup;
1971 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1974 RNA_def_int(ot->srna, "keys", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
1977 static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time)
1979 PTCacheEdit *edit= PE_get_current(scene, ob);
1980 ParticleSystem *psys;
1981 ParticleSimulationData sim = {scene, ob, edit ? edit->psys : NULL, NULL};
1984 HairKey *new_keys, *key;
1985 PTCacheEditKey *ekey;
1988 if(!edit || !edit->psys) return;
1992 pa= psys->particles + pa_index;
1994 pa->flag |= PARS_REKEY;
1996 key= new_keys= MEM_dupallocN(pa->hair);
1998 /* interpolate new keys from old ones (roots stay the same) */
1999 for(k=1, key++; k < pa->totkey; k++, key++) {
2000 state.time= path_time * (float)k / (float)(pa->totkey-1);
2001 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2002 VECCOPY(key->co, state.co);
2005 /* replace hair keys */
2007 MEM_freeN(pa->hair);
2010 /* update edit pointers */
2011 for(k=0, key=pa->hair, ekey=edit->points[pa_index].keys; k<pa->totkey; k++, key++, ekey++) {
2013 ekey->time= &key->time;
2016 pa->flag &= ~PARS_REKEY;
2019 /************************* utilities **************************/
2021 static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psys, int mirror)
2023 PTCacheEdit *edit = psys->edit;
2024 ParticleData *pa, *npa=0, *new_pars=0;
2026 PTCacheEditPoint *npoint=0, *new_points=0;
2027 ParticleSystemModifierData *psmd;
2028 int i, totpart, new_totpart= psys->totpart, removed= 0;
2032 psmd= psys_get_modifier(ob, psys);
2033 totpart= psys->totpart;
2035 LOOP_TAGGED_POINTS {
2036 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
2040 LOOP_TAGGED_POINTS {
2045 if(new_totpart != psys->totpart) {
2047 npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
2048 npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
2051 pa= psys->particles;
2052 point= edit->points;
2053 for(i=0; i<psys->totpart; i++, pa++, point++) {
2054 if(point->flag & PEP_TAG) {
2056 MEM_freeN(point->keys);
2058 MEM_freeN(pa->hair);
2061 memcpy(npa, pa, sizeof(ParticleData));
2062 memcpy(npoint, point, sizeof(PTCacheEditPoint));
2068 if(psys->particles) MEM_freeN(psys->particles);
2069 psys->particles= new_pars;
2071 if(edit->points) MEM_freeN(edit->points);
2072 edit->points= new_points;
2074 if(edit->mirror_cache) {
2075 MEM_freeN(edit->mirror_cache);
2076 edit->mirror_cache= NULL;
2080 MEM_freeN(psys->child);
2085 edit->totpoint= psys->totpart= new_totpart;
2091 static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
2093 PTCacheEdit *edit= psys->edit;
2095 HairKey *hkey, *nhkey, *new_hkeys=0;
2097 ParticleSystemModifierData *psmd;
2100 if(pe_x_mirror(ob)) {
2101 /* mirror key tags */
2102 psmd= psys_get_modifier(ob, psys);
2106 PE_mirror_particle(ob, psmd->dm, psys, psys->particles + p, NULL);
2113 new_totkey= point->totkey;
2117 /* we can't have elements with less than two keys*/
2119 point->flag |= PEP_TAG;
2121 remove_tagged_particles(scene, ob, psys, pe_x_mirror(ob));
2124 pa = psys->particles + p;
2125 new_totkey= pa->totkey;
2131 if(new_totkey != pa->totkey) {
2133 nhkey= new_hkeys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
2136 while(key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
2141 if(hkey < pa->hair + pa->totkey) {
2142 VECCOPY(nhkey->co, hkey->co);
2143 nhkey->time= hkey->time;
2144 nhkey->weight= hkey->weight;
2150 MEM_freeN(pa->hair);
2152 pa->hair= new_hkeys;
2154 point->totkey= pa->totkey= new_totkey;
2157 MEM_freeN(point->keys);
2158 key= point->keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys");
2163 key->time= &hkey->time;
2170 /************************ subdivide opertor *********************/
2172 /* works like normal edit mode subdivide, inserts keys between neighbouring selected keys */
2173 static void subdivide_particle(PEData *data, int pa_index)
2175 PTCacheEdit *edit= data->edit;
2176 ParticleSystem *psys= edit->psys;
2177 ParticleSimulationData sim = {data->scene, data->ob, edit->psys, NULL};
2178 ParticleData *pa= psys->particles + pa_index;
2179 PTCacheEditPoint *point = edit->points + pa_index;
2181 HairKey *key, *nkey, *new_keys;
2182 PTCacheEditKey *ekey, *nekey, *new_ekeys;
2188 for(k=0, ekey=point->keys; k<pa->totkey-1; k++,ekey++) {
2189 if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
2193 if(totnewkey==0) return;
2195 pa->flag |= PARS_REKEY;
2197 nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys");
2198 nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(PTCacheEditKey)),"Hair subdivide edit keys");
2201 endtime= key[pa->totkey-1].time;
2203 for(k=0, ekey=point->keys; k<pa->totkey-1; k++, key++, ekey++) {
2205 memcpy(nkey,key,sizeof(HairKey));
2206 memcpy(nekey,ekey,sizeof(PTCacheEditKey));
2208 nekey->co= nkey->co;
2209 nekey->time= &nkey->time;
2214 if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) {
2215 nkey->time= (key->time + (key+1)->time)*0.5f;
2216 state.time= (endtime != 0.0f)? nkey->time/endtime: 0.0f;
2217 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2218 VECCOPY(nkey->co, state.co);
2220 nekey->co= nkey->co;
2221 nekey->time= &nkey->time;
2222 nekey->flag |= PEK_SELECT;
2223 if(!(psys->flag & PSYS_GLOBAL_HAIR))
2224 nekey->flag |= PEK_USE_WCO;
2230 /*tip still not copied*/
2231 memcpy(nkey,key,sizeof(HairKey));
2232 memcpy(nekey,ekey,sizeof(PTCacheEditKey));
2234 nekey->co= nkey->co;
2235 nekey->time= &nkey->time;
2238 MEM_freeN(pa->hair);
2242 MEM_freeN(point->keys);
2243 point->keys= new_ekeys;
2245 point->totkey = pa->totkey = pa->totkey + totnewkey;
2246 point->flag |= PEP_EDIT_RECALC;
2247 pa->flag &= ~PARS_REKEY;
2250 static int subdivide_exec(bContext *C, wmOperator *op)
2254 PE_set_data(C, &data);
2255 foreach_point(&data, subdivide_particle);
2257 recalc_lengths(data.edit);
2258 PE_update_object(data.scene, data.ob, 1);
2259 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob);
2261 return OPERATOR_FINISHED;
2264 void PARTICLE_OT_subdivide(wmOperatorType *ot)
2267 ot->name= "Subdivide";
2268 ot->idname= "PARTICLE_OT_subdivide";
2271 ot->exec= subdivide_exec;
2275 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2278 /************************ remove doubles opertor *********************/
2280 static int remove_doubles_exec(bContext *C, wmOperator *op)
2282 Scene *scene= CTX_data_scene(C);
2283 Object *ob= CTX_data_active_object(C);
2284 PTCacheEdit *edit= PE_get_current(scene, ob);
2285 ParticleSystem *psys = edit->psys;
2286 ParticleSystemModifierData *psmd;
2288 KDTreeNearest nearest[10];
2290 float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
2291 int n, totn, removed, totremoved;
2293 if(psys->flag & PSYS_GLOBAL_HAIR)
2294 return OPERATOR_CANCELLED;
2297 psmd= psys_get_modifier(ob, psys);
2303 tree=BLI_kdtree_new(psys->totpart);
2305 /* insert particles into kd tree */
2306 LOOP_SELECTED_POINTS {
2307 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
2308 VECCOPY(co, point->keys->co);
2310 BLI_kdtree_insert(tree, p, co, NULL);
2313 BLI_kdtree_balance(tree);
2315 /* tag particles to be removed */
2316 LOOP_SELECTED_POINTS {
2317 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, psys->particles+p, mat);
2318 VECCOPY(co, point->keys->co);
2321 totn= BLI_kdtree_find_n_nearest(tree,10,co,NULL,nearest);
2323 for(n=0; n<totn; n++) {
2324 /* this needs a custom threshold still */
2325 if(nearest[n].index > p && nearest[n].dist < threshold) {
2326 if(!(point->flag & PEP_TAG)) {
2327 point->flag |= PEP_TAG;
2334 BLI_kdtree_free(tree);
2336 /* remove tagged particles - don't do mirror here! */
2337 remove_tagged_particles(scene, ob, psys, 0);
2338 totremoved += removed;
2342 return OPERATOR_CANCELLED;
2344 BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved);
2346 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
2347 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
2349 return OPERATOR_FINISHED;
2352 void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
2355 ot->name= "Remove Doubles";
2356 ot->idname= "PARTICLE_OT_remove_doubles";
2359 ot->exec= remove_doubles_exec;
2363 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2366 RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
2370 static int weight_set_exec(bContext *C, wmOperator *op)
2372 Scene *scene= CTX_data_scene(C);
2373 ParticleEditSettings *pset= PE_settings(scene);
2374 Object *ob= CTX_data_active_object(C);
2375 PTCacheEdit *edit= PE_get_current(scene, ob);
2376 ParticleSystem *psys = edit->psys;
2381 ParticleBrushData *brush= &pset->brush[pset->brushtype];
2384 weight= (float)(brush->strength / 100.0f);
2386 LOOP_SELECTED_POINTS {
2387 ParticleData *pa= psys->particles + p;
2389 LOOP_SELECTED_KEYS {
2391 hkey->weight= weight;
2395 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
2396 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
2398 return OPERATOR_FINISHED;
2401 void PARTICLE_OT_weight_set(wmOperatorType *ot)
2404 ot->name= "Weight Set";
2405 ot->idname= "PARTICLE_OT_weight_set";
2408 ot->exec= weight_set_exec;
2412 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2415 /************************ cursor drawing *******************************/
2417 static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
2419 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2420 ParticleBrushData *brush;
2422 if(pset->brushtype < 0)
2425 brush= &pset->brush[pset->brushtype];
2430 glTranslatef((float)x, (float)y, 0.0f);
2432 glColor4ub(255, 255, 255, 128);
2433 glEnable(GL_LINE_SMOOTH );
2435 glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
2436 glDisable(GL_BLEND);
2437 glDisable(GL_LINE_SMOOTH );
2443 static void toggle_particle_cursor(bContext *C, int enable)
2445 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2447 if(pset->paintcursor && !enable) {
2448 WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
2449 pset->paintcursor = NULL;
2452 pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_3dview, brush_drawcursor, NULL);
2455 /********************* radial control operator *********************/
2457 static int brush_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
2459 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2460 ParticleBrushData *brush;
2461 int mode = RNA_enum_get(op->ptr, "mode");
2462 float original_value=1.0f;
2464 if(pset->brushtype < 0)
2465 return OPERATOR_CANCELLED;
2467 brush= &pset->brush[pset->brushtype];
2469 toggle_particle_cursor(C, 0);
2471 if(mode == WM_RADIALCONTROL_SIZE)
2472 original_value = brush->size;
2473 else if(mode == WM_RADIALCONTROL_STRENGTH)
2474 original_value = brush->strength;
2476 RNA_float_set(op->ptr, "initial_value", original_value);
2478 return WM_radial_control_invoke(C, op, event);
2481 static int brush_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
2483 int ret = WM_radial_control_modal(C, op, event);
2485 if(ret != OPERATOR_RUNNING_MODAL)
2486 toggle_particle_cursor(C, 1);
2491 static int brush_radial_control_exec(bContext *C, wmOperator *op)
2493 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2494 ParticleBrushData *brush;
2495 int mode = RNA_enum_get(op->ptr, "mode");
2496 float new_value = RNA_float_get(op->ptr, "new_value");
2498 if(pset->brushtype < 0)
2499 return OPERATOR_CANCELLED;
2501 brush= &pset->brush[pset->brushtype];
2503 if(mode == WM_RADIALCONTROL_SIZE)
2504 brush->size= new_value;
2505 else if(mode == WM_RADIALCONTROL_STRENGTH)
2506 brush->strength= new_value;
2508 return OPERATOR_FINISHED;
2511 void PARTICLE_OT_brush_radial_control(wmOperatorType *ot)
2513 WM_OT_radial_control_partial(ot);
2515 ot->name= "Brush Radial Control";
2516 ot->idname= "PARTICLE_OT_brush_radial_control";
2518 ot->invoke= brush_radial_control_invoke;
2519 ot->modal= brush_radial_control_modal;
2520 ot->exec= brush_radial_control_exec;
2524 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
2527 /*************************** delete operator **************************/
2529 enum { DEL_PARTICLE, DEL_KEY };
2531 static EnumPropertyItem delete_type_items[]= {
2532 {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
2533 {DEL_KEY, "KEY", 0, "Key", ""},
2534 {0, NULL, 0, NULL, NULL}};
2536 static void set_delete_particle(PEData *data, int pa_index)
2538 PTCacheEdit *edit= data->edit;
2540 edit->points[pa_index].flag |= PEP_TAG;
2543 static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
2545 PTCacheEdit *edit= data->edit;
2547 edit->points[pa_index].keys[key_index].flag |= PEK_TAG;
2550 static int delete_exec(bContext *C, wmOperator *op)
2553 int type= RNA_enum_get(op->ptr, "type");
2555 PE_set_data(C, &data);
2557 if(type == DEL_KEY) {
2558 foreach_selected_key(&data, set_delete_particle_key);
2559 remove_tagged_keys(data.scene, data.ob, data.edit->psys);
2560 recalc_lengths(data.edit);
2562 else if(type == DEL_PARTICLE) {
2563 foreach_selected_point(&data, set_delete_particle);
2564 remove_tagged_particles(data.scene, data.ob, data.edit->psys, pe_x_mirror(data.ob));
2565 recalc_lengths(data.edit);
2568 DAG_id_flush_update(&data.ob->id, OB_RECALC_DATA);
2569 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob);
2571 return OPERATOR_FINISHED;
2574 void PARTICLE_OT_delete(wmOperatorType *ot)
2578 ot->idname= "PARTICLE_OT_delete";
2581 ot->exec= delete_exec;
2582 ot->invoke= WM_menu_invoke;
2583 ot->poll= PE_hair_poll;
2586 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2589 ot->prop= RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys.");
2592 /*************************** mirror operator **************************/
2594 static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
2596 Mesh *me= (Mesh*)(ob->data);
2597 ParticleSystemModifierData *psmd;
2598 PTCacheEdit *edit= PE_get_current(scene, ob);
2599 ParticleSystem *psys = edit->psys;
2600 ParticleData *pa, *newpa, *new_pars;
2601 PTCacheEditPoint *newpoint, *new_points;
2605 int rotation, totpart, newtotpart;
2607 if(psys->flag & PSYS_GLOBAL_HAIR)
2610 psmd= psys_get_modifier(ob, psys);
2614 mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
2616 if(!edit->mirror_cache)
2617 PE_update_mirror_cache(ob, psys);
2619 totpart= psys->totpart;
2620 newtotpart= psys->totpart;
2621 LOOP_VISIBLE_POINTS {
2622 pa = psys->particles + p;
2624 if(point_is_selected(point)) {
2625 if(edit->mirror_cache[p] != -1) {
2626 /* already has a mirror, don't need to duplicate */
2627 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
2631 point->flag |= PEP_TAG;
2635 if((point->flag & PEP_TAG) && mirrorfaces[pa->num*2] != -1)
2639 if(newtotpart != psys->totpart) {
2640 /* allocate new arrays and copy existing */
2641 new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
2642 new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
2644 if(psys->particles) {
2645 memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
2646 MEM_freeN(psys->particles);
2648 psys->particles= new_pars;
2651 memcpy(new_points, edit->points, totpart*sizeof(PTCacheEditPoint));
2652 MEM_freeN(edit->points);
2654 edit->points= new_points;
2656 if(edit->mirror_cache) {
2657 MEM_freeN(edit->mirror_cache);
2658 edit->mirror_cache= NULL;
2661 edit->totpoint= psys->totpart= newtotpart;
2663 /* create new elements */
2664 newpa= psys->particles + totpart;
2665 newpoint= edit->points + totpart;
2667 for(p=0, point=edit->points; p<totpart; p++, point++) {
2668 pa = psys->particles + p;
2670 if(point->flag & PEP_HIDE)
2672 if(!(point->flag & PEP_TAG) || mirrorfaces[pa->num*2] == -1)
2678 if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
2679 if(point->keys) newpoint->keys= MEM_dupallocN(point->keys);
2681 /* rotate weights according to vertex index rotation */
2682 rotation= mirrorfaces[pa->num*2+1];
2683 newpa->fuv[0]= pa->fuv[2];
2684 newpa->fuv[1]= pa->fuv[1];
2685 newpa->fuv[2]= pa->fuv[0];
2686 newpa->fuv[3]= pa->fuv[3];
2687 while(rotation-- > 0)
2688 if(me->mface[pa->num].v4)
2689 SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
2691 SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
2693 /* assign face inddex */
2694 newpa->num= mirrorfaces[pa->num*2];
2695 newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
2697 /* update edit key pointers */
2698 key= newpoint->keys;
2699 for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, key++) {
2701 key->time= &hkey->time;
2704 /* map key positions as mirror over x axis */
2705 PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
2713 point->flag &= ~PEP_TAG;
2716 MEM_freeN(mirrorfaces);
2719 static int mirror_exec(bContext *C, wmOperator *op)
2721 Scene *scene= CTX_data_scene(C);
2722 Object *ob= CTX_data_active_object(C);
2723 PTCacheEdit *edit= PE_get_current(scene, ob);
2725 PE_mirror_x(scene, ob, 0);
2727 update_world_cos(ob, edit);
2728 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, ob);
2729 DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
2731 return OPERATOR_FINISHED;
2734 void PARTICLE_OT_mirror(wmOperatorType *ot)
2738 ot->idname= "PARTICLE_OT_mirror";
2741 ot->exec= mirror_exec;
2745 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2748 /************************* brush edit callbacks ********************/
2750 static void brush_comb(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
2752 ParticleEditSettings *pset= PE_settings(data->scene);
2755 if(pset->flag & PE_LOCK_FIRST && key_index == 0) return;
2757 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
2759 VECCOPY(cvec,data->dvec);
2760 mul_mat3_m4_v3(imat,cvec);
2761 mul_v3_fl(cvec, fac);
2762 VECADD(key->co, key->co, cvec);
2764 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
2767 static void brush_cut(PEData *data, int pa_index)
2769 PTCacheEdit *edit = data->edit;
2770 ARegion *ar= data->vc.ar;
2771 Object *ob= data->ob;
2772 ParticleEditSettings *pset= PE_settings(data->scene);
2773 ParticleCacheKey *key= edit->pathcache[pa_index];
2774 float rad2, cut_time= 1.0;
2775 float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
2776 int k, cut, keys= (int)pow(2.0, (double)pset->draw_step);
2779 /* blunt scissors */
2780 if(BLI_frand() > data->cutfac) return;
2782 /* don't cut hidden */
2783 if(edit->points[pa_index].flag & PEP_HIDE)
2786 rad2= data->rad * data->rad;
2790 project_short_noclip(ar, key->co, vertco);
2791 x0= (float)vertco[0];
2792 x1= (float)vertco[1];
2794 o0= (float)data->mval[0];
2795 o1= (float)data->mval[1];
2800 /* check if root is inside circle */
2801 if(xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) {
2806 /* calculate path time closest to root that was inside the circle */
2807 for(k=1, key++; k<=keys; k++, key++) {
2808 project_short_noclip(ar, key->co, vertco);
2810 if(key_test_depth(data, key->co) == 0) {
2811 x0= (float)vertco[0];
2812 x1= (float)vertco[1];
2819 v0= (float)vertco[0] - x0;
2820 v1= (float)vertco[1] - x1;
2824 d= (v0*xo1 - v1*xo0);
2831 cut_time= -(v0*xo0 + v1*xo1 + d);
2833 if(cut_time > 0.0f) {
2836 if(cut_time < 1.0f) {
2837 cut_time += (float)(k-1);
2838 cut_time /= (float)keys;
2845 x0= (float)vertco[0];
2846 x1= (float)vertco[1];
2854 if(cut_time < 0.0f) {
2855 edit->points[pa_index].flag |= PEP_TAG;
2858 rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
2859 edit->points[pa_index].flag |= PEP_EDIT_RECALC;
2864 static void brush_length(PEData *data, int point_index)
2866 PTCacheEdit *edit= data->edit;
2867 PTCacheEditPoint *point = edit->points + point_index;
2869 float dvec[3],pvec[3] = {0.0f, 0.0f, 0.0f};
2873 VECCOPY(pvec,key->co);
2876 VECSUB(dvec,key->co,pvec);
2877 VECCOPY(pvec,key->co);
2878 mul_v3_fl(dvec,data->growfac);
2879 VECADD(key->co,(key-1)->co,dvec);
2883 point->flag |= PEP_EDIT_RECALC;
2886 static void brush_puff(PEData *data, int point_index)
2888 PTCacheEdit *edit = data->edit;
2889 ParticleSystem *psys = edit->psys;
2890 PTCacheEditPoint *point = edit->points + point_index;
2892 float mat[4][4], imat[4][4];
2894 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;
2895 int puff_volume = 0;
2899 ParticleEditSettings *pset= PE_settings(data->scene);
2900 ParticleBrushData *brush= &pset->brush[pset->brushtype];
2901 puff_volume = brush->flag & PE_BRUSH_DATA_PUFF_VOLUME;
2904 if(psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
2905 psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
2906 invert_m4_m4(imat,mat);
2915 /* find root coordinate and normal on emitter */
2916 VECCOPY(co, key->co);
2918 mul_v3_m4v3(kco, data->ob->imat, co); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
2920 point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL);
2921 if(point_index == -1) return;
2923 VECCOPY(rootco, co);
2924 copy_v3_v3(nor, &edit->emitter_cosnos[point_index*6+3]);
2925 mul_mat3_m4_v3(data->ob->obmat, nor); /* normal into worldspace */
2930 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac);
2936 /* compute position as if hair was standing up straight.
2938 VECCOPY(lastco, co);
2939 VECCOPY(co, key->co);
2941 length += len_v3v3(lastco, co);
2942 if((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE)) {
2943 VECADDFAC(kco, rootco, nor, length);
2945 /* blend between the current and straight position */
2946 VECSUB(dco, kco, co);
2947 VECADDFAC(co, co, dco, fac);
2949 /* re-use dco to compare before and after translation and add to the offset */
2950 VECCOPY(dco, key->co);
2952 mul_v3_m4v3(key->co, imat, co);
2955 /* accumulate the total distance moved to apply to unselected
2956 * keys that come after */
2957 ofs[0] += key->co[0] - dco[0];
2958 ofs[1] += key->co[1] - dco[1];
2959 ofs[2] += key->co[2] - dco[2];
2967 /* this is simple but looks bad, adds annoying kinks */
2968 add_v3_v3(key->co, ofs);
2970 /* translate (not rotate) the rest of the hair if its not selected */
2971 if(ofs[0] || ofs[1] || ofs[2]) {
2972 #if 0 /* kindof works but looks worse then whats below */
2974 /* Move the unselected point on a vector based on the
2975 * hair direction and the offset */
2977 VECSUB(dco, lastco, co);
2978 mul_mat3_m4_v3(imat, dco); /* into particle space */
2980 /* move the point allong a vector perpendicular to the
2981 * hairs direction, reduces odd kinks, */
2982 cross_v3_v3v3(c1, ofs, dco);
2983 cross_v3_v3v3(c2, c1, dco);
2985 mul_v3_fl(c2, len_v3(ofs));
2986 add_v3_v3(key->co, c2);
2988 /* Move the unselected point on a vector based on the
2989 * the normal of the closest geometry */
2990 float oco[3], onor[3];
2991 VECCOPY(oco, key->co);
2992 mul_m4_v3(mat, oco);
2993 mul_v3_m4v3(kco, data->ob->imat, oco); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
2995 point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL, NULL);
2996 if(point_index != -1) {
2997 copy_v3_v3(onor, &edit->emitter_cosnos[point_index*6+3]);
2998 mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */
2999 mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */
3003 mul_v3_fl(onor, len_v3(ofs));
3004 add_v3_v3(key->co, onor);
3015 point->flag |= PEP_EDIT_RECALC;
3019 static void brush_weight(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
3021 /* roots have full weight allways */
3023 PTCacheEdit *edit = data->edit;
3024 ParticleSystem *psys = edit->psys;
3026 ParticleData *pa= psys->particles + point_index;
3027 pa->hair[key_index].weight = data->weightfac;
3029 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
3033 static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
3038 sub_v3_v3v3(dvec,key->co,(key-1)->co);
3039 mul_mat3_m4_v3(mat,dvec);
3040 VECADD(data->vec,data->vec,dvec);
3045 static void brush_smooth_do(PEData *data, float mat[][4], float imat[][4], int point_index, int key_index, PTCacheEditKey *key)
3047 float vec[3], dvec[3];
3050 VECCOPY(vec,data->vec);
3051 mul_mat3_m4_v3(imat,vec);
3053 sub_v3_v3v3(dvec,key->co,(key-1)->co);
3055 VECSUB(dvec,vec,dvec);
3056 mul_v3_fl(dvec,data->smoothfac);
3058 VECADD(key->co,key->co,dvec);
3061 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
3064 static int brush_add(PEData *data, short number)
3066 Scene *scene= data->scene;
3067 Object *ob= data->ob;
3068 PTCacheEdit *edit = data->edit;
3069 ParticleSystem *psys= edit->psys;
3070 ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add");
3071 ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
3072 ParticleSimulationData sim = {scene, ob, psys, psmd};
3073 ParticleEditSettings *pset= PE_settings(scene);
3074 int i, k, n= 0, totpart= psys->totpart;
3076 short dmx= 0, dmy= 0;
3077 float co1[3], co2[3], min_d, imat[4][4];
3078 float framestep, timestep= psys_get_timestep(&sim);
3079 short size= pset->brush[PE_BRUSH_ADD].size;
3080 short size2= size*size;
3082 invert_m4_m4(imat,ob->obmat);
3084 if(psys->flag & PSYS_GLOBAL_HAIR)
3087 BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
3089 /* painting onto the deformed mesh, could be an option? */
3090 if(psmd->dm->deformedOnly)
3093 dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
3095 for(i=0; i<number; i++) {
3098 while(dmx*dmx+dmy*dmy>size2) {
3099 dmx=(short)((2.0f*BLI_frand()-1.0f)*size);
3100 dmy=(short)((2.0f*BLI_frand()-1.0f)*size);
3104 mco[0]= data->mval[0] + dmx;
3105 mco[1]= data->mval[1] + dmy;
3106 viewline(data->vc.ar, data->vc.v3d, mco, co1, co2);
3108 mul_m4_v3(imat,co1);
3109 mul_m4_v3(imat,co2);
3112 /* warning, returns the derived mesh face */
3113 if(psys_intersect_dm(scene, ob,dm,0,co1,co2,&min_d,&add_pars[n].num,add_pars[n].fuv,0,0,0,0)) {
3114 add_pars[n].num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,add_pars[n].num,add_pars[n].fuv,NULL);
3119 int newtotpart=totpart+n;
3120 float hairmat[4][4], cur_co[3];
3122 ParticleData *pa, *new_pars= MEM_callocN(newtotpart*sizeof(ParticleData),"ParticleData new");
3123 PTCacheEditPoint *point, *new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint),"PTCacheEditPoint array new");
3124 PTCacheEditKey *key;
3127 /* save existing elements */
3128 memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
3129 memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint));
3131 /* change old arrays to new ones */
3132 if(psys->particles) MEM_freeN(psys->particles);
3133 psys->particles= new_pars;
3135 if(edit->points) MEM_freeN(edit->points);
3136 edit->points= new_points;
3138 if(edit->mirror_cache) {
3139 MEM_freeN(edit->mirror_cache);
3140 edit->mirror_cache= NULL;
3143 /* create tree for interpolation */
3144 if(pset->flag & PE_INTERPOLATE_ADDED && psys->totpart) {
3145 tree=BLI_kdtree_new(psys->totpart);
3147 for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
3148 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);
3149 BLI_kdtree_insert(tree, i, cur_co, NULL);
3152 BLI_kdtree_balance(tree);
3155 edit->totpoint= psys->totpart= newtotpart;
3157 /* create new elements */
3158 pa= psys->particles + totpart;
3159 point= edit->points + totpart;
3161 for(i=totpart; i<newtotpart; i++, pa++, point++) {
3162 memcpy(pa, add_pars + i - totpart, sizeof(ParticleData));
3163 pa->hair= MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add");
3164 key= point->keys= MEM_callocN(pset->totaddkey * sizeof(PTCacheEditKey), "PTCacheEditKey add");
3165 point->totkey= pa->totkey= pset->totaddkey;
3167 for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++) {
3169 key->time= &hkey->time;
3171 if(!(psys->flag & PSYS_GLOBAL_HAIR))
3172 key->flag |= PEK_USE_WCO;