2 * $Id: editparticle.c $
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"
62 #include "BLI_arithb.h"
63 #include "BLI_blenlib.h"
64 #include "BLI_dynstr.h"
65 #include "BLI_kdtree.h"
71 #include "BIF_glutil.h"
73 #include "ED_particle.h"
74 #include "ED_view3d.h"
76 #include "UI_interface.h"
77 #include "UI_resources.h"
82 #include "RNA_access.h"
83 #include "RNA_define.h"
85 #include "physics_intern.h"
87 static void ParticleUndo_clear(ParticleSystem *psys);
89 #define LOOP_PARTICLES(i,pa) for(i=0, pa=psys->particles; i<totpart; i++, pa++)
90 #define LOOP_KEYS(k,key) if(psys->edit)for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++)
93 static void error() {}
94 static int lasso_inside() {return 0;}
95 static void *mesh_get_x_mirror_faces() {return NULL;}
97 #define RADIALCONTROL_SIZE 0
98 #define RADIALCONTROL_STRENGTH 0
99 #define RADIALCONTROL_NONE 0
103 /**************************** utilities *******************************/
105 static int PE_poll(bContext *C)
107 Scene *scene= CTX_data_scene(C);
108 Object *ob= CTX_data_active_object(C);
109 ParticleSystem *psys;
114 psys= PE_get_current(scene, ob);
116 return (psys && psys->edit && (G.f & G_PARTICLEEDIT));
119 static int PE_poll_3dview(bContext *C)
121 Scene *scene= CTX_data_scene(C);
122 Object *ob= CTX_data_active_object(C);
123 ParticleSystem *psys;
125 if(!scene || !ob || !CTX_wm_region_view3d(C))
128 psys= PE_get_current(scene, ob);
130 return (psys && psys->edit && (G.f & G_PARTICLEEDIT));
133 void PE_free_particle_edit(ParticleSystem *psys)
135 ParticleEdit *edit=psys->edit;
136 int i, totpart=psys->totpart;
140 ParticleUndo_clear(psys);
143 for(i=0; i<totpart; i++) {
145 MEM_freeN(edit->keys[i]);
148 MEM_freeN(edit->keys);
151 if(edit->mirror_cache)
152 MEM_freeN(edit->mirror_cache);
154 if(edit->emitter_cosnos) {
155 MEM_freeN(edit->emitter_cosnos);
156 edit->emitter_cosnos= 0;
159 if(edit->emitter_field) {
160 BLI_kdtree_free(edit->emitter_field);
161 edit->emitter_field= 0;
169 /************************************************/
170 /* Edit Mode Helpers */
171 /************************************************/
173 int PE_can_edit(ParticleSystem *psys)
175 return (psys && psys->edit && (G.f & G_PARTICLEEDIT));
178 ParticleEditSettings *PE_settings(Scene *scene)
180 return &scene->toolsettings->particle;
183 void PE_change_act(void *ob_v, void *act_v)
185 Scene *scene= NULL; // XXX
187 ParticleSystem *psys;
188 short act= *((short*)act_v) - 1;
190 if((psys=psys_get_current(ob)))
191 psys->flag &= ~PSYS_CURRENT;
194 if((psys=BLI_findlink(&ob->particlesystem,act))) {
195 psys->flag |= PSYS_CURRENT;
197 if(psys_check_enabled(ob, psys)) {
198 if(G.f & G_PARTICLEEDIT && !psys->edit)
199 PE_create_particle_edit(scene, ob, psys);
200 PE_recalc_world_cos(ob, psys);
206 void PE_change_act_psys(Scene *scene, Object *ob, ParticleSystem *psys)
210 if((p=psys_get_current(ob)))
211 p->flag &= ~PSYS_CURRENT;
213 psys->flag |= PSYS_CURRENT;
215 if(psys_check_enabled(ob, psys)) {
216 if(G.f & G_PARTICLEEDIT && !psys->edit)
217 PE_create_particle_edit(scene, ob, psys);
218 PE_recalc_world_cos(ob, psys);
222 /* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set */
223 ParticleSystem *PE_get_current(Scene *scene, Object *ob)
225 ParticleSystem *psys;
230 psys= ob->particlesystem.first;
232 if(psys->flag & PSYS_CURRENT)
237 if(psys==NULL && ob->particlesystem.first) {
238 psys=ob->particlesystem.first;
239 psys->flag |= PSYS_CURRENT;
242 if(psys && psys_check_enabled(ob, psys)) // XXX && (ob == scene->obact) && (G.f & G_PARTICLEEDIT))
243 if(psys->part->type == PART_HAIR && psys->flag & PSYS_EDITED)
244 if(psys->edit == NULL)
245 PE_create_particle_edit(scene, ob, psys);
250 /* returns -1 if no system has PSYS_CURRENT flag */
251 short PE_get_current_num(Object *ob)
254 ParticleSystem *psys= ob->particlesystem.first;
257 if(psys->flag & PSYS_CURRENT)
266 void PE_hide_keys_time(Scene *scene, ParticleSystem *psys, float cfra)
269 ParticleEditKey *key;
270 ParticleEditSettings *pset=PE_settings(scene);
271 int i, k, totpart=psys->totpart;
273 if(pset->draw_timed && scene->selectmode==SCE_SELECT_POINT) {
274 LOOP_PARTICLES(i,pa) {
276 if(fabs(cfra-*key->time) < pset->draw_timed)
277 key->flag &= ~PEK_HIDE;
279 key->flag |= PEK_HIDE;
280 key->flag &= ~PEK_SELECT;
286 LOOP_PARTICLES(i,pa) {
288 key->flag &= ~PEK_HIDE;
294 /****************** common struct passed to callbacks ******************/
296 typedef struct PEData {
303 ParticleSystem *psys;
325 static void PE_set_data(bContext *C, PEData *data)
327 memset(data, 0, sizeof(*data));
329 data->scene= CTX_data_scene(C);
330 data->ob= CTX_data_active_object(C);
331 data->psys= PE_get_current(data->scene, data->ob);
334 static void PE_set_view3d_data(bContext *C, PEData *data)
336 PE_set_data(C, data);
338 view3d_set_viewcontext(C, &data->vc);
339 view3d_get_transformation(&data->vc, data->ob, &data->mats);
342 /*************************** selection utilities *******************************/
344 static int key_test_depth(PEData *data, float co[3])
346 View3D *v3d= data->vc.v3d;
347 RegionView3D *rv3d= data->vc.rv3d;
353 if((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
356 project_short(data->vc.ar, co, wco);
358 if(wco[0] == IS_CLIPPED)
361 gluProject(co[0],co[1],co[2], data->mats.modelview, data->mats.projection,
362 (GLint *)data->mats.viewport, &ux, &uy, &uz);
369 if(rv3d->depths && x<rv3d->depths->w && y<rv3d->depths->h) {
370 /* the 0.0001 is an experimental threshold to make selecting keys right next to a surface work better */
371 if((float)uz - 0.0001 > rv3d->depths->depths[y*rv3d->depths->w+x])
377 x+= (short)data->vc.ar->winrct.xmin;
378 y+= (short)data->vc.ar->winrct.ymin;
380 glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
382 if((float)uz - 0.0001 > depth)
389 static int key_inside_circle(PEData *data, float co[3], float *distance)
394 project_short(data->vc.ar, co, sco);
396 if(sco[0] == IS_CLIPPED)
399 dx= data->mval[0] - sco[0];
400 dy= data->mval[1] - sco[1];
401 dist= sqrt(dx*dx + dy*dy);
406 if(key_test_depth(data, co)) {
416 static int key_inside_rect(PEData *data, float co[3])
420 project_short(data->vc.ar, co,sco);
422 if(sco[0] == IS_CLIPPED)
425 if(sco[0] > data->rect->xmin && sco[0] < data->rect->xmax &&
426 sco[1] > data->rect->ymin && sco[1] < data->rect->ymax)
427 return key_test_depth(data, co);
432 static int key_inside_test(PEData *data, float co[3])
435 return key_inside_circle(data, co, NULL);
437 return key_inside_rect(data, co);
440 static int particle_is_selected(ParticleSystem *psys, ParticleData *pa)
442 ParticleEditKey *key;
445 if(pa->flag & PARS_HIDE)
449 i= pa - psys->particles;
452 if(key->flag & PEK_SELECT)
458 /*************************** iterators *******************************/
460 typedef void (*ForParticleFunc)(PEData *data, int pa_index);
461 typedef void (*ForKeyFunc)(PEData *data, int pa_index, int key_index);
462 typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index);
464 static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
466 ParticleSystem *psys= data->psys;
467 ParticleEdit *edit= psys->edit;
469 ParticleEditKey *key;
470 int i, k, totpart, nearest_pa, nearest_key;
471 float dist= data->rad;
473 /* in path select mode we have no keys */
474 if(data->scene->selectmode==SCE_SELECT_PATH)
477 totpart= psys->totpart;
481 LOOP_PARTICLES(i, pa) {
482 if(pa->flag & PARS_HIDE) continue;
484 if(data->scene->selectmode == SCE_SELECT_END) {
485 /* only do end keys */
486 key= edit->keys[i] + pa->totkey-1;
489 if(key_inside_circle(data, key->world_co, &dist)) {
491 nearest_key= pa->totkey-1;
494 else if(key_inside_test(data, key->world_co))
495 func(data, i, pa->totkey-1);
502 if(key->flag & PEK_HIDE) continue;
505 if(key_inside_circle(data, key->world_co, &dist)) {
510 else if(key_inside_test(data, key->world_co))
516 /* do nearest only */
517 if(nearest && nearest_pa > -1)
518 func(data, nearest_pa, nearest_key);
521 static void foreach_mouse_hit_particle(PEData *data, ForParticleFunc func, int selected)
523 ParticleSystem *psys= data->psys;
525 ParticleEditKey *key;
528 totpart= psys->totpart;
530 /* all is selected in path mode */
531 if(data->scene->selectmode==SCE_SELECT_PATH)
534 LOOP_PARTICLES(i, pa) {
535 if(pa->flag & PARS_HIDE) continue;
537 if(data->scene->selectmode==SCE_SELECT_END) {
538 /* only do end keys */
539 key= psys->edit->keys[i] + pa->totkey-1;
541 if(selected==0 || key->flag & PEK_SELECT)
542 if(key_inside_circle(data, key->world_co, &data->dist))
548 if(key->flag & PEK_HIDE) continue;
550 if(selected==0 || key->flag & PEK_SELECT) {
551 if(key_inside_circle(data, key->world_co, &data->dist)) {
561 static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
563 ParticleSystem *psys= data->psys;
565 ParticleEditKey *key;
566 ParticleSystemModifierData *psmd=0;
568 float mat[4][4], imat[4][4];
570 psmd= psys_get_modifier(data->ob,psys);
571 totpart= psys->totpart;
573 /* all is selected in path mode */
574 if(data->scene->selectmode==SCE_SELECT_PATH)
580 LOOP_PARTICLES(i,pa) {
581 if(pa->flag & PARS_HIDE) continue;
583 psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, pa, mat);
584 Mat4Invert(imat,mat);
586 if(data->scene->selectmode==SCE_SELECT_END) {
587 /* only do end keys */
588 key= psys->edit->keys[i] + pa->totkey-1;
590 if(selected==0 || key->flag & PEK_SELECT)
591 if(key_inside_circle(data, key->world_co, &data->dist))
592 func(data, mat, imat, i, pa->totkey-1);
597 if(key->flag&PEK_HIDE) continue;
599 if(selected==0 || key->flag & PEK_SELECT)
600 if(key_inside_circle(data, key->world_co, &data->dist))
601 func(data, mat, imat, i, k);
607 static void foreach_selected_particle(PEData *data, ForParticleFunc func)
609 ParticleSystem *psys= data->psys;
613 totpart= psys->totpart;
616 if(particle_is_selected(psys, pa))
620 static void foreach_selected_key(PEData *data, ForKeyFunc func)
622 ParticleSystem *psys= data->psys;
624 ParticleEditKey *key;
627 totpart= psys->totpart;
629 LOOP_PARTICLES(i,pa) {
630 if(pa->flag & PARS_HIDE) continue;
632 key= psys->edit->keys[i];
635 if(key->flag & PEK_SELECT)
640 void PE_foreach_particle(PEData *data, ForParticleFunc func)
642 ParticleSystem *psys= data->psys;
645 totpart= psys->totpart;
647 for(i=0; i<totpart; i++)
651 static int count_selected_keys(Scene *scene, ParticleSystem *psys)
654 ParticleEditKey *key;
655 int i, k, totpart, sel= 0;
657 totpart= psys->totpart;
659 LOOP_PARTICLES(i,pa) {
660 if(pa->flag & PARS_HIDE) continue;
662 key= psys->edit->keys[i];
664 if(scene->selectmode==SCE_SELECT_POINT) {
665 for(k=0; k<pa->totkey; k++,key++)
666 if(key->flag & PEK_SELECT)
669 else if(scene->selectmode==SCE_SELECT_END) {
672 if(key->flag & PEK_SELECT)
680 /************************************************/
681 /* Particle Edit Mirroring */
682 /************************************************/
684 static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
688 ParticleSystemModifierData *psmd;
690 KDTreeNearest nearest;
691 float mat[4][4], co[3];
692 int i, index, totpart;
695 psmd= psys_get_modifier(ob, psys);
696 totpart= psys->totpart;
698 tree= BLI_kdtree_new(totpart);
700 /* insert particles into kd tree */
701 LOOP_PARTICLES(i,pa) {
702 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
703 VECCOPY(co, pa->hair[0].co);
704 Mat4MulVecfl(mat, co);
705 BLI_kdtree_insert(tree, i, co, NULL);
708 BLI_kdtree_balance(tree);
710 /* lookup particles and set in mirror cache */
711 if(!edit->mirror_cache)
712 edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
714 LOOP_PARTICLES(i,pa) {
715 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
716 VECCOPY(co, pa->hair[0].co);
717 Mat4MulVecfl(mat, co);
720 index= BLI_kdtree_find_nearest(tree, co, NULL, &nearest);
722 /* this needs a custom threshold still, duplicated for editmode mirror */
723 if(index != -1 && index != i && (nearest.dist <= 0.0002f))
724 edit->mirror_cache[i]= index;
726 edit->mirror_cache[i]= -1;
729 /* make sure mirrors are in two directions */
730 LOOP_PARTICLES(i,pa) {
731 if(edit->mirror_cache[i]) {
732 index= edit->mirror_cache[i];
733 if(edit->mirror_cache[index] != i)
734 edit->mirror_cache[i]= -1;
738 BLI_kdtree_free(tree);
741 static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
743 HairKey *hkey, *mhkey;
744 ParticleEditKey *key, *mkey;
746 float mat[4][4], mmat[4][4], immat[4][4];
750 i= pa - psys->particles;
752 /* find mirrored particle if needed */
754 if(!edit->mirror_cache)
755 PE_update_mirror_cache(ob, psys);
757 mi= edit->mirror_cache[i];
760 mpa= psys->particles + mi;
763 mi= mpa - psys->particles;
765 /* make sure they have the same amount of keys */
766 if(pa->totkey != mpa->totkey) {
767 if(mpa->hair) MEM_freeN(mpa->hair);
768 if(edit->keys[mi]) MEM_freeN(edit->keys[mi]);
770 mpa->hair= MEM_dupallocN(pa->hair);
771 edit->keys[mi]= MEM_dupallocN(edit->keys[i]);
772 mpa->totkey= pa->totkey;
775 mkey= edit->keys[mi];
776 for(k=0; k<mpa->totkey; k++, mkey++, mhkey++) {
778 mkey->time= &mhkey->time;
779 mkey->flag &= PEK_SELECT;
783 /* mirror positions and tags */
784 psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
785 psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
786 Mat4Invert(immat, mmat);
791 mkey= edit->keys[mi];
792 for(k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
793 VECCOPY(mhkey->co, hkey->co);
794 Mat4MulVecfl(mat, mhkey->co);
795 mhkey->co[0]= -mhkey->co[0];
796 Mat4MulVecfl(immat, mhkey->co);
798 if(key->flag & PEK_TAG)
799 mkey->flag |= PEK_TAG;
802 if(pa->flag & PARS_TAG)
803 mpa->flag |= PARS_TAG;
804 if(pa->flag & PARS_EDIT_RECALC)
805 mpa->flag |= PARS_EDIT_RECALC;
808 static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
812 ParticleSystemModifierData *psmd;
816 psmd= psys_get_modifier(ob, psys);
817 totpart= psys->totpart;
819 /* we delay settings the PARS_EDIT_RECALC for mirrored particles
820 * to avoid doing mirror twice */
821 LOOP_PARTICLES(i,pa) {
822 if(pa->flag & PARS_EDIT_RECALC) {
823 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
825 if(edit->mirror_cache[i] != -1)
826 psys->particles[edit->mirror_cache[i]].flag &= ~PARS_EDIT_RECALC;
831 if(pa->flag & PARS_EDIT_RECALC)
832 if(edit->mirror_cache[i] != -1)
833 psys->particles[edit->mirror_cache[i]].flag |= PARS_EDIT_RECALC;
835 edit->totkeys= psys_count_keys(psys);
838 /************************************************/
839 /* Edit Calculation */
840 /************************************************/
841 /* tries to stop edited particles from going through the emitter's surface */
842 static void pe_deflect_emitter(Scene *scene, Object *ob, ParticleSystem *psys)
846 ParticleEditKey *key;
847 ParticleEditSettings *pset= PE_settings(scene);
848 ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
849 int i, k, totpart,index;
850 float *vec, *nor, dvec[3], dot, dist_1st;
851 float hairimat[4][4], hairmat[4][4];
856 if((pset->flag & PE_DEFLECT_EMITTER)==0)
860 totpart=psys->totpart;
862 LOOP_PARTICLES(i,pa) {
863 if(!(pa->flag & PARS_EDIT_RECALC))
866 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat);
869 Mat4MulVecfl(hairmat, key->co);
873 //LOOP_PARTICLES(i,pa) {
874 key=psys->edit->keys[i]+1;
876 dist_1st=VecLenf((key-1)->co,key->co);
877 dist_1st*=0.75f*pset->emitterdist;
879 for(k=1; k<pa->totkey; k++, key++) {
880 index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL);
882 vec=edit->emitter_cosnos +index*6;
885 VecSubf(dvec, key->co, vec);
893 VecMulf(dvec,dist_1st-dot);
894 VecAddf(key->co,key->co,dvec);
899 VecMulf(dvec,dist_1st-dot);
900 VecAddf(key->co,key->co,dvec);
907 //LOOP_PARTICLES(i,pa) {
909 Mat4Invert(hairimat,hairmat);
912 Mat4MulVecfl(hairimat, key->co);
916 /* force set distances between neighbouring keys */
917 void PE_apply_lengths(Scene *scene, ParticleSystem *psys)
921 ParticleEditKey *key;
922 ParticleEditSettings *pset=PE_settings(scene);
929 if((pset->flag & PE_KEEP_LENGTHS)==0)
933 totpart=psys->totpart;
935 LOOP_PARTICLES(i,pa) {
936 if(!(pa->flag & PARS_EDIT_RECALC))
939 for(k=1, key=edit->keys[i] + 1; k<pa->totkey; k++, key++) {
940 VecSubf(dv1, key->co, (key - 1)->co);
942 VecMulf(dv1, (key - 1)->length);
943 VecAddf(key->co, (key - 1)->co, dv1);
947 /* try to find a nice solution to keep distances between neighbouring keys */
948 static void pe_iterate_lengths(Scene *scene, ParticleSystem *psys)
952 ParticleEditKey *key;
953 ParticleEditSettings *pset=PE_settings(scene);
954 int i, j, k, totpart;
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};
963 if((pset->flag & PE_KEEP_LENGTHS)==0)
967 totpart=psys->totpart;
969 LOOP_PARTICLES(i,pa) {
970 if(!(pa->flag & PARS_EDIT_RECALC))
973 for(j=1; j<pa->totkey; j++) {
974 float mul= 1.0f / (float)pa->totkey;
976 if(pset->flag & PE_LOCK_FIRST) {
977 key= edit->keys[i] + 1;
979 dv1[0]= dv1[1]= dv1[2]= 0.0;
984 dv0[0]= dv0[1]= dv0[2]= 0.0;
987 for(; k<pa->totkey; k++, key++) {
989 VecSubf(dv0, (key - 1)->co, key->co);
990 tlen= Normalize(dv0);
991 VecMulf(dv0, (mul * (tlen - (key - 1)->length)));
994 if(k < pa->totkey - 1) {
995 VecSubf(dv2, (key + 1)->co, key->co);
996 tlen= Normalize(dv2);
997 VecMulf(dv2, mul * (tlen - key->length));
1001 VecAddf((key-1)->co,(key-1)->co,dv1);
1004 VECADD(dv1,dv0,dv2);
1009 /* set current distances to be kept between neighbouting keys */
1010 static void recalc_lengths(ParticleSystem *psys)
1013 ParticleEditKey *key;
1019 totpart= psys->totpart;
1021 LOOP_PARTICLES(i,pa) {
1022 key= psys->edit->keys[i];
1023 for(k=0; k<pa->totkey-1; k++, key++) {
1024 key->length= VecLenf(key->co, (key + 1)->co);
1028 /* calculate and store key locations in world coordinates */
1029 void PE_recalc_world_cos(Object *ob, ParticleSystem *psys)
1031 ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
1033 ParticleEditKey *key;
1035 float hairmat[4][4];
1040 totpart= psys->totpart;
1042 LOOP_PARTICLES(i,pa) {
1043 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
1046 VECCOPY(key->world_co,key->co);
1047 Mat4MulVecfl(hairmat, key->world_co);
1051 /* calculate a tree for finding nearest emitter's vertice */
1052 static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
1054 DerivedMesh *dm=psys_get_modifier(ob,psys)->dm;
1055 ParticleEdit *edit= psys->edit;
1059 int i, totface, totvert;
1061 if(edit->emitter_cosnos)
1062 MEM_freeN(edit->emitter_cosnos);
1064 BLI_kdtree_free(edit->emitter_field);
1066 totface=dm->getNumFaces(dm);
1067 totvert=dm->getNumVerts(dm);
1069 edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos");
1071 edit->emitter_field= BLI_kdtree_new(totface);
1073 vec=edit->emitter_cosnos;
1076 mvert=dm->getVertDataArray(dm,CD_MVERT);
1077 for(i=0; i<totface; i++, vec+=6, nor+=6) {
1078 mface=dm->getFaceData(dm,i,CD_MFACE);
1080 mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
1081 VECCOPY(vec,mvert->co);
1082 VECCOPY(nor,mvert->no);
1084 mvert=dm->getVertData(dm,mface->v2,CD_MVERT);
1085 VECADD(vec,vec,mvert->co);
1086 VECADD(nor,nor,mvert->no);
1088 mvert=dm->getVertData(dm,mface->v3,CD_MVERT);
1089 VECADD(vec,vec,mvert->co);
1090 VECADD(nor,nor,mvert->no);
1093 mvert=dm->getVertData(dm,mface->v4,CD_MVERT);
1094 VECADD(vec,vec,mvert->co);
1095 VECADD(nor,nor,mvert->no);
1100 VecMulf(vec,0.3333f);
1104 BLI_kdtree_insert(edit->emitter_field, i, vec, NULL);
1107 BLI_kdtree_balance(edit->emitter_field);
1110 void PE_update_selection(Scene *scene, Object *ob, int useflag)
1112 ParticleSystem *psys= PE_get_current(scene, ob);
1113 ParticleEdit *edit= psys->edit;
1114 ParticleEditSettings *pset= PE_settings(scene);
1115 ParticleSettings *part= psys->part;
1118 ParticleEditKey *key;
1122 totpart= psys->totpart;
1124 /* flag all particles to be updated if not using flag */
1126 LOOP_PARTICLES(i,pa)
1127 pa->flag |= PARS_EDIT_RECALC;
1129 /* flush edit key flag to hair key flag to preserve selection
1131 LOOP_PARTICLES(i,pa) {
1134 for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++)
1135 hkey->editflag= key->flag;
1138 psys_cache_paths(scene, ob, psys, CFRA, 1);
1140 if(part->childtype && (pset->flag & PE_SHOW_CHILD))
1141 psys_cache_child_paths(scene, ob, psys, cfra, 1);
1143 /* disable update flag */
1144 LOOP_PARTICLES(i,pa)
1145 pa->flag &= ~PARS_EDIT_RECALC;
1148 void PE_update_object(Scene *scene, Object *ob, int useflag)
1150 ParticleSystem *psys= PE_get_current(scene, ob);
1151 ParticleEditSettings *pset= PE_settings(scene);
1152 ParticleSettings *part= psys->part;
1155 int i, totpart= psys->totpart;
1157 /* flag all particles to be updated if not using flag */
1159 LOOP_PARTICLES(i,pa)
1160 pa->flag |= PARS_EDIT_RECALC;
1162 /* do post process on particle edit keys */
1163 pe_iterate_lengths(scene, psys);
1164 pe_deflect_emitter(scene, ob, psys);
1165 PE_apply_lengths(scene, psys);
1166 if(pset->flag & PE_X_MIRROR)
1167 PE_apply_mirror(ob,psys);
1168 PE_recalc_world_cos(ob,psys);
1169 PE_hide_keys_time(scene, psys, cfra);
1171 /* regenerate path caches */
1172 psys_cache_paths(scene, ob, psys, cfra, 1);
1174 if(part->childtype && (pset->flag & PE_SHOW_CHILD))
1175 psys_cache_child_paths(scene, ob, psys, cfra, 1);
1177 /* disable update flag */
1178 LOOP_PARTICLES(i,pa)
1179 pa->flag &= ~PARS_EDIT_RECALC;
1182 /************************ particle edit toggle operator ************************/
1184 /* initialize needed data for bake edit */
1185 void PE_create_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys)
1187 ParticleEdit *edit=psys->edit;
1189 ParticleEditKey *key;
1191 int i, k, totpart=psys->totpart, alloc=1;
1193 if((psys->flag & PSYS_EDITED)==0)
1197 int newtotkeys= psys_count_keys(psys);
1198 if(newtotkeys == edit->totkeys)
1204 error("ParticleEdit exists allready! Poke jahka!");
1205 PE_free_particle_edit(psys);
1208 edit=psys->edit=MEM_callocN(sizeof(ParticleEdit), "PE_create_particle_edit");
1210 edit->keys=MEM_callocN(totpart*sizeof(ParticleEditKey*),"ParticleEditKey array");
1212 LOOP_PARTICLES(i,pa) {
1213 key= edit->keys[i]= MEM_callocN(pa->totkey*sizeof(ParticleEditKey),"ParticleEditKeys");
1214 for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++) {
1216 key->time= &hkey->time;
1217 key->flag= hkey->editflag;
1221 edit->totkeys= psys_count_keys(psys);
1224 recalc_lengths(psys);
1225 recalc_emitter_field(ob, psys);
1226 PE_recalc_world_cos(ob, psys);
1229 ParticleUndo_clear(psys);
1230 PE_undo_push(scene, "Original");
1234 static int particle_edit_toggle_poll(bContext *C)
1236 Scene *scene= CTX_data_scene(C);
1237 Object *ob= CTX_data_active_object(C);
1239 if(!scene || !ob || ob->id.lib)
1242 return (ob->particlesystem.first != NULL);
1245 static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
1247 Scene *scene= CTX_data_scene(C);
1248 Object *ob= CTX_data_active_object(C);
1249 ParticleSystem *psys= PE_get_current(scene, ob);
1252 psys= ob->particlesystem.first;
1253 psys->flag |= PSYS_CURRENT;
1256 if(!(G.f & G_PARTICLEEDIT)) {
1257 if(psys && psys->part->type == PART_HAIR && psys->flag & PSYS_EDITED) {
1258 if(psys_check_enabled(ob, psys)) {
1259 if(psys->edit==NULL)
1260 PE_create_particle_edit(scene, ob, psys);
1262 PE_recalc_world_cos(ob, psys);
1266 G.f |= G_PARTICLEEDIT;
1267 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_PARTICLE, NULL);
1270 G.f &= ~G_PARTICLEEDIT;
1271 WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL);
1274 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
1276 return OPERATOR_FINISHED;
1279 void PARTICLE_OT_particle_edit_toggle(wmOperatorType *ot)
1282 ot->name= "Particle Edit Toggle";
1283 ot->idname= "PARTICLE_OT_particle_edit_toggle";
1286 ot->exec= particle_edit_toggle_exec;
1287 ot->poll= particle_edit_toggle_poll;
1290 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1293 /************************************************/
1294 /* Edit Selections */
1295 /************************************************/
1297 /*-----selection callbacks-----*/
1299 static void select_key(PEData *data, int pa_index, int key_index)
1301 ParticleSystem *psys= data->psys;
1302 ParticleData *pa= psys->particles + pa_index;
1303 ParticleEditKey *key= psys->edit->keys[pa_index] + key_index;
1306 key->flag |= PEK_SELECT;
1308 key->flag &= ~PEK_SELECT;
1310 pa->flag |= PARS_EDIT_RECALC;
1313 static void select_keys(PEData *data, int pa_index, int key_index)
1315 ParticleSystem *psys= data->psys;
1316 ParticleData *pa= psys->particles + pa_index;
1317 ParticleEditKey *key= psys->edit->keys[pa_index];
1320 for(k=0; k<pa->totkey; k++,key++) {
1322 key->flag |= PEK_SELECT;
1324 key->flag &= ~PEK_SELECT;
1327 pa->flag |= PARS_EDIT_RECALC;
1330 static void toggle_key_select(PEData *data, int pa_index, int key_index)
1332 ParticleSystem *psys= data->psys;
1333 ParticleData *pa= psys->particles + pa_index;
1335 if(psys->edit->keys[pa_index][key_index].flag&PEK_SELECT)
1336 psys->edit->keys[pa_index][key_index].flag &= ~PEK_SELECT;
1338 psys->edit->keys[pa_index][key_index].flag |= PEK_SELECT;
1340 pa->flag |= PARS_EDIT_RECALC;
1343 /************************ de select all operator ************************/
1345 static int de_select_all_exec(bContext *C, wmOperator *op)
1347 Scene *scene= CTX_data_scene(C);
1348 Object *ob= CTX_data_active_object(C);
1349 ParticleSystem *psys= PE_get_current(scene, ob);
1350 ParticleEdit *edit= 0;
1352 ParticleEditKey *key;
1353 int i, k, totpart, sel= 0;
1356 totpart= psys->totpart;
1358 LOOP_PARTICLES(i,pa) {
1359 if(pa->flag & PARS_HIDE) continue;
1361 if(key->flag & PEK_SELECT) {
1363 key->flag &= ~PEK_SELECT;
1364 pa->flag |= PARS_EDIT_RECALC;
1370 LOOP_PARTICLES(i,pa) {
1371 if(pa->flag & PARS_HIDE) continue;
1373 if(!(key->flag & PEK_SELECT)) {
1374 key->flag |= PEK_SELECT;
1375 pa->flag |= PARS_EDIT_RECALC;
1381 PE_update_selection(scene, ob, 1);
1382 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
1384 return OPERATOR_FINISHED;
1387 void PARTICLE_OT_de_select_all(wmOperatorType *ot)
1390 ot->name= "Select or Deselect All";
1391 ot->idname= "PARTICLE_OT_de_select_all";
1394 ot->exec= de_select_all_exec;
1398 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1401 /************************ pick select operator ************************/
1403 void PE_mouse_particles(void)
1405 bContext *C= NULL; // XXX
1407 Scene *scene= CTX_data_scene(C);
1408 Object *ob= CTX_data_active_object(C);
1409 ParticleSystem *psys= PE_get_current(scene, ob);
1410 ParticleEdit *edit= 0;
1412 ParticleEditKey *key;
1415 int shift= 0; // XXX
1417 if(!PE_can_edit(psys)) return;
1421 totpart= psys->totpart;
1424 glReadBuffer(GL_BACK);
1425 glDrawBuffer(GL_BACK);
1426 // persp(PERSP_VIEW);
1429 LOOP_PARTICLES(i,pa) {
1430 if(pa->flag & PARS_HIDE) continue;
1432 if(key->flag & PEK_SELECT) {
1433 key->flag &= ~PEK_SELECT;
1434 pa->flag |= PARS_EDIT_RECALC;
1441 PE_set_view3d_data(C, &data);
1445 for_mouse_hit_keys(&data, toggle_key_select, 1); /* nearest only */
1447 PE_update_selection(scene, ob, 1);
1451 /************************ select first operator ************************/
1453 static void select_root(PEData *data, int pa_index)
1455 ParticleSystem *psys= data->psys;
1457 psys->edit->keys[pa_index]->flag |= PEK_SELECT;
1460 static int select_first_exec(bContext *C, wmOperator *op)
1464 PE_set_data(C, &data);
1465 PE_foreach_particle(&data, select_root);
1466 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1468 return OPERATOR_FINISHED;
1471 void PARTICLE_OT_select_first(wmOperatorType *ot)
1474 ot->name= "Select First";
1475 ot->idname= "PARTICLE_OT_select_first";
1478 ot->exec= select_first_exec;
1482 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1485 /************************ select last operator ************************/
1487 static void select_tip(PEData *data, int pa_index)
1489 ParticleSystem *psys= data->psys;
1490 ParticleData *pa= psys->particles + pa_index;
1491 ParticleEditKey *key= psys->edit->keys[pa_index] + pa->totkey-1;
1493 key->flag |= PEK_SELECT;
1496 static int select_last_exec(bContext *C, wmOperator *op)
1500 PE_set_data(C, &data);
1501 PE_foreach_particle(&data, select_tip);
1502 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1504 return OPERATOR_FINISHED;
1507 void PARTICLE_OT_select_last(wmOperatorType *ot)
1510 ot->name= "Select Last";
1511 ot->idname= "PARTICLE_OT_select_last";
1514 ot->exec= select_last_exec;
1518 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1521 /************************ select linked operator ************************/
1523 static int select_linked_exec(bContext *C, wmOperator *op)
1529 RNA_int_get_array(op->ptr, "location", location);
1530 mval[0]= location[0];
1531 mval[1]= location[1];
1533 PE_set_view3d_data(C, &data);
1536 data.select= !RNA_boolean_get(op->ptr, "deselect");
1538 for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */
1539 PE_update_selection(data.scene, data.ob, 1);
1540 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1542 return OPERATOR_FINISHED;
1545 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
1547 ARegion *ar= CTX_wm_region(C);
1550 location[0]= event->x - ar->winrct.xmin;
1551 location[1]= event->y - ar->winrct.ymin;
1552 RNA_int_set_array(op->ptr, "location", location);
1554 return select_linked_exec(C, op);
1557 void PARTICLE_OT_select_linked(wmOperatorType *ot)
1560 ot->name= "Select Linked";
1561 ot->idname= "PARTICLE_OT_select_linked";
1564 ot->exec= select_linked_exec;
1565 ot->invoke= select_linked_invoke;
1566 ot->poll= PE_poll_3dview;
1569 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1572 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them.");
1573 RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
1576 /************************ border select operator ************************/
1578 void PE_border_select(ViewContext *vc, rcti *rect, int select)
1580 Scene *scene= vc->scene;
1581 Object *ob= vc->obact;
1582 ParticleSystem *psys= PE_get_current(scene, ob);
1585 if(!PE_can_edit(psys)) return;
1587 memset(&data, 0, sizeof(data));
1593 data.select= select;
1595 for_mouse_hit_keys(&data, select_key, 0);
1597 PE_update_selection(scene, ob, 1);
1599 /* XXX undo, notifier */
1600 PE_undo_push(scene, "Border Select");
1603 /************************ circle select operator ************************/
1605 void PE_circle_select(ViewContext *vc, int selecting, short *mval, float rad)
1607 Scene *scene= vc->scene;
1608 Object *ob= vc->obact;
1609 ParticleSystem *psys= PE_get_current(scene, ob);
1612 if(!PE_can_edit(psys)) return;
1614 memset(&data, 0, sizeof(data));
1621 data.select= selecting;
1623 for_mouse_hit_keys(&data, select_key, 0);
1625 /* XXX undo, notifier */
1626 PE_undo_push(scene, "Circle Select");
1629 /************************ lasso select operator ************************/
1631 void PE_lasso_select(ViewContext *vc, short mcords[][2], short moves, short select)
1633 Scene *scene= vc->scene;
1634 ARegion *ar= vc->ar;
1636 ParticleSystem *psys= PE_get_current(scene, ob);
1637 ParticleSystemModifierData *psmd;
1640 ParticleEditKey *key;
1641 float co[3], mat[4][4];
1645 if(!PE_can_edit(psys)) return;
1647 psmd= psys_get_modifier(ob, psys);
1649 totpart=psys->totpart;
1651 LOOP_PARTICLES(i,pa) {
1652 if(pa->flag & PARS_HIDE) continue;
1654 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
1656 if(scene->selectmode==SCE_SELECT_POINT) {
1658 VECCOPY(co, key->co);
1659 Mat4MulVecfl(mat, co);
1660 project_short(ar, co, vertco);
1661 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
1662 if(select && !(key->flag & PEK_SELECT)) {
1663 key->flag |= PEK_SELECT;
1664 pa->flag |= PARS_EDIT_RECALC;
1666 else if(key->flag & PEK_SELECT) {
1667 key->flag &= ~PEK_SELECT;
1668 pa->flag |= PARS_EDIT_RECALC;
1673 else if(scene->selectmode==SCE_SELECT_END) {
1674 key= edit->keys[i] + pa->totkey - 1;
1676 VECCOPY(co, key->co);
1677 Mat4MulVecfl(mat, co);
1678 project_short(ar, co,vertco);
1679 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
1680 if(select && !(key->flag & PEK_SELECT)) {
1681 key->flag |= PEK_SELECT;
1682 pa->flag |= PARS_EDIT_RECALC;
1684 else if(key->flag & PEK_SELECT) {
1685 key->flag &= ~PEK_SELECT;
1686 pa->flag |= PARS_EDIT_RECALC;
1692 PE_update_selection(scene, ob, 1);
1694 /* XXX undo, notifier */
1695 PE_undo_push(scene, "Lasso select particles");
1698 /*************************** hide operator **************************/
1700 static int hide_exec(bContext *C, wmOperator *op)
1702 Object *ob= CTX_data_active_object(C);
1703 Scene *scene= CTX_data_scene(C);
1704 ParticleSystem *psys= PE_get_current(scene, ob);
1706 ParticleEditKey *key;
1711 totpart= psys->totpart;
1713 if(RNA_enum_get(op->ptr, "unselected")) {
1714 LOOP_PARTICLES(i, pa) {
1715 if(!particle_is_selected(psys, pa)) {
1716 pa->flag |= PARS_HIDE;
1717 pa->flag |= PARS_EDIT_RECALC;
1720 key->flag &= ~PEK_SELECT;
1725 LOOP_PARTICLES(i, pa) {
1726 if(particle_is_selected(psys, pa)) {
1727 pa->flag |= PARS_HIDE;
1728 pa->flag |= PARS_EDIT_RECALC;
1731 key->flag &= ~PEK_SELECT;
1736 PE_update_selection(scene, ob, 1);
1737 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
1739 return OPERATOR_FINISHED;
1742 void PARTICLE_OT_hide(wmOperatorType *ot)
1745 ot->name= "Hide Selected";
1746 ot->idname= "PARTICLE_OT_hide";
1749 ot->exec= hide_exec;
1753 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1756 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1759 /*************************** reveal operator **************************/
1761 static int reveal_exec(bContext *C, wmOperator *op)
1763 Object *ob= CTX_data_active_object(C);
1764 Scene *scene= CTX_data_scene(C);
1765 ParticleSystem *psys= PE_get_current(scene, ob);
1767 ParticleEditKey *key;
1772 totpart= psys->totpart;
1774 LOOP_PARTICLES(i, pa) {
1775 if(pa->flag & PARS_HIDE) {
1776 pa->flag &= ~PARS_HIDE;
1777 pa->flag |= PARS_EDIT_RECALC;
1780 key->flag |= PEK_SELECT;
1784 PE_update_selection(scene, ob, 1);
1785 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
1787 return OPERATOR_FINISHED;
1790 void PARTICLE_OT_reveal(wmOperatorType *ot)
1794 ot->idname= "PARTICLE_OT_reveal";
1797 ot->exec= reveal_exec;
1801 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1804 /************************ select less operator ************************/
1806 static void select_less_keys(PEData *data, int pa_index)
1808 ParticleSystem *psys= data->psys;
1809 ParticleEdit *edit= psys->edit;
1810 ParticleData *pa= &psys->particles[pa_index];
1811 ParticleEditKey *key;
1814 for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
1815 if((key->flag & PEK_SELECT)==0) continue;
1818 if(((key+1)->flag&PEK_SELECT)==0)
1819 key->flag |= PEK_TO_SELECT;
1821 else if(k==pa->totkey-1) {
1822 if(((key-1)->flag&PEK_SELECT)==0)
1823 key->flag |= PEK_TO_SELECT;
1826 if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
1827 key->flag |= PEK_TO_SELECT;
1831 for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
1832 if(key->flag&PEK_TO_SELECT)
1833 key->flag &= ~(PEK_TO_SELECT|PEK_SELECT);
1837 static int select_less_exec(bContext *C, wmOperator *op)
1841 PE_set_data(C, &data);
1842 PE_foreach_particle(&data, select_less_keys);
1843 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1845 return OPERATOR_FINISHED;
1848 void PARTICLE_OT_select_less(wmOperatorType *ot)
1851 ot->name= "Select Less";
1852 ot->idname= "PARTICLE_OT_select_less";
1855 ot->exec= select_less_exec;
1859 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1862 /************************ select more operator ************************/
1864 static void select_more_keys(PEData *data, int pa_index)
1866 ParticleSystem *psys= data->psys;
1867 ParticleEdit *edit= psys->edit;
1868 ParticleData *pa= &psys->particles[pa_index];
1869 ParticleEditKey *key;
1872 for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
1873 if(key->flag & PEK_SELECT) continue;
1876 if((key+1)->flag&PEK_SELECT)
1877 key->flag |= PEK_TO_SELECT;
1879 else if(k==pa->totkey-1) {
1880 if((key-1)->flag&PEK_SELECT)
1881 key->flag |= PEK_TO_SELECT;
1884 if(((key-1)->flag | (key+1)->flag) & PEK_SELECT)
1885 key->flag |= PEK_TO_SELECT;
1889 for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
1890 if(key->flag&PEK_TO_SELECT) {
1891 key->flag &= ~PEK_TO_SELECT;
1892 key->flag |= PEK_SELECT;
1897 static int select_more_exec(bContext *C, wmOperator *op)
1901 PE_set_data(C, &data);
1902 PE_foreach_particle(&data, select_more_keys);
1903 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1905 return OPERATOR_FINISHED;
1908 void PARTICLE_OT_select_more(wmOperatorType *ot)
1911 ot->name= "Select More";
1912 ot->idname= "PARTICLE_OT_select_more";
1915 ot->exec= select_more_exec;
1919 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1922 /************************ rekey operator ************************/
1924 static void rekey_particle(PEData *data, int pa_index)
1926 ParticleSystem *psys= data->psys;
1927 ParticleData *pa= &psys->particles[pa_index];
1928 ParticleEdit *edit= psys->edit;
1929 ParticleEditSettings *pset= PE_settings(data->scene);
1931 HairKey *key, *new_keys;
1932 ParticleEditKey *ekey;
1933 float dval, sta, end;
1936 pa->flag |= PARS_REKEY;
1938 key= new_keys= MEM_callocN(pset->totrekey * sizeof(HairKey),"Hair re-key keys");
1940 /* root and tip stay the same */
1941 VECCOPY(key->co, pa->hair->co);
1942 VECCOPY((key + pset->totrekey - 1)->co, (pa->hair + pa->totkey - 1)->co);
1944 sta= key->time= pa->hair->time;
1945 end= (key + pset->totrekey - 1)->time= (pa->hair + pa->totkey - 1)->time;
1946 dval= (end - sta) / (float)(pset->totrekey - 1);
1948 /* interpolate new keys from old ones */
1949 for(k=1,key++; k<pset->totrekey-1; k++,key++) {
1950 state.time= (float)k / (float)(pset->totrekey-1);
1951 psys_get_particle_on_path(data->scene, data->ob, psys, pa_index, &state, 0);
1952 VECCOPY(key->co, state.co);
1953 key->time= sta + k * dval;
1958 MEM_freeN(pa->hair);
1961 pa->totkey=pset->totrekey;
1963 if(edit->keys[pa_index])
1964 MEM_freeN(edit->keys[pa_index]);
1965 ekey= edit->keys[pa_index]= MEM_callocN(pa->totkey * sizeof(ParticleEditKey),"Hair re-key edit keys");
1967 for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
1969 ekey->time= &key->time;
1972 pa->flag &= ~PARS_REKEY;
1973 pa->flag |= PARS_EDIT_RECALC;
1976 static int rekey_exec(bContext *C, wmOperator *op)
1979 ParticleEditSettings *pset;
1981 PE_set_data(C, &data);
1983 pset= PE_settings(data.scene);
1984 pset->totrekey= RNA_int_get(op->ptr, "keys");
1986 data.dval= 1.0f / (float)(pset->totrekey-1);
1988 foreach_selected_particle(&data, rekey_particle);
1990 data.psys->edit->totkeys= psys_count_keys(data.psys);
1991 recalc_lengths(data.psys);
1993 PE_update_object(data.scene, data.ob, 1);
1994 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
1996 return OPERATOR_FINISHED;
1999 void PARTICLE_OT_rekey(wmOperatorType *ot)
2003 ot->idname= "PARTICLE_OT_rekey";
2006 ot->exec= rekey_exec;
2007 // XXX show buttons ot->invoke= rekey_invoke;
2011 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2014 RNA_def_int(ot->srna, "keys", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
2017 static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time)
2019 ParticleSystem *psys= PE_get_current(scene, ob);
2020 ParticleEdit *edit=0;
2023 HairKey *new_keys, *key;
2024 ParticleEditKey *ekey;
2031 pa= &psys->particles[pa_index];
2033 pa->flag |= PARS_REKEY;
2035 key= new_keys= MEM_dupallocN(pa->hair);
2037 /* interpolate new keys from old ones (roots stay the same) */
2038 for(k=1, key++; k < pa->totkey; k++, key++) {
2039 state.time= path_time * (float)k / (float)(pa->totkey-1);
2040 psys_get_particle_on_path(scene, ob, psys, pa_index, &state, 0);
2041 VECCOPY(key->co, state.co);
2044 /* replace hair keys */
2046 MEM_freeN(pa->hair);
2049 /* update edit pointers */
2050 for(k=0, key=pa->hair, ekey=edit->keys[pa_index]; k<pa->totkey; k++, key++, ekey++) {
2052 ekey->time= &key->time;
2055 pa->flag &= ~PARS_REKEY;
2058 /************************* utilities **************************/
2060 static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psys)
2062 ParticleEdit *edit= psys->edit;
2063 ParticleEditSettings *pset= PE_settings(scene);
2064 ParticleData *pa, *npa=0, *new_pars=0;
2065 ParticleEditKey **key, **nkey=0, **new_keys=0;
2066 ParticleSystemModifierData *psmd;
2067 int i, totpart, new_totpart= psys->totpart, removed= 0;
2069 if(pset->flag & PE_X_MIRROR) {
2071 psmd= psys_get_modifier(ob, psys);
2072 totpart= psys->totpart;
2074 LOOP_PARTICLES(i,pa)
2075 if(pa->flag & PARS_TAG)
2076 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
2079 for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++) {
2080 if(pa->flag & PARS_TAG) {
2086 if(new_totpart != psys->totpart) {
2088 npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
2089 nkey= new_keys= MEM_callocN(new_totpart * sizeof(ParticleEditKey *), "ParticleEditKey array");
2092 pa= psys->particles;
2094 for(i=0; i<psys->totpart; i++, pa++, key++) {
2095 if(pa->flag & PARS_TAG) {
2099 MEM_freeN(pa->hair);
2102 memcpy(npa, pa, sizeof(ParticleData));
2103 memcpy(nkey, key, sizeof(ParticleEditKey*));
2109 if(psys->particles) MEM_freeN(psys->particles);
2110 psys->particles= new_pars;
2112 if(edit->keys) MEM_freeN(edit->keys);
2113 edit->keys= new_keys;
2115 if(edit->mirror_cache) {
2116 MEM_freeN(edit->mirror_cache);
2117 edit->mirror_cache= NULL;
2120 psys->totpart= new_totpart;
2122 edit->totkeys= psys_count_keys(psys);
2128 static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
2130 ParticleEdit *edit= psys->edit;
2131 ParticleEditSettings *pset= PE_settings(scene);
2133 HairKey *key, *nkey, *new_keys=0;
2134 ParticleEditKey *ekey;
2135 ParticleSystemModifierData *psmd;
2136 int i, k, totpart= psys->totpart;
2139 if(pset->flag & PE_X_MIRROR) {
2140 /* mirror key tags */
2141 psmd= psys_get_modifier(ob, psys);
2143 LOOP_PARTICLES(i,pa) {
2145 if(ekey->flag & PEK_TAG) {
2146 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
2153 LOOP_PARTICLES(i,pa) {
2154 new_totkey= pa->totkey;
2156 if(ekey->flag & PEK_TAG)
2159 /* we can't have elements with less than two keys*/
2161 pa->flag |= PARS_TAG;
2163 remove_tagged_particles(scene, ob, psys);
2165 totpart= psys->totpart;
2167 LOOP_PARTICLES(i,pa) {
2168 new_totkey= pa->totkey;
2170 if(ekey->flag & PEK_TAG)
2173 if(new_totkey != pa->totkey) {
2175 nkey= new_keys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
2177 for(k=0, ekey=edit->keys[i]; k<new_totkey; k++, key++, nkey++, ekey++) {
2178 while(ekey->flag & PEK_TAG && key < pa->hair + pa->totkey) {
2183 if(key < pa->hair + pa->totkey) {
2184 VECCOPY(nkey->co, key->co);
2185 nkey->time= key->time;
2186 nkey->weight= key->weight;
2190 MEM_freeN(pa->hair);
2194 pa->totkey=new_totkey;
2197 MEM_freeN(edit->keys[i]);
2198 ekey= edit->keys[i]= MEM_callocN(new_totkey*sizeof(ParticleEditKey), "particle edit keys");
2200 for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
2202 ekey->time= &key->time;
2207 edit->totkeys= psys_count_keys(psys);
2210 /************************ subdivide opertor *********************/
2212 /* works like normal edit mode subdivide, inserts keys between neighbouring selected keys */
2213 static void subdivide_particle(PEData *data, int pa_index)
2215 ParticleSystem *psys= data->psys;
2216 ParticleEdit *edit= psys->edit;
2217 ParticleData *pa= &psys->particles[pa_index];
2220 HairKey *key, *nkey, *new_keys;
2221 ParticleEditKey *ekey, *nekey, *new_ekeys;
2227 for(k=0, ekey=edit->keys[pa_index]; k<pa->totkey-1; k++,ekey++) {
2228 if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
2232 if(totnewkey==0) return;
2234 pa->flag |= PARS_REKEY;
2236 nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys");
2237 nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(ParticleEditKey)),"Hair subdivide edit keys");
2238 endtime= pa->hair[pa->totkey-1].time;
2240 for(k=0, key=pa->hair, ekey=edit->keys[pa_index]; k<pa->totkey-1; k++, key++, ekey++) {
2242 memcpy(nkey,key,sizeof(HairKey));
2243 memcpy(nekey,ekey,sizeof(ParticleEditKey));
2245 nekey->co= nkey->co;
2246 nekey->time= &nkey->time;
2251 if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) {
2252 nkey->time= (key->time + (key+1)->time)*0.5f;
2253 state.time= (endtime != 0.0f)? nkey->time/endtime: 0.0f;
2254 psys_get_particle_on_path(data->scene, data->ob, psys, pa_index, &state, 0);
2255 VECCOPY(nkey->co, state.co);
2257 nekey->co= nkey->co;
2258 nekey->time= &nkey->time;
2259 nekey->flag |= PEK_SELECT;
2265 /*tip still not copied*/
2266 memcpy(nkey,key,sizeof(HairKey));
2267 memcpy(nekey,ekey,sizeof(ParticleEditKey));
2269 nekey->co= nkey->co;
2270 nekey->time= &nkey->time;
2273 MEM_freeN(pa->hair);
2276 if(edit->keys[pa_index])
2277 MEM_freeN(edit->keys[pa_index]);
2279 edit->keys[pa_index]= new_ekeys;
2281 pa->totkey += totnewkey;
2282 pa->flag |= PARS_EDIT_RECALC;
2283 pa->flag &= ~PARS_REKEY;
2286 static int subdivide_exec(bContext *C, wmOperator *op)
2290 PE_set_data(C, &data);
2291 PE_foreach_particle(&data, subdivide_particle);
2293 data.psys->edit->totkeys= psys_count_keys(data.psys);
2295 recalc_lengths(data.psys);
2296 PE_recalc_world_cos(data.ob, data.psys);
2298 PE_update_object(data.scene, data.ob, 1);
2299 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
2301 return OPERATOR_FINISHED;
2304 void PARTICLE_OT_subdivide(wmOperatorType *ot)
2307 ot->name= "Subdivide";
2308 ot->idname= "PARTICLE_OT_subdivide";
2311 ot->exec= subdivide_exec;
2315 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2318 /************************ remove doubles opertor *********************/
2320 static int remove_doubles_exec(bContext *C, wmOperator *op)
2322 Scene *scene= CTX_data_scene(C);
2323 Object *ob= CTX_data_active_object(C);
2324 ParticleSystem *psys= PE_get_current(scene, ob);
2325 ParticleEditSettings *pset=PE_settings(scene);
2328 ParticleSystemModifierData *psmd;
2330 KDTreeNearest nearest[10];
2331 float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
2332 int i, n, totn, removed, totpart, flag, totremoved;
2335 psmd= psys_get_modifier(ob, psys);
2341 totpart= psys->totpart;
2342 tree=BLI_kdtree_new(totpart);
2344 /* insert particles into kd tree */
2345 LOOP_PARTICLES(i,pa) {
2346 if(particle_is_selected(psys, pa)) {
2347 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, mat);
2348 VECCOPY(co, pa->hair[0].co);
2349 Mat4MulVecfl(mat, co);
2350 BLI_kdtree_insert(tree, i, co, NULL);
2354 BLI_kdtree_balance(tree);
2356 /* tag particles to be removed */
2357 LOOP_PARTICLES(i,pa) {
2358 if(particle_is_selected(psys, pa)) {
2359 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, mat);
2360 VECCOPY(co, pa->hair[0].co);
2361 Mat4MulVecfl(mat, co);
2363 totn= BLI_kdtree_find_n_nearest(tree,10,co,NULL,nearest);
2365 for(n=0; n<totn; n++) {
2366 /* this needs a custom threshold still */
2367 if(nearest[n].index > i && nearest[n].dist < threshold) {
2368 if(!(pa->flag & PARS_TAG)) {
2369 pa->flag |= PARS_TAG;
2377 BLI_kdtree_free(tree);
2379 /* remove tagged particles - don't do mirror here! */
2381 pset->flag &= ~PE_X_MIRROR;
2382 remove_tagged_particles(scene, ob, psys);
2384 totremoved += removed;
2388 return OPERATOR_CANCELLED;
2390 BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved);
2392 PE_recalc_world_cos(ob, psys);
2393 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2394 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
2396 return OPERATOR_FINISHED;
2399 void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
2402 ot->name= "Remove Doubles";
2403 ot->idname= "PARTICLE_OT_remove_doubles";
2406 ot->exec= remove_doubles_exec;
2410 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2413 RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
2416 /********************* radial control operator *********************/
2419 void PE_radialcontrol_callback(const int mode, const int val)
2421 ParticleEditSettings *pset= NULL; // XXX PE_settings(scene);
2423 if(pset->brushtype>=0) {
2424 ParticleBrushData *brush= &pset->brush[pset->brushtype];
2426 if(mode == RADIALCONTROL_SIZE)
2428 else if(mode == RADIALCONTROL_STRENGTH)
2429 brush->strength= val;
2432 (*PE_radialcontrol())= NULL;
2435 struct RadialControl **PE_radialcontrol(void)
2437 static struct RadialControl *rc= NULL;
2441 void PE_radialcontrol_start(const int mode)
2443 ParticleEditSettings *pset= NULL; // XXX PE_settings(scene);
2446 if(pset->brushtype>=0) {
2447 ParticleBrushData *brush= &pset->brush[pset->brushtype];
2449 if(mode == RADIALCONTROL_SIZE)
2451 else if(mode == RADIALCONTROL_STRENGTH)
2452 orig= brush->strength;
2454 // if(mode != RADIALCONTROL_NONE)
2455 // (*PE_radialcontrol())= radialcontrol_start(mode, PE_radialcontrol_callback, orig, 100, 0);
2459 /*************************** delete operator **************************/
2461 enum { DEL_PARTICLE, DEL_KEY };
2463 static EnumPropertyItem delete_type_items[]= {
2464 {DEL_PARTICLE, "PARTICLE", "Particle", ""},
2465 {DEL_KEY, "KEY", "Key", ""},
2468 static void set_delete_particle(PEData *data, int pa_index)
2470 ParticleSystem *psys= data->psys;
2472 psys->particles[pa_index].flag |= PARS_TAG;
2475 static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
2477 ParticleSystem *psys= data->psys;
2479 psys->edit->keys[pa_index][key_index].flag |= PEK_TAG;
2482 static int delete_exec(bContext *C, wmOperator *op)
2485 int type= RNA_enum_get(op->ptr, "type");
2487 PE_set_data(C, &data);
2489 if(type == DEL_KEY) {
2490 foreach_selected_key(&data, set_delete_particle_key);
2491 remove_tagged_keys(data.scene, data.ob, data.psys);
2492 recalc_lengths(data.psys);
2494 else if(type == DEL_PARTICLE) {
2495 foreach_selected_particle(&data, set_delete_particle);
2496 remove_tagged_particles(data.scene, data.ob, data.psys);
2497 recalc_lengths(data.psys);
2500 DAG_object_flush_update(data.scene, data.ob, OB_RECALC_DATA);
2501 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
2503 return OPERATOR_FINISHED;
2506 void PARTICLE_OT_delete(wmOperatorType *ot)
2510 ot->idname= "PARTICLE_OT_delete";
2513 ot->exec= delete_exec;
2514 ot->invoke= WM_menu_invoke;
2518 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2521 RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys.");
2524 /*************************** mirror operator **************************/
2526 static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
2528 Mesh *me= (Mesh*)(ob->data);
2529 ParticleSystemModifierData *psmd;
2530 ParticleSystem *psys= PE_get_current(scene, ob);
2532 ParticleData *pa, *newpa, *new_pars;
2533 ParticleEditKey *ekey, **newkey, **key, **new_keys;
2536 int i, k, rotation, totpart, newtotpart;
2539 psmd= psys_get_modifier(ob, psys);
2541 mirrorfaces= mesh_get_x_mirror_faces(ob);
2543 if(!edit->mirror_cache)
2544 PE_update_mirror_cache(ob, psys);
2546 totpart= psys->totpart;
2547 newtotpart= psys->totpart;
2548 LOOP_PARTICLES(i,pa) {
2549 if(pa->flag & PARS_HIDE) continue;
2552 if(particle_is_selected(psys, pa)) {
2553 if(edit->mirror_cache[i] != -1) {
2554 /* already has a mirror, don't need to duplicate */
2555 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
2559 pa->flag |= PARS_TAG;
2563 if((pa->flag & PARS_TAG) && mirrorfaces[pa->num*2] != -1)
2567 if(newtotpart != psys->totpart) {
2568 /* allocate new arrays and copy existing */
2569 new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
2570 new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey*), "ParticleEditKey new");
2572 memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
2573 memcpy(new_keys, edit->keys, totpart*sizeof(ParticleEditKey*));
2575 if(psys->particles) MEM_freeN(psys->particles);
2576 psys->particles= new_pars;
2578 if(edit->keys) MEM_freeN(edit->keys);
2579 edit->keys= new_keys;
2581 if(edit->mirror_cache) {
2582 MEM_freeN(edit->mirror_cache);
2583 edit->mirror_cache= NULL;
2586 psys->totpart= newtotpart;
2588 /* create new elements */
2589 pa= psys->particles;
2590 newpa= psys->particles + totpart;
2592 newkey= edit->keys + totpart;
2594 for(i=0; i<totpart; i++, pa++, key++) {
2595 if(pa->flag & PARS_HIDE) continue;
2597 if(!(pa->flag & PARS_TAG) || mirrorfaces[pa->num*2] == -1)
2602 if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
2603 if(pa->keys) newpa->keys= MEM_dupallocN(pa->keys);
2604 if(*key) *newkey= MEM_dupallocN(*key);
2606 /* rotate weights according to vertex index rotation */
2607 rotation= mirrorfaces[pa->num*2+1];
2608 newpa->fuv[0]= pa->fuv[2];
2609 newpa->fuv[1]= pa->fuv[1];
2610 newpa->fuv[2]= pa->fuv[0];
2611 newpa->fuv[3]= pa->fuv[3];
2612 while(rotation-- > 0)
2613 if(me->mface[pa->num].v4)
2614 SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
2616 SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
2618 /* assign face inddex */
2619 newpa->num= mirrorfaces[pa->num*2];
2620 newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
2622 /* update edit key pointers */
2624 for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, ekey++) {
2626 ekey->time= &hkey->time;
2629 /* map key positions as mirror over x axis */
2630 PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
2636 edit->totkeys= psys_count_keys(psys);
2639 for(pa=psys->particles, i=0; i<psys->totpart; i++, pa++)
2640 pa->flag &= ~PARS_TAG;
2642 MEM_freeN(mirrorfaces);
2645 static int mirror_exec(bContext *C, wmOperator *op)
2647 Scene *scene= CTX_data_scene(C);
2648 Object *ob= CTX_data_active_object(C);
2649 ParticleSystem *psys= PE_get_current(scene, ob);
2651 PE_mirror_x(scene, ob, 0);
2653 PE_recalc_world_cos(ob, psys);
2654 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
2655 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2657 return OPERATOR_FINISHED;
2660 void PARTICLE_OT_mirror(wmOperatorType *ot)
2664 ot->idname= "PARTICLE_OT_mirror";
2667 ot->exec= mirror_exec;
2671 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2674 /*********************** set brush operator **********************/
2676 static EnumPropertyItem brush_type_items[]= {
2677 {PE_BRUSH_NONE, "NONE", "None", ""},
2678 {PE_BRUSH_COMB, "COMB", "Comb", ""},
2679 {PE_BRUSH_SMOOTH, "SMOOTH", "Smooth", ""},
2680 {PE_BRUSH_WEIGHT, "WEIGHT", "Weight", ""},
2681 {PE_BRUSH_ADD, "ADD", "Add", ""},
2682 {PE_BRUSH_LENGTH, "LENGTH", "Length", ""},
2683 {PE_BRUSH_PUFF, "PUFF", "Puff", ""},
2684 {PE_BRUSH_CUT, "CUT", "Cut", ""},
2685 {0, NULL, NULL, NULL}
2688 static int set_brush_exec(bContext *C, wmOperator *op)
2690 Scene *scene= CTX_data_scene(C);
2691 ParticleEditSettings *pset= PE_settings(scene);
2693 pset->brushtype= RNA_enum_get(op->ptr, "type");
2695 return OPERATOR_FINISHED;
2698 void PARTICLE_OT_set_brush(wmOperatorType *ot)
2701 ot->name= "Set Brush";
2702 ot->idname= "PARTICLE_OT_set_brush";
2705 ot->exec= set_brush_exec;
2706 ot->invoke= WM_menu_invoke;
2710 RNA_def_enum(ot->srna, "type", brush_type_items, PE_BRUSH_NONE, "Type", "Brush type to select for editing.");
2713 /************************* brush edit callbacks ********************/
2715 static void brush_comb(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
2717 ParticleSystem *psys= data->psys;
2718 ParticleData *pa= &psys->particles[pa_index];
2719 ParticleEditSettings *pset= PE_settings(data->scene);
2720 HairKey *key= pa->hair + key_index;
2723 if(pset->flag & PE_LOCK_FIRST && key_index == 0) return;
2725 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
2727 VECCOPY(cvec,data->dvec);
2728 Mat4Mul3Vecfl(imat,cvec);
2730 VECADD(key->co, key->co, cvec);
2732 pa->flag |= PARS_EDIT_RECALC;
2735 static void brush_cut(PEData *data, int pa_index)
2737 ParticleSystem *psys= data->psys;
2738 ARegion *ar= data->vc.ar;
2739 Object *ob= data->ob;
2740 ParticleData *pa= &psys->particles[pa_index];
2741 ParticleCacheKey *key= psys->pathcache[pa_index];
2742 float rad2, cut_time= 1.0;
2743 float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
2744 int k, cut, keys= (int)pow(2.0, (double)psys->part->draw_step);
2747 /* blunt scissors */
2748 if(BLI_frand() > data->cutfac) return;
2750 rad2= data->rad * data->rad;
2754 project_short_noclip(ar, key->co, vertco);
2755 x0= (float)vertco[0];
2756 x1= (float)vertco[1];
2758 o0= (float)data->mval[0];
2759 o1= (float)data->mval[1];
2764 /* check if root is inside circle */
2765 if(xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) {
2770 /* calculate path time closest to root that was inside the circle */
2771 for(k=1, key++; k<=keys; k++, key++) {
2772 project_short_noclip(ar, key->co, vertco);
2774 if(key_test_depth(data, key->co) == 0) {
2775 x0= (float)vertco[0];
2776 x1= (float)vertco[1];
2783 v0= (float)vertco[0] - x0;
2784 v1= (float)vertco[1] - x1;
2788 d= (v0*xo1 - v1*xo0);
2795 cut_time= -(v0*xo0 + v1*xo1 + d);
2797 if(cut_time > 0.0f) {
2800 if(cut_time < 1.0f) {
2801 cut_time += (float)(k-1);
2802 cut_time /= (float)keys;
2809 x0= (float)vertco[0];
2810 x1= (float)vertco[1];
2818 if(cut_time < 0.0f) {
2819 pa->flag |= PARS_TAG;
2822 rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
2823 pa->flag |= PARS_EDIT_RECALC;
2828 static void brush_length(PEData *data, int pa_index)
2830 ParticleSystem *psys= data->psys;
2831 ParticleData *pa= &psys->particles[pa_index];
2833 float dvec[3],pvec[3];
2837 VECCOPY(pvec,key->co);
2839 for(k=1, key++; k<pa->totkey; k++,key++) {
2840 VECSUB(dvec,key->co,pvec);
2841 VECCOPY(pvec,key->co);
2842 VecMulf(dvec,data->growfac);
2843 VECADD(key->co,(key-1)->co,dvec);
2846 pa->flag |= PARS_EDIT_RECALC;
2849 static void brush_puff(PEData *data, int pa_index)
2851 ParticleSystem *psys= data->psys;
2852 ParticleData *pa= &psys->particles[pa_index];
2853 ParticleEdit *edit= psys->edit;
2855 float mat[4][4], imat[4][4];
2856 float lastco[3], rootco[3], co[3], nor[3], kco[3], dco[3], fac, length;
2859 psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, pa, mat);
2860 Mat4Invert(imat,mat);
2862 /* find root coordinate and normal on emitter */
2864 VECCOPY(co, key->co);
2865 Mat4MulVecfl(mat, co);
2867 pa_index= BLI_kdtree_find_nearest(edit->emitter_field, co, NULL, NULL);
2868 if(pa_index == -1) return;
2870 VECCOPY(rootco, co);
2871 VecCopyf(nor, &psys->edit->emitter_cosnos[pa_index*6+3]);
2875 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac);
2880 for(k=1, key++; k<pa->totkey; k++, key++) {
2881 /* compute position as if hair was standing up straight */
2882 VECCOPY(lastco, co);
2883 VECCOPY(co, key->co);
2884 Mat4MulVecfl(mat, co);
2885 length += VecLenf(lastco, co);
2887 VECADDFAC(kco, rootco, nor, length);
2889 /* blend between the current and straight position */
2890 VECSUB(dco, kco, co);
2891 VECADDFAC(co, co, dco, fac);
2893 VECCOPY(key->co, co);
2894 Mat4MulVecfl(imat, key->co);
2897 pa->flag |= PARS_EDIT_RECALC;
2900 static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
2902 ParticleSystem *psys= data->psys;
2903 ParticleData *pa= &psys->particles[pa_index];
2904 HairKey *key= pa->hair + key_index;
2909 VecSubf(dvec,key->co,(key-1)->co);
2910 Mat4Mul3Vecfl(mat,dvec);
2911 VECADD(data->vec,data->vec,dvec);
2916 static void brush_smooth_do(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
2918 ParticleSystem *psys= data->psys;
2919 ParticleData *pa= &psys->particles[pa_index];
2920 HairKey *key= pa->hair + key_index;
2921 float vec[3], dvec[3];
2924 VECCOPY(vec,data->vec);
2925 Mat4Mul3Vecfl(imat,vec);
2927 VecSubf(dvec,key->co,(key-1)->co);
2929 VECSUB(dvec,vec,dvec);
2930 VecMulf(dvec,data->smoothfac);
2932 VECADD(key->co,key->co,dvec);
2935 pa->flag |= PARS_EDIT_RECALC;
2938 static void brush_add(PEData *data, short number)
2940 Scene *scene= data->scene;
2941 Object *ob= data->ob;
2942 ParticleSystem *psys= data->psys;
2943 ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add");
2944 ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
2945 ParticleEditSettings *pset= PE_settings(scene);
2946 ParticleEdit *edit= psys->edit;
2947 int i, k, n= 0, totpart= psys->totpart;
2949 short dmx= 0, dmy= 0;
2950 float co1[3], co2[3], min_d, imat[4][4];
2951 float framestep, timestep= psys_get_timestep(psys->part);
2952 short size= pset->brush[PE_BRUSH_ADD].size;
2953 short size2= size*size;
2955 Mat4Invert(imat,ob->obmat);
2957 BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
2959 /* painting onto the deformed mesh, could be an option? */
2960 if(psmd->dm->deformedOnly)
2963 dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
2965 for(i=0; i<number; i++) {
2968 while(dmx*dmx+dmy*dmy>size2) {
2969 dmx=(short)((2.0f*BLI_frand()-1.0f)*size);
2970 dmy=(short)((2.0f*BLI_frand()-1.0f)*size);
2974 mco[0]= data->mval[0] + dmx;
2975 mco[1]= data->mval[1] + dmy;
2976 viewline(data->vc.ar, data->vc.v3d, mco, co1, co2);
2978 Mat4MulVecfl(imat,co1);
2979 Mat4MulVecfl(imat,co2);
2982 /* warning, returns the derived mesh face */
2983 if(psys_intersect_dm(scene, ob,dm,0,co1,co2,&min_d,&add_pars[n].num,add_pars[n].fuv,0,0,0,0)) {
2984 add_pars[n].num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,add_pars[n].num,add_pars[n].fuv,NULL);
2989 int newtotpart=totpart+n;
2990 float hairmat[4][4], cur_co[3];
2992 ParticleData *pa, *new_pars= MEM_callocN(newtotpart*sizeof(ParticleData),"ParticleData new");
2993 ParticleEditKey *ekey, **key, **new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey *),"ParticleEditKey array new");
2996 /* save existing elements */
2997 memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
2998 memcpy(new_keys, edit->keys, totpart * sizeof(ParticleEditKey*));
3000 /* change old arrays to new ones */
3001 if(psys->particles) MEM_freeN(psys->particles);
3002 psys->particles= new_pars;
3004 if(edit->keys) MEM_freeN(edit->keys);
3005 edit->keys= new_keys;
3007 if(edit->mirror_cache) {
3008 MEM_freeN(edit->mirror_cache);
3009 edit->mirror_cache= NULL;
3012 /* create tree for interpolation */
3013 if(pset->flag & PE_INTERPOLATE_ADDED && psys->totpart) {
3014 tree=BLI_kdtree_new(psys->totpart);
3016 for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
3017 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);
3018 BLI_kdtree_insert(tree, i, cur_co, NULL);
3021 BLI_kdtree_balance(tree);
3024 psys->totpart= newtotpart;
3026 /* create new elements */
3027 pa= psys->particles + totpart;
3028 key= edit->keys + totpart;
3030 for(i=totpart; i<newtotpart; i++, pa++, key++) {
3031 memcpy(pa, add_pars + i - totpart, sizeof(ParticleData));
3032 pa->hair= MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add");
3033 ekey= *key= MEM_callocN(pset->totaddkey * sizeof(ParticleEditKey), "ParticleEditKey add");
3034 pa->totkey= pset->totaddkey;
3036 for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, ekey++) {
3038 ekey->time= &hkey->time;
3042 initialize_particle(pa,i,ob,psys,psmd);
3043 reset_particle(scene, pa,psys,psmd,ob,0.0,1.0,0,0,0);
3044 pa->flag |= PARS_EDIT_RECALC;
3045 if(pset->flag & PE_X_MIRROR)
3046 pa->flag |= PARS_TAG; /* signal for duplicate */
3048 framestep= pa->lifetime/(float)(pset->totaddkey-1);
3053 KDTreeNearest ptn[3];
3055 float maxd, mind, dd, totw=0.0, weight[3];
3057 psys_particle_on_dm(psmd->dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,0,0);
3058 maxw= BLI_kdtree_find_n_nearest(tree,3,co1,NULL,ptn);
3060 maxd= ptn[maxw-1].dist;
3064 for(w=0; w<maxw; w++) {
3065 weight[w]= (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
3072 for(w=0; w<maxw; w++)
3075 for(k=0; k<pset->totaddkey; k++) {
3077 hkey->time= pa->time + k * framestep;
3079 key[0].time= hkey->time/ 100.0f;
3080 psys_get_particle_on_path(scene, ob, psys, ptn[0].index, key, 0);
3081 VecMulf(key[0].co, weight[0]);
3084 key[1].time= key[0].time;
3085 psys_get_particle_on_path(scene, ob, psys, ptn[1].index, key + 1, 0);
3086 VecMulf(key[1].co, weight[1]);
3087 VECADD(key[0].co, key[0].co, key[1].co);
3090 key[2].time= key[0].time;
3091 psys_get_particle_on_path(scene, ob, psys, ptn[2].index, key + 2, 0);
3092 VecMulf(key[2].co, weight[2]);
3093 VECADD(key[0].co, key[0].co, key[2].co);
3098 VECSUB(co1, pa->state.co, key[0].co);
3100 VECADD(pa->hair[k].co, key[0].co, co1);
3102 pa->hair[k].time= key[0].time;
3106 for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
3107 VECADDFAC(hkey->co, pa->state.co, pa->state.vel, k * framestep * timestep);
3108 pa->hair[k].time += k * framestep;
3111 for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
3112 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
3113 Mat4Invert(imat,hairmat);
3114 Mat4MulVecfl(imat, hkey->co);
3117 edit->totkeys= psys_count_keys(psys);
3120 BLI_kdtree_free(tree);
3123 MEM_freeN(add_pars);
3125 if(!psmd->dm->deformedOnly)
3129 static void brush_weight(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
3131 ParticleSystem *psys= data->psys;
3134 /* roots have full weight allways */
3136 pa= &psys->particles[pa_index];
3137 pa->hair[key_index].weight= data->weightfac;
3138 pa->flag |= PARS_EDIT_RECALC;
3142 /************************* brush edit operator ********************/
3144 typedef struct BrushEdit {
3147 ParticleSystem *psys;
3153 static int brush_edit_init(bContext *C, wmOperator *op)
3155 Scene *scene= CTX_data_scene(C);
3156 Object *ob= CTX_data_active_object(C);
3157 ParticleSystem *psys= PE_get_current(scene, ob);
3158 ParticleEditSettings *pset= PE_settings(scene);
3159 ARegion *ar= CTX_wm_region(C);
3162 if(pset->brushtype < 0)
3166 initgrabz(ar->regiondata, ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]);
3168 bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit");
3170 op->customdata= bedit;
3172 bedit->scene= scene;
3179 static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
3181 BrushEdit *bedit= op->customdata;
3182 Scene *scene= bedit->scene;
3183 Object *ob= bedit->ob;
3184 ParticleSystem *psys= bedit->psys;
3185 ParticleEditSettings *pset= PE_settings(scene);
3186 ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
3187 ParticleBrushData *brush= &pset->brush[pset->brushtype];
3188 ARegion *ar= CTX_wm_region(C);
3189 float vec1[3], vec2[3];
3190 short mval[2], mvalo[2];
3191 int flip, mouse[2], dx, dy, removed= 0, selected= 0;
3193 RNA_int_get_array(itemptr, "mouse", mouse);
3194 flip= RNA_boolean_get(itemptr, "flip");
3197 glReadBuffer(GL_BACK);
3198 glDrawBuffer(GL_BACK);
3199 // persp(PERSP_VIEW);
3201 dx= mouse[0] - bedit->lastmouse[0];
3202 dy= mouse[1] - bedit->lastmouse[1];
3207 mvalo[0]= bedit->lastmouse[0];
3208 mvalo[1]= bedit->lastmouse[1];
3210 if(((pset->brushtype == PE_BRUSH_ADD) ?
3211 (sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0))
3214 selected= (short)count_selected_keys(scene, psys);
3216 switch(pset->brushtype) {
3221 PE_set_view3d_data(C, &data);
3223 data.rad= (float)brush->size;
3225 data.combfac= (float)(brush->strength - 50) / 50.0f;
3226 if(data.combfac < 0.0f)
3227 data.combfac= 1.0f - 9.0f * data.combfac;
3229 data.combfac= 1.0f - data.combfac;
3231 Mat4Invert(ob->imat, ob->obmat);
3233 window_to_3d(ar, vec1, mvalo[0], mvalo[1]);
3234 window_to_3d(ar, vec2, mval[0], mval[1]);
3235 VECSUB(vec1, vec2, vec1);