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"
74 #include "ED_particle.h"
75 #include "ED_view3d.h"
77 #include "UI_interface.h"
78 #include "UI_resources.h"
83 #include "RNA_access.h"
84 #include "RNA_define.h"
86 #include "physics_intern.h"
88 static void PE_create_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys);
89 static void ParticleUndo_clear(ParticleSystem *psys);
91 #define LOOP_PARTICLES(i, pa) for(i=0, pa=psys->particles; i<totpart; i++, pa++)
92 #define LOOP_KEYS(k, key) if(psys->edit)for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++)
94 /**************************** utilities *******************************/
96 static int PE_poll(bContext *C)
98 Scene *scene= CTX_data_scene(C);
99 Object *ob= CTX_data_active_object(C);
100 ParticleSystem *psys;
105 psys= PE_get_current(scene, ob);
107 return (psys && psys->edit && (G.f & G_PARTICLEEDIT));
110 static int PE_poll_3dview(bContext *C)
112 Scene *scene= CTX_data_scene(C);
113 Object *ob= CTX_data_active_object(C);
114 ParticleSystem *psys;
116 if(!scene || !ob || !CTX_wm_region_view3d(C))
119 psys= PE_get_current(scene, ob);
121 return (psys && psys->edit && (G.f & G_PARTICLEEDIT));
124 static void PE_free_particle_edit(ParticleSystem *psys)
126 ParticleEdit *edit= psys->edit;
127 int i, totpart= psys->totpart;
131 ParticleUndo_clear(psys);
134 for(i=0; i<totpart; i++) {
136 MEM_freeN(edit->keys[i]);
139 MEM_freeN(edit->keys);
142 if(edit->mirror_cache)
143 MEM_freeN(edit->mirror_cache);
145 if(edit->emitter_cosnos) {
146 MEM_freeN(edit->emitter_cosnos);
147 edit->emitter_cosnos= 0;
150 if(edit->emitter_field) {
151 BLI_kdtree_free(edit->emitter_field);
152 edit->emitter_field= 0;
158 psys->free_edit= NULL;
161 /************************************************/
162 /* Edit Mode Helpers */
163 /************************************************/
165 int PE_can_edit(ParticleSystem *psys)
167 return (psys && psys->edit && (G.f & G_PARTICLEEDIT));
170 ParticleEditSettings *PE_settings(Scene *scene)
172 return &scene->toolsettings->particle;
175 /* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set */
176 ParticleSystem *PE_get_current(Scene *scene, Object *ob)
178 ParticleSystem *psys;
183 psys= ob->particlesystem.first;
185 if(psys->flag & PSYS_CURRENT)
190 if(psys==NULL && ob->particlesystem.first) {
191 psys=ob->particlesystem.first;
192 psys->flag |= PSYS_CURRENT;
195 /* this happens when Blender is started with particle
196 * edit mode enabled XXX there's a draw error then? */
197 if(psys && psys_check_enabled(ob, psys) && (ob == OBACT) && (G.f & G_PARTICLEEDIT))
198 if(psys->part->type == PART_HAIR && psys->flag & PSYS_EDITED)
199 if(psys->edit == NULL)
200 PE_create_particle_edit(scene, ob, psys);
205 /* returns -1 if no system has PSYS_CURRENT flag */
206 short PE_get_current_num(Object *ob)
209 ParticleSystem *psys= ob->particlesystem.first;
212 if(psys->flag & PSYS_CURRENT)
221 void PE_hide_keys_time(Scene *scene, ParticleSystem *psys, float cfra)
224 ParticleEditKey *key;
225 ParticleEditSettings *pset=PE_settings(scene);
226 int i, k, totpart= psys->totpart;
228 if(pset->draw_timed && pset->selectmode==SCE_SELECT_POINT) {
229 LOOP_PARTICLES(i, pa) {
231 if(fabs(cfra-*key->time) < pset->draw_timed)
232 key->flag &= ~PEK_HIDE;
234 key->flag |= PEK_HIDE;
235 key->flag &= ~PEK_SELECT;
241 LOOP_PARTICLES(i, pa) {
243 key->flag &= ~PEK_HIDE;
249 /****************** common struct passed to callbacks ******************/
251 typedef struct PEData {
258 ParticleSystem *psys;
280 static void PE_set_data(bContext *C, PEData *data)
282 memset(data, 0, sizeof(*data));
284 data->scene= CTX_data_scene(C);
285 data->ob= CTX_data_active_object(C);
286 data->psys= PE_get_current(data->scene, data->ob);
289 static void PE_set_view3d_data(bContext *C, PEData *data)
291 PE_set_data(C, data);
293 view3d_set_viewcontext(C, &data->vc);
294 view3d_get_transformation(&data->vc, data->ob, &data->mats);
296 if((data->vc.v3d->drawtype>OB_WIRE) && (data->vc.v3d->flag & V3D_ZBUF_SELECT))
297 view3d_validate_backbuf(&data->vc);
300 /*************************** selection utilities *******************************/
302 static int key_test_depth(PEData *data, float co[3])
304 View3D *v3d= data->vc.v3d;
305 RegionView3D *rv3d= data->vc.rv3d;
311 if((v3d->drawtype<=OB_WIRE) || (v3d->flag & V3D_ZBUF_SELECT)==0)
314 project_short(data->vc.ar, co, wco);
316 if(wco[0] == IS_CLIPPED)
319 gluProject(co[0],co[1],co[2], data->mats.modelview, data->mats.projection,
320 (GLint *)data->mats.viewport, &ux, &uy, &uz);
327 if(rv3d->depths && x<rv3d->depths->w && y<rv3d->depths->h) {
328 /* the 0.0001 is an experimental threshold to make selecting keys right next to a surface work better */
329 if((float)uz - 0.0001 > rv3d->depths->depths[y*rv3d->depths->w+x])
335 x+= (short)data->vc.ar->winrct.xmin;
336 y+= (short)data->vc.ar->winrct.ymin;
338 glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
340 if((float)uz - 0.0001 > depth)
347 static int key_inside_circle(PEData *data, float rad, float co[3], float *distance)
352 project_short(data->vc.ar, co, sco);
354 if(sco[0] == IS_CLIPPED)
357 dx= data->mval[0] - sco[0];
358 dy= data->mval[1] - sco[1];
359 dist= sqrt(dx*dx + dy*dy);
364 if(key_test_depth(data, co)) {
374 static int key_inside_rect(PEData *data, float co[3])
378 project_short(data->vc.ar, co,sco);
380 if(sco[0] == IS_CLIPPED)
383 if(sco[0] > data->rect->xmin && sco[0] < data->rect->xmax &&
384 sco[1] > data->rect->ymin && sco[1] < data->rect->ymax)
385 return key_test_depth(data, co);
390 static int key_inside_test(PEData *data, float co[3])
393 return key_inside_circle(data, data->rad, co, NULL);
395 return key_inside_rect(data, co);
398 static int particle_is_selected(ParticleSystem *psys, ParticleData *pa)
400 ParticleEditKey *key;
403 if(pa->flag & PARS_HIDE)
407 i= pa - psys->particles;
410 if(key->flag & PEK_SELECT)
416 /*************************** iterators *******************************/
418 typedef void (*ForParticleFunc)(PEData *data, int pa_index);
419 typedef void (*ForKeyFunc)(PEData *data, int pa_index, int key_index);
420 typedef void (*ForKeyMatFunc)(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index);
422 static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
424 ParticleSystem *psys= data->psys;
425 ParticleEdit *edit= psys->edit;
427 ParticleEditKey *key;
428 ParticleEditSettings *pset= PE_settings(data->scene);
429 int i, k, totpart, nearest_pa, nearest_key;
430 float dist= data->rad;
432 /* in path select mode we have no keys */
433 if(pset->selectmode==SCE_SELECT_PATH)
436 totpart= psys->totpart;
440 LOOP_PARTICLES(i, pa) {
441 if(pa->flag & PARS_HIDE) continue;
443 if(pset->selectmode == SCE_SELECT_END) {
444 /* only do end keys */
445 key= edit->keys[i] + pa->totkey-1;
448 if(key_inside_circle(data, dist, key->world_co, &dist)) {
450 nearest_key= pa->totkey-1;
453 else if(key_inside_test(data, key->world_co))
454 func(data, i, pa->totkey-1);
461 if(key->flag & PEK_HIDE) continue;
464 if(key_inside_circle(data, dist, key->world_co, &dist)) {
469 else if(key_inside_test(data, key->world_co))
475 /* do nearest only */
476 if(nearest && nearest_pa > -1)
477 func(data, nearest_pa, nearest_key);
480 static void foreach_mouse_hit_particle(PEData *data, ForParticleFunc func, int selected)
482 ParticleSystem *psys= data->psys;
484 ParticleEditKey *key;
485 ParticleEditSettings *pset= PE_settings(data->scene);
488 totpart= psys->totpart;
490 /* all is selected in path mode */
491 if(pset->selectmode==SCE_SELECT_PATH)
494 LOOP_PARTICLES(i, pa) {
495 if(pa->flag & PARS_HIDE) continue;
497 if(pset->selectmode==SCE_SELECT_END) {
498 /* only do end keys */
499 key= psys->edit->keys[i] + pa->totkey-1;
501 if(selected==0 || key->flag & PEK_SELECT)
502 if(key_inside_circle(data, data->rad, key->world_co, &data->dist))
508 if(key->flag & PEK_HIDE) continue;
510 if(selected==0 || key->flag & PEK_SELECT) {
511 if(key_inside_circle(data, data->rad, key->world_co, &data->dist)) {
521 static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
523 ParticleSystem *psys= data->psys;
525 ParticleEditKey *key;
526 ParticleSystemModifierData *psmd=0;
527 ParticleEditSettings *pset= PE_settings(data->scene);
529 float mat[4][4], imat[4][4];
531 psmd= psys_get_modifier(data->ob,psys);
532 totpart= psys->totpart;
534 /* all is selected in path mode */
535 if(pset->selectmode==SCE_SELECT_PATH)
541 LOOP_PARTICLES(i, pa) {
542 if(pa->flag & PARS_HIDE) continue;
544 psys_mat_hair_to_global(data->ob, psmd->dm, psys->part->from, pa, mat);
545 Mat4Invert(imat,mat);
547 if(pset->selectmode==SCE_SELECT_END) {
548 /* only do end keys */
549 key= psys->edit->keys[i] + pa->totkey-1;
551 if(selected==0 || key->flag & PEK_SELECT)
552 if(key_inside_circle(data, data->rad, key->world_co, &data->dist))
553 func(data, mat, imat, i, pa->totkey-1);
558 if(key->flag&PEK_HIDE) continue;
560 if(selected==0 || key->flag & PEK_SELECT)
561 if(key_inside_circle(data, data->rad, key->world_co, &data->dist))
562 func(data, mat, imat, i, k);
568 static void foreach_selected_particle(PEData *data, ForParticleFunc func)
570 ParticleSystem *psys= data->psys;
574 totpart= psys->totpart;
576 LOOP_PARTICLES(i, pa)
577 if(particle_is_selected(psys, pa))
581 static void foreach_selected_key(PEData *data, ForKeyFunc func)
583 ParticleSystem *psys= data->psys;
585 ParticleEditKey *key;
588 totpart= psys->totpart;
590 LOOP_PARTICLES(i, pa) {
591 if(pa->flag & PARS_HIDE) continue;
593 key= psys->edit->keys[i];
596 if(key->flag & PEK_SELECT)
601 void PE_foreach_particle(PEData *data, ForParticleFunc func)
603 ParticleSystem *psys= data->psys;
606 totpart= psys->totpart;
608 for(i=0; i<totpart; i++)
612 static int count_selected_keys(Scene *scene, ParticleSystem *psys)
615 ParticleEditKey *key;
616 ParticleEditSettings *pset= PE_settings(scene);
617 int i, k, totpart, sel= 0;
619 totpart= psys->totpart;
621 LOOP_PARTICLES(i, pa) {
622 if(pa->flag & PARS_HIDE) continue;
624 key= psys->edit->keys[i];
626 if(pset->selectmode==SCE_SELECT_POINT) {
627 for(k=0; k<pa->totkey; k++,key++)
628 if(key->flag & PEK_SELECT)
631 else if(pset->selectmode==SCE_SELECT_END) {
634 if(key->flag & PEK_SELECT)
642 /************************************************/
643 /* Particle Edit Mirroring */
644 /************************************************/
646 static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
650 ParticleSystemModifierData *psmd;
652 KDTreeNearest nearest;
653 float mat[4][4], co[3];
654 int i, index, totpart;
657 psmd= psys_get_modifier(ob, psys);
658 totpart= psys->totpart;
660 tree= BLI_kdtree_new(totpart);
662 /* insert particles into kd tree */
663 LOOP_PARTICLES(i, pa) {
664 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
665 VECCOPY(co, pa->hair[0].co);
666 Mat4MulVecfl(mat, co);
667 BLI_kdtree_insert(tree, i, co, NULL);
670 BLI_kdtree_balance(tree);
672 /* lookup particles and set in mirror cache */
673 if(!edit->mirror_cache)
674 edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
676 LOOP_PARTICLES(i, pa) {
677 psys_mat_hair_to_orco(ob, psmd->dm, psys->part->from, pa, mat);
678 VECCOPY(co, pa->hair[0].co);
679 Mat4MulVecfl(mat, co);
682 index= BLI_kdtree_find_nearest(tree, co, NULL, &nearest);
684 /* this needs a custom threshold still, duplicated for editmode mirror */
685 if(index != -1 && index != i && (nearest.dist <= 0.0002f))
686 edit->mirror_cache[i]= index;
688 edit->mirror_cache[i]= -1;
691 /* make sure mirrors are in two directions */
692 LOOP_PARTICLES(i, pa) {
693 if(edit->mirror_cache[i]) {
694 index= edit->mirror_cache[i];
695 if(edit->mirror_cache[index] != i)
696 edit->mirror_cache[i]= -1;
700 BLI_kdtree_free(tree);
703 static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
705 HairKey *hkey, *mhkey;
706 ParticleEditKey *key, *mkey;
708 float mat[4][4], mmat[4][4], immat[4][4];
712 i= pa - psys->particles;
714 /* find mirrored particle if needed */
716 if(!edit->mirror_cache)
717 PE_update_mirror_cache(ob, psys);
719 mi= edit->mirror_cache[i];
722 mpa= psys->particles + mi;
725 mi= mpa - psys->particles;
727 /* make sure they have the same amount of keys */
728 if(pa->totkey != mpa->totkey) {
729 if(mpa->hair) MEM_freeN(mpa->hair);
730 if(edit->keys[mi]) MEM_freeN(edit->keys[mi]);
732 mpa->hair= MEM_dupallocN(pa->hair);
733 edit->keys[mi]= MEM_dupallocN(edit->keys[i]);
734 mpa->totkey= pa->totkey;
737 mkey= edit->keys[mi];
738 for(k=0; k<mpa->totkey; k++, mkey++, mhkey++) {
740 mkey->time= &mhkey->time;
741 mkey->flag &= PEK_SELECT;
745 /* mirror positions and tags */
746 psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
747 psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
748 Mat4Invert(immat, mmat);
753 mkey= edit->keys[mi];
754 for(k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
755 VECCOPY(mhkey->co, hkey->co);
756 Mat4MulVecfl(mat, mhkey->co);
757 mhkey->co[0]= -mhkey->co[0];
758 Mat4MulVecfl(immat, mhkey->co);
760 if(key->flag & PEK_TAG)
761 mkey->flag |= PEK_TAG;
764 if(pa->flag & PARS_TAG)
765 mpa->flag |= PARS_TAG;
766 if(pa->flag & PARS_EDIT_RECALC)
767 mpa->flag |= PARS_EDIT_RECALC;
770 static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
774 ParticleSystemModifierData *psmd;
778 psmd= psys_get_modifier(ob, psys);
779 totpart= psys->totpart;
781 /* we delay settings the PARS_EDIT_RECALC for mirrored particles
782 * to avoid doing mirror twice */
783 LOOP_PARTICLES(i, pa) {
784 if(pa->flag & PARS_EDIT_RECALC) {
785 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
787 if(edit->mirror_cache[i] != -1)
788 psys->particles[edit->mirror_cache[i]].flag &= ~PARS_EDIT_RECALC;
792 LOOP_PARTICLES(i, pa)
793 if(pa->flag & PARS_EDIT_RECALC)
794 if(edit->mirror_cache[i] != -1)
795 psys->particles[edit->mirror_cache[i]].flag |= PARS_EDIT_RECALC;
797 edit->totkeys= psys_count_keys(psys);
800 /************************************************/
801 /* Edit Calculation */
802 /************************************************/
803 /* tries to stop edited particles from going through the emitter's surface */
804 static void pe_deflect_emitter(Scene *scene, Object *ob, ParticleSystem *psys)
808 ParticleEditKey *key;
809 ParticleEditSettings *pset= PE_settings(scene);
810 ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
811 int i, k, totpart,index;
812 float *vec, *nor, dvec[3], dot, dist_1st;
813 float hairimat[4][4], hairmat[4][4];
818 if((pset->flag & PE_DEFLECT_EMITTER)==0)
822 totpart= psys->totpart;
824 LOOP_PARTICLES(i, pa) {
825 if(!(pa->flag & PARS_EDIT_RECALC))
828 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, hairmat);
831 Mat4MulVecfl(hairmat, key->co);
835 //LOOP_PARTICLES(i, pa) {
836 key=psys->edit->keys[i]+1;
838 dist_1st=VecLenf((key-1)->co,key->co);
839 dist_1st*=0.75f*pset->emitterdist;
841 for(k=1; k<pa->totkey; k++, key++) {
842 index= BLI_kdtree_find_nearest(edit->emitter_field,key->co,NULL,NULL);
844 vec=edit->emitter_cosnos +index*6;
847 VecSubf(dvec, key->co, vec);
855 VecMulf(dvec,dist_1st-dot);
856 VecAddf(key->co,key->co,dvec);
861 VecMulf(dvec,dist_1st-dot);
862 VecAddf(key->co,key->co,dvec);
869 //LOOP_PARTICLES(i, pa) {
871 Mat4Invert(hairimat,hairmat);
874 Mat4MulVecfl(hairimat, key->co);
878 /* force set distances between neighbouring keys */
879 void PE_apply_lengths(Scene *scene, ParticleSystem *psys)
883 ParticleEditKey *key;
884 ParticleEditSettings *pset=PE_settings(scene);
891 if((pset->flag & PE_KEEP_LENGTHS)==0)
895 totpart= psys->totpart;
897 LOOP_PARTICLES(i, pa) {
898 if(!(pa->flag & PARS_EDIT_RECALC))
901 for(k=1, key=edit->keys[i] + 1; k<pa->totkey; k++, key++) {
902 VecSubf(dv1, key->co, (key - 1)->co);
904 VecMulf(dv1, (key - 1)->length);
905 VecAddf(key->co, (key - 1)->co, dv1);
909 /* try to find a nice solution to keep distances between neighbouring keys */
910 static void pe_iterate_lengths(Scene *scene, ParticleSystem *psys)
914 ParticleEditKey *key;
915 ParticleEditSettings *pset=PE_settings(scene);
916 int i, j, k, totpart;
918 float dv0[3]= {0.0f, 0.0f, 0.0f};
919 float dv1[3]= {0.0f, 0.0f, 0.0f};
920 float dv2[3]= {0.0f, 0.0f, 0.0f};
925 if((pset->flag & PE_KEEP_LENGTHS)==0)
929 totpart= psys->totpart;
931 LOOP_PARTICLES(i, pa) {
932 if(!(pa->flag & PARS_EDIT_RECALC))
935 for(j=1; j<pa->totkey; j++) {
936 float mul= 1.0f / (float)pa->totkey;
938 if(pset->flag & PE_LOCK_FIRST) {
939 key= edit->keys[i] + 1;
941 dv1[0]= dv1[1]= dv1[2]= 0.0;
946 dv0[0]= dv0[1]= dv0[2]= 0.0;
949 for(; k<pa->totkey; k++, key++) {
951 VecSubf(dv0, (key - 1)->co, key->co);
952 tlen= Normalize(dv0);
953 VecMulf(dv0, (mul * (tlen - (key - 1)->length)));
956 if(k < pa->totkey - 1) {
957 VecSubf(dv2, (key + 1)->co, key->co);
958 tlen= Normalize(dv2);
959 VecMulf(dv2, mul * (tlen - key->length));
963 VecAddf((key-1)->co,(key-1)->co,dv1);
971 /* set current distances to be kept between neighbouting keys */
972 static void recalc_lengths(ParticleSystem *psys)
975 ParticleEditKey *key;
981 totpart= psys->totpart;
983 LOOP_PARTICLES(i, pa) {
984 key= psys->edit->keys[i];
985 for(k=0; k<pa->totkey-1; k++, key++) {
986 key->length= VecLenf(key->co, (key + 1)->co);
991 /* calculate a tree for finding nearest emitter's vertice */
992 static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
994 DerivedMesh *dm=psys_get_modifier(ob,psys)->dm;
995 ParticleEdit *edit= psys->edit;
999 int i, totface, totvert;
1001 if(edit->emitter_cosnos)
1002 MEM_freeN(edit->emitter_cosnos);
1004 BLI_kdtree_free(edit->emitter_field);
1006 totface=dm->getNumFaces(dm);
1007 totvert=dm->getNumVerts(dm);
1009 edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos");
1011 edit->emitter_field= BLI_kdtree_new(totface);
1013 vec=edit->emitter_cosnos;
1016 mvert=dm->getVertDataArray(dm,CD_MVERT);
1017 for(i=0; i<totface; i++, vec+=6, nor+=6) {
1018 mface=dm->getFaceData(dm,i,CD_MFACE);
1020 mvert=dm->getVertData(dm,mface->v1,CD_MVERT);
1021 VECCOPY(vec,mvert->co);
1022 VECCOPY(nor,mvert->no);
1024 mvert=dm->getVertData(dm,mface->v2,CD_MVERT);
1025 VECADD(vec,vec,mvert->co);
1026 VECADD(nor,nor,mvert->no);
1028 mvert=dm->getVertData(dm,mface->v3,CD_MVERT);
1029 VECADD(vec,vec,mvert->co);
1030 VECADD(nor,nor,mvert->no);
1033 mvert=dm->getVertData(dm,mface->v4,CD_MVERT);
1034 VECADD(vec,vec,mvert->co);
1035 VECADD(nor,nor,mvert->no);
1040 VecMulf(vec,0.3333f);
1044 BLI_kdtree_insert(edit->emitter_field, i, vec, NULL);
1047 BLI_kdtree_balance(edit->emitter_field);
1050 static void PE_update_selection(Scene *scene, Object *ob, int useflag)
1052 ParticleSystem *psys= PE_get_current(scene, ob);
1053 ParticleEdit *edit= psys->edit;
1054 ParticleEditSettings *pset= PE_settings(scene);
1055 ParticleSettings *part= psys->part;
1058 ParticleEditKey *key;
1062 totpart= psys->totpart;
1064 /* flag all particles to be updated if not using flag */
1066 LOOP_PARTICLES(i, pa)
1067 pa->flag |= PARS_EDIT_RECALC;
1069 /* flush edit key flag to hair key flag to preserve selection
1071 LOOP_PARTICLES(i, pa) {
1074 for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, key++)
1075 hkey->editflag= key->flag;
1078 psys_cache_paths(scene, ob, psys, CFRA, 1);
1080 if(part->childtype && (pset->flag & PE_SHOW_CHILD))
1081 psys_cache_child_paths(scene, ob, psys, cfra, 1);
1083 /* disable update flag */
1084 LOOP_PARTICLES(i, pa)
1085 pa->flag &= ~PARS_EDIT_RECALC;
1088 void PE_update_object(Scene *scene, Object *ob, int useflag)
1090 ParticleSystem *psys= PE_get_current(scene, ob);
1091 ParticleEditSettings *pset= PE_settings(scene);
1092 ParticleSettings *part= psys->part;
1095 int i, totpart= psys->totpart;
1097 /* flag all particles to be updated if not using flag */
1099 LOOP_PARTICLES(i, pa)
1100 pa->flag |= PARS_EDIT_RECALC;
1102 /* do post process on particle edit keys */
1103 pe_iterate_lengths(scene, psys);
1104 pe_deflect_emitter(scene, ob, psys);
1105 PE_apply_lengths(scene, psys);
1106 if(pset->flag & PE_X_MIRROR)
1107 PE_apply_mirror(ob,psys);
1108 psys_update_world_cos(ob,psys);
1109 PE_hide_keys_time(scene, psys, cfra);
1111 /* regenerate path caches */
1112 psys_cache_paths(scene, ob, psys, cfra, 1);
1114 if(part->childtype && (pset->flag & PE_SHOW_CHILD))
1115 psys_cache_child_paths(scene, ob, psys, cfra, 1);
1117 /* disable update flag */
1118 LOOP_PARTICLES(i, pa)
1119 pa->flag &= ~PARS_EDIT_RECALC;
1122 /************************************************/
1123 /* Edit Selections */
1124 /************************************************/
1126 /*-----selection callbacks-----*/
1128 static void select_key(PEData *data, int pa_index, int key_index)
1130 ParticleSystem *psys= data->psys;
1131 ParticleData *pa= psys->particles + pa_index;
1132 ParticleEditKey *key= psys->edit->keys[pa_index] + key_index;
1135 key->flag |= PEK_SELECT;
1137 key->flag &= ~PEK_SELECT;
1139 pa->flag |= PARS_EDIT_RECALC;
1142 static void select_keys(PEData *data, int pa_index, int key_index)
1144 ParticleSystem *psys= data->psys;
1145 ParticleData *pa= psys->particles + pa_index;
1146 ParticleEditKey *key= psys->edit->keys[pa_index];
1149 for(k=0; k<pa->totkey; k++,key++) {
1151 key->flag |= PEK_SELECT;
1153 key->flag &= ~PEK_SELECT;
1156 pa->flag |= PARS_EDIT_RECALC;
1159 static void toggle_key_select(PEData *data, int pa_index, int key_index)
1161 ParticleSystem *psys= data->psys;
1162 ParticleData *pa= psys->particles + pa_index;
1164 if(psys->edit->keys[pa_index][key_index].flag&PEK_SELECT)
1165 psys->edit->keys[pa_index][key_index].flag &= ~PEK_SELECT;
1167 psys->edit->keys[pa_index][key_index].flag |= PEK_SELECT;
1169 pa->flag |= PARS_EDIT_RECALC;
1172 /************************ de select all operator ************************/
1174 static int de_select_all_exec(bContext *C, wmOperator *op)
1176 Scene *scene= CTX_data_scene(C);
1177 Object *ob= CTX_data_active_object(C);
1178 ParticleSystem *psys= PE_get_current(scene, ob);
1179 ParticleEdit *edit= 0;
1181 ParticleEditKey *key;
1182 int i, k, totpart, sel= 0;
1185 totpart= psys->totpart;
1187 LOOP_PARTICLES(i, pa) {
1188 if(pa->flag & PARS_HIDE) continue;
1190 if(key->flag & PEK_SELECT) {
1192 key->flag &= ~PEK_SELECT;
1193 pa->flag |= PARS_EDIT_RECALC;
1199 LOOP_PARTICLES(i, pa) {
1200 if(pa->flag & PARS_HIDE) continue;
1202 if(!(key->flag & PEK_SELECT)) {
1203 key->flag |= PEK_SELECT;
1204 pa->flag |= PARS_EDIT_RECALC;
1210 PE_update_selection(scene, ob, 1);
1211 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
1213 return OPERATOR_FINISHED;
1216 void PARTICLE_OT_select_all_toggle(wmOperatorType *ot)
1219 ot->name= "Select or Deselect All";
1220 ot->idname= "PARTICLE_OT_select_all_toggle";
1223 ot->exec= de_select_all_exec;
1227 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1230 /************************ pick select operator ************************/
1232 int PE_mouse_particles(bContext *C, short *mval, int extend)
1235 Scene *scene= CTX_data_scene(C);
1236 Object *ob= CTX_data_active_object(C);
1237 ParticleSystem *psys= PE_get_current(scene, ob);
1238 ParticleEdit *edit= 0;
1240 ParticleEditKey *key;
1243 if(!PE_can_edit(psys))
1244 return OPERATOR_CANCELLED;
1247 totpart= psys->totpart;
1250 LOOP_PARTICLES(i, pa) {
1251 if(pa->flag & PARS_HIDE) continue;
1253 if(key->flag & PEK_SELECT) {
1254 key->flag &= ~PEK_SELECT;
1255 pa->flag |= PARS_EDIT_RECALC;
1261 PE_set_view3d_data(C, &data);
1265 for_mouse_hit_keys(&data, toggle_key_select, 1); /* nearest only */
1267 PE_update_selection(scene, ob, 1);
1268 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1270 return OPERATOR_FINISHED;
1273 /************************ select first operator ************************/
1275 static void select_root(PEData *data, int pa_index)
1277 ParticleSystem *psys= data->psys;
1279 psys->edit->keys[pa_index]->flag |= PEK_SELECT;
1282 static int select_first_exec(bContext *C, wmOperator *op)
1286 PE_set_data(C, &data);
1287 PE_foreach_particle(&data, select_root);
1288 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1290 return OPERATOR_FINISHED;
1293 void PARTICLE_OT_select_first(wmOperatorType *ot)
1296 ot->name= "Select First";
1297 ot->idname= "PARTICLE_OT_select_first";
1300 ot->exec= select_first_exec;
1304 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1307 /************************ select last operator ************************/
1309 static void select_tip(PEData *data, int pa_index)
1311 ParticleSystem *psys= data->psys;
1312 ParticleData *pa= psys->particles + pa_index;
1313 ParticleEditKey *key= psys->edit->keys[pa_index] + pa->totkey-1;
1315 key->flag |= PEK_SELECT;
1318 static int select_last_exec(bContext *C, wmOperator *op)
1322 PE_set_data(C, &data);
1323 PE_foreach_particle(&data, select_tip);
1324 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1326 return OPERATOR_FINISHED;
1329 void PARTICLE_OT_select_last(wmOperatorType *ot)
1332 ot->name= "Select Last";
1333 ot->idname= "PARTICLE_OT_select_last";
1336 ot->exec= select_last_exec;
1340 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1343 /************************ select linked operator ************************/
1345 static int select_linked_exec(bContext *C, wmOperator *op)
1351 RNA_int_get_array(op->ptr, "location", location);
1352 mval[0]= location[0];
1353 mval[1]= location[1];
1355 view3d_operator_needs_opengl(C);
1357 PE_set_view3d_data(C, &data);
1360 data.select= !RNA_boolean_get(op->ptr, "deselect");
1362 for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */
1363 PE_update_selection(data.scene, data.ob, 1);
1364 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1366 return OPERATOR_FINISHED;
1369 static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *event)
1371 ARegion *ar= CTX_wm_region(C);
1374 location[0]= event->x - ar->winrct.xmin;
1375 location[1]= event->y - ar->winrct.ymin;
1376 RNA_int_set_array(op->ptr, "location", location);
1378 return select_linked_exec(C, op);
1381 void PARTICLE_OT_select_linked(wmOperatorType *ot)
1384 ot->name= "Select Linked";
1385 ot->idname= "PARTICLE_OT_select_linked";
1388 ot->exec= select_linked_exec;
1389 ot->invoke= select_linked_invoke;
1390 ot->poll= PE_poll_3dview;
1393 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1396 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them.");
1397 RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
1400 /************************ border select operator ************************/
1402 int PE_border_select(bContext *C, rcti *rect, int select)
1404 Scene *scene= CTX_data_scene(C);
1405 Object *ob= CTX_data_active_object(C);
1406 ParticleSystem *psys= PE_get_current(scene, ob);
1409 if(!PE_can_edit(psys))
1410 return OPERATOR_CANCELLED;
1412 PE_set_view3d_data(C, &data);
1414 data.select= select;
1416 for_mouse_hit_keys(&data, select_key, 0);
1418 PE_update_selection(scene, ob, 1);
1419 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
1421 return OPERATOR_FINISHED;
1424 /************************ circle select operator ************************/
1426 int PE_circle_select(bContext *C, int selecting, short *mval, float rad)
1428 Scene *scene= CTX_data_scene(C);
1429 Object *ob= CTX_data_active_object(C);
1430 ParticleSystem *psys= PE_get_current(scene, ob);
1433 if(!PE_can_edit(psys))
1434 return OPERATOR_FINISHED;
1436 PE_set_view3d_data(C, &data);
1439 data.select= selecting;
1441 for_mouse_hit_keys(&data, select_key, 0);
1443 PE_update_selection(scene, ob, 1);
1444 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
1446 return OPERATOR_FINISHED;
1449 /************************ lasso select operator ************************/
1451 int PE_lasso_select(bContext *C, short mcords[][2], short moves, short select)
1453 Scene *scene= CTX_data_scene(C);
1454 Object *ob= CTX_data_active_object(C);
1455 ARegion *ar= CTX_wm_region(C);
1456 ParticleSystem *psys= PE_get_current(scene, ob);
1457 ParticleSystemModifierData *psmd;
1460 ParticleEditKey *key;
1461 ParticleEditSettings *pset= PE_settings(scene);
1462 float co[3], mat[4][4];
1466 if(!PE_can_edit(psys))
1467 return OPERATOR_CANCELLED;
1469 psmd= psys_get_modifier(ob, psys);
1471 totpart= psys->totpart;
1473 LOOP_PARTICLES(i, pa) {
1474 if(pa->flag & PARS_HIDE) continue;
1476 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat);
1478 if(pset->selectmode==SCE_SELECT_POINT) {
1480 VECCOPY(co, key->co);
1481 Mat4MulVecfl(mat, co);
1482 project_short(ar, co, vertco);
1483 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
1484 if(select && !(key->flag & PEK_SELECT)) {
1485 key->flag |= PEK_SELECT;
1486 pa->flag |= PARS_EDIT_RECALC;
1488 else if(key->flag & PEK_SELECT) {
1489 key->flag &= ~PEK_SELECT;
1490 pa->flag |= PARS_EDIT_RECALC;
1495 else if(pset->selectmode==SCE_SELECT_END) {
1496 key= edit->keys[i] + pa->totkey - 1;
1498 VECCOPY(co, key->co);
1499 Mat4MulVecfl(mat, co);
1500 project_short(ar, co,vertco);
1501 if((vertco[0] != IS_CLIPPED) && lasso_inside(mcords,moves,vertco[0],vertco[1])) {
1502 if(select && !(key->flag & PEK_SELECT)) {
1503 key->flag |= PEK_SELECT;
1504 pa->flag |= PARS_EDIT_RECALC;
1506 else if(key->flag & PEK_SELECT) {
1507 key->flag &= ~PEK_SELECT;
1508 pa->flag |= PARS_EDIT_RECALC;
1514 PE_update_selection(scene, ob, 1);
1515 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
1517 return OPERATOR_FINISHED;
1520 /*************************** hide operator **************************/
1522 static int hide_exec(bContext *C, wmOperator *op)
1524 Object *ob= CTX_data_active_object(C);
1525 Scene *scene= CTX_data_scene(C);
1526 ParticleSystem *psys= PE_get_current(scene, ob);
1528 ParticleEditKey *key;
1533 totpart= psys->totpart;
1535 if(RNA_enum_get(op->ptr, "unselected")) {
1536 LOOP_PARTICLES(i, pa) {
1537 if(!particle_is_selected(psys, pa)) {
1538 pa->flag |= PARS_HIDE;
1539 pa->flag |= PARS_EDIT_RECALC;
1542 key->flag &= ~PEK_SELECT;
1547 LOOP_PARTICLES(i, pa) {
1548 if(particle_is_selected(psys, pa)) {
1549 pa->flag |= PARS_HIDE;
1550 pa->flag |= PARS_EDIT_RECALC;
1553 key->flag &= ~PEK_SELECT;
1558 PE_update_selection(scene, ob, 1);
1559 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
1561 return OPERATOR_FINISHED;
1564 void PARTICLE_OT_hide(wmOperatorType *ot)
1567 ot->name= "Hide Selected";
1568 ot->idname= "PARTICLE_OT_hide";
1571 ot->exec= hide_exec;
1575 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1578 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
1581 /*************************** reveal operator **************************/
1583 static int reveal_exec(bContext *C, wmOperator *op)
1585 Object *ob= CTX_data_active_object(C);
1586 Scene *scene= CTX_data_scene(C);
1587 ParticleSystem *psys= PE_get_current(scene, ob);
1589 ParticleEditKey *key;
1594 totpart= psys->totpart;
1596 LOOP_PARTICLES(i, pa) {
1597 if(pa->flag & PARS_HIDE) {
1598 pa->flag &= ~PARS_HIDE;
1599 pa->flag |= PARS_EDIT_RECALC;
1602 key->flag |= PEK_SELECT;
1606 PE_update_selection(scene, ob, 1);
1607 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, ob);
1609 return OPERATOR_FINISHED;
1612 void PARTICLE_OT_reveal(wmOperatorType *ot)
1616 ot->idname= "PARTICLE_OT_reveal";
1619 ot->exec= reveal_exec;
1623 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1626 /************************ select less operator ************************/
1628 static void select_less_keys(PEData *data, int pa_index)
1630 ParticleSystem *psys= data->psys;
1631 ParticleEdit *edit= psys->edit;
1632 ParticleData *pa= &psys->particles[pa_index];
1633 ParticleEditKey *key;
1636 for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
1637 if((key->flag & PEK_SELECT)==0) continue;
1640 if(((key+1)->flag&PEK_SELECT)==0)
1641 key->flag |= PEK_TO_SELECT;
1643 else if(k==pa->totkey-1) {
1644 if(((key-1)->flag&PEK_SELECT)==0)
1645 key->flag |= PEK_TO_SELECT;
1648 if((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
1649 key->flag |= PEK_TO_SELECT;
1653 for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
1654 if(key->flag&PEK_TO_SELECT)
1655 key->flag &= ~(PEK_TO_SELECT|PEK_SELECT);
1659 static int select_less_exec(bContext *C, wmOperator *op)
1663 PE_set_data(C, &data);
1664 PE_foreach_particle(&data, select_less_keys);
1665 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1667 return OPERATOR_FINISHED;
1670 void PARTICLE_OT_select_less(wmOperatorType *ot)
1673 ot->name= "Select Less";
1674 ot->idname= "PARTICLE_OT_select_less";
1677 ot->exec= select_less_exec;
1681 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1684 /************************ select more operator ************************/
1686 static void select_more_keys(PEData *data, int pa_index)
1688 ParticleSystem *psys= data->psys;
1689 ParticleEdit *edit= psys->edit;
1690 ParticleData *pa= &psys->particles[pa_index];
1691 ParticleEditKey *key;
1694 for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
1695 if(key->flag & PEK_SELECT) continue;
1698 if((key+1)->flag&PEK_SELECT)
1699 key->flag |= PEK_TO_SELECT;
1701 else if(k==pa->totkey-1) {
1702 if((key-1)->flag&PEK_SELECT)
1703 key->flag |= PEK_TO_SELECT;
1706 if(((key-1)->flag | (key+1)->flag) & PEK_SELECT)
1707 key->flag |= PEK_TO_SELECT;
1711 for(k=0,key=edit->keys[pa_index]; k<pa->totkey; k++,key++) {
1712 if(key->flag&PEK_TO_SELECT) {
1713 key->flag &= ~PEK_TO_SELECT;
1714 key->flag |= PEK_SELECT;
1719 static int select_more_exec(bContext *C, wmOperator *op)
1723 PE_set_data(C, &data);
1724 PE_foreach_particle(&data, select_more_keys);
1725 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, data.ob);
1727 return OPERATOR_FINISHED;
1730 void PARTICLE_OT_select_more(wmOperatorType *ot)
1733 ot->name= "Select More";
1734 ot->idname= "PARTICLE_OT_select_more";
1737 ot->exec= select_more_exec;
1741 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1744 /************************ rekey operator ************************/
1746 static void rekey_particle(PEData *data, int pa_index)
1748 ParticleSystem *psys= data->psys;
1749 ParticleData *pa= &psys->particles[pa_index];
1750 ParticleEdit *edit= psys->edit;
1751 ParticleEditSettings *pset= PE_settings(data->scene);
1753 HairKey *key, *new_keys;
1754 ParticleEditKey *ekey;
1755 float dval, sta, end;
1758 pa->flag |= PARS_REKEY;
1760 key= new_keys= MEM_callocN(pset->totrekey * sizeof(HairKey),"Hair re-key keys");
1762 /* root and tip stay the same */
1763 VECCOPY(key->co, pa->hair->co);
1764 VECCOPY((key + pset->totrekey - 1)->co, (pa->hair + pa->totkey - 1)->co);
1766 sta= key->time= pa->hair->time;
1767 end= (key + pset->totrekey - 1)->time= (pa->hair + pa->totkey - 1)->time;
1768 dval= (end - sta) / (float)(pset->totrekey - 1);
1770 /* interpolate new keys from old ones */
1771 for(k=1,key++; k<pset->totrekey-1; k++,key++) {
1772 state.time= (float)k / (float)(pset->totrekey-1);
1773 psys_get_particle_on_path(data->scene, data->ob, psys, pa_index, &state, 0);
1774 VECCOPY(key->co, state.co);
1775 key->time= sta + k * dval;
1780 MEM_freeN(pa->hair);
1783 pa->totkey=pset->totrekey;
1785 if(edit->keys[pa_index])
1786 MEM_freeN(edit->keys[pa_index]);
1787 ekey= edit->keys[pa_index]= MEM_callocN(pa->totkey * sizeof(ParticleEditKey),"Hair re-key edit keys");
1789 for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
1791 ekey->time= &key->time;
1794 pa->flag &= ~PARS_REKEY;
1795 pa->flag |= PARS_EDIT_RECALC;
1798 static int rekey_exec(bContext *C, wmOperator *op)
1801 ParticleEditSettings *pset;
1803 PE_set_data(C, &data);
1805 pset= PE_settings(data.scene);
1806 pset->totrekey= RNA_int_get(op->ptr, "keys");
1808 data.dval= 1.0f / (float)(pset->totrekey-1);
1810 foreach_selected_particle(&data, rekey_particle);
1812 data.psys->edit->totkeys= psys_count_keys(data.psys);
1813 recalc_lengths(data.psys);
1815 PE_update_object(data.scene, data.ob, 1);
1816 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
1818 return OPERATOR_FINISHED;
1821 void PARTICLE_OT_rekey(wmOperatorType *ot)
1825 ot->idname= "PARTICLE_OT_rekey";
1828 ot->exec= rekey_exec;
1829 ot->invoke= WM_operator_props_popup;
1833 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1836 RNA_def_int(ot->srna, "keys", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
1839 static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time)
1841 ParticleSystem *psys= PE_get_current(scene, ob);
1842 ParticleEdit *edit=0;
1845 HairKey *new_keys, *key;
1846 ParticleEditKey *ekey;
1853 pa= &psys->particles[pa_index];
1855 pa->flag |= PARS_REKEY;
1857 key= new_keys= MEM_dupallocN(pa->hair);
1859 /* interpolate new keys from old ones (roots stay the same) */
1860 for(k=1, key++; k < pa->totkey; k++, key++) {
1861 state.time= path_time * (float)k / (float)(pa->totkey-1);
1862 psys_get_particle_on_path(scene, ob, psys, pa_index, &state, 0);
1863 VECCOPY(key->co, state.co);
1866 /* replace hair keys */
1868 MEM_freeN(pa->hair);
1871 /* update edit pointers */
1872 for(k=0, key=pa->hair, ekey=edit->keys[pa_index]; k<pa->totkey; k++, key++, ekey++) {
1874 ekey->time= &key->time;
1877 pa->flag &= ~PARS_REKEY;
1880 /************************* utilities **************************/
1882 static int remove_tagged_particles(Scene *scene, Object *ob, ParticleSystem *psys)
1884 ParticleEdit *edit= psys->edit;
1885 ParticleEditSettings *pset= PE_settings(scene);
1886 ParticleData *pa, *npa=0, *new_pars=0;
1887 ParticleEditKey **key, **nkey=0, **new_keys=0;
1888 ParticleSystemModifierData *psmd;
1889 int i, totpart, new_totpart= psys->totpart, removed= 0;
1891 if(pset->flag & PE_X_MIRROR) {
1893 psmd= psys_get_modifier(ob, psys);
1894 totpart= psys->totpart;
1896 LOOP_PARTICLES(i, pa)
1897 if(pa->flag & PARS_TAG)
1898 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
1901 for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++) {
1902 if(pa->flag & PARS_TAG) {
1908 if(new_totpart != psys->totpart) {
1910 npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
1911 nkey= new_keys= MEM_callocN(new_totpart * sizeof(ParticleEditKey *), "ParticleEditKey array");
1914 pa= psys->particles;
1916 for(i=0; i<psys->totpart; i++, pa++, key++) {
1917 if(pa->flag & PARS_TAG) {
1921 MEM_freeN(pa->hair);
1924 memcpy(npa, pa, sizeof(ParticleData));
1925 memcpy(nkey, key, sizeof(ParticleEditKey*));
1931 if(psys->particles) MEM_freeN(psys->particles);
1932 psys->particles= new_pars;
1934 if(edit->keys) MEM_freeN(edit->keys);
1935 edit->keys= new_keys;
1937 if(edit->mirror_cache) {
1938 MEM_freeN(edit->mirror_cache);
1939 edit->mirror_cache= NULL;
1942 psys->totpart= new_totpart;
1944 edit->totkeys= psys_count_keys(psys);
1950 static void remove_tagged_keys(Scene *scene, Object *ob, ParticleSystem *psys)
1952 ParticleEdit *edit= psys->edit;
1953 ParticleEditSettings *pset= PE_settings(scene);
1955 HairKey *key, *nkey, *new_keys=0;
1956 ParticleEditKey *ekey;
1957 ParticleSystemModifierData *psmd;
1958 int i, k, totpart= psys->totpart;
1961 if(pset->flag & PE_X_MIRROR) {
1962 /* mirror key tags */
1963 psmd= psys_get_modifier(ob, psys);
1965 LOOP_PARTICLES(i, pa) {
1967 if(ekey->flag & PEK_TAG) {
1968 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
1975 LOOP_PARTICLES(i, pa) {
1976 new_totkey= pa->totkey;
1978 if(ekey->flag & PEK_TAG)
1981 /* we can't have elements with less than two keys*/
1983 pa->flag |= PARS_TAG;
1985 remove_tagged_particles(scene, ob, psys);
1987 totpart= psys->totpart;
1989 LOOP_PARTICLES(i, pa) {
1990 new_totkey= pa->totkey;
1992 if(ekey->flag & PEK_TAG)
1995 if(new_totkey != pa->totkey) {
1997 nkey= new_keys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
1999 for(k=0, ekey=edit->keys[i]; k<new_totkey; k++, key++, nkey++, ekey++) {
2000 while(ekey->flag & PEK_TAG && key < pa->hair + pa->totkey) {
2005 if(key < pa->hair + pa->totkey) {
2006 VECCOPY(nkey->co, key->co);
2007 nkey->time= key->time;
2008 nkey->weight= key->weight;
2012 MEM_freeN(pa->hair);
2016 pa->totkey=new_totkey;
2019 MEM_freeN(edit->keys[i]);
2020 ekey= edit->keys[i]= MEM_callocN(new_totkey*sizeof(ParticleEditKey), "particle edit keys");
2022 for(k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
2024 ekey->time= &key->time;
2029 edit->totkeys= psys_count_keys(psys);
2032 /************************ subdivide opertor *********************/
2034 /* works like normal edit mode subdivide, inserts keys between neighbouring selected keys */
2035 static void subdivide_particle(PEData *data, int pa_index)
2037 ParticleSystem *psys= data->psys;
2038 ParticleEdit *edit= psys->edit;
2039 ParticleData *pa= &psys->particles[pa_index];
2042 HairKey *key, *nkey, *new_keys;
2043 ParticleEditKey *ekey, *nekey, *new_ekeys;
2049 for(k=0, ekey=edit->keys[pa_index]; k<pa->totkey-1; k++,ekey++) {
2050 if(ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
2054 if(totnewkey==0) return;
2056 pa->flag |= PARS_REKEY;
2058 nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)),"Hair subdivide keys");
2059 nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(ParticleEditKey)),"Hair subdivide edit keys");
2060 endtime= pa->hair[pa->totkey-1].time;
2062 for(k=0, key=pa->hair, ekey=edit->keys[pa_index]; k<pa->totkey-1; k++, key++, ekey++) {
2064 memcpy(nkey,key,sizeof(HairKey));
2065 memcpy(nekey,ekey,sizeof(ParticleEditKey));
2067 nekey->co= nkey->co;
2068 nekey->time= &nkey->time;
2073 if(ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) {
2074 nkey->time= (key->time + (key+1)->time)*0.5f;
2075 state.time= (endtime != 0.0f)? nkey->time/endtime: 0.0f;
2076 psys_get_particle_on_path(data->scene, data->ob, psys, pa_index, &state, 0);
2077 VECCOPY(nkey->co, state.co);
2079 nekey->co= nkey->co;
2080 nekey->time= &nkey->time;
2081 nekey->flag |= PEK_SELECT;
2087 /*tip still not copied*/
2088 memcpy(nkey,key,sizeof(HairKey));
2089 memcpy(nekey,ekey,sizeof(ParticleEditKey));
2091 nekey->co= nkey->co;
2092 nekey->time= &nkey->time;
2095 MEM_freeN(pa->hair);
2098 if(edit->keys[pa_index])
2099 MEM_freeN(edit->keys[pa_index]);
2101 edit->keys[pa_index]= new_ekeys;
2103 pa->totkey += totnewkey;
2104 pa->flag |= PARS_EDIT_RECALC;
2105 pa->flag &= ~PARS_REKEY;
2108 static int subdivide_exec(bContext *C, wmOperator *op)
2112 PE_set_data(C, &data);
2113 PE_foreach_particle(&data, subdivide_particle);
2115 data.psys->edit->totkeys= psys_count_keys(data.psys);
2117 recalc_lengths(data.psys);
2118 psys_update_world_cos(data.ob, data.psys);
2120 PE_update_object(data.scene, data.ob, 1);
2121 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
2123 return OPERATOR_FINISHED;
2126 void PARTICLE_OT_subdivide(wmOperatorType *ot)
2129 ot->name= "Subdivide";
2130 ot->idname= "PARTICLE_OT_subdivide";
2133 ot->exec= subdivide_exec;
2137 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2140 /************************ remove doubles opertor *********************/
2142 static int remove_doubles_exec(bContext *C, wmOperator *op)
2144 Scene *scene= CTX_data_scene(C);
2145 Object *ob= CTX_data_active_object(C);
2146 ParticleSystem *psys= PE_get_current(scene, ob);
2147 ParticleEditSettings *pset=PE_settings(scene);
2150 ParticleSystemModifierData *psmd;
2152 KDTreeNearest nearest[10];
2153 float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
2154 int i, n, totn, removed, totpart, flag, totremoved;
2157 psmd= psys_get_modifier(ob, psys);
2163 totpart= psys->totpart;
2164 tree=BLI_kdtree_new(totpart);
2166 /* insert particles into kd tree */
2167 LOOP_PARTICLES(i, pa) {
2168 if(particle_is_selected(psys, pa)) {
2169 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, mat);
2170 VECCOPY(co, pa->hair[0].co);
2171 Mat4MulVecfl(mat, co);
2172 BLI_kdtree_insert(tree, i, co, NULL);
2176 BLI_kdtree_balance(tree);
2178 /* tag particles to be removed */
2179 LOOP_PARTICLES(i, pa) {
2180 if(particle_is_selected(psys, pa)) {
2181 psys_mat_hair_to_object(ob, psmd->dm, psys->part->from, pa, mat);
2182 VECCOPY(co, pa->hair[0].co);
2183 Mat4MulVecfl(mat, co);
2185 totn= BLI_kdtree_find_n_nearest(tree,10,co,NULL,nearest);
2187 for(n=0; n<totn; n++) {
2188 /* this needs a custom threshold still */
2189 if(nearest[n].index > i && nearest[n].dist < threshold) {
2190 if(!(pa->flag & PARS_TAG)) {
2191 pa->flag |= PARS_TAG;
2199 BLI_kdtree_free(tree);
2201 /* remove tagged particles - don't do mirror here! */
2203 pset->flag &= ~PE_X_MIRROR;
2204 remove_tagged_particles(scene, ob, psys);
2206 totremoved += removed;
2210 return OPERATOR_CANCELLED;
2212 BKE_reportf(op->reports, RPT_INFO, "Remove %d double particles.", totremoved);
2214 psys_update_world_cos(ob, psys);
2215 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2216 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
2218 return OPERATOR_FINISHED;
2221 void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
2224 ot->name= "Remove Doubles";
2225 ot->idname= "PARTICLE_OT_remove_doubles";
2228 ot->exec= remove_doubles_exec;
2232 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2235 RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX, "Threshold", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
2238 /************************ cursor drawing *******************************/
2240 static void brush_drawcursor(bContext *C, int x, int y, void *customdata)
2242 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2243 ParticleBrushData *brush;
2245 if(pset->brushtype < 0)
2248 brush= &pset->brush[pset->brushtype];
2253 glTranslatef((float)x, (float)y, 0.0f);
2255 glColor4ub(255, 255, 255, 128);
2256 glEnable(GL_LINE_SMOOTH );
2258 glutil_draw_lined_arc(0.0, M_PI*2.0, brush->size, 40);
2259 glDisable(GL_BLEND);
2260 glDisable(GL_LINE_SMOOTH );
2266 static void toggle_particle_cursor(bContext *C, int enable)
2268 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2270 if(pset->paintcursor && !enable) {
2271 WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
2272 pset->paintcursor = NULL;
2275 pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll, brush_drawcursor, NULL);
2278 /********************* radial control operator *********************/
2280 static int brush_radial_control_invoke(bContext *C, wmOperator *op, wmEvent *event)
2282 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2283 ParticleBrushData *brush;
2284 int mode = RNA_enum_get(op->ptr, "mode");
2285 float original_value=1.0f;
2287 if(pset->brushtype < 0)
2288 return OPERATOR_CANCELLED;
2290 brush= &pset->brush[pset->brushtype];
2292 toggle_particle_cursor(C, 0);
2294 if(mode == WM_RADIALCONTROL_SIZE)
2295 original_value = brush->size;
2296 else if(mode == WM_RADIALCONTROL_STRENGTH)
2297 original_value = brush->strength;
2299 RNA_float_set(op->ptr, "initial_value", original_value);
2301 return WM_radial_control_invoke(C, op, event);
2304 static int brush_radial_control_modal(bContext *C, wmOperator *op, wmEvent *event)
2306 int ret = WM_radial_control_modal(C, op, event);
2308 if(ret != OPERATOR_RUNNING_MODAL)
2309 toggle_particle_cursor(C, 1);
2314 static int brush_radial_control_exec(bContext *C, wmOperator *op)
2316 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2317 ParticleBrushData *brush;
2318 int mode = RNA_enum_get(op->ptr, "mode");
2319 float new_value = RNA_float_get(op->ptr, "new_value");
2321 if(pset->brushtype < 0)
2322 return OPERATOR_CANCELLED;
2324 brush= &pset->brush[pset->brushtype];
2326 if(mode == WM_RADIALCONTROL_SIZE)
2327 brush->size= new_value;
2328 else if(mode == WM_RADIALCONTROL_STRENGTH)
2329 brush->strength= new_value;
2331 return OPERATOR_FINISHED;
2334 void PARTICLE_OT_brush_radial_control(wmOperatorType *ot)
2336 WM_OT_radial_control_partial(ot);
2338 ot->name= "Brush Radial Control";
2339 ot->idname= "PARTICLE_OT_brush_radial_control";
2341 ot->invoke= brush_radial_control_invoke;
2342 ot->modal= brush_radial_control_modal;
2343 ot->exec= brush_radial_control_exec;
2347 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
2350 /*************************** delete operator **************************/
2352 enum { DEL_PARTICLE, DEL_KEY };
2354 static EnumPropertyItem delete_type_items[]= {
2355 {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
2356 {DEL_KEY, "KEY", 0, "Key", ""},
2357 {0, NULL, 0, NULL, NULL}};
2359 static void set_delete_particle(PEData *data, int pa_index)
2361 ParticleSystem *psys= data->psys;
2363 psys->particles[pa_index].flag |= PARS_TAG;
2366 static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
2368 ParticleSystem *psys= data->psys;
2370 psys->edit->keys[pa_index][key_index].flag |= PEK_TAG;
2373 static int delete_exec(bContext *C, wmOperator *op)
2376 int type= RNA_enum_get(op->ptr, "type");
2378 PE_set_data(C, &data);
2380 if(type == DEL_KEY) {
2381 foreach_selected_key(&data, set_delete_particle_key);
2382 remove_tagged_keys(data.scene, data.ob, data.psys);
2383 recalc_lengths(data.psys);
2385 else if(type == DEL_PARTICLE) {
2386 foreach_selected_particle(&data, set_delete_particle);
2387 remove_tagged_particles(data.scene, data.ob, data.psys);
2388 recalc_lengths(data.psys);
2391 DAG_object_flush_update(data.scene, data.ob, OB_RECALC_DATA);
2392 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, data.ob);
2394 return OPERATOR_FINISHED;
2397 void PARTICLE_OT_delete(wmOperatorType *ot)
2401 ot->idname= "PARTICLE_OT_delete";
2404 ot->exec= delete_exec;
2405 ot->invoke= WM_menu_invoke;
2409 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2412 RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys.");
2415 /*************************** mirror operator **************************/
2417 static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
2419 Mesh *me= (Mesh*)(ob->data);
2420 ParticleSystemModifierData *psmd;
2421 ParticleSystem *psys= PE_get_current(scene, ob);
2423 ParticleData *pa, *newpa, *new_pars;
2424 ParticleEditKey *ekey, **newkey, **key, **new_keys;
2427 int i, k, rotation, totpart, newtotpart;
2430 psmd= psys_get_modifier(ob, psys);
2432 mirrorfaces= mesh_get_x_mirror_faces(ob, NULL);
2434 if(!edit->mirror_cache)
2435 PE_update_mirror_cache(ob, psys);
2437 totpart= psys->totpart;
2438 newtotpart= psys->totpart;
2439 LOOP_PARTICLES(i, pa) {
2440 if(pa->flag & PARS_HIDE) continue;
2443 if(particle_is_selected(psys, pa)) {
2444 if(edit->mirror_cache[i] != -1) {
2445 /* already has a mirror, don't need to duplicate */
2446 PE_mirror_particle(ob, psmd->dm, psys, pa, NULL);
2450 pa->flag |= PARS_TAG;
2454 if((pa->flag & PARS_TAG) && mirrorfaces[pa->num*2] != -1)
2458 if(newtotpart != psys->totpart) {
2459 /* allocate new arrays and copy existing */
2460 new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
2461 new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey*), "ParticleEditKey new");
2463 if(psys->particles) {
2464 memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
2465 MEM_freeN(psys->particles);
2467 psys->particles= new_pars;
2470 memcpy(new_keys, edit->keys, totpart*sizeof(ParticleEditKey*));
2471 MEM_freeN(edit->keys);
2473 edit->keys= new_keys;
2475 if(edit->mirror_cache) {
2476 MEM_freeN(edit->mirror_cache);
2477 edit->mirror_cache= NULL;
2480 psys->totpart= newtotpart;
2482 /* create new elements */
2483 pa= psys->particles;
2484 newpa= psys->particles + totpart;
2486 newkey= edit->keys + totpart;
2488 for(i=0; i<totpart; i++, pa++, key++) {
2489 if(pa->flag & PARS_HIDE) continue;
2491 if(!(pa->flag & PARS_TAG) || mirrorfaces[pa->num*2] == -1)
2496 if(pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
2497 if(pa->keys) newpa->keys= MEM_dupallocN(pa->keys);
2498 if(*key) *newkey= MEM_dupallocN(*key);
2500 /* rotate weights according to vertex index rotation */
2501 rotation= mirrorfaces[pa->num*2+1];
2502 newpa->fuv[0]= pa->fuv[2];
2503 newpa->fuv[1]= pa->fuv[1];
2504 newpa->fuv[2]= pa->fuv[0];
2505 newpa->fuv[3]= pa->fuv[3];
2506 while(rotation-- > 0)
2507 if(me->mface[pa->num].v4)
2508 SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3])
2510 SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2])
2512 /* assign face inddex */
2513 newpa->num= mirrorfaces[pa->num*2];
2514 newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL);
2516 /* update edit key pointers */
2518 for(k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, ekey++) {
2520 ekey->time= &hkey->time;
2523 /* map key positions as mirror over x axis */
2524 PE_mirror_particle(ob, psmd->dm, psys, pa, newpa);
2530 edit->totkeys= psys_count_keys(psys);
2533 for(pa=psys->particles, i=0; i<psys->totpart; i++, pa++)
2534 pa->flag &= ~PARS_TAG;
2536 MEM_freeN(mirrorfaces);
2539 static int mirror_exec(bContext *C, wmOperator *op)
2541 Scene *scene= CTX_data_scene(C);
2542 Object *ob= CTX_data_active_object(C);
2543 ParticleSystem *psys= PE_get_current(scene, ob);
2545 PE_mirror_x(scene, ob, 0);
2547 psys_update_world_cos(ob, psys);
2548 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_DATA, ob);
2549 DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
2551 return OPERATOR_FINISHED;
2554 void PARTICLE_OT_mirror(wmOperatorType *ot)
2558 ot->idname= "PARTICLE_OT_mirror";
2561 ot->exec= mirror_exec;
2565 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2568 /*********************** set brush operator **********************/
2570 static EnumPropertyItem brush_type_items[]= {
2571 {PE_BRUSH_NONE, "NONE", 0, "None", ""},
2572 {PE_BRUSH_COMB, "COMB", 0, "Comb", ""},
2573 {PE_BRUSH_SMOOTH, "SMOOTH", 0, "Smooth", ""},
2574 {PE_BRUSH_WEIGHT, "WEIGHT", 0, "Weight", ""},
2575 {PE_BRUSH_ADD, "ADD", 0, "Add", ""},
2576 {PE_BRUSH_LENGTH, "LENGTH", 0, "Length", ""},
2577 {PE_BRUSH_PUFF, "PUFF", 0, "Puff", ""},
2578 {PE_BRUSH_CUT, "CUT", 0, "Cut", ""},
2579 {0, NULL, 0, NULL, NULL}
2582 static int set_brush_exec(bContext *C, wmOperator *op)
2584 Scene *scene= CTX_data_scene(C);
2585 ParticleEditSettings *pset= PE_settings(scene);
2587 pset->brushtype= RNA_enum_get(op->ptr, "type");
2589 return OPERATOR_FINISHED;
2592 void PARTICLE_OT_brush_set(wmOperatorType *ot)
2595 ot->name= "Set Brush";
2596 ot->idname= "PARTICLE_OT_brush_set";
2599 ot->exec= set_brush_exec;
2600 ot->invoke= WM_menu_invoke;
2604 RNA_def_enum(ot->srna, "type", brush_type_items, PE_BRUSH_NONE, "Type", "Brush type to select for editing.");
2607 /************************* brush edit callbacks ********************/
2609 static void brush_comb(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
2611 ParticleSystem *psys= data->psys;
2612 ParticleData *pa= &psys->particles[pa_index];
2613 ParticleEditSettings *pset= PE_settings(data->scene);
2614 HairKey *key= pa->hair + key_index;
2617 if(pset->flag & PE_LOCK_FIRST && key_index == 0) return;
2619 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
2621 VECCOPY(cvec,data->dvec);
2622 Mat4Mul3Vecfl(imat,cvec);
2624 VECADD(key->co, key->co, cvec);
2626 pa->flag |= PARS_EDIT_RECALC;
2629 static void brush_cut(PEData *data, int pa_index)
2631 ParticleSystem *psys= data->psys;
2632 ARegion *ar= data->vc.ar;
2633 Object *ob= data->ob;
2634 ParticleData *pa= &psys->particles[pa_index];
2635 ParticleCacheKey *key= psys->pathcache[pa_index];
2636 float rad2, cut_time= 1.0;
2637 float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
2638 int k, cut, keys= (int)pow(2.0, (double)psys->part->draw_step);
2641 /* blunt scissors */
2642 if(BLI_frand() > data->cutfac) return;
2644 rad2= data->rad * data->rad;
2648 project_short_noclip(ar, key->co, vertco);
2649 x0= (float)vertco[0];
2650 x1= (float)vertco[1];
2652 o0= (float)data->mval[0];
2653 o1= (float)data->mval[1];
2658 /* check if root is inside circle */
2659 if(xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co)) {
2664 /* calculate path time closest to root that was inside the circle */
2665 for(k=1, key++; k<=keys; k++, key++) {
2666 project_short_noclip(ar, key->co, vertco);
2668 if(key_test_depth(data, key->co) == 0) {
2669 x0= (float)vertco[0];
2670 x1= (float)vertco[1];
2677 v0= (float)vertco[0] - x0;
2678 v1= (float)vertco[1] - x1;
2682 d= (v0*xo1 - v1*xo0);
2689 cut_time= -(v0*xo0 + v1*xo1 + d);
2691 if(cut_time > 0.0f) {
2694 if(cut_time < 1.0f) {
2695 cut_time += (float)(k-1);
2696 cut_time /= (float)keys;
2703 x0= (float)vertco[0];
2704 x1= (float)vertco[1];
2712 if(cut_time < 0.0f) {
2713 pa->flag |= PARS_TAG;
2716 rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
2717 pa->flag |= PARS_EDIT_RECALC;
2722 static void brush_length(PEData *data, int pa_index)
2724 ParticleSystem *psys= data->psys;
2725 ParticleData *pa= &psys->particles[pa_index];
2727 float dvec[3],pvec[3];
2731 VECCOPY(pvec,key->co);
2733 for(k=1, key++; k<pa->totkey; k++,key++) {
2734 VECSUB(dvec,key->co,pvec);
2735 VECCOPY(pvec,key->co);
2736 VecMulf(dvec,data->growfac);
2737 VECADD(key->co,(key-1)->co,dvec);
2740 pa->flag |= PARS_EDIT_RECALC;
2743 static void brush_puff(PEData *data, int pa_index)
2745 ParticleSystem *psys= data->psys;
2746 ParticleData *pa= &psys->particles[pa_index];
2747 ParticleEdit *edit= psys->edit;
2749 float mat[4][4], imat[4][4];
2750 float lastco[3], rootco[3], co[3], nor[3], kco[3], dco[3], fac, length;
2753 psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, pa, mat);
2754 Mat4Invert(imat,mat);
2756 /* find root coordinate and normal on emitter */
2758 VECCOPY(co, key->co);
2759 Mat4MulVecfl(mat, co);
2761 pa_index= BLI_kdtree_find_nearest(edit->emitter_field, co, NULL, NULL);
2762 if(pa_index == -1) return;
2764 VECCOPY(rootco, co);
2765 VecCopyf(nor, &psys->edit->emitter_cosnos[pa_index*6+3]);
2769 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac);
2774 for(k=1, key++; k<pa->totkey; k++, key++) {
2775 /* compute position as if hair was standing up straight */
2776 VECCOPY(lastco, co);
2777 VECCOPY(co, key->co);
2778 Mat4MulVecfl(mat, co);
2779 length += VecLenf(lastco, co);
2781 VECADDFAC(kco, rootco, nor, length);
2783 /* blend between the current and straight position */
2784 VECSUB(dco, kco, co);
2785 VECADDFAC(co, co, dco, fac);
2787 VECCOPY(key->co, co);
2788 Mat4MulVecfl(imat, key->co);
2791 pa->flag |= PARS_EDIT_RECALC;
2794 static void brush_smooth_get(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
2796 ParticleSystem *psys= data->psys;
2797 ParticleData *pa= &psys->particles[pa_index];
2798 HairKey *key= pa->hair + key_index;
2803 VecSubf(dvec,key->co,(key-1)->co);
2804 Mat4Mul3Vecfl(mat,dvec);
2805 VECADD(data->vec,data->vec,dvec);
2810 static void brush_smooth_do(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
2812 ParticleSystem *psys= data->psys;
2813 ParticleData *pa= &psys->particles[pa_index];
2814 HairKey *key= pa->hair + key_index;
2815 float vec[3], dvec[3];
2818 VECCOPY(vec,data->vec);
2819 Mat4Mul3Vecfl(imat,vec);
2821 VecSubf(dvec,key->co,(key-1)->co);
2823 VECSUB(dvec,vec,dvec);
2824 VecMulf(dvec,data->smoothfac);
2826 VECADD(key->co,key->co,dvec);
2829 pa->flag |= PARS_EDIT_RECALC;
2832 static void brush_add(PEData *data, short number)
2834 Scene *scene= data->scene;
2835 Object *ob= data->ob;
2836 ParticleSystem *psys= data->psys;
2837 ParticleData *add_pars= MEM_callocN(number*sizeof(ParticleData),"ParticleData add");
2838 ParticleSystemModifierData *psmd= psys_get_modifier(ob,psys);
2839 ParticleEditSettings *pset= PE_settings(scene);
2840 ParticleEdit *edit= psys->edit;
2841 int i, k, n= 0, totpart= psys->totpart;
2843 short dmx= 0, dmy= 0;
2844 float co1[3], co2[3], min_d, imat[4][4];
2845 float framestep, timestep= psys_get_timestep(psys->part);
2846 short size= pset->brush[PE_BRUSH_ADD].size;
2847 short size2= size*size;
2849 Mat4Invert(imat,ob->obmat);
2851 BLI_srandom(psys->seed+data->mval[0]+data->mval[1]);
2853 /* painting onto the deformed mesh, could be an option? */
2854 if(psmd->dm->deformedOnly)
2857 dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
2859 for(i=0; i<number; i++) {
2862 while(dmx*dmx+dmy*dmy>size2) {
2863 dmx=(short)((2.0f*BLI_frand()-1.0f)*size);
2864 dmy=(short)((2.0f*BLI_frand()-1.0f)*size);
2868 mco[0]= data->mval[0] + dmx;
2869 mco[1]= data->mval[1] + dmy;
2870 viewline(data->vc.ar, data->vc.v3d, mco, co1, co2);
2872 Mat4MulVecfl(imat,co1);
2873 Mat4MulVecfl(imat,co2);
2876 /* warning, returns the derived mesh face */
2877 if(psys_intersect_dm(scene, ob,dm,0,co1,co2,&min_d,&add_pars[n].num,add_pars[n].fuv,0,0,0,0)) {
2878 add_pars[n].num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,add_pars[n].num,add_pars[n].fuv,NULL);
2883 int newtotpart=totpart+n;
2884 float hairmat[4][4], cur_co[3];
2886 ParticleData *pa, *new_pars= MEM_callocN(newtotpart*sizeof(ParticleData),"ParticleData new");
2887 ParticleEditKey *ekey, **key, **new_keys= MEM_callocN(newtotpart*sizeof(ParticleEditKey *),"ParticleEditKey array new");
2890 /* save existing elements */
2891 memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
2892 memcpy(new_keys, edit->keys, totpart * sizeof(ParticleEditKey*));
2894 /* change old arrays to new ones */
2895 if(psys->particles) MEM_freeN(psys->particles);
2896 psys->particles= new_pars;
2898 if(edit->keys) MEM_freeN(edit->keys);
2899 edit->keys= new_keys;
2901 if(edit->mirror_cache) {
2902 MEM_freeN(edit->mirror_cache);
2903 edit->mirror_cache= NULL;
2906 /* create tree for interpolation */
2907 if(pset->flag & PE_INTERPOLATE_ADDED && psys->totpart) {
2908 tree=BLI_kdtree_new(psys->totpart);
2910 for(i=0, pa=psys->particles; i<totpart; i++, pa++) {
2911 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);
2912 BLI_kdtree_insert(tree, i, cur_co, NULL);
2915 BLI_kdtree_balance(tree);
2918 psys->totpart= newtotpart;
2920 /* create new elements */
2921 pa= psys->particles + totpart;
2922 key= edit->keys + totpart;
2924 for(i=totpart; i<newtotpart; i++, pa++, key++) {
2925 memcpy(pa, add_pars + i - totpart, sizeof(ParticleData));
2926 pa->hair= MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add");
2927 ekey= *key= MEM_callocN(pset->totaddkey * sizeof(ParticleEditKey), "ParticleEditKey add");
2928 pa->totkey= pset->totaddkey;
2930 for(k=0, hkey=pa->hair; k<pa->totkey; k++, hkey++, ekey++) {
2932 ekey->time= &hkey->time;
2936 initialize_particle(pa,i,ob,psys,psmd);
2937 reset_particle(scene, pa,psys,psmd,ob,0.0,1.0,0,0,0);
2938 pa->flag |= PARS_EDIT_RECALC;
2939 if(pset->flag & PE_X_MIRROR)
2940 pa->flag |= PARS_TAG; /* signal for duplicate */
2942 framestep= pa->lifetime/(float)(pset->totaddkey-1);
2947 KDTreeNearest ptn[3];
2949 float maxd, mind, dd, totw=0.0, weight[3];
2951 psys_particle_on_dm(psmd->dm,psys->part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,0,0);
2952 maxw= BLI_kdtree_find_n_nearest(tree,3,co1,NULL,ptn);
2954 maxd= ptn[maxw-1].dist;
2958 for(w=0; w<maxw; w++) {
2959 weight[w]= (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
2966 for(w=0; w<maxw; w++)
2969 for(k=0; k<pset->totaddkey; k++) {
2971 hkey->time= pa->time + k * framestep;
2973 key[0].time= hkey->time/ 100.0f;
2974 psys_get_particle_on_path(scene, ob, psys, ptn[0].index, key, 0);
2975 VecMulf(key[0].co, weight[0]);
2978 key[1].time= key[0].time;
2979 psys_get_particle_on_path(scene, ob, psys, ptn[1].index, key + 1, 0);
2980 VecMulf(key[1].co, weight[1]);
2981 VECADD(key[0].co, key[0].co, key[1].co);
2984 key[2].time= key[0].time;
2985 psys_get_particle_on_path(scene, ob, psys, ptn[2].index, key + 2, 0);
2986 VecMulf(key[2].co, weight[2]);
2987 VECADD(key[0].co, key[0].co, key[2].co);
2992 VECSUB(co1, pa->state.co, key[0].co);
2994 VECADD(pa->hair[k].co, key[0].co, co1);
2996 pa->hair[k].time= key[0].time;
3000 for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
3001 VECADDFAC(hkey->co, pa->state.co, pa->state.vel, k * framestep * timestep);
3002 pa->hair[k].time += k * framestep;
3005 for(k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) {
3006 psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
3007 Mat4Invert(imat,hairmat);
3008 Mat4MulVecfl(imat, hkey->co);
3011 edit->totkeys= psys_count_keys(psys);
3014 BLI_kdtree_free(tree);
3017 MEM_freeN(add_pars);
3019 if(!psmd->dm->deformedOnly)
3023 static void brush_weight(PEData *data, float mat[][4], float imat[][4], int pa_index, int key_index)
3025 ParticleSystem *psys= data->psys;
3028 /* roots have full weight allways */
3030 pa= &psys->particles[pa_index];
3031 pa->hair[key_index].weight= data->weightfac;
3032 pa->flag |= PARS_EDIT_RECALC;
3036 /************************* brush edit operator ********************/
3038 typedef struct BrushEdit {
3041 ParticleSystem *psys;
3047 static int brush_edit_init(bContext *C, wmOperator *op)
3049 Scene *scene= CTX_data_scene(C);
3050 Object *ob= CTX_data_active_object(C);
3051 ParticleSystem *psys= PE_get_current(scene, ob);
3052 ParticleEditSettings *pset= PE_settings(scene);
3053 ARegion *ar= CTX_wm_region(C);
3056 if(pset->brushtype < 0)
3059 initgrabz(ar->regiondata, ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2]);
3061 bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit");
3063 op->customdata= bedit;
3065 bedit->scene= scene;
3072 static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
3074 BrushEdit *bedit= op->customdata;
3075 Scene *scene= bedit->scene;
3076 Object *ob= bedit->ob;
3077 ParticleSystem *psys= bedit->psys;
3078 ParticleEditSettings *pset= PE_settings(scene);
3079 ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
3080 ParticleBrushData *brush= &pset->brush[pset->brushtype];
3081 ARegion *ar= CTX_wm_region(C);
3082 float vec1[3], vec2[3];
3083 short mval[2], mvalo[2];
3084 int flip, mouse[2], dx, dy, removed= 0, selected= 0;
3086 RNA_int_get_array(itemptr, "mouse", mouse);
3087 flip= RNA_boolean_get(itemptr, "flip");
3090 bedit->lastmouse[0]= mouse[0];
3091 bedit->lastmouse[1]= mouse[1];
3094 dx= mouse[0] - bedit->lastmouse[0];
3095 dy= mouse[1] - bedit->lastmouse[1];
3100 mvalo[0]= bedit->lastmouse[0];
3101 mvalo[1]= bedit->lastmouse[1];
3103 if(((pset->brushtype == PE_BRUSH_ADD) ?
3104 (sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0))
3107 view3d_operator_needs_opengl(C);
3108 selected= (short)count_selected_keys(scene, psys);
3110 switch(pset->brushtype) {
3115 PE_set_view3d_data(C, &data);
3117 data.rad= (float)brush->size;
3119 data.combfac= (float)(brush->strength - 50) / 50.0f;
3120 if(data.combfac < 0.0f)
3121 data.combfac= 1.0f - 9.0f * data.combfac;
3123 data.combfac= 1.0f - data.combfac;
3125 Mat4Invert(ob->imat, ob->obmat);
3127 window_to_3d(ar, vec1, mvalo[0], mvalo[1]);
3128 window_to_3d(ar, vec2, mval[0], mval[1]);
3129 VECSUB(vec1, vec2, vec1);
3132 foreach_mouse_hit_key(&data, brush_comb, selected);
3139 PE_set_view3d_data(C, &data);
3141 data.rad= (float)brush->size;
3142 data.cutfac= (float)(brush->strength / 100.0f);
3145 foreach_selected_particle(&data, brush_cut);
3147 PE_foreach_particle(&data, brush_cut);
3149 removed= remove_tagged_particles(scene, ob, psys);
3150 if(pset->flag & PE_KEEP_LENGTHS)
3151 recalc_lengths(psys);
3154 case PE_BRUSH_LENGTH:
3158 PE_set_view3d_data(C, &data);
3161 data.rad= (float)brush->size;
3162 data.growfac= (float)brush->strength / 5000.0f;
3164 if(brush->invert ^ flip)
3165 data.growfac= 1.0f - data.growfac;
3167 data.growfac= 1.0f + data.growfac;
3169 foreach_mouse_hit_particle(&data, brush_length, selected);
3171 if(pset->flag & PE_KEEP_LENGTHS)
3172 recalc_lengths(psys);
3179 PE_set_view3d_data(C, &data);
3182 data.rad= (float)brush->size;
3184 data.pufffac= (float)(brush->strength - 50) / 50.0f;
3185 if(data.pufffac < 0.0f)
3186 data.pufffac= 1.0f - 9.0f * data.pufffac;
3188 data.pufffac= 1.0f - data.pufffac;
3190 data.invert= (brush->invert ^ flip);
3191 Mat4Invert(ob->imat, ob->obmat);
3193 foreach_mouse_hit_particle(&data, brush_puff, selected);
3200 if(psys->part->from==PART_FROM_FACE) {
3201 PE_set_view3d_data(C, &data);
3204 brush_add(&data, brush->strength);
3206 if(pset->flag & PE_KEEP_LENGTHS)
3207 recalc_lengths(psys);
3211 case PE_BRUSH_WEIGHT: