2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2007 by Janne Karhu.
19 * All rights reserved.
21 * The Original Code is: all of this file.
23 * Contributor(s): none yet.
25 * ***** END GPL LICENSE BLOCK *****
28 /** \file blender/editors/physics/particle_edit.c
38 #include "MEM_guardedalloc.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_mesh_types.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_view3d_types.h"
44 #include "DNA_screen_types.h"
45 #include "DNA_space_types.h"
48 #include "BLI_lasso.h"
49 #include "BLI_listbase.h"
50 #include "BLI_string.h"
51 #include "BLI_kdtree.h"
53 #include "BLI_utildefines.h"
55 #include "BKE_context.h"
56 #include "BKE_depsgraph.h"
57 #include "BKE_DerivedMesh.h"
58 #include "BKE_global.h"
59 #include "BKE_object.h"
61 #include "BKE_modifier.h"
62 #include "BKE_particle.h"
63 #include "BKE_report.h"
64 #include "BKE_bvhutils.h"
65 #include "BKE_pointcache.h"
69 #include "ED_object.h"
70 #include "ED_physics.h"
72 #include "ED_particle.h"
73 #include "ED_view3d.h"
75 #include "GPU_immediate.h"
76 #include "GPU_immediate_util.h"
78 #include "UI_resources.h"
83 #include "RNA_access.h"
84 #include "RNA_define.h"
86 #include "physics_intern.h"
88 void PE_create_particle_edit(Scene *scene, SceneLayer *sl, Object *ob, PointCache *cache, ParticleSystem *psys);
89 void PTCacheUndo_clear(PTCacheEdit *edit);
90 void recalc_lengths(PTCacheEdit *edit);
91 void recalc_emitter_field(Object *ob, ParticleSystem *psys);
92 void update_world_cos(Object *ob, PTCacheEdit *edit);
94 #define KEY_K PTCacheEditKey *key; int k
95 #define POINT_P PTCacheEditPoint *point; int p
96 #define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++)
97 #define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE))
98 #define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point))
99 #define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point))
100 #define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC)
101 #define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG)
102 #define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++)
103 #define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE))
104 #define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
105 #define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG)
107 #define KEY_WCO ((key->flag & PEK_USE_WCO) ? key->world_co : key->co)
109 /**************************** utilities *******************************/
111 int PE_poll(bContext *C)
113 Scene *scene= CTX_data_scene(C);
114 SceneLayer *sl = CTX_data_scene_layer(C);
115 Object *ob= CTX_data_active_object(C);
117 if (!scene || !sl || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
120 return (PE_get_current(scene, sl, ob) != NULL);
123 int PE_hair_poll(bContext *C)
125 Scene *scene= CTX_data_scene(C);
126 SceneLayer *sl = CTX_data_scene_layer(C);
127 Object *ob= CTX_data_active_object(C);
130 if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
133 edit= PE_get_current(scene, sl, ob);
135 return (edit && edit->psys);
138 int PE_poll_view3d(bContext *C)
140 ScrArea *sa = CTX_wm_area(C);
141 ARegion *ar = CTX_wm_region(C);
143 return (PE_poll(C) &&
144 (sa && sa->spacetype == SPACE_VIEW3D) &&
145 (ar && ar->regiontype == RGN_TYPE_WINDOW));
148 void PE_free_ptcache_edit(PTCacheEdit *edit)
154 PTCacheUndo_clear(edit);
159 MEM_freeN(point->keys);
162 MEM_freeN(edit->points);
165 if (edit->mirror_cache)
166 MEM_freeN(edit->mirror_cache);
168 if (edit->emitter_cosnos) {
169 MEM_freeN(edit->emitter_cosnos);
170 edit->emitter_cosnos= 0;
173 if (edit->emitter_field) {
174 BLI_kdtree_free(edit->emitter_field);
175 edit->emitter_field= 0;
178 psys_free_path_cache(edit->psys, edit);
183 /************************************************/
184 /* Edit Mode Helpers */
185 /************************************************/
187 int PE_start_edit(PTCacheEdit *edit)
192 edit->psys->flag |= PSYS_EDITED;
199 ParticleEditSettings *PE_settings(Scene *scene)
201 return scene->toolsettings ? &scene->toolsettings->particle : NULL;
204 static float pe_brush_size_get(const Scene *UNUSED(scene), ParticleBrushData *brush)
206 // here we can enable unified brush size, needs more work...
207 // UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
208 // float size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
210 return brush->size * U.pixelsize;
214 /* always gets at least the first particlesystem even if PSYS_CURRENT flag is not set
216 * note: this function runs on poll, therefor it can runs many times a second
218 static PTCacheEdit *pe_get_current(Scene *scene, SceneLayer *sl, Object *ob, int create)
220 ParticleEditSettings *pset= PE_settings(scene);
221 PTCacheEdit *edit = NULL;
225 if (pset==NULL || ob==NULL)
229 pset->scene_layer = sl;
232 BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
234 /* in the case of only one editable thing, set pset->edittype accordingly */
235 if (BLI_listbase_is_single(&pidlist)) {
238 case PTCACHE_TYPE_PARTICLES:
239 pset->edittype = PE_TYPE_PARTICLES;
241 case PTCACHE_TYPE_SOFTBODY:
242 pset->edittype = PE_TYPE_SOFTBODY;
244 case PTCACHE_TYPE_CLOTH:
245 pset->edittype = PE_TYPE_CLOTH;
250 for (pid=pidlist.first; pid; pid=pid->next) {
251 if (pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) {
252 ParticleSystem *psys = pid->calldata;
254 if (psys->flag & PSYS_CURRENT) {
255 if (psys->part && psys->part->type == PART_HAIR) {
256 if (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
257 if (create && !psys->pointcache->edit)
258 PE_create_particle_edit(scene, sl, ob, pid->cache, NULL);
259 edit = pid->cache->edit;
262 if (create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
263 PE_create_particle_edit(scene, sl, ob, NULL, psys);
268 if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
269 PE_create_particle_edit(scene, sl, ob, pid->cache, psys);
270 edit = pid->cache->edit;
276 else if (pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
277 if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
278 pset->flag |= PE_FADE_TIME;
279 // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
280 PE_create_particle_edit(scene, sl, ob, pid->cache, NULL);
282 edit = pid->cache->edit;
285 else if (pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
286 if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
287 pset->flag |= PE_FADE_TIME;
288 // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
289 PE_create_particle_edit(scene, sl, ob, pid->cache, NULL);
291 edit = pid->cache->edit;
299 BLI_freelistN(&pidlist);
304 PTCacheEdit *PE_get_current(Scene *scene, SceneLayer *sl, Object *ob)
306 return pe_get_current(scene, sl, ob, 0);
309 PTCacheEdit *PE_create_current(Scene *scene, Object *ob)
311 return pe_get_current(scene, NULL, ob, 1);
314 void PE_current_changed(Scene *scene, Object *ob)
316 if (ob->mode == OB_MODE_PARTICLE_EDIT)
317 PE_create_current(scene, ob);
320 void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
322 ParticleEditSettings *pset=PE_settings(scene);
326 if (pset->flag & PE_FADE_TIME && pset->selectmode==SCE_SELECT_POINT) {
329 if (fabsf(cfra - *key->time) < pset->fade_frames)
330 key->flag &= ~PEK_HIDE;
332 key->flag |= PEK_HIDE;
333 //key->flag &= ~PEK_SELECT;
341 key->flag &= ~PEK_HIDE;
347 static int pe_x_mirror(Object *ob)
349 if (ob->type == OB_MESH)
350 return (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X);
355 /****************** common struct passed to callbacks ******************/
357 typedef struct PEData {
361 SceneLayer *scene_layer;
365 BVHTreeFromMesh shape_bvh;
388 int select_toggle_action;
391 static void PE_set_data(bContext *C, PEData *data)
393 memset(data, 0, sizeof(*data));
395 data->scene= CTX_data_scene(C);
396 data->scene_layer = CTX_data_scene_layer(C);
397 data->ob= CTX_data_active_object(C);
398 data->edit= PE_get_current(data->scene, data->scene_layer, data->ob);
401 static void PE_set_view3d_data(bContext *C, PEData *data)
403 PE_set_data(C, data);
405 view3d_set_viewcontext(C, &data->vc);
407 if (V3D_IS_ZBUF(data->vc.v3d)) {
408 if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
409 /* needed or else the draw matrix can be incorrect */
410 view3d_operator_needs_opengl(C);
412 ED_view3d_backbuf_validate(&data->vc);
413 /* we may need to force an update here by setting the rv3d as dirty
414 * for now it seems ok, but take care!:
415 * rv3d->depths->dirty = 1; */
416 ED_view3d_depth_update(data->vc.ar);
421 static bool PE_create_shape_tree(PEData *data, Object *shapeob)
423 DerivedMesh *dm = shapeob->derivedFinal;
425 memset(&data->shape_bvh, 0, sizeof(data->shape_bvh));
431 DM_ensure_looptri(dm);
432 return (bvhtree_from_mesh_looptri(&data->shape_bvh, dm, 0.0f, 4, 8) != NULL);
435 static void PE_free_shape_tree(PEData *data)
437 free_bvhtree_from_mesh(&data->shape_bvh);
440 /*************************** selection utilities *******************************/
442 static bool key_test_depth(PEData *data, const float co[3], const int screen_co[2])
444 View3D *v3d= data->vc.v3d;
445 ViewDepths *vd = data->vc.rv3d->depths;
449 if (!V3D_IS_ZBUF(v3d))
452 /* used to calculate here but all callers have the screen_co already, so pass as arg */
454 if (ED_view3d_project_int_global(data->vc.ar, co, screen_co,
455 V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK)
461 /* check if screen_co is within bounds because brush_cut uses out of screen coords */
462 if (screen_co[0] >= 0 && screen_co[0] < vd->w && screen_co[1] >= 0 && screen_co[1] < vd->h) {
463 BLI_assert(vd && vd->depths);
464 /* we know its not clipped */
465 depth = vd->depths[screen_co[1] * vd->w + screen_co[0]];
471 ED_view3d_project(data->vc.ar, co, win);
473 if (win[2] - 0.00001f > depth)
479 static bool key_inside_circle(PEData *data, float rad, const float co[3], float *distance)
484 /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
485 if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK) {
489 dx= data->mval[0] - screen_co[0];
490 dy= data->mval[1] - screen_co[1];
491 dist = sqrtf(dx * dx + dy * dy);
496 if (key_test_depth(data, co, screen_co)) {
506 static bool key_inside_rect(PEData *data, const float co[3])
510 if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK) {
514 if (screen_co[0] > data->rect->xmin && screen_co[0] < data->rect->xmax &&
515 screen_co[1] > data->rect->ymin && screen_co[1] < data->rect->ymax)
517 return key_test_depth(data, co, screen_co);
523 static bool key_inside_test(PEData *data, const float co[3])
526 return key_inside_circle(data, data->rad, co, NULL);
528 return key_inside_rect(data, co);
531 static bool point_is_selected(PTCacheEditPoint *point)
535 if (point->flag & PEP_HIDE)
545 /*************************** iterators *******************************/
547 typedef void (*ForPointFunc)(PEData *data, int point_index);
548 typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index);
549 typedef void (*ForKeyMatFunc)(PEData *data, float mat[4][4], float imat[4][4], int point_index, int key_index, PTCacheEditKey *key);
551 static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
553 ParticleEditSettings *pset= PE_settings(data->scene);
554 PTCacheEdit *edit= data->edit;
556 int nearest_point, nearest_key;
557 float dist= data->rad;
559 /* in path select mode we have no keys */
560 if (pset->selectmode==SCE_SELECT_PATH)
566 LOOP_VISIBLE_POINTS {
567 if (pset->selectmode == SCE_SELECT_END) {
569 /* only do end keys */
570 key= point->keys + point->totkey-1;
573 if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
575 nearest_key= point->totkey-1;
578 else if (key_inside_test(data, KEY_WCO))
579 func(data, p, point->totkey-1);
586 if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
591 else if (key_inside_test(data, KEY_WCO))
597 /* do nearest only */
598 if (nearest && nearest_point > -1)
599 func(data, nearest_point, nearest_key);
602 static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected)
604 ParticleEditSettings *pset= PE_settings(data->scene);
605 PTCacheEdit *edit= data->edit;
608 /* all is selected in path mode */
609 if (pset->selectmode==SCE_SELECT_PATH)
612 LOOP_VISIBLE_POINTS {
613 if (pset->selectmode==SCE_SELECT_END) {
615 /* only do end keys */
616 key= point->keys + point->totkey - 1;
618 if (selected==0 || key->flag & PEK_SELECT)
619 if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
626 if (selected==0 || key->flag & PEK_SELECT) {
627 if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
637 static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
639 PTCacheEdit *edit = data->edit;
640 ParticleSystem *psys = edit->psys;
641 ParticleSystemModifierData *psmd = NULL;
642 ParticleEditSettings *pset= PE_settings(data->scene);
644 float mat[4][4], imat[4][4];
650 psmd= psys_get_modifier(data->ob, edit->psys);
652 /* all is selected in path mode */
653 if (pset->selectmode==SCE_SELECT_PATH)
656 LOOP_VISIBLE_POINTS {
657 if (pset->selectmode==SCE_SELECT_END) {
659 /* only do end keys */
660 key= point->keys + point->totkey-1;
662 if (selected==0 || key->flag & PEK_SELECT) {
663 if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
664 if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
665 psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
666 invert_m4_m4(imat, mat);
669 func(data, mat, imat, p, point->totkey-1, key);
677 if (selected==0 || key->flag & PEK_SELECT) {
678 if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
679 if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
680 psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
681 invert_m4_m4(imat, mat);
684 func(data, mat, imat, p, k, key);
692 static void foreach_selected_point(PEData *data, ForPointFunc func)
694 PTCacheEdit *edit = data->edit;
697 LOOP_SELECTED_POINTS {
702 static void foreach_selected_key(PEData *data, ForKeyFunc func)
704 PTCacheEdit *edit = data->edit;
707 LOOP_VISIBLE_POINTS {
714 static void foreach_point(PEData *data, ForPointFunc func)
716 PTCacheEdit *edit = data->edit;
724 static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
726 ParticleEditSettings *pset= PE_settings(scene);
730 LOOP_VISIBLE_POINTS {
731 if (pset->selectmode==SCE_SELECT_POINT) {
736 else if (pset->selectmode==SCE_SELECT_END) {
738 key = point->keys + point->totkey - 1;
739 if (key->flag & PEK_SELECT)
748 /************************************************/
749 /* Particle Edit Mirroring */
750 /************************************************/
752 static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
755 ParticleSystemModifierData *psmd;
757 KDTreeNearest nearest;
760 float mat[4][4], co[3];
764 psmd= psys_get_modifier(ob, psys);
765 totpart= psys->totpart;
770 tree= BLI_kdtree_new(totpart);
772 /* insert particles into kd tree */
775 psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat);
776 copy_v3_v3(co, key->co);
778 BLI_kdtree_insert(tree, p, co);
781 BLI_kdtree_balance(tree);
783 /* lookup particles and set in mirror cache */
784 if (!edit->mirror_cache)
785 edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
789 psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat);
790 copy_v3_v3(co, key->co);
794 index= BLI_kdtree_find_nearest(tree, co, &nearest);
796 /* this needs a custom threshold still, duplicated for editmode mirror */
797 if (index != -1 && index != p && (nearest.dist <= 0.0002f))
798 edit->mirror_cache[p] = index;
800 edit->mirror_cache[p] = -1;
803 /* make sure mirrors are in two directions */
805 if (edit->mirror_cache[p]) {
806 index= edit->mirror_cache[p];
807 if (edit->mirror_cache[index] != p)
808 edit->mirror_cache[p] = -1;
812 BLI_kdtree_free(tree);
815 static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
817 HairKey *hkey, *mhkey;
818 PTCacheEditPoint *point, *mpoint;
819 PTCacheEditKey *key, *mkey;
821 float mat[4][4], mmat[4][4], immat[4][4];
825 i= pa - psys->particles;
827 /* find mirrored particle if needed */
829 if (!edit->mirror_cache)
830 PE_update_mirror_cache(ob, psys);
832 if (!edit->mirror_cache)
833 return; /* something went wrong! */
835 mi= edit->mirror_cache[i];
838 mpa= psys->particles + mi;
841 mi= mpa - psys->particles;
843 point = edit->points + i;
844 mpoint = edit->points + mi;
846 /* make sure they have the same amount of keys */
847 if (pa->totkey != mpa->totkey) {
848 if (mpa->hair) MEM_freeN(mpa->hair);
849 if (mpoint->keys) MEM_freeN(mpoint->keys);
851 mpa->hair= MEM_dupallocN(pa->hair);
852 mpa->totkey= pa->totkey;
853 mpoint->keys= MEM_dupallocN(point->keys);
854 mpoint->totkey= point->totkey;
858 for (k=0; k<mpa->totkey; k++, mkey++, mhkey++) {
860 mkey->time= &mhkey->time;
861 mkey->flag &= ~PEK_SELECT;
865 /* mirror positions and tags */
866 psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
867 psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
868 invert_m4_m4(immat, mmat);
874 for (k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
875 copy_v3_v3(mhkey->co, hkey->co);
876 mul_m4_v3(mat, mhkey->co);
877 mhkey->co[0] = -mhkey->co[0];
878 mul_m4_v3(immat, mhkey->co);
880 if (key->flag & PEK_TAG)
881 mkey->flag |= PEK_TAG;
883 mkey->length = key->length;
886 if (point->flag & PEP_TAG)
887 mpoint->flag |= PEP_TAG;
888 if (point->flag & PEP_EDIT_RECALC)
889 mpoint->flag |= PEP_EDIT_RECALC;
892 static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
895 ParticleSystemModifierData *psmd;
902 psmd= psys_get_modifier(ob, psys);
907 if (!edit->mirror_cache)
908 PE_update_mirror_cache(ob, psys);
910 if (!edit->mirror_cache)
911 return; /* something went wrong */
913 /* we delay settings the PARS_EDIT_RECALC for mirrored particles
914 * to avoid doing mirror twice */
916 if (point->flag & PEP_EDIT_RECALC) {
917 PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
919 if (edit->mirror_cache[p] != -1)
920 edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
925 if (point->flag & PEP_EDIT_RECALC)
926 if (edit->mirror_cache[p] != -1)
927 edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
931 /************************************************/
932 /* Edit Calculation */
933 /************************************************/
934 /* tries to stop edited particles from going through the emitter's surface */
935 static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
937 ParticleEditSettings *pset= PE_settings(scene);
938 ParticleSystem *psys;
939 ParticleSystemModifierData *psmd;
942 float *vec, *nor, dvec[3], dot, dist_1st=0.0f;
943 float hairimat[4][4], hairmat[4][4];
944 const float dist = ED_view3d_select_dist_px() * 0.01f;
946 if (edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0 || (edit->psys->flag & PSYS_GLOBAL_HAIR))
950 psmd = psys_get_modifier(ob, psys);
956 psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles + p, hairmat);
959 mul_m4_v3(hairmat, key->co);
964 dist_1st = len_v3v3((key+1)->co, key->co);
965 dist_1st *= dist * pset->emitterdist;
968 index= BLI_kdtree_find_nearest(edit->emitter_field, key->co, NULL);
970 vec=edit->emitter_cosnos +index*6;
973 sub_v3_v3v3(dvec, key->co, vec);
975 dot=dot_v3v3(dvec, nor);
976 copy_v3_v3(dvec, nor);
981 mul_v3_fl(dvec, dist_1st-dot);
982 add_v3_v3(key->co, dvec);
987 mul_v3_fl(dvec, dist_1st-dot);
988 add_v3_v3(key->co, dvec);
995 invert_m4_m4(hairimat, hairmat);
998 mul_m4_v3(hairimat, key->co);
1002 /* force set distances between neighboring keys */
1003 static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
1006 ParticleEditSettings *pset=PE_settings(scene);
1010 if (edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
1013 if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
1016 LOOP_EDITED_POINTS {
1019 sub_v3_v3v3(dv1, key->co, (key - 1)->co);
1021 mul_v3_fl(dv1, (key - 1)->length);
1022 add_v3_v3v3(key->co, (key - 1)->co, dv1);
1027 /* try to find a nice solution to keep distances between neighboring keys */
1028 static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
1030 ParticleEditSettings *pset=PE_settings(scene);
1032 PTCacheEditKey *key;
1035 float dv0[3] = {0.0f, 0.0f, 0.0f};
1036 float dv1[3] = {0.0f, 0.0f, 0.0f};
1037 float dv2[3] = {0.0f, 0.0f, 0.0f};
1039 if (edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
1042 if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
1045 LOOP_EDITED_POINTS {
1046 for (j=1; j<point->totkey; j++) {
1047 float mul= 1.0f / (float)point->totkey;
1049 if (pset->flag & PE_LOCK_FIRST) {
1050 key= point->keys + 1;
1052 dv1[0] = dv1[1] = dv1[2] = 0.0;
1057 dv0[0] = dv0[1] = dv0[2] = 0.0;
1060 for (; k<point->totkey; k++, key++) {
1062 sub_v3_v3v3(dv0, (key - 1)->co, key->co);
1063 tlen= normalize_v3(dv0);
1064 mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
1067 if (k < point->totkey - 1) {
1068 sub_v3_v3v3(dv2, (key + 1)->co, key->co);
1069 tlen= normalize_v3(dv2);
1070 mul_v3_fl(dv2, mul * (tlen - key->length));
1074 add_v3_v3((key-1)->co, dv1);
1077 add_v3_v3v3(dv1, dv0, dv2);
1082 /* set current distances to be kept between neighbouting keys */
1083 void recalc_lengths(PTCacheEdit *edit)
1090 LOOP_EDITED_POINTS {
1092 for (k=0; k<point->totkey-1; k++, key++) {
1093 key->length= len_v3v3(key->co, (key + 1)->co);
1098 /* calculate a tree for finding nearest emitter's vertice */
1099 void recalc_emitter_field(Object *ob, ParticleSystem *psys)
1101 DerivedMesh *dm=psys_get_modifier(ob, psys)->dm_final;
1102 PTCacheEdit *edit= psys->edit;
1104 int i, totface /*, totvert*/;
1109 if (edit->emitter_cosnos)
1110 MEM_freeN(edit->emitter_cosnos);
1112 BLI_kdtree_free(edit->emitter_field);
1114 totface=dm->getNumTessFaces(dm);
1115 /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/
1117 edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float), "emitter cosnos");
1119 edit->emitter_field= BLI_kdtree_new(totface);
1121 vec=edit->emitter_cosnos;
1124 for (i=0; i<totface; i++, vec+=6, nor+=6) {
1125 MFace *mface=dm->getTessFaceData(dm, i, CD_MFACE);
1128 mvert=dm->getVertData(dm, mface->v1, CD_MVERT);
1129 copy_v3_v3(vec, mvert->co);
1130 VECCOPY(nor, mvert->no);
1132 mvert=dm->getVertData(dm, mface->v2, CD_MVERT);
1133 add_v3_v3v3(vec, vec, mvert->co);
1134 VECADD(nor, nor, mvert->no);
1136 mvert=dm->getVertData(dm, mface->v3, CD_MVERT);
1137 add_v3_v3v3(vec, vec, mvert->co);
1138 VECADD(nor, nor, mvert->no);
1141 mvert=dm->getVertData(dm, mface->v4, CD_MVERT);
1142 add_v3_v3v3(vec, vec, mvert->co);
1143 VECADD(nor, nor, mvert->no);
1145 mul_v3_fl(vec, 0.25);
1148 mul_v3_fl(vec, 1.0f / 3.0f);
1152 BLI_kdtree_insert(edit->emitter_field, i, vec);
1155 BLI_kdtree_balance(edit->emitter_field);
1158 static void PE_update_selection(Scene *scene, SceneLayer *sl, Object *ob, int useflag)
1160 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1164 /* flag all particles to be updated if not using flag */
1167 point->flag |= PEP_EDIT_RECALC;
1169 /* flush edit key flag to hair key flag to preserve selection
1171 if (edit->psys) LOOP_POINTS {
1172 hkey = edit->psys->particles[p].hair;
1174 hkey->editflag= key->flag;
1179 psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
1182 /* disable update flag */
1184 point->flag &= ~PEP_EDIT_RECALC;
1187 void update_world_cos(Object *ob, PTCacheEdit *edit)
1189 ParticleSystem *psys = edit->psys;
1190 ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
1192 float hairmat[4][4];
1194 if (psys==0 || psys->edit==0 || psmd->dm_final==NULL)
1198 if (!(psys->flag & PSYS_GLOBAL_HAIR))
1199 psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles+p, hairmat);
1202 copy_v3_v3(key->world_co, key->co);
1203 if (!(psys->flag & PSYS_GLOBAL_HAIR))
1204 mul_m4_v3(hairmat, key->world_co);
1208 static void update_velocities(PTCacheEdit *edit)
1210 /*TODO: get frs_sec properly */
1211 float vec1[3], vec2[3], frs_sec, dfra;
1214 /* hair doesn't use velocities */
1215 if (edit->psys || !edit->points || !edit->points->keys->vel)
1218 frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
1220 LOOP_EDITED_POINTS {
1223 dfra = *(key+1)->time - *key->time;
1228 sub_v3_v3v3(key->vel, (key+1)->co, key->co);
1230 if (point->totkey>2) {
1231 sub_v3_v3v3(vec1, (key+1)->co, (key+2)->co);
1232 project_v3_v3v3(vec2, vec1, key->vel);
1233 sub_v3_v3v3(vec2, vec1, vec2);
1234 madd_v3_v3fl(key->vel, vec2, 0.5f);
1237 else if (k==point->totkey-1) {
1238 dfra = *key->time - *(key-1)->time;
1243 sub_v3_v3v3(key->vel, key->co, (key-1)->co);
1245 if (point->totkey>2) {
1246 sub_v3_v3v3(vec1, (key-2)->co, (key-1)->co);
1247 project_v3_v3v3(vec2, vec1, key->vel);
1248 sub_v3_v3v3(vec2, vec1, vec2);
1249 madd_v3_v3fl(key->vel, vec2, 0.5f);
1253 dfra = *(key+1)->time - *(key-1)->time;
1258 sub_v3_v3v3(key->vel, (key+1)->co, (key-1)->co);
1260 mul_v3_fl(key->vel, frs_sec/dfra);
1265 void PE_update_object(Scene *scene, SceneLayer *sl, Object *ob, int useflag)
1267 /* use this to do partial particle updates, not usable when adding or
1268 * removing, then a full redo is necessary and calling this may crash */
1269 ParticleEditSettings *pset= PE_settings(scene);
1270 PTCacheEdit *edit = PE_get_current(scene, sl, ob);
1276 /* flag all particles to be updated if not using flag */
1279 point->flag |= PEP_EDIT_RECALC;
1282 /* do post process on particle edit keys */
1283 pe_iterate_lengths(scene, edit);
1284 pe_deflect_emitter(scene, ob, edit);
1285 PE_apply_lengths(scene, edit);
1286 if (pe_x_mirror(ob))
1287 PE_apply_mirror(ob, edit->psys);
1289 update_world_cos(ob, edit);
1290 if (pset->flag & PE_AUTO_VELOCITY)
1291 update_velocities(edit);
1292 PE_hide_keys_time(scene, edit, CFRA);
1294 /* regenerate path caches */
1295 psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
1297 /* disable update flag */
1299 point->flag &= ~PEP_EDIT_RECALC;
1303 edit->psys->flag &= ~PSYS_HAIR_UPDATED;
1306 /************************************************/
1307 /* Edit Selections */
1308 /************************************************/
1310 /*-----selection callbacks-----*/
1312 static void select_key(PEData *data, int point_index, int key_index)
1314 PTCacheEdit *edit = data->edit;
1315 PTCacheEditPoint *point = edit->points + point_index;
1316 PTCacheEditKey *key = point->keys + key_index;
1319 key->flag |= PEK_SELECT;
1321 key->flag &= ~PEK_SELECT;
1323 point->flag |= PEP_EDIT_RECALC;
1326 static void select_keys(PEData *data, int point_index, int UNUSED(key_index))
1328 PTCacheEdit *edit = data->edit;
1329 PTCacheEditPoint *point = edit->points + point_index;
1334 key->flag |= PEK_SELECT;
1336 key->flag &= ~PEK_SELECT;
1339 point->flag |= PEP_EDIT_RECALC;
1342 static void extend_key_select(PEData *data, int point_index, int key_index)
1344 PTCacheEdit *edit = data->edit;
1345 PTCacheEditPoint *point = edit->points + point_index;
1346 PTCacheEditKey *key = point->keys + key_index;
1348 key->flag |= PEK_SELECT;
1349 point->flag |= PEP_EDIT_RECALC;
1352 static void deselect_key_select(PEData *data, int point_index, int key_index)
1354 PTCacheEdit *edit = data->edit;
1355 PTCacheEditPoint *point = edit->points + point_index;
1356 PTCacheEditKey *key = point->keys + key_index;
1358 key->flag &= ~PEK_SELECT;
1359 point->flag |= PEP_EDIT_RECALC;
1362 static void toggle_key_select(PEData *data, int point_index, int key_index)
1364 PTCacheEdit *edit = data->edit;
1365 PTCacheEditPoint *point = edit->points + point_index;
1366 PTCacheEditKey *key = point->keys + key_index;
1368 key->flag ^= PEK_SELECT;
1369 point->flag |= PEP_EDIT_RECALC;
1372 /************************ de select all operator ************************/
1374 static void select_action_apply(PTCacheEditPoint *point, PTCacheEditKey *key, int action)
1378 if ((key->flag & PEK_SELECT) == 0) {
1379 key->flag |= PEK_SELECT;
1380 point->flag |= PEP_EDIT_RECALC;
1384 if (key->flag & PEK_SELECT) {
1385 key->flag &= ~PEK_SELECT;
1386 point->flag |= PEP_EDIT_RECALC;
1390 if ((key->flag & PEK_SELECT) == 0) {
1391 key->flag |= PEK_SELECT;
1392 point->flag |= PEP_EDIT_RECALC;
1395 key->flag &= ~PEK_SELECT;
1396 point->flag |= PEP_EDIT_RECALC;
1402 static int pe_select_all_exec(bContext *C, wmOperator *op)
1404 Scene *scene= CTX_data_scene(C);
1405 SceneLayer *sl = CTX_data_scene_layer(C);
1406 Object *ob= CTX_data_active_object(C);
1407 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1409 int action = RNA_enum_get(op->ptr, "action");
1411 if (action == SEL_TOGGLE) {
1412 action = SEL_SELECT;
1413 LOOP_VISIBLE_POINTS {
1414 LOOP_SELECTED_KEYS {
1415 action = SEL_DESELECT;
1419 if (action == SEL_DESELECT)
1424 LOOP_VISIBLE_POINTS {
1426 select_action_apply(point, key, action);
1430 PE_update_selection(scene, sl, ob, 1);
1431 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1433 return OPERATOR_FINISHED;
1436 void PARTICLE_OT_select_all(wmOperatorType *ot)
1439 ot->name = "(De)select All";
1440 ot->idname = "PARTICLE_OT_select_all";
1441 ot->description = "(De)select all particles' keys";
1444 ot->exec = pe_select_all_exec;
1448 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1450 WM_operator_properties_select_all(ot);
1453 /************************ pick select operator ************************/
1455 int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
1458 Scene *scene= CTX_data_scene(C);
1459 SceneLayer *sl = CTX_data_scene_layer(C);
1460 Object *ob= CTX_data_active_object(C);
1461 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1464 if (!PE_start_edit(edit))
1465 return OPERATOR_CANCELLED;
1467 if (!extend && !deselect && !toggle) {
1468 LOOP_VISIBLE_POINTS {
1469 LOOP_SELECTED_KEYS {
1470 key->flag &= ~PEK_SELECT;
1471 point->flag |= PEP_EDIT_RECALC;
1476 PE_set_view3d_data(C, &data);
1478 data.rad = ED_view3d_select_dist_px();
1480 /* 1 = nearest only */
1482 for_mouse_hit_keys(&data, extend_key_select, 1);
1484 for_mouse_hit_keys(&data, deselect_key_select, 1);
1486 for_mouse_hit_keys(&data, toggle_key_select, 1);
1488 PE_update_selection(scene, sl, ob, 1);
1489 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1491 return OPERATOR_FINISHED;
1494 /************************ select root operator ************************/
1496 static void select_root(PEData *data, int point_index)
1498 PTCacheEditPoint *point = data->edit->points + point_index;
1499 PTCacheEditKey *key = point->keys;
1501 if (point->flag & PEP_HIDE)
1504 if (data->select_action != SEL_TOGGLE)
1505 select_action_apply(point, key, data->select_action);
1506 else if (key->flag & PEK_SELECT)
1507 data->select_toggle_action = SEL_DESELECT;
1510 static int select_roots_exec(bContext *C, wmOperator *op)
1513 int action = RNA_enum_get(op->ptr, "action");
1515 PE_set_data(C, &data);
1517 if (action == SEL_TOGGLE) {
1518 data.select_action = SEL_TOGGLE;
1519 data.select_toggle_action = SEL_SELECT;
1521 foreach_point(&data, select_root);
1523 action = data.select_toggle_action;
1526 data.select_action = action;
1527 foreach_point(&data, select_root);
1529 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
1530 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1532 return OPERATOR_FINISHED;
1535 void PARTICLE_OT_select_roots(wmOperatorType *ot)
1538 ot->name = "Select Roots";
1539 ot->idname = "PARTICLE_OT_select_roots";
1540 ot->description = "Select roots of all visible particles";
1543 ot->exec = select_roots_exec;
1547 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1550 WM_operator_properties_select_action(ot, SEL_SELECT);
1553 /************************ select tip operator ************************/
1555 static void select_tip(PEData *data, int point_index)
1557 PTCacheEditPoint *point = data->edit->points + point_index;
1558 PTCacheEditKey *key;
1560 if (point->totkey == 0) {
1564 key = &point->keys[point->totkey - 1];
1566 if (point->flag & PEP_HIDE)
1569 if (data->select_action != SEL_TOGGLE)
1570 select_action_apply(point, key, data->select_action);
1571 else if (key->flag & PEK_SELECT)
1572 data->select_toggle_action = SEL_DESELECT;
1575 static int select_tips_exec(bContext *C, wmOperator *op)
1578 int action = RNA_enum_get(op->ptr, "action");
1580 PE_set_data(C, &data);
1582 if (action == SEL_TOGGLE) {
1583 data.select_action = SEL_TOGGLE;
1584 data.select_toggle_action = SEL_SELECT;
1586 foreach_point(&data, select_tip);
1588 action = data.select_toggle_action;
1591 data.select_action = action;
1592 foreach_point(&data, select_tip);
1594 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
1595 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1597 return OPERATOR_FINISHED;
1600 void PARTICLE_OT_select_tips(wmOperatorType *ot)
1603 ot->name = "Select Tips";
1604 ot->idname = "PARTICLE_OT_select_tips";
1605 ot->description = "Select tips of all visible particles";
1608 ot->exec = select_tips_exec;
1612 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1615 WM_operator_properties_select_action(ot, SEL_SELECT);
1618 /*********************** select random operator ************************/
1620 enum { RAN_HAIR, RAN_POINTS };
1622 static EnumPropertyItem select_random_type_items[] = {
1623 {RAN_HAIR, "HAIR", 0, "Hair", ""},
1624 {RAN_POINTS, "POINTS", 0, "Points", ""},
1625 {0, NULL, 0, NULL, NULL}
1628 static int select_random_exec(bContext *C, wmOperator *op)
1636 /* used by LOOP_VISIBLE_POINTS, LOOP_VISIBLE_KEYS and LOOP_KEYS */
1638 PTCacheEditPoint *point;
1639 PTCacheEditKey *key;
1643 const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
1644 const int seed = WM_operator_properties_select_random_seed_increment_get(op);
1645 const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
1648 type = RNA_enum_get(op->ptr, "type");
1650 PE_set_data(C, &data);
1651 data.select_action = SEL_SELECT;
1652 scene = CTX_data_scene(C);
1653 sl = CTX_data_scene_layer(C);
1654 ob = CTX_data_active_object(C);
1655 edit = PE_get_current(scene, sl, ob);
1657 rng = BLI_rng_new_srandom(seed);
1661 LOOP_VISIBLE_POINTS {
1662 int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
1664 select_action_apply (point, key, flag);
1669 LOOP_VISIBLE_POINTS {
1671 int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
1672 select_action_apply (point, key, flag);
1680 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
1681 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1683 return OPERATOR_FINISHED;
1686 void PARTICLE_OT_select_random(wmOperatorType *ot)
1689 ot->name = "Select Random";
1690 ot->idname = "PARTICLE_OT_select_random";
1691 ot->description = "Select a randomly distributed set of hair or points";
1694 ot->exec = select_random_exec;
1698 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1701 WM_operator_properties_select_random(ot);
1702 ot->prop = RNA_def_enum (ot->srna, "type", select_random_type_items, RAN_HAIR,
1703 "Type", "Select either hair or points");
1706 /************************ select linked operator ************************/
1708 static int select_linked_exec(bContext *C, wmOperator *op)
1714 RNA_int_get_array(op->ptr, "location", location);
1715 mval[0] = location[0];
1716 mval[1] = location[1];
1718 PE_set_view3d_data(C, &data);
1721 data.select= !RNA_boolean_get(op->ptr, "deselect");
1723 for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */
1724 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
1725 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1727 return OPERATOR_FINISHED;
1730 static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1732 RNA_int_set_array(op->ptr, "location", event->mval);
1733 return select_linked_exec(C, op);
1736 void PARTICLE_OT_select_linked(wmOperatorType *ot)
1739 ot->name = "Select Linked";
1740 ot->idname = "PARTICLE_OT_select_linked";
1741 ot->description = "Select nearest particle from mouse pointer";
1744 ot->exec = select_linked_exec;
1745 ot->invoke = select_linked_invoke;
1746 ot->poll = PE_poll_view3d;
1749 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1752 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them");
1753 RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
1756 /************************ border select operator ************************/
1757 void PE_deselect_all_visible(PTCacheEdit *edit)
1761 LOOP_VISIBLE_POINTS {
1762 LOOP_SELECTED_KEYS {
1763 key->flag &= ~PEK_SELECT;
1764 point->flag |= PEP_EDIT_RECALC;
1769 int PE_border_select(bContext *C, rcti *rect, bool select, bool extend)
1771 Scene *scene= CTX_data_scene(C);
1772 SceneLayer *sl = CTX_data_scene_layer(C);
1773 Object *ob= CTX_data_active_object(C);
1774 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1777 if (!PE_start_edit(edit))
1778 return OPERATOR_CANCELLED;
1780 if (extend == 0 && select)
1781 PE_deselect_all_visible(edit);
1783 PE_set_view3d_data(C, &data);
1785 data.select= select;
1787 for_mouse_hit_keys(&data, select_key, 0);
1789 PE_update_selection(scene, sl, ob, 1);
1790 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1792 return OPERATOR_FINISHED;
1795 /************************ circle select operator ************************/
1797 int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
1799 Scene *scene= CTX_data_scene(C);
1800 SceneLayer *sl = CTX_data_scene_layer(C);
1801 Object *ob= CTX_data_active_object(C);
1802 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1805 if (!PE_start_edit(edit))
1806 return OPERATOR_FINISHED;
1808 PE_set_view3d_data(C, &data);
1811 data.select= selecting;
1813 for_mouse_hit_keys(&data, select_key, 0);
1815 PE_update_selection(scene, sl, ob, 1);
1816 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1818 return OPERATOR_FINISHED;
1821 /************************ lasso select operator ************************/
1823 int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool extend, bool select)
1825 Scene *scene= CTX_data_scene(C);
1826 SceneLayer *sl = CTX_data_scene_layer(C);
1827 Object *ob= CTX_data_active_object(C);
1828 ARegion *ar= CTX_wm_region(C);
1829 ParticleEditSettings *pset= PE_settings(scene);
1830 PTCacheEdit *edit = PE_get_current(scene, sl, ob);
1831 ParticleSystem *psys = edit->psys;
1832 ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
1834 float co[3], mat[4][4];
1841 if (!PE_start_edit(edit))
1842 return OPERATOR_CANCELLED;
1844 if (extend == 0 && select)
1845 PE_deselect_all_visible(edit);
1847 /* only for depths */
1848 PE_set_view3d_data(C, &data);
1850 LOOP_VISIBLE_POINTS {
1851 if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
1852 psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
1854 if (pset->selectmode==SCE_SELECT_POINT) {
1856 copy_v3_v3(co, key->co);
1858 if ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) &&
1859 BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
1860 key_test_depth(&data, co, screen_co))
1863 if (!(key->flag & PEK_SELECT)) {
1864 key->flag |= PEK_SELECT;
1865 point->flag |= PEP_EDIT_RECALC;
1869 if (key->flag & PEK_SELECT) {
1870 key->flag &= ~PEK_SELECT;
1871 point->flag |= PEP_EDIT_RECALC;
1877 else if (pset->selectmode==SCE_SELECT_END) {
1878 if (point->totkey) {
1879 key= point->keys + point->totkey - 1;
1881 copy_v3_v3(co, key->co);
1883 if ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) &&
1884 BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
1885 key_test_depth(&data, co, screen_co))
1888 if (!(key->flag & PEK_SELECT)) {
1889 key->flag |= PEK_SELECT;
1890 point->flag |= PEP_EDIT_RECALC;
1894 if (key->flag & PEK_SELECT) {
1895 key->flag &= ~PEK_SELECT;
1896 point->flag |= PEP_EDIT_RECALC;
1904 PE_update_selection(scene, sl, ob, 1);
1905 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1907 return OPERATOR_FINISHED;
1910 /*************************** hide operator **************************/
1912 static int hide_exec(bContext *C, wmOperator *op)
1914 Object *ob= CTX_data_active_object(C);
1915 Scene *scene= CTX_data_scene(C);
1916 SceneLayer *sl = CTX_data_scene_layer(C);
1917 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1920 if (RNA_enum_get(op->ptr, "unselected")) {
1921 LOOP_UNSELECTED_POINTS {
1922 point->flag |= PEP_HIDE;
1923 point->flag |= PEP_EDIT_RECALC;
1926 key->flag &= ~PEK_SELECT;
1930 LOOP_SELECTED_POINTS {
1931 point->flag |= PEP_HIDE;
1932 point->flag |= PEP_EDIT_RECALC;
1935 key->flag &= ~PEK_SELECT;
1939 PE_update_selection(scene, sl, ob, 1);
1940 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1942 return OPERATOR_FINISHED;
1945 void PARTICLE_OT_hide(wmOperatorType *ot)
1948 ot->name = "Hide Selected";
1949 ot->idname = "PARTICLE_OT_hide";
1950 ot->description = "Hide selected particles";
1953 ot->exec = hide_exec;
1957 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1960 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
1963 /*************************** reveal operator **************************/
1965 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
1967 Object *ob= CTX_data_active_object(C);
1968 Scene *scene= CTX_data_scene(C);
1969 SceneLayer *sl = CTX_data_scene_layer(C);
1970 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1974 if (point->flag & PEP_HIDE) {
1975 point->flag &= ~PEP_HIDE;
1976 point->flag |= PEP_EDIT_RECALC;
1979 key->flag |= PEK_SELECT;
1983 PE_update_selection(scene, sl, ob, 1);
1984 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1986 return OPERATOR_FINISHED;
1989 void PARTICLE_OT_reveal(wmOperatorType *ot)
1992 ot->name = "Reveal";
1993 ot->idname = "PARTICLE_OT_reveal";
1994 ot->description = "Show hidden particles";
1997 ot->exec = reveal_exec;
2001 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2004 /************************ select less operator ************************/
2006 static void select_less_keys(PEData *data, int point_index)
2008 PTCacheEdit *edit= data->edit;
2009 PTCacheEditPoint *point = edit->points + point_index;
2012 LOOP_SELECTED_KEYS {
2014 if (((key+1)->flag&PEK_SELECT)==0)
2015 key->flag |= PEK_TAG;
2017 else if (k==point->totkey-1) {
2018 if (((key-1)->flag&PEK_SELECT)==0)
2019 key->flag |= PEK_TAG;
2022 if ((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
2023 key->flag |= PEK_TAG;
2028 if (key->flag&PEK_TAG) {
2029 key->flag &= ~(PEK_TAG|PEK_SELECT);
2030 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
2035 static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
2039 PE_set_data(C, &data);
2040 foreach_point(&data, select_less_keys);
2042 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
2043 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
2045 return OPERATOR_FINISHED;
2048 void PARTICLE_OT_select_less(wmOperatorType *ot)
2051 ot->name = "Select Less";
2052 ot->idname = "PARTICLE_OT_select_less";
2053 ot->description = "Deselect boundary selected keys of each particle";
2056 ot->exec = select_less_exec;
2060 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2063 /************************ select more operator ************************/
2065 static void select_more_keys(PEData *data, int point_index)
2067 PTCacheEdit *edit= data->edit;
2068 PTCacheEditPoint *point = edit->points + point_index;
2072 if (key->flag & PEK_SELECT) continue;
2075 if ((key+1)->flag&PEK_SELECT)
2076 key->flag |= PEK_TAG;
2078 else if (k==point->totkey-1) {
2079 if ((key-1)->flag&PEK_SELECT)
2080 key->flag |= PEK_TAG;
2083 if (((key-1)->flag | (key+1)->flag) & PEK_SELECT)
2084 key->flag |= PEK_TAG;
2089 if (key->flag&PEK_TAG) {
2090 key->flag &= ~PEK_TAG;
2091 key->flag |= PEK_SELECT;
2092 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
2097 static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
2101 PE_set_data(C, &data);
2102 foreach_point(&data, select_more_keys);
2104 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
2105 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
2107 return OPERATOR_FINISHED;
2110 void PARTICLE_OT_select_more(wmOperatorType *ot)
2113 ot->name = "Select More";
2114 ot->idname = "PARTICLE_OT_select_more";
2115 ot->description = "Select keys linked to boundary selected keys of each particle";
2118 ot->exec = select_more_exec;
2122 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2125 /************************ rekey operator ************************/
2127 static void rekey_particle(PEData *data, int pa_index)
2129 PTCacheEdit *edit= data->edit;
2130 ParticleSystem *psys= edit->psys;
2131 ParticleSimulationData sim= {0};
2132 ParticleData *pa= psys->particles + pa_index;
2133 PTCacheEditPoint *point = edit->points + pa_index;
2135 HairKey *key, *new_keys, *okey;
2136 PTCacheEditKey *ekey;
2137 float dval, sta, end;
2140 sim.scene= data->scene;
2142 sim.psys= edit->psys;
2144 pa->flag |= PARS_REKEY;
2146 key= new_keys= MEM_callocN(data->totrekey * sizeof(HairKey), "Hair re-key keys");
2149 /* root and tip stay the same */
2150 copy_v3_v3(key->co, okey->co);
2151 copy_v3_v3((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co);
2153 sta= key->time= okey->time;
2154 end= (key + data->totrekey - 1)->time= (okey + pa->totkey - 1)->time;
2155 dval= (end - sta) / (float)(data->totrekey - 1);
2157 /* interpolate new keys from old ones */
2158 for (k=1, key++; k<data->totrekey-1; k++, key++) {
2159 state.time= (float)k / (float)(data->totrekey-1);
2160 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2161 copy_v3_v3(key->co, state.co);
2162 key->time= sta + k * dval;
2167 MEM_freeN(pa->hair);
2170 point->totkey=pa->totkey=data->totrekey;
2174 MEM_freeN(point->keys);
2175 ekey= point->keys= MEM_callocN(pa->totkey * sizeof(PTCacheEditKey), "Hair re-key edit keys");
2177 for (k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
2179 ekey->time= &key->time;
2180 ekey->flag |= PEK_SELECT;
2181 if (!(psys->flag & PSYS_GLOBAL_HAIR))
2182 ekey->flag |= PEK_USE_WCO;
2185 pa->flag &= ~PARS_REKEY;
2186 point->flag |= PEP_EDIT_RECALC;
2189 static int rekey_exec(bContext *C, wmOperator *op)
2193 PE_set_data(C, &data);
2195 data.dval= 1.0f / (float)(data.totrekey-1);
2196 data.totrekey= RNA_int_get(op->ptr, "keys_number");
2198 foreach_selected_point(&data, rekey_particle);
2200 recalc_lengths(data.edit);
2201 PE_update_object(data.scene, data.scene_layer, data.ob, 1);
2202 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
2204 return OPERATOR_FINISHED;
2207 void PARTICLE_OT_rekey(wmOperatorType *ot)
2211 ot->idname = "PARTICLE_OT_rekey";
2212 ot->description = "Change the number of keys of selected particles (root and tip keys included)";
2215 ot->exec = rekey_exec;
2216 ot->invoke = WM_operator_props_popup;
2217 ot->poll = PE_hair_poll;
2220 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2223 RNA_def_int(ot->srna, "keys_number", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
2226 static void rekey_particle_to_time(Scene *scene, SceneLayer *sl, Object *ob, int pa_index, float path_time)
2228 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
2229 ParticleSystem *psys;
2230 ParticleSimulationData sim= {0};
2233 HairKey *new_keys, *key;
2234 PTCacheEditKey *ekey;
2237 if (!edit || !edit->psys) return;
2245 pa= psys->particles + pa_index;
2247 pa->flag |= PARS_REKEY;
2249 key= new_keys= MEM_dupallocN(pa->hair);
2251 /* interpolate new keys from old ones (roots stay the same) */
2252 for (k=1, key++; k < pa->totkey; k++, key++) {
2253 state.time= path_time * (float)k / (float)(pa->totkey-1);
2254 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2255 copy_v3_v3(key->co, state.co);
2258 /* replace hair keys */
2260 MEM_freeN(pa->hair);
2263 /* update edit pointers */
2264 for (k=0, key=pa->hair, ekey=edit->points[pa_index].keys; k<pa->totkey; k++, key++, ekey++) {
2266 ekey->time= &key->time;
2269 pa->flag &= ~PARS_REKEY;
2272 /************************* utilities **************************/
2274 static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
2276 PTCacheEdit *edit = psys->edit;
2277 ParticleData *pa, *npa=0, *new_pars=0;
2279 PTCacheEditPoint *npoint=0, *new_points=0;
2280 ParticleSystemModifierData *psmd;
2281 int i, new_totpart= psys->totpart, removed= 0;
2285 psmd= psys_get_modifier(ob, psys);
2287 LOOP_TAGGED_POINTS {
2288 PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
2292 LOOP_TAGGED_POINTS {
2297 if (new_totpart != psys->totpart) {
2299 npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
2300 npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
2302 if (ELEM(NULL, new_pars, new_points)) {
2303 /* allocation error! */
2305 MEM_freeN(new_pars);
2307 MEM_freeN(new_points);
2312 pa= psys->particles;
2313 point= edit->points;
2314 for (i=0; i<psys->totpart; i++, pa++, point++) {
2315 if (point->flag & PEP_TAG) {
2317 MEM_freeN(point->keys);
2319 MEM_freeN(pa->hair);
2322 memcpy(npa, pa, sizeof(ParticleData));
2323 memcpy(npoint, point, sizeof(PTCacheEditPoint));
2329 if (psys->particles) MEM_freeN(psys->particles);
2330 psys->particles= new_pars;
2332 if (edit->points) MEM_freeN(edit->points);
2333 edit->points= new_points;
2335 if (edit->mirror_cache) {
2336 MEM_freeN(edit->mirror_cache);
2337 edit->mirror_cache= NULL;
2341 MEM_freeN(psys->child);
2346 edit->totpoint= psys->totpart= new_totpart;
2352 static void remove_tagged_keys(Object *ob, ParticleSystem *psys)
2354 PTCacheEdit *edit= psys->edit;
2356 HairKey *hkey, *nhkey, *new_hkeys=0;
2358 PTCacheEditKey *nkey, *new_keys;
2359 ParticleSystemModifierData *psmd;
2362 if (pe_x_mirror(ob)) {
2363 /* mirror key tags */
2364 psmd= psys_get_modifier(ob, psys);
2368 PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
2375 new_totkey= point->totkey;
2379 /* we can't have elements with less than two keys*/
2381 point->flag |= PEP_TAG;
2383 remove_tagged_particles(ob, psys, pe_x_mirror(ob));
2386 pa = psys->particles + p;
2387 new_totkey= pa->totkey;
2393 if (new_totkey != pa->totkey) {
2394 nhkey= new_hkeys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
2395 nkey= new_keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys");
2399 while (key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
2404 if (hkey < pa->hair + pa->totkey) {
2405 copy_v3_v3(nhkey->co, hkey->co);
2406 nhkey->editflag = hkey->editflag;
2407 nhkey->time= hkey->time;
2408 nhkey->weight= hkey->weight;
2410 nkey->co= nhkey->co;
2411 nkey->time= &nhkey->time;
2412 /* these can be copied from old edit keys */
2413 nkey->flag = key->flag;
2414 nkey->ftime = key->ftime;
2415 nkey->length = key->length;
2416 copy_v3_v3(nkey->world_co, key->world_co);
2424 MEM_freeN(pa->hair);
2427 MEM_freeN(point->keys);
2429 pa->hair= new_hkeys;
2430 point->keys= new_keys;
2432 point->totkey= pa->totkey= new_totkey;
2434 /* flag for recalculating length */
2435 point->flag |= PEP_EDIT_RECALC;
2440 /************************ subdivide opertor *********************/
2442 /* works like normal edit mode subdivide, inserts keys between neighboring selected keys */
2443 static void subdivide_particle(PEData *data, int pa_index)
2445 PTCacheEdit *edit= data->edit;
2446 ParticleSystem *psys= edit->psys;
2447 ParticleSimulationData sim= {0};
2448 ParticleData *pa= psys->particles + pa_index;
2449 PTCacheEditPoint *point = edit->points + pa_index;
2451 HairKey *key, *nkey, *new_keys;
2452 PTCacheEditKey *ekey, *nekey, *new_ekeys;
2458 sim.scene= data->scene;
2460 sim.psys= edit->psys;
2462 for (k=0, ekey=point->keys; k<pa->totkey-1; k++, ekey++) {
2463 if (ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
2467 if (totnewkey==0) return;
2469 pa->flag |= PARS_REKEY;
2471 nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)), "Hair subdivide keys");
2472 nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(PTCacheEditKey)), "Hair subdivide edit keys");
2475 endtime= key[pa->totkey-1].time;
2477 for (k=0, ekey=point->keys; k<pa->totkey-1; k++, key++, ekey++) {
2479 memcpy(nkey, key, sizeof(HairKey));
2480 memcpy(nekey, ekey, sizeof(PTCacheEditKey));
2482 nekey->co= nkey->co;
2483 nekey->time= &nkey->time;
2488 if (ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) {
2489 nkey->time = (key->time + (key + 1)->time) * 0.5f;
2490 state.time = (endtime != 0.0f) ? nkey->time / endtime: 0.0f;
2491 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2492 copy_v3_v3(nkey->co, state.co);
2494 nekey->co= nkey->co;
2495 nekey->time = &nkey->time;
2496 nekey->flag |= PEK_SELECT;
2497 if (!(psys->flag & PSYS_GLOBAL_HAIR))
2498 nekey->flag |= PEK_USE_WCO;
2504 /*tip still not copied*/
2505 memcpy(nkey, key, sizeof(HairKey));
2506 memcpy(nekey, ekey, sizeof(PTCacheEditKey));
2508 nekey->co= nkey->co;
2509 nekey->time= &nkey->time;
2512 MEM_freeN(pa->hair);
2516 MEM_freeN(point->keys);
2517 point->keys= new_ekeys;
2519 point->totkey = pa->totkey = pa->totkey + totnewkey;
2520 point->flag |= PEP_EDIT_RECALC;
2521 pa->flag &= ~PARS_REKEY;
2524 static int subdivide_exec(bContext *C, wmOperator *UNUSED(op))
2528 PE_set_data(C, &data);
2529 foreach_point(&data, subdivide_particle);
2531 recalc_lengths(data.edit);
2532 PE_update_object(data.scene, data.scene_layer, data.ob, 1);
2533 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
2535 return OPERATOR_FINISHED;
2538 void PARTICLE_OT_subdivide(wmOperatorType *ot)
2541 ot->name = "Subdivide";
2542 ot->idname = "PARTICLE_OT_subdivide";
2543 ot->description = "Subdivide selected particles segments (adds keys)";
2546 ot->exec = subdivide_exec;
2547 ot->poll = PE_hair_poll;
2550 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2553 /************************ remove doubles opertor *********************/
2555 static int remove_doubles_exec(bContext *C, wmOperator *op)
2557 Scene *scene= CTX_data_scene(C);
2558 SceneLayer *sl = CTX_data_scene_layer(C);
2559 Object *ob= CTX_data_active_object(C);
2560 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
2561 ParticleSystem *psys = edit->psys;
2562 ParticleSystemModifierData *psmd;
2564 KDTreeNearest nearest[10];
2566 float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
2567 int n, totn, removed, totremoved;
2569 if (psys->flag & PSYS_GLOBAL_HAIR)
2570 return OPERATOR_CANCELLED;
2573 psmd= psys_get_modifier(ob, psys);
2579 tree=BLI_kdtree_new(psys->totpart);
2581 /* insert particles into kd tree */
2582 LOOP_SELECTED_POINTS {
2583 psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat);
2584 copy_v3_v3(co, point->keys->co);
2586 BLI_kdtree_insert(tree, p, co);
2589 BLI_kdtree_balance(tree);
2591 /* tag particles to be removed */
2592 LOOP_SELECTED_POINTS {
2593 psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat);
2594 copy_v3_v3(co, point->keys->co);
2597 totn = BLI_kdtree_find_nearest_n(tree, co, nearest, 10);
2599 for (n=0; n<totn; n++) {
2600 /* this needs a custom threshold still */
2601 if (nearest[n].index > p && nearest[n].dist < threshold) {
2602 if (!(point->flag & PEP_TAG)) {
2603 point->flag |= PEP_TAG;
2610 BLI_kdtree_free(tree);
2612 /* remove tagged particles - don't do mirror here! */
2613 remove_tagged_particles(ob, psys, 0);
2614 totremoved += removed;
2617 if (totremoved == 0)
2618 return OPERATOR_CANCELLED;
2620 BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved);
2622 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2623 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2625 return OPERATOR_FINISHED;
2628 void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
2631 ot->name = "Remove Doubles";
2632 ot->idname = "PARTICLE_OT_remove_doubles";
2633 ot->description = "Remove selected particles close enough of others";
2636 ot->exec = remove_doubles_exec;
2637 ot->poll = PE_hair_poll;
2640 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2643 RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX,
2644 "Merge Distance", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
2648 static int weight_set_exec(bContext *C, wmOperator *op)
2650 Scene *scene= CTX_data_scene(C);
2651 SceneLayer *sl = CTX_data_scene_layer(C);
2652 ParticleEditSettings *pset= PE_settings(scene);
2653 Object *ob= CTX_data_active_object(C);
2654 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
2655 ParticleSystem *psys = edit->psys;
2660 ParticleBrushData *brush= &pset->brush[pset->brushtype];
2661 float factor= RNA_float_get(op->ptr, "factor");
2663 weight= brush->strength;
2666 LOOP_SELECTED_POINTS {
2667 ParticleData *pa= psys->particles + p;
2669 LOOP_SELECTED_KEYS {
2671 hkey->weight= interpf(weight, hkey->weight, factor);
2675 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2676 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2678 return OPERATOR_FINISHED;
2681 void PARTICLE_OT_weight_set(wmOperatorType *ot)
2684 ot->name = "Weight Set";
2685 ot->idname = "PARTICLE_OT_weight_set";
2686 ot->description = "Set the weight of selected keys";
2689 ot->exec = weight_set_exec;
2690 ot->poll = PE_hair_poll;
2693 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2695 RNA_def_float(ot->srna, "factor", 1, 0, 1, "Factor",
2696 "Interpolation factor between current brush weight, and keys' weights", 0, 1);
2699 /************************ cursor drawing *******************************/
2701 static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
2703 Scene *scene = CTX_data_scene(C);
2704 ParticleEditSettings *pset= PE_settings(scene);
2705 ParticleBrushData *brush;
2707 if (pset->brushtype < 0) {
2711 brush = &pset->brush[pset->brushtype];
2714 unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT);
2715 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
2717 immUniformColor4ub(255, 255, 255, 128);
2719 glEnable(GL_LINE_SMOOTH);
2722 imm_draw_circle_wire(pos, (float)x, (float)y, pe_brush_size_get(scene, brush), 40);
2724 glDisable(GL_BLEND);
2725 glDisable(GL_LINE_SMOOTH);
2731 static void toggle_particle_cursor(bContext *C, int enable)
2733 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2735 if (pset->paintcursor && !enable) {
2736 WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
2737 pset->paintcursor = NULL;
2740 pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_view3d, brush_drawcursor, NULL);
2743 /*************************** delete operator **************************/
2745 enum { DEL_PARTICLE, DEL_KEY };
2747 static EnumPropertyItem delete_type_items[] = {
2748 {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
2749 {DEL_KEY, "KEY", 0, "Key", ""},
2750 {0, NULL, 0, NULL, NULL}};
2752 static void set_delete_particle(PEData *data, int pa_index)
2754 PTCacheEdit *edit= data->edit;
2756 edit->points[pa_index].flag |= PEP_TAG;
2759 static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
2761 PTCacheEdit *edit= data->edit;
2763 edit->points[pa_index].keys[key_index].flag |= PEK_TAG;
2766 static int delete_exec(bContext *C, wmOperator *op)
2769 int type= RNA_enum_get(op->ptr, "type");
2771 PE_set_data(C, &data);
2773 if (type == DEL_KEY) {
2774 foreach_selected_key(&data, set_delete_particle_key);
2775 remove_tagged_keys(data.ob, data.edit->psys);
2776 recalc_lengths(data.edit);
2778 else if (type == DEL_PARTICLE) {
2779 foreach_selected_point(&data, set_delete_particle);
2780 remove_tagged_particles(data.ob, data.edit->psys, pe_x_mirror(data.ob));
2781 recalc_lengths(data.edit);
2784 DAG_id_tag_update(&data.ob->id, OB_RECALC_DATA);
2785 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
2787 return OPERATOR_FINISHED;
2790 void PARTICLE_OT_delete(wmOperatorType *ot)
2793 ot->name = "Delete";
2794 ot->idname = "PARTICLE_OT_delete";
2795 ot->description = "Delete selected particles or keys";
2798 ot->exec = delete_exec;
2799 ot->invoke = WM_menu_invoke;
2800 ot->poll = PE_hair_poll;
2803 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2806 ot->prop = RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys");
2809 /*************************** mirror operator **************************/
2811 static void PE_mirror_x(Scene *scene, SceneLayer *sl, Object *ob, int tagged)
2813 Mesh *me= (Mesh *)(ob->data);
2814 ParticleSystemModifierData *psmd;
2815 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
2816 ParticleSystem *psys = edit->psys;
2817 ParticleData *pa, *newpa, *new_pars;
2818 PTCacheEditPoint *newpoint, *new_points;
2821 int *mirrorfaces = NULL;
2822 int rotation, totpart, newtotpart;
2824 if (psys->flag & PSYS_GLOBAL_HAIR)
2827 psmd= psys_get_modifier(ob, psys);
2828 if (!psmd->dm_final)
2831 const bool use_dm_final_indices = (psys->part->use_modifier_stack && !psmd->dm_final->deformedOnly);
2833 /* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */
2834 BKE_mesh_tessface_ensure(me);
2836 /* Note: In case psys uses DM tessface indices, we mirror final DM itself, not orig mesh. Avoids an (impossible)
2837 * dm -> orig -> dm tessface indices conversion... */
2838 mirrorfaces = mesh_get_x_mirror_faces(ob, NULL, use_dm_final_indices ? psmd->dm_final : NULL);
2840 if (!edit->mirror_cache)
2841 PE_update_mirror_cache(ob, psys);
2843 totpart= psys->totpart;
2844 newtotpart= psys->totpart;
2845 LOOP_VISIBLE_POINTS {
2846 pa = psys->particles + p;
2849 if (point_is_selected(point)) {
2850 if (edit->mirror_cache[p] != -1) {
2851 /* already has a mirror, don't need to duplicate */
2852 PE_mirror_particle(ob, psmd->dm_final, psys, pa, NULL);
2856 point->flag |= PEP_TAG;
2860 if ((point->flag & PEP_TAG) && mirrorfaces[pa->num*2] != -1)
2864 if (newtotpart != psys->totpart) {
2865 MFace *mtessface = use_dm_final_indices ? psmd->dm_final->getTessFaceArray(psmd->dm_final) : me->mface;
2867 /* allocate new arrays and copy existing */
2868 new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
2869 new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
2871 if (psys->particles) {
2872 memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
2873 MEM_freeN(psys->particles);
2875 psys->particles= new_pars;
2878 memcpy(new_points, edit->points, totpart*sizeof(PTCacheEditPoint));
2879 MEM_freeN(edit->points);
2881 edit->points= new_points;
2883 if (edit->mirror_cache) {
2884 MEM_freeN(edit->mirror_cache);
2885 edit->mirror_cache= NULL;
2888 edit->totpoint= psys->totpart= newtotpart;
2890 /* create new elements */
2891 newpa= psys->particles + totpart;
2892 newpoint= edit->points + totpart;
2894 for (p=0, point=edit->points; p<totpart; p++, point++) {
2895 pa = psys->particles + p;
2896 const int pa_num = pa->num;
2898 if (point->flag & PEP_HIDE)
2901 if (!(point->flag & PEP_TAG) || mirrorfaces[pa_num * 2] == -1)
2907 if (pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
2908 if (point->keys) newpoint->keys= MEM_dupallocN(point->keys);
2910 /* rotate weights according to vertex index rotation */
2911 rotation= mirrorfaces[pa_num * 2 + 1];
2912 newpa->fuv[0] = pa->fuv[2];
2913 newpa->fuv[1] = pa->fuv[1];
2914 newpa->fuv[2] = pa->fuv[0];
2915 newpa->fuv[3] = pa->fuv[3];
2916 while (rotation--) {
2917 if (mtessface[pa_num].v4) {
2918 SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3]);
2921 SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2]);
2925 /* assign face index */
2926 /* NOTE: mesh_get_x_mirror_faces generates -1 for non-found mirror, same as DMCACHE_NOTFOUND... */
2927 newpa->num = mirrorfaces[pa_num * 2];
2929 if (use_dm_final_indices) {
2930 newpa->num_dmcache = DMCACHE_ISCHILD;
2933 newpa->num_dmcache = psys_particle_dm_face_lookup(
2934 psmd->dm_final, psmd->dm_deformed, newpa->num, newpa->fuv, NULL);
2937 /* update edit key pointers */
2938 key= newpoint->keys;
2939 for (k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, key++) {
2941 key->time= &hkey->time;
2944 /* map key positions as mirror over x axis */
2945 PE_mirror_particle(ob, psmd->dm_final, psys, pa, newpa);
2953 point->flag &= ~PEP_TAG;
2956 MEM_freeN(mirrorfaces);
2959 static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
2961 Scene *scene= CTX_data_scene(C);
2962 SceneLayer *sl = CTX_data_scene_layer(C);
2963 Object *ob= CTX_data_active_object(C);
2964 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
2966 PE_mirror_x(scene, sl, ob, 0);
2968 update_world_cos(ob, edit);
2969 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2970 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
2972 return OPERATOR_FINISHED;
2975 void PARTICLE_OT_mirror(wmOperatorType *ot)
2978 ot->name = "Mirror";
2979 ot->idname = "PARTICLE_OT_mirror";
2980 ot->description = "Duplicate and mirror the selected particles along the local X axis";
2983 ot->exec = mirror_exec;
2984 ot->poll = PE_hair_poll;
2987 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2990 /************************* brush edit callbacks ********************/
2992 static void brush_comb(PEData *data, float UNUSED(mat[4][4]), float imat[4][4], int point_index, int key_index, PTCacheEditKey *key)
2994 ParticleEditSettings *pset= PE_settings(data->scene);
2997 if (pset->flag & PE_LOCK_FIRST && key_index == 0) return;
2999 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
3001 copy_v3_v3(cvec, data->dvec);
3002 mul_mat3_m4_v3(imat, cvec);
3003 mul_v3_fl(cvec, fac);
3004 add_v3_v3(key->co, cvec);
3006 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
3009 static void brush_cut(PEData *data, int pa_index)
3011 PTCacheEdit *edit = data->edit;
3012 ARegion *ar= data->vc.ar;
3013 Object *ob= data->ob;
3014 ParticleEditSettings *pset= PE_settings(data->scene);
3015 ParticleCacheKey *key= edit->pathcache[pa_index];
3016 float rad2, cut_time= 1.0;
3017 float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
3018 int k, cut, keys= (int)pow(2.0, (double)pset->draw_step);
3021 /* blunt scissors */
3022 if (BLI_frand() > data->cutfac) return;
3024 /* don't cut hidden */
3025 if (edit->points[pa_index].flag & PEP_HIDE)
3028 if (ED_view3d_project_int_global(ar, key->co, screen_co, V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK)
3031 rad2= data->rad * data->rad;
3035 x0 = (float)screen_co[0];
3036 x1 = (float)screen_co[1];
3038 o0= (float)data->mval[0];
3039 o1= (float)data->mval[1];
3044 /* check if root is inside circle */
3045 if (xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co, screen_co)) {
3050 /* calculate path time closest to root that was inside the circle */
3051 for (k=1, key++; k<=keys; k++, key++) {
3053 if ((ED_view3d_project_int_global(ar, key->co, screen_co, V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK) ||
3054 key_test_depth(data, key->co, screen_co) == 0)
3056 x0 = (float)screen_co[0];
3057 x1 = (float)screen_co[1];
3064 v0 = (float)screen_co[0] - x0;
3065 v1 = (float)screen_co[1] - x1;
3069 d= (v0*xo1 - v1*xo0);
3076 cut_time= -(v0*xo0 + v1*xo1 + d);
3078 if (cut_time > 0.0f) {
3081 if (cut_time < 1.0f) {
3082 cut_time += (float)(k-1);
3083 cut_time /= (float)keys;
3090 x0 = (float)screen_co[0];
3091 x1 = (float)screen_co[1];
3099 if (cut_time < 0.0f) {
3100 edit->points[pa_index].flag |= PEP_TAG;
3103 rekey_particle_to_time(data->scene, data->scene_layer, ob, pa_index, cut_time);
3104 edit->points[pa_index].flag |= PEP_EDIT_RECALC;
3109 static void brush_length(PEData *data, int point_index)
3111 PTCacheEdit *edit= data->edit;
3112 PTCacheEditPoint *point = edit->points + point_index;
3114 float dvec[3], pvec[3] = {0.0f, 0.0f, 0.0f};
3118 copy_v3_v3(pvec, key->co);
3121 sub_v3_v3v3(dvec, key->co, pvec);
3122 copy_v3_v3(pvec, key->co);
3123 mul_v3_fl(dvec, data->growfac);
3124 add_v3_v3v3(key->co, (key-1)->co, dvec);
3128 point->flag |= PEP_EDIT_RECALC;
3131 static void brush_puff(PEData *data, int point_index)
3133 PTCacheEdit *edit = data->edit;
3134 ParticleSystem *psys = edit->psys;
3135 PTCacheEditPoint *point = edit->points + point_index;
3137 float mat[4][4], imat[4][4];
3139 float onor_prev[3]; /* previous normal (particle-space) */
3140 float ofs_prev[3]; /* accumulate offset for puff_volume (particle-space) */
3141 float co_root[3], no_root[3]; /* root location and normal (global-space) */
3142 float co_prev[3], co[3]; /* track key coords as we loop (global-space) */
3143 float fac = 0.0f, length_accum = 0.0f;
3144 bool puff_volume = false;
3145 bool changed = false;
3150 ParticleEditSettings *pset= PE_settings(data->scene);
3151 ParticleBrushData *brush= &pset->brush[pset->brushtype];
3152 puff_volume = (brush->flag & PE_BRUSH_DATA_PUFF_VOLUME) != 0;
3155 if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
3156 psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
3157 invert_m4_m4(imat, mat);
3168 /* find root coordinate and normal on emitter */
3169 copy_v3_v3(co, key->co);
3171 mul_v3_m4v3(kco, data->ob->imat, co); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
3173 point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL);
3174 if (point_index == -1) return;
3176 copy_v3_v3(co_root, co);
3177 copy_v3_v3(no_root, &edit->emitter_cosnos[point_index * 6 + 3]);
3178 mul_mat3_m4_v3(data->ob->obmat, no_root); /* normal into global-space */
3179 normalize_v3(no_root);
3182 copy_v3_v3(onor_prev, no_root);
3183 mul_mat3_m4_v3(imat, onor_prev); /* global-space into particle space */
3184 normalize_v3(onor_prev);
3187 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac);
3193 /* compute position as if hair was standing up straight.
3196 copy_v3_v3(co_prev, co);
3197 copy_v3_v3(co, key->co);
3199 length = len_v3v3(co_prev, co);
3200 length_accum += length;
3202 if ((data->select==0 || (key->flag & PEK_SELECT)) && !(key->flag & PEK_HIDE)) {
3203 float dco[3]; /* delta temp var */
3205 madd_v3_v3v3fl(kco, co_root, no_root, length_accum);
3207 /* blend between the current and straight position */
3208 sub_v3_v3v3(dco, kco, co);
3209 madd_v3_v3fl(co, dco, fac);
3210 /* keep the same distance from the root or we get glitches [#35406] */
3211 dist_ensure_v3_v3fl(co, co_root, length_accum);
3213 /* re-use dco to compare before and after translation and add to the offset */
3214 copy_v3_v3(dco, key->co);
3216 mul_v3_m4v3(key->co, imat, co);
3219 /* accumulate the total distance moved to apply to unselected
3220 * keys that come after */
3221 sub_v3_v3v3(ofs_prev, key->co, dco);
3229 /* this is simple but looks bad, adds annoying kinks */
3230 add_v3_v3(key->co, ofs);
3232 /* translate (not rotate) the rest of the hair if its not selected */
3234 #if 0 /* kindof works but looks worse then whats below */
3236 /* Move the unselected point on a vector based on the
3237 * hair direction and the offset */