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_DerivedMesh.h"
57 #include "BKE_global.h"
58 #include "BKE_object.h"
60 #include "BKE_modifier.h"
61 #include "BKE_particle.h"
62 #include "BKE_report.h"
63 #include "BKE_bvhutils.h"
64 #include "BKE_pointcache.h"
66 #include "DEG_depsgraph.h"
70 #include "ED_object.h"
71 #include "ED_physics.h"
73 #include "ED_particle.h"
74 #include "ED_view3d.h"
76 #include "GPU_immediate.h"
77 #include "GPU_immediate_util.h"
79 #include "UI_resources.h"
84 #include "RNA_access.h"
85 #include "RNA_define.h"
87 #include "physics_intern.h"
89 void PE_create_particle_edit(Scene *scene, SceneLayer *sl, Object *ob, PointCache *cache, ParticleSystem *psys);
90 void PTCacheUndo_clear(PTCacheEdit *edit);
91 void recalc_lengths(PTCacheEdit *edit);
92 void recalc_emitter_field(Object *ob, ParticleSystem *psys);
93 void update_world_cos(Object *ob, PTCacheEdit *edit);
95 #define KEY_K PTCacheEditKey *key; int k
96 #define POINT_P PTCacheEditPoint *point; int p
97 #define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++)
98 #define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE))
99 #define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point))
100 #define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point))
101 #define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC)
102 #define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG)
103 #define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++)
104 #define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE))
105 #define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
106 #define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG)
108 #define KEY_WCO ((key->flag & PEK_USE_WCO) ? key->world_co : key->co)
110 /**************************** utilities *******************************/
112 int PE_poll(bContext *C)
114 Scene *scene= CTX_data_scene(C);
115 SceneLayer *sl = CTX_data_scene_layer(C);
116 Object *ob= CTX_data_active_object(C);
118 if (!scene || !sl || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
121 return (PE_get_current(scene, sl, ob) != NULL);
124 int PE_hair_poll(bContext *C)
126 Scene *scene= CTX_data_scene(C);
127 SceneLayer *sl = CTX_data_scene_layer(C);
128 Object *ob= CTX_data_active_object(C);
131 if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
134 edit= PE_get_current(scene, sl, ob);
136 return (edit && edit->psys);
139 int PE_poll_view3d(bContext *C)
141 ScrArea *sa = CTX_wm_area(C);
142 ARegion *ar = CTX_wm_region(C);
144 return (PE_poll(C) &&
145 (sa && sa->spacetype == SPACE_VIEW3D) &&
146 (ar && ar->regiontype == RGN_TYPE_WINDOW));
149 void PE_free_ptcache_edit(PTCacheEdit *edit)
155 PTCacheUndo_clear(edit);
160 MEM_freeN(point->keys);
163 MEM_freeN(edit->points);
166 if (edit->mirror_cache)
167 MEM_freeN(edit->mirror_cache);
169 if (edit->emitter_cosnos) {
170 MEM_freeN(edit->emitter_cosnos);
171 edit->emitter_cosnos= 0;
174 if (edit->emitter_field) {
175 BLI_kdtree_free(edit->emitter_field);
176 edit->emitter_field= 0;
179 psys_free_path_cache(edit->psys, edit);
184 /************************************************/
185 /* Edit Mode Helpers */
186 /************************************************/
188 int PE_start_edit(PTCacheEdit *edit)
193 edit->psys->flag |= PSYS_EDITED;
200 ParticleEditSettings *PE_settings(Scene *scene)
202 return scene->toolsettings ? &scene->toolsettings->particle : NULL;
205 static float pe_brush_size_get(const Scene *UNUSED(scene), ParticleBrushData *brush)
207 // here we can enable unified brush size, needs more work...
208 // UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
209 // float size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
211 return brush->size * U.pixelsize;
215 /* always gets at least the first particlesystem even if PSYS_CURRENT flag is not set
217 * note: this function runs on poll, therefor it can runs many times a second
219 static PTCacheEdit *pe_get_current(Scene *scene, SceneLayer *sl, Object *ob, int create)
221 ParticleEditSettings *pset= PE_settings(scene);
222 PTCacheEdit *edit = NULL;
226 if (pset==NULL || ob==NULL)
230 pset->scene_layer = sl;
233 BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
235 /* in the case of only one editable thing, set pset->edittype accordingly */
236 if (BLI_listbase_is_single(&pidlist)) {
239 case PTCACHE_TYPE_PARTICLES:
240 pset->edittype = PE_TYPE_PARTICLES;
242 case PTCACHE_TYPE_SOFTBODY:
243 pset->edittype = PE_TYPE_SOFTBODY;
245 case PTCACHE_TYPE_CLOTH:
246 pset->edittype = PE_TYPE_CLOTH;
251 for (pid=pidlist.first; pid; pid=pid->next) {
252 if (pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) {
253 ParticleSystem *psys = pid->calldata;
255 if (psys->flag & PSYS_CURRENT) {
256 if (psys->part && psys->part->type == PART_HAIR) {
257 if (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
258 if (create && !psys->pointcache->edit)
259 PE_create_particle_edit(scene, sl, ob, pid->cache, NULL);
260 edit = pid->cache->edit;
263 if (create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
264 PE_create_particle_edit(scene, sl, ob, NULL, psys);
269 if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
270 PE_create_particle_edit(scene, sl, ob, pid->cache, psys);
271 edit = pid->cache->edit;
277 else if (pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
278 if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
279 pset->flag |= PE_FADE_TIME;
280 // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
281 PE_create_particle_edit(scene, sl, ob, pid->cache, NULL);
283 edit = pid->cache->edit;
286 else if (pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
287 if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
288 pset->flag |= PE_FADE_TIME;
289 // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
290 PE_create_particle_edit(scene, sl, ob, pid->cache, NULL);
292 edit = pid->cache->edit;
300 BLI_freelistN(&pidlist);
305 PTCacheEdit *PE_get_current(Scene *scene, SceneLayer *sl, Object *ob)
307 return pe_get_current(scene, sl, ob, 0);
310 PTCacheEdit *PE_create_current(Scene *scene, Object *ob)
312 return pe_get_current(scene, NULL, ob, 1);
315 void PE_current_changed(Scene *scene, Object *ob)
317 if (ob->mode == OB_MODE_PARTICLE_EDIT)
318 PE_create_current(scene, ob);
321 void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
323 ParticleEditSettings *pset=PE_settings(scene);
327 if (pset->flag & PE_FADE_TIME && pset->selectmode==SCE_SELECT_POINT) {
330 if (fabsf(cfra - *key->time) < pset->fade_frames)
331 key->flag &= ~PEK_HIDE;
333 key->flag |= PEK_HIDE;
334 //key->flag &= ~PEK_SELECT;
342 key->flag &= ~PEK_HIDE;
348 static int pe_x_mirror(Object *ob)
350 if (ob->type == OB_MESH)
351 return (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X);
356 /****************** common struct passed to callbacks ******************/
358 typedef struct PEData {
362 SceneLayer *scene_layer;
366 BVHTreeFromMesh shape_bvh;
389 int select_toggle_action;
392 static void PE_set_data(bContext *C, PEData *data)
394 memset(data, 0, sizeof(*data));
396 data->scene= CTX_data_scene(C);
397 data->scene_layer = CTX_data_scene_layer(C);
398 data->ob= CTX_data_active_object(C);
399 data->edit= PE_get_current(data->scene, data->scene_layer, data->ob);
402 static void PE_set_view3d_data(bContext *C, PEData *data)
404 PE_set_data(C, data);
406 view3d_set_viewcontext(C, &data->vc);
408 if (V3D_IS_ZBUF(data->vc.v3d)) {
409 if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
410 /* needed or else the draw matrix can be incorrect */
411 view3d_operator_needs_opengl(C);
413 ED_view3d_backbuf_validate(&data->vc);
414 /* we may need to force an update here by setting the rv3d as dirty
415 * for now it seems ok, but take care!:
416 * rv3d->depths->dirty = 1; */
417 ED_view3d_depth_update(data->vc.ar);
422 static bool PE_create_shape_tree(PEData *data, Object *shapeob)
424 DerivedMesh *dm = shapeob->derivedFinal;
426 memset(&data->shape_bvh, 0, sizeof(data->shape_bvh));
432 DM_ensure_looptri(dm);
433 return (bvhtree_from_mesh_looptri(&data->shape_bvh, dm, 0.0f, 4, 8) != NULL);
436 static void PE_free_shape_tree(PEData *data)
438 free_bvhtree_from_mesh(&data->shape_bvh);
441 /*************************** selection utilities *******************************/
443 static bool key_test_depth(PEData *data, const float co[3], const int screen_co[2])
445 View3D *v3d= data->vc.v3d;
446 ViewDepths *vd = data->vc.rv3d->depths;
450 if (!V3D_IS_ZBUF(v3d))
453 /* used to calculate here but all callers have the screen_co already, so pass as arg */
455 if (ED_view3d_project_int_global(data->vc.ar, co, screen_co,
456 V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK)
462 /* check if screen_co is within bounds because brush_cut uses out of screen coords */
463 if (screen_co[0] >= 0 && screen_co[0] < vd->w && screen_co[1] >= 0 && screen_co[1] < vd->h) {
464 BLI_assert(vd && vd->depths);
465 /* we know its not clipped */
466 depth = vd->depths[screen_co[1] * vd->w + screen_co[0]];
472 ED_view3d_project(data->vc.ar, co, win);
474 if (win[2] - 0.00001f > depth)
480 static bool key_inside_circle(PEData *data, float rad, const float co[3], float *distance)
485 /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
486 if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK) {
490 dx= data->mval[0] - screen_co[0];
491 dy= data->mval[1] - screen_co[1];
492 dist = sqrtf(dx * dx + dy * dy);
497 if (key_test_depth(data, co, screen_co)) {
507 static bool key_inside_rect(PEData *data, const float co[3])
511 if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK) {
515 if (screen_co[0] > data->rect->xmin && screen_co[0] < data->rect->xmax &&
516 screen_co[1] > data->rect->ymin && screen_co[1] < data->rect->ymax)
518 return key_test_depth(data, co, screen_co);
524 static bool key_inside_test(PEData *data, const float co[3])
527 return key_inside_circle(data, data->rad, co, NULL);
529 return key_inside_rect(data, co);
532 static bool point_is_selected(PTCacheEditPoint *point)
536 if (point->flag & PEP_HIDE)
546 /*************************** iterators *******************************/
548 typedef void (*ForPointFunc)(PEData *data, int point_index);
549 typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index);
550 typedef void (*ForKeyMatFunc)(PEData *data, float mat[4][4], float imat[4][4], int point_index, int key_index, PTCacheEditKey *key);
552 static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, int nearest)
554 ParticleEditSettings *pset= PE_settings(data->scene);
555 PTCacheEdit *edit= data->edit;
557 int nearest_point, nearest_key;
558 float dist= data->rad;
560 /* in path select mode we have no keys */
561 if (pset->selectmode==SCE_SELECT_PATH)
567 LOOP_VISIBLE_POINTS {
568 if (pset->selectmode == SCE_SELECT_END) {
570 /* only do end keys */
571 key= point->keys + point->totkey-1;
574 if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
576 nearest_key= point->totkey-1;
579 else if (key_inside_test(data, KEY_WCO))
580 func(data, p, point->totkey-1);
587 if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
592 else if (key_inside_test(data, KEY_WCO))
598 /* do nearest only */
599 if (nearest && nearest_point > -1)
600 func(data, nearest_point, nearest_key);
603 static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected)
605 ParticleEditSettings *pset= PE_settings(data->scene);
606 PTCacheEdit *edit= data->edit;
609 /* all is selected in path mode */
610 if (pset->selectmode==SCE_SELECT_PATH)
613 LOOP_VISIBLE_POINTS {
614 if (pset->selectmode==SCE_SELECT_END) {
616 /* only do end keys */
617 key= point->keys + point->totkey - 1;
619 if (selected==0 || key->flag & PEK_SELECT)
620 if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist))
627 if (selected==0 || key->flag & PEK_SELECT) {
628 if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
638 static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected)
640 PTCacheEdit *edit = data->edit;
641 ParticleSystem *psys = edit->psys;
642 ParticleSystemModifierData *psmd = NULL;
643 ParticleEditSettings *pset= PE_settings(data->scene);
645 float mat[4][4], imat[4][4];
651 psmd= psys_get_modifier(data->ob, edit->psys);
653 /* all is selected in path mode */
654 if (pset->selectmode==SCE_SELECT_PATH)
657 LOOP_VISIBLE_POINTS {
658 if (pset->selectmode==SCE_SELECT_END) {
660 /* only do end keys */
661 key= point->keys + point->totkey-1;
663 if (selected==0 || key->flag & PEK_SELECT) {
664 if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
665 if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
666 psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
667 invert_m4_m4(imat, mat);
670 func(data, mat, imat, p, point->totkey-1, key);
678 if (selected==0 || key->flag & PEK_SELECT) {
679 if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) {
680 if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
681 psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
682 invert_m4_m4(imat, mat);
685 func(data, mat, imat, p, k, key);
693 static void foreach_selected_point(PEData *data, ForPointFunc func)
695 PTCacheEdit *edit = data->edit;
698 LOOP_SELECTED_POINTS {
703 static void foreach_selected_key(PEData *data, ForKeyFunc func)
705 PTCacheEdit *edit = data->edit;
708 LOOP_VISIBLE_POINTS {
715 static void foreach_point(PEData *data, ForPointFunc func)
717 PTCacheEdit *edit = data->edit;
725 static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
727 ParticleEditSettings *pset= PE_settings(scene);
731 LOOP_VISIBLE_POINTS {
732 if (pset->selectmode==SCE_SELECT_POINT) {
737 else if (pset->selectmode==SCE_SELECT_END) {
739 key = point->keys + point->totkey - 1;
740 if (key->flag & PEK_SELECT)
749 /************************************************/
750 /* Particle Edit Mirroring */
751 /************************************************/
753 static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
756 ParticleSystemModifierData *psmd;
758 KDTreeNearest nearest;
761 float mat[4][4], co[3];
765 psmd= psys_get_modifier(ob, psys);
766 totpart= psys->totpart;
771 tree= BLI_kdtree_new(totpart);
773 /* insert particles into kd tree */
776 psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat);
777 copy_v3_v3(co, key->co);
779 BLI_kdtree_insert(tree, p, co);
782 BLI_kdtree_balance(tree);
784 /* lookup particles and set in mirror cache */
785 if (!edit->mirror_cache)
786 edit->mirror_cache= MEM_callocN(sizeof(int)*totpart, "PE mirror cache");
790 psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat);
791 copy_v3_v3(co, key->co);
795 index= BLI_kdtree_find_nearest(tree, co, &nearest);
797 /* this needs a custom threshold still, duplicated for editmode mirror */
798 if (index != -1 && index != p && (nearest.dist <= 0.0002f))
799 edit->mirror_cache[p] = index;
801 edit->mirror_cache[p] = -1;
804 /* make sure mirrors are in two directions */
806 if (edit->mirror_cache[p]) {
807 index= edit->mirror_cache[p];
808 if (edit->mirror_cache[index] != p)
809 edit->mirror_cache[p] = -1;
813 BLI_kdtree_free(tree);
816 static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
818 HairKey *hkey, *mhkey;
819 PTCacheEditPoint *point, *mpoint;
820 PTCacheEditKey *key, *mkey;
822 float mat[4][4], mmat[4][4], immat[4][4];
826 i= pa - psys->particles;
828 /* find mirrored particle if needed */
830 if (!edit->mirror_cache)
831 PE_update_mirror_cache(ob, psys);
833 if (!edit->mirror_cache)
834 return; /* something went wrong! */
836 mi= edit->mirror_cache[i];
839 mpa= psys->particles + mi;
842 mi= mpa - psys->particles;
844 point = edit->points + i;
845 mpoint = edit->points + mi;
847 /* make sure they have the same amount of keys */
848 if (pa->totkey != mpa->totkey) {
849 if (mpa->hair) MEM_freeN(mpa->hair);
850 if (mpoint->keys) MEM_freeN(mpoint->keys);
852 mpa->hair= MEM_dupallocN(pa->hair);
853 mpa->totkey= pa->totkey;
854 mpoint->keys= MEM_dupallocN(point->keys);
855 mpoint->totkey= point->totkey;
859 for (k=0; k<mpa->totkey; k++, mkey++, mhkey++) {
861 mkey->time= &mhkey->time;
862 mkey->flag &= ~PEK_SELECT;
866 /* mirror positions and tags */
867 psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat);
868 psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat);
869 invert_m4_m4(immat, mmat);
875 for (k=0; k<pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
876 copy_v3_v3(mhkey->co, hkey->co);
877 mul_m4_v3(mat, mhkey->co);
878 mhkey->co[0] = -mhkey->co[0];
879 mul_m4_v3(immat, mhkey->co);
881 if (key->flag & PEK_TAG)
882 mkey->flag |= PEK_TAG;
884 mkey->length = key->length;
887 if (point->flag & PEP_TAG)
888 mpoint->flag |= PEP_TAG;
889 if (point->flag & PEP_EDIT_RECALC)
890 mpoint->flag |= PEP_EDIT_RECALC;
893 static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
896 ParticleSystemModifierData *psmd;
903 psmd= psys_get_modifier(ob, psys);
908 if (!edit->mirror_cache)
909 PE_update_mirror_cache(ob, psys);
911 if (!edit->mirror_cache)
912 return; /* something went wrong */
914 /* we delay settings the PARS_EDIT_RECALC for mirrored particles
915 * to avoid doing mirror twice */
917 if (point->flag & PEP_EDIT_RECALC) {
918 PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
920 if (edit->mirror_cache[p] != -1)
921 edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
926 if (point->flag & PEP_EDIT_RECALC)
927 if (edit->mirror_cache[p] != -1)
928 edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
932 /************************************************/
933 /* Edit Calculation */
934 /************************************************/
935 /* tries to stop edited particles from going through the emitter's surface */
936 static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
938 ParticleEditSettings *pset= PE_settings(scene);
939 ParticleSystem *psys;
940 ParticleSystemModifierData *psmd;
943 float *vec, *nor, dvec[3], dot, dist_1st=0.0f;
944 float hairimat[4][4], hairmat[4][4];
945 const float dist = ED_view3d_select_dist_px() * 0.01f;
947 if (edit==NULL || edit->psys==NULL || (pset->flag & PE_DEFLECT_EMITTER)==0 || (edit->psys->flag & PSYS_GLOBAL_HAIR))
951 psmd = psys_get_modifier(ob, psys);
957 psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles + p, hairmat);
960 mul_m4_v3(hairmat, key->co);
965 dist_1st = len_v3v3((key+1)->co, key->co);
966 dist_1st *= dist * pset->emitterdist;
969 index= BLI_kdtree_find_nearest(edit->emitter_field, key->co, NULL);
971 vec=edit->emitter_cosnos +index*6;
974 sub_v3_v3v3(dvec, key->co, vec);
976 dot=dot_v3v3(dvec, nor);
977 copy_v3_v3(dvec, nor);
982 mul_v3_fl(dvec, dist_1st-dot);
983 add_v3_v3(key->co, dvec);
988 mul_v3_fl(dvec, dist_1st-dot);
989 add_v3_v3(key->co, dvec);
996 invert_m4_m4(hairimat, hairmat);
999 mul_m4_v3(hairimat, key->co);
1003 /* force set distances between neighboring keys */
1004 static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
1007 ParticleEditSettings *pset=PE_settings(scene);
1011 if (edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
1014 if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
1017 LOOP_EDITED_POINTS {
1020 sub_v3_v3v3(dv1, key->co, (key - 1)->co);
1022 mul_v3_fl(dv1, (key - 1)->length);
1023 add_v3_v3v3(key->co, (key - 1)->co, dv1);
1028 /* try to find a nice solution to keep distances between neighboring keys */
1029 static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
1031 ParticleEditSettings *pset=PE_settings(scene);
1033 PTCacheEditKey *key;
1036 float dv0[3] = {0.0f, 0.0f, 0.0f};
1037 float dv1[3] = {0.0f, 0.0f, 0.0f};
1038 float dv2[3] = {0.0f, 0.0f, 0.0f};
1040 if (edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0)
1043 if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
1046 LOOP_EDITED_POINTS {
1047 for (j=1; j<point->totkey; j++) {
1048 float mul= 1.0f / (float)point->totkey;
1050 if (pset->flag & PE_LOCK_FIRST) {
1051 key= point->keys + 1;
1053 dv1[0] = dv1[1] = dv1[2] = 0.0;
1058 dv0[0] = dv0[1] = dv0[2] = 0.0;
1061 for (; k<point->totkey; k++, key++) {
1063 sub_v3_v3v3(dv0, (key - 1)->co, key->co);
1064 tlen= normalize_v3(dv0);
1065 mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
1068 if (k < point->totkey - 1) {
1069 sub_v3_v3v3(dv2, (key + 1)->co, key->co);
1070 tlen= normalize_v3(dv2);
1071 mul_v3_fl(dv2, mul * (tlen - key->length));
1075 add_v3_v3((key-1)->co, dv1);
1078 add_v3_v3v3(dv1, dv0, dv2);
1083 /* set current distances to be kept between neighbouting keys */
1084 void recalc_lengths(PTCacheEdit *edit)
1091 LOOP_EDITED_POINTS {
1093 for (k=0; k<point->totkey-1; k++, key++) {
1094 key->length= len_v3v3(key->co, (key + 1)->co);
1099 /* calculate a tree for finding nearest emitter's vertice */
1100 void recalc_emitter_field(Object *ob, ParticleSystem *psys)
1102 DerivedMesh *dm=psys_get_modifier(ob, psys)->dm_final;
1103 PTCacheEdit *edit= psys->edit;
1105 int i, totface /*, totvert*/;
1110 if (edit->emitter_cosnos)
1111 MEM_freeN(edit->emitter_cosnos);
1113 BLI_kdtree_free(edit->emitter_field);
1115 totface=dm->getNumTessFaces(dm);
1116 /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/
1118 edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float), "emitter cosnos");
1120 edit->emitter_field= BLI_kdtree_new(totface);
1122 vec=edit->emitter_cosnos;
1125 for (i=0; i<totface; i++, vec+=6, nor+=6) {
1126 MFace *mface=dm->getTessFaceData(dm, i, CD_MFACE);
1129 mvert=dm->getVertData(dm, mface->v1, CD_MVERT);
1130 copy_v3_v3(vec, mvert->co);
1131 VECCOPY(nor, mvert->no);
1133 mvert=dm->getVertData(dm, mface->v2, CD_MVERT);
1134 add_v3_v3v3(vec, vec, mvert->co);
1135 VECADD(nor, nor, mvert->no);
1137 mvert=dm->getVertData(dm, mface->v3, CD_MVERT);
1138 add_v3_v3v3(vec, vec, mvert->co);
1139 VECADD(nor, nor, mvert->no);
1142 mvert=dm->getVertData(dm, mface->v4, CD_MVERT);
1143 add_v3_v3v3(vec, vec, mvert->co);
1144 VECADD(nor, nor, mvert->no);
1146 mul_v3_fl(vec, 0.25);
1149 mul_v3_fl(vec, 1.0f / 3.0f);
1153 BLI_kdtree_insert(edit->emitter_field, i, vec);
1156 BLI_kdtree_balance(edit->emitter_field);
1159 static void PE_update_selection(Scene *scene, SceneLayer *sl, Object *ob, int useflag)
1161 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1165 /* flag all particles to be updated if not using flag */
1168 point->flag |= PEP_EDIT_RECALC;
1170 /* flush edit key flag to hair key flag to preserve selection
1172 if (edit->psys) LOOP_POINTS {
1173 hkey = edit->psys->particles[p].hair;
1175 hkey->editflag= key->flag;
1180 psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
1183 /* disable update flag */
1185 point->flag &= ~PEP_EDIT_RECALC;
1188 void update_world_cos(Object *ob, PTCacheEdit *edit)
1190 ParticleSystem *psys = edit->psys;
1191 ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
1193 float hairmat[4][4];
1195 if (psys==0 || psys->edit==0 || psmd->dm_final==NULL)
1199 if (!(psys->flag & PSYS_GLOBAL_HAIR))
1200 psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles+p, hairmat);
1203 copy_v3_v3(key->world_co, key->co);
1204 if (!(psys->flag & PSYS_GLOBAL_HAIR))
1205 mul_m4_v3(hairmat, key->world_co);
1209 static void update_velocities(PTCacheEdit *edit)
1211 /*TODO: get frs_sec properly */
1212 float vec1[3], vec2[3], frs_sec, dfra;
1215 /* hair doesn't use velocities */
1216 if (edit->psys || !edit->points || !edit->points->keys->vel)
1219 frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
1221 LOOP_EDITED_POINTS {
1224 dfra = *(key+1)->time - *key->time;
1229 sub_v3_v3v3(key->vel, (key+1)->co, key->co);
1231 if (point->totkey>2) {
1232 sub_v3_v3v3(vec1, (key+1)->co, (key+2)->co);
1233 project_v3_v3v3(vec2, vec1, key->vel);
1234 sub_v3_v3v3(vec2, vec1, vec2);
1235 madd_v3_v3fl(key->vel, vec2, 0.5f);
1238 else if (k==point->totkey-1) {
1239 dfra = *key->time - *(key-1)->time;
1244 sub_v3_v3v3(key->vel, key->co, (key-1)->co);
1246 if (point->totkey>2) {
1247 sub_v3_v3v3(vec1, (key-2)->co, (key-1)->co);
1248 project_v3_v3v3(vec2, vec1, key->vel);
1249 sub_v3_v3v3(vec2, vec1, vec2);
1250 madd_v3_v3fl(key->vel, vec2, 0.5f);
1254 dfra = *(key+1)->time - *(key-1)->time;
1259 sub_v3_v3v3(key->vel, (key+1)->co, (key-1)->co);
1261 mul_v3_fl(key->vel, frs_sec/dfra);
1266 void PE_update_object(Scene *scene, SceneLayer *sl, Object *ob, int useflag)
1268 /* use this to do partial particle updates, not usable when adding or
1269 * removing, then a full redo is necessary and calling this may crash */
1270 ParticleEditSettings *pset= PE_settings(scene);
1271 PTCacheEdit *edit = PE_get_current(scene, sl, ob);
1277 /* flag all particles to be updated if not using flag */
1280 point->flag |= PEP_EDIT_RECALC;
1283 /* do post process on particle edit keys */
1284 pe_iterate_lengths(scene, edit);
1285 pe_deflect_emitter(scene, ob, edit);
1286 PE_apply_lengths(scene, edit);
1287 if (pe_x_mirror(ob))
1288 PE_apply_mirror(ob, edit->psys);
1290 update_world_cos(ob, edit);
1291 if (pset->flag & PE_AUTO_VELOCITY)
1292 update_velocities(edit);
1293 PE_hide_keys_time(scene, edit, CFRA);
1295 /* regenerate path caches */
1296 psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering);
1298 /* disable update flag */
1300 point->flag &= ~PEP_EDIT_RECALC;
1304 edit->psys->flag &= ~PSYS_HAIR_UPDATED;
1307 /************************************************/
1308 /* Edit Selections */
1309 /************************************************/
1311 /*-----selection callbacks-----*/
1313 static void select_key(PEData *data, int point_index, int key_index)
1315 PTCacheEdit *edit = data->edit;
1316 PTCacheEditPoint *point = edit->points + point_index;
1317 PTCacheEditKey *key = point->keys + key_index;
1320 key->flag |= PEK_SELECT;
1322 key->flag &= ~PEK_SELECT;
1324 point->flag |= PEP_EDIT_RECALC;
1327 static void select_keys(PEData *data, int point_index, int UNUSED(key_index))
1329 PTCacheEdit *edit = data->edit;
1330 PTCacheEditPoint *point = edit->points + point_index;
1335 key->flag |= PEK_SELECT;
1337 key->flag &= ~PEK_SELECT;
1340 point->flag |= PEP_EDIT_RECALC;
1343 static void extend_key_select(PEData *data, int point_index, int key_index)
1345 PTCacheEdit *edit = data->edit;
1346 PTCacheEditPoint *point = edit->points + point_index;
1347 PTCacheEditKey *key = point->keys + key_index;
1349 key->flag |= PEK_SELECT;
1350 point->flag |= PEP_EDIT_RECALC;
1353 static void deselect_key_select(PEData *data, int point_index, int key_index)
1355 PTCacheEdit *edit = data->edit;
1356 PTCacheEditPoint *point = edit->points + point_index;
1357 PTCacheEditKey *key = point->keys + key_index;
1359 key->flag &= ~PEK_SELECT;
1360 point->flag |= PEP_EDIT_RECALC;
1363 static void toggle_key_select(PEData *data, int point_index, int key_index)
1365 PTCacheEdit *edit = data->edit;
1366 PTCacheEditPoint *point = edit->points + point_index;
1367 PTCacheEditKey *key = point->keys + key_index;
1369 key->flag ^= PEK_SELECT;
1370 point->flag |= PEP_EDIT_RECALC;
1373 /************************ de select all operator ************************/
1375 static void select_action_apply(PTCacheEditPoint *point, PTCacheEditKey *key, int action)
1379 if ((key->flag & PEK_SELECT) == 0) {
1380 key->flag |= PEK_SELECT;
1381 point->flag |= PEP_EDIT_RECALC;
1385 if (key->flag & PEK_SELECT) {
1386 key->flag &= ~PEK_SELECT;
1387 point->flag |= PEP_EDIT_RECALC;
1391 if ((key->flag & PEK_SELECT) == 0) {
1392 key->flag |= PEK_SELECT;
1393 point->flag |= PEP_EDIT_RECALC;
1396 key->flag &= ~PEK_SELECT;
1397 point->flag |= PEP_EDIT_RECALC;
1403 static int pe_select_all_exec(bContext *C, wmOperator *op)
1405 Scene *scene= CTX_data_scene(C);
1406 SceneLayer *sl = CTX_data_scene_layer(C);
1407 Object *ob= CTX_data_active_object(C);
1408 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1410 int action = RNA_enum_get(op->ptr, "action");
1412 if (action == SEL_TOGGLE) {
1413 action = SEL_SELECT;
1414 LOOP_VISIBLE_POINTS {
1415 LOOP_SELECTED_KEYS {
1416 action = SEL_DESELECT;
1420 if (action == SEL_DESELECT)
1425 LOOP_VISIBLE_POINTS {
1427 select_action_apply(point, key, action);
1431 PE_update_selection(scene, sl, ob, 1);
1432 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1434 return OPERATOR_FINISHED;
1437 void PARTICLE_OT_select_all(wmOperatorType *ot)
1440 ot->name = "(De)select All";
1441 ot->idname = "PARTICLE_OT_select_all";
1442 ot->description = "(De)select all particles' keys";
1445 ot->exec = pe_select_all_exec;
1449 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1451 WM_operator_properties_select_all(ot);
1454 /************************ pick select operator ************************/
1456 int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
1459 Scene *scene= CTX_data_scene(C);
1460 SceneLayer *sl = CTX_data_scene_layer(C);
1461 Object *ob= CTX_data_active_object(C);
1462 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1465 if (!PE_start_edit(edit))
1466 return OPERATOR_CANCELLED;
1468 if (!extend && !deselect && !toggle) {
1469 LOOP_VISIBLE_POINTS {
1470 LOOP_SELECTED_KEYS {
1471 key->flag &= ~PEK_SELECT;
1472 point->flag |= PEP_EDIT_RECALC;
1477 PE_set_view3d_data(C, &data);
1479 data.rad = ED_view3d_select_dist_px();
1481 /* 1 = nearest only */
1483 for_mouse_hit_keys(&data, extend_key_select, 1);
1485 for_mouse_hit_keys(&data, deselect_key_select, 1);
1487 for_mouse_hit_keys(&data, toggle_key_select, 1);
1489 PE_update_selection(scene, sl, ob, 1);
1490 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1492 return OPERATOR_FINISHED;
1495 /************************ select root operator ************************/
1497 static void select_root(PEData *data, int point_index)
1499 PTCacheEditPoint *point = data->edit->points + point_index;
1500 PTCacheEditKey *key = point->keys;
1502 if (point->flag & PEP_HIDE)
1505 if (data->select_action != SEL_TOGGLE)
1506 select_action_apply(point, key, data->select_action);
1507 else if (key->flag & PEK_SELECT)
1508 data->select_toggle_action = SEL_DESELECT;
1511 static int select_roots_exec(bContext *C, wmOperator *op)
1514 int action = RNA_enum_get(op->ptr, "action");
1516 PE_set_data(C, &data);
1518 if (action == SEL_TOGGLE) {
1519 data.select_action = SEL_TOGGLE;
1520 data.select_toggle_action = SEL_SELECT;
1522 foreach_point(&data, select_root);
1524 action = data.select_toggle_action;
1527 data.select_action = action;
1528 foreach_point(&data, select_root);
1530 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
1531 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1533 return OPERATOR_FINISHED;
1536 void PARTICLE_OT_select_roots(wmOperatorType *ot)
1539 ot->name = "Select Roots";
1540 ot->idname = "PARTICLE_OT_select_roots";
1541 ot->description = "Select roots of all visible particles";
1544 ot->exec = select_roots_exec;
1548 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1551 WM_operator_properties_select_action(ot, SEL_SELECT);
1554 /************************ select tip operator ************************/
1556 static void select_tip(PEData *data, int point_index)
1558 PTCacheEditPoint *point = data->edit->points + point_index;
1559 PTCacheEditKey *key;
1561 if (point->totkey == 0) {
1565 key = &point->keys[point->totkey - 1];
1567 if (point->flag & PEP_HIDE)
1570 if (data->select_action != SEL_TOGGLE)
1571 select_action_apply(point, key, data->select_action);
1572 else if (key->flag & PEK_SELECT)
1573 data->select_toggle_action = SEL_DESELECT;
1576 static int select_tips_exec(bContext *C, wmOperator *op)
1579 int action = RNA_enum_get(op->ptr, "action");
1581 PE_set_data(C, &data);
1583 if (action == SEL_TOGGLE) {
1584 data.select_action = SEL_TOGGLE;
1585 data.select_toggle_action = SEL_SELECT;
1587 foreach_point(&data, select_tip);
1589 action = data.select_toggle_action;
1592 data.select_action = action;
1593 foreach_point(&data, select_tip);
1595 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
1596 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1598 return OPERATOR_FINISHED;
1601 void PARTICLE_OT_select_tips(wmOperatorType *ot)
1604 ot->name = "Select Tips";
1605 ot->idname = "PARTICLE_OT_select_tips";
1606 ot->description = "Select tips of all visible particles";
1609 ot->exec = select_tips_exec;
1613 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1616 WM_operator_properties_select_action(ot, SEL_SELECT);
1619 /*********************** select random operator ************************/
1621 enum { RAN_HAIR, RAN_POINTS };
1623 static EnumPropertyItem select_random_type_items[] = {
1624 {RAN_HAIR, "HAIR", 0, "Hair", ""},
1625 {RAN_POINTS, "POINTS", 0, "Points", ""},
1626 {0, NULL, 0, NULL, NULL}
1629 static int select_random_exec(bContext *C, wmOperator *op)
1637 /* used by LOOP_VISIBLE_POINTS, LOOP_VISIBLE_KEYS and LOOP_KEYS */
1639 PTCacheEditPoint *point;
1640 PTCacheEditKey *key;
1644 const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
1645 const int seed = WM_operator_properties_select_random_seed_increment_get(op);
1646 const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
1649 type = RNA_enum_get(op->ptr, "type");
1651 PE_set_data(C, &data);
1652 data.select_action = SEL_SELECT;
1653 scene = CTX_data_scene(C);
1654 sl = CTX_data_scene_layer(C);
1655 ob = CTX_data_active_object(C);
1656 edit = PE_get_current(scene, sl, ob);
1658 rng = BLI_rng_new_srandom(seed);
1662 LOOP_VISIBLE_POINTS {
1663 int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
1665 select_action_apply (point, key, flag);
1670 LOOP_VISIBLE_POINTS {
1672 int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
1673 select_action_apply (point, key, flag);
1681 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
1682 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1684 return OPERATOR_FINISHED;
1687 void PARTICLE_OT_select_random(wmOperatorType *ot)
1690 ot->name = "Select Random";
1691 ot->idname = "PARTICLE_OT_select_random";
1692 ot->description = "Select a randomly distributed set of hair or points";
1695 ot->exec = select_random_exec;
1699 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1702 WM_operator_properties_select_random(ot);
1703 ot->prop = RNA_def_enum (ot->srna, "type", select_random_type_items, RAN_HAIR,
1704 "Type", "Select either hair or points");
1707 /************************ select linked operator ************************/
1709 static int select_linked_exec(bContext *C, wmOperator *op)
1715 RNA_int_get_array(op->ptr, "location", location);
1716 mval[0] = location[0];
1717 mval[1] = location[1];
1719 PE_set_view3d_data(C, &data);
1722 data.select= !RNA_boolean_get(op->ptr, "deselect");
1724 for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */
1725 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
1726 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
1728 return OPERATOR_FINISHED;
1731 static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1733 RNA_int_set_array(op->ptr, "location", event->mval);
1734 return select_linked_exec(C, op);
1737 void PARTICLE_OT_select_linked(wmOperatorType *ot)
1740 ot->name = "Select Linked";
1741 ot->idname = "PARTICLE_OT_select_linked";
1742 ot->description = "Select nearest particle from mouse pointer";
1745 ot->exec = select_linked_exec;
1746 ot->invoke = select_linked_invoke;
1747 ot->poll = PE_poll_view3d;
1750 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1753 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them");
1754 RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
1757 /************************ border select operator ************************/
1758 void PE_deselect_all_visible(PTCacheEdit *edit)
1762 LOOP_VISIBLE_POINTS {
1763 LOOP_SELECTED_KEYS {
1764 key->flag &= ~PEK_SELECT;
1765 point->flag |= PEP_EDIT_RECALC;
1770 int PE_border_select(bContext *C, rcti *rect, bool select, bool extend)
1772 Scene *scene= CTX_data_scene(C);
1773 SceneLayer *sl = CTX_data_scene_layer(C);
1774 Object *ob= CTX_data_active_object(C);
1775 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1778 if (!PE_start_edit(edit))
1779 return OPERATOR_CANCELLED;
1781 if (extend == 0 && select)
1782 PE_deselect_all_visible(edit);
1784 PE_set_view3d_data(C, &data);
1786 data.select= select;
1788 for_mouse_hit_keys(&data, select_key, 0);
1790 PE_update_selection(scene, sl, ob, 1);
1791 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1793 return OPERATOR_FINISHED;
1796 /************************ circle select operator ************************/
1798 int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad)
1800 Scene *scene= CTX_data_scene(C);
1801 SceneLayer *sl = CTX_data_scene_layer(C);
1802 Object *ob= CTX_data_active_object(C);
1803 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1806 if (!PE_start_edit(edit))
1807 return OPERATOR_FINISHED;
1809 PE_set_view3d_data(C, &data);
1812 data.select= selecting;
1814 for_mouse_hit_keys(&data, select_key, 0);
1816 PE_update_selection(scene, sl, ob, 1);
1817 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1819 return OPERATOR_FINISHED;
1822 /************************ lasso select operator ************************/
1824 int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool extend, bool select)
1826 Scene *scene= CTX_data_scene(C);
1827 SceneLayer *sl = CTX_data_scene_layer(C);
1828 Object *ob= CTX_data_active_object(C);
1829 ARegion *ar= CTX_wm_region(C);
1830 ParticleEditSettings *pset= PE_settings(scene);
1831 PTCacheEdit *edit = PE_get_current(scene, sl, ob);
1832 ParticleSystem *psys = edit->psys;
1833 ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
1835 float co[3], mat[4][4];
1842 if (!PE_start_edit(edit))
1843 return OPERATOR_CANCELLED;
1845 if (extend == 0 && select)
1846 PE_deselect_all_visible(edit);
1848 /* only for depths */
1849 PE_set_view3d_data(C, &data);
1851 LOOP_VISIBLE_POINTS {
1852 if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
1853 psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + p, mat);
1855 if (pset->selectmode==SCE_SELECT_POINT) {
1857 copy_v3_v3(co, key->co);
1859 if ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) &&
1860 BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
1861 key_test_depth(&data, co, screen_co))
1864 if (!(key->flag & PEK_SELECT)) {
1865 key->flag |= PEK_SELECT;
1866 point->flag |= PEP_EDIT_RECALC;
1870 if (key->flag & PEK_SELECT) {
1871 key->flag &= ~PEK_SELECT;
1872 point->flag |= PEP_EDIT_RECALC;
1878 else if (pset->selectmode==SCE_SELECT_END) {
1879 if (point->totkey) {
1880 key= point->keys + point->totkey - 1;
1882 copy_v3_v3(co, key->co);
1884 if ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) &&
1885 BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
1886 key_test_depth(&data, co, screen_co))
1889 if (!(key->flag & PEK_SELECT)) {
1890 key->flag |= PEK_SELECT;
1891 point->flag |= PEP_EDIT_RECALC;
1895 if (key->flag & PEK_SELECT) {
1896 key->flag &= ~PEK_SELECT;
1897 point->flag |= PEP_EDIT_RECALC;
1905 PE_update_selection(scene, sl, ob, 1);
1906 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1908 return OPERATOR_FINISHED;
1911 /*************************** hide operator **************************/
1913 static int hide_exec(bContext *C, wmOperator *op)
1915 Object *ob= CTX_data_active_object(C);
1916 Scene *scene= CTX_data_scene(C);
1917 SceneLayer *sl = CTX_data_scene_layer(C);
1918 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1921 if (RNA_enum_get(op->ptr, "unselected")) {
1922 LOOP_UNSELECTED_POINTS {
1923 point->flag |= PEP_HIDE;
1924 point->flag |= PEP_EDIT_RECALC;
1927 key->flag &= ~PEK_SELECT;
1931 LOOP_SELECTED_POINTS {
1932 point->flag |= PEP_HIDE;
1933 point->flag |= PEP_EDIT_RECALC;
1936 key->flag &= ~PEK_SELECT;
1940 PE_update_selection(scene, sl, ob, 1);
1941 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1943 return OPERATOR_FINISHED;
1946 void PARTICLE_OT_hide(wmOperatorType *ot)
1949 ot->name = "Hide Selected";
1950 ot->idname = "PARTICLE_OT_hide";
1951 ot->description = "Hide selected particles";
1954 ot->exec = hide_exec;
1958 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1961 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
1964 /*************************** reveal operator **************************/
1966 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
1968 Object *ob= CTX_data_active_object(C);
1969 Scene *scene= CTX_data_scene(C);
1970 SceneLayer *sl = CTX_data_scene_layer(C);
1971 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
1975 if (point->flag & PEP_HIDE) {
1976 point->flag &= ~PEP_HIDE;
1977 point->flag |= PEP_EDIT_RECALC;
1980 key->flag |= PEK_SELECT;
1984 PE_update_selection(scene, sl, ob, 1);
1985 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob);
1987 return OPERATOR_FINISHED;
1990 void PARTICLE_OT_reveal(wmOperatorType *ot)
1993 ot->name = "Reveal";
1994 ot->idname = "PARTICLE_OT_reveal";
1995 ot->description = "Show hidden particles";
1998 ot->exec = reveal_exec;
2002 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2005 /************************ select less operator ************************/
2007 static void select_less_keys(PEData *data, int point_index)
2009 PTCacheEdit *edit= data->edit;
2010 PTCacheEditPoint *point = edit->points + point_index;
2013 LOOP_SELECTED_KEYS {
2015 if (((key+1)->flag&PEK_SELECT)==0)
2016 key->flag |= PEK_TAG;
2018 else if (k==point->totkey-1) {
2019 if (((key-1)->flag&PEK_SELECT)==0)
2020 key->flag |= PEK_TAG;
2023 if ((((key-1)->flag & (key+1)->flag) & PEK_SELECT)==0)
2024 key->flag |= PEK_TAG;
2029 if (key->flag&PEK_TAG) {
2030 key->flag &= ~(PEK_TAG|PEK_SELECT);
2031 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
2036 static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
2040 PE_set_data(C, &data);
2041 foreach_point(&data, select_less_keys);
2043 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
2044 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
2046 return OPERATOR_FINISHED;
2049 void PARTICLE_OT_select_less(wmOperatorType *ot)
2052 ot->name = "Select Less";
2053 ot->idname = "PARTICLE_OT_select_less";
2054 ot->description = "Deselect boundary selected keys of each particle";
2057 ot->exec = select_less_exec;
2061 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2064 /************************ select more operator ************************/
2066 static void select_more_keys(PEData *data, int point_index)
2068 PTCacheEdit *edit= data->edit;
2069 PTCacheEditPoint *point = edit->points + point_index;
2073 if (key->flag & PEK_SELECT) continue;
2076 if ((key+1)->flag&PEK_SELECT)
2077 key->flag |= PEK_TAG;
2079 else if (k==point->totkey-1) {
2080 if ((key-1)->flag&PEK_SELECT)
2081 key->flag |= PEK_TAG;
2084 if (((key-1)->flag | (key+1)->flag) & PEK_SELECT)
2085 key->flag |= PEK_TAG;
2090 if (key->flag&PEK_TAG) {
2091 key->flag &= ~PEK_TAG;
2092 key->flag |= PEK_SELECT;
2093 point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
2098 static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
2102 PE_set_data(C, &data);
2103 foreach_point(&data, select_more_keys);
2105 PE_update_selection(data.scene, data.scene_layer, data.ob, 1);
2106 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
2108 return OPERATOR_FINISHED;
2111 void PARTICLE_OT_select_more(wmOperatorType *ot)
2114 ot->name = "Select More";
2115 ot->idname = "PARTICLE_OT_select_more";
2116 ot->description = "Select keys linked to boundary selected keys of each particle";
2119 ot->exec = select_more_exec;
2123 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2126 /************************ rekey operator ************************/
2128 static void rekey_particle(PEData *data, int pa_index)
2130 PTCacheEdit *edit= data->edit;
2131 ParticleSystem *psys= edit->psys;
2132 ParticleSimulationData sim= {0};
2133 ParticleData *pa= psys->particles + pa_index;
2134 PTCacheEditPoint *point = edit->points + pa_index;
2136 HairKey *key, *new_keys, *okey;
2137 PTCacheEditKey *ekey;
2138 float dval, sta, end;
2141 sim.scene= data->scene;
2143 sim.psys= edit->psys;
2145 pa->flag |= PARS_REKEY;
2147 key= new_keys= MEM_callocN(data->totrekey * sizeof(HairKey), "Hair re-key keys");
2150 /* root and tip stay the same */
2151 copy_v3_v3(key->co, okey->co);
2152 copy_v3_v3((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co);
2154 sta= key->time= okey->time;
2155 end= (key + data->totrekey - 1)->time= (okey + pa->totkey - 1)->time;
2156 dval= (end - sta) / (float)(data->totrekey - 1);
2158 /* interpolate new keys from old ones */
2159 for (k=1, key++; k<data->totrekey-1; k++, key++) {
2160 state.time= (float)k / (float)(data->totrekey-1);
2161 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2162 copy_v3_v3(key->co, state.co);
2163 key->time= sta + k * dval;
2168 MEM_freeN(pa->hair);
2171 point->totkey=pa->totkey=data->totrekey;
2175 MEM_freeN(point->keys);
2176 ekey= point->keys= MEM_callocN(pa->totkey * sizeof(PTCacheEditKey), "Hair re-key edit keys");
2178 for (k=0, key=pa->hair; k<pa->totkey; k++, key++, ekey++) {
2180 ekey->time= &key->time;
2181 ekey->flag |= PEK_SELECT;
2182 if (!(psys->flag & PSYS_GLOBAL_HAIR))
2183 ekey->flag |= PEK_USE_WCO;
2186 pa->flag &= ~PARS_REKEY;
2187 point->flag |= PEP_EDIT_RECALC;
2190 static int rekey_exec(bContext *C, wmOperator *op)
2194 PE_set_data(C, &data);
2196 data.dval= 1.0f / (float)(data.totrekey-1);
2197 data.totrekey= RNA_int_get(op->ptr, "keys_number");
2199 foreach_selected_point(&data, rekey_particle);
2201 recalc_lengths(data.edit);
2202 PE_update_object(data.scene, data.scene_layer, data.ob, 1);
2203 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
2205 return OPERATOR_FINISHED;
2208 void PARTICLE_OT_rekey(wmOperatorType *ot)
2212 ot->idname = "PARTICLE_OT_rekey";
2213 ot->description = "Change the number of keys of selected particles (root and tip keys included)";
2216 ot->exec = rekey_exec;
2217 ot->invoke = WM_operator_props_popup;
2218 ot->poll = PE_hair_poll;
2221 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2224 RNA_def_int(ot->srna, "keys_number", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
2227 static void rekey_particle_to_time(Scene *scene, SceneLayer *sl, Object *ob, int pa_index, float path_time)
2229 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
2230 ParticleSystem *psys;
2231 ParticleSimulationData sim= {0};
2234 HairKey *new_keys, *key;
2235 PTCacheEditKey *ekey;
2238 if (!edit || !edit->psys) return;
2246 pa= psys->particles + pa_index;
2248 pa->flag |= PARS_REKEY;
2250 key= new_keys= MEM_dupallocN(pa->hair);
2252 /* interpolate new keys from old ones (roots stay the same) */
2253 for (k=1, key++; k < pa->totkey; k++, key++) {
2254 state.time= path_time * (float)k / (float)(pa->totkey-1);
2255 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2256 copy_v3_v3(key->co, state.co);
2259 /* replace hair keys */
2261 MEM_freeN(pa->hair);
2264 /* update edit pointers */
2265 for (k=0, key=pa->hair, ekey=edit->points[pa_index].keys; k<pa->totkey; k++, key++, ekey++) {
2267 ekey->time= &key->time;
2270 pa->flag &= ~PARS_REKEY;
2273 /************************* utilities **************************/
2275 static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
2277 PTCacheEdit *edit = psys->edit;
2278 ParticleData *pa, *npa=0, *new_pars=0;
2280 PTCacheEditPoint *npoint=0, *new_points=0;
2281 ParticleSystemModifierData *psmd;
2282 int i, new_totpart= psys->totpart, removed= 0;
2286 psmd= psys_get_modifier(ob, psys);
2288 LOOP_TAGGED_POINTS {
2289 PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
2293 LOOP_TAGGED_POINTS {
2298 if (new_totpart != psys->totpart) {
2300 npa= new_pars= MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
2301 npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
2303 if (ELEM(NULL, new_pars, new_points)) {
2304 /* allocation error! */
2306 MEM_freeN(new_pars);
2308 MEM_freeN(new_points);
2313 pa= psys->particles;
2314 point= edit->points;
2315 for (i=0; i<psys->totpart; i++, pa++, point++) {
2316 if (point->flag & PEP_TAG) {
2318 MEM_freeN(point->keys);
2320 MEM_freeN(pa->hair);
2323 memcpy(npa, pa, sizeof(ParticleData));
2324 memcpy(npoint, point, sizeof(PTCacheEditPoint));
2330 if (psys->particles) MEM_freeN(psys->particles);
2331 psys->particles= new_pars;
2333 if (edit->points) MEM_freeN(edit->points);
2334 edit->points= new_points;
2336 if (edit->mirror_cache) {
2337 MEM_freeN(edit->mirror_cache);
2338 edit->mirror_cache= NULL;
2342 MEM_freeN(psys->child);
2347 edit->totpoint= psys->totpart= new_totpart;
2353 static void remove_tagged_keys(Object *ob, ParticleSystem *psys)
2355 PTCacheEdit *edit= psys->edit;
2357 HairKey *hkey, *nhkey, *new_hkeys=0;
2359 PTCacheEditKey *nkey, *new_keys;
2360 ParticleSystemModifierData *psmd;
2363 if (pe_x_mirror(ob)) {
2364 /* mirror key tags */
2365 psmd= psys_get_modifier(ob, psys);
2369 PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL);
2376 new_totkey= point->totkey;
2380 /* we can't have elements with less than two keys*/
2382 point->flag |= PEP_TAG;
2384 remove_tagged_particles(ob, psys, pe_x_mirror(ob));
2387 pa = psys->particles + p;
2388 new_totkey= pa->totkey;
2394 if (new_totkey != pa->totkey) {
2395 nhkey= new_hkeys= MEM_callocN(new_totkey*sizeof(HairKey), "HairKeys");
2396 nkey= new_keys= MEM_callocN(new_totkey*sizeof(PTCacheEditKey), "particle edit keys");
2400 while (key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
2405 if (hkey < pa->hair + pa->totkey) {
2406 copy_v3_v3(nhkey->co, hkey->co);
2407 nhkey->editflag = hkey->editflag;
2408 nhkey->time= hkey->time;
2409 nhkey->weight= hkey->weight;
2411 nkey->co= nhkey->co;
2412 nkey->time= &nhkey->time;
2413 /* these can be copied from old edit keys */
2414 nkey->flag = key->flag;
2415 nkey->ftime = key->ftime;
2416 nkey->length = key->length;
2417 copy_v3_v3(nkey->world_co, key->world_co);
2425 MEM_freeN(pa->hair);
2428 MEM_freeN(point->keys);
2430 pa->hair= new_hkeys;
2431 point->keys= new_keys;
2433 point->totkey= pa->totkey= new_totkey;
2435 /* flag for recalculating length */
2436 point->flag |= PEP_EDIT_RECALC;
2441 /************************ subdivide opertor *********************/
2443 /* works like normal edit mode subdivide, inserts keys between neighboring selected keys */
2444 static void subdivide_particle(PEData *data, int pa_index)
2446 PTCacheEdit *edit= data->edit;
2447 ParticleSystem *psys= edit->psys;
2448 ParticleSimulationData sim= {0};
2449 ParticleData *pa= psys->particles + pa_index;
2450 PTCacheEditPoint *point = edit->points + pa_index;
2452 HairKey *key, *nkey, *new_keys;
2453 PTCacheEditKey *ekey, *nekey, *new_ekeys;
2459 sim.scene= data->scene;
2461 sim.psys= edit->psys;
2463 for (k=0, ekey=point->keys; k<pa->totkey-1; k++, ekey++) {
2464 if (ekey->flag&PEK_SELECT && (ekey+1)->flag&PEK_SELECT)
2468 if (totnewkey==0) return;
2470 pa->flag |= PARS_REKEY;
2472 nkey= new_keys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(HairKey)), "Hair subdivide keys");
2473 nekey= new_ekeys= MEM_callocN((pa->totkey+totnewkey)*(sizeof(PTCacheEditKey)), "Hair subdivide edit keys");
2476 endtime= key[pa->totkey-1].time;
2478 for (k=0, ekey=point->keys; k<pa->totkey-1; k++, key++, ekey++) {
2480 memcpy(nkey, key, sizeof(HairKey));
2481 memcpy(nekey, ekey, sizeof(PTCacheEditKey));
2483 nekey->co= nkey->co;
2484 nekey->time= &nkey->time;
2489 if (ekey->flag & PEK_SELECT && (ekey+1)->flag & PEK_SELECT) {
2490 nkey->time = (key->time + (key + 1)->time) * 0.5f;
2491 state.time = (endtime != 0.0f) ? nkey->time / endtime: 0.0f;
2492 psys_get_particle_on_path(&sim, pa_index, &state, 0);
2493 copy_v3_v3(nkey->co, state.co);
2495 nekey->co= nkey->co;
2496 nekey->time = &nkey->time;
2497 nekey->flag |= PEK_SELECT;
2498 if (!(psys->flag & PSYS_GLOBAL_HAIR))
2499 nekey->flag |= PEK_USE_WCO;
2505 /*tip still not copied*/
2506 memcpy(nkey, key, sizeof(HairKey));
2507 memcpy(nekey, ekey, sizeof(PTCacheEditKey));
2509 nekey->co= nkey->co;
2510 nekey->time= &nkey->time;
2513 MEM_freeN(pa->hair);
2517 MEM_freeN(point->keys);
2518 point->keys= new_ekeys;
2520 point->totkey = pa->totkey = pa->totkey + totnewkey;
2521 point->flag |= PEP_EDIT_RECALC;
2522 pa->flag &= ~PARS_REKEY;
2525 static int subdivide_exec(bContext *C, wmOperator *UNUSED(op))
2529 PE_set_data(C, &data);
2530 foreach_point(&data, subdivide_particle);
2532 recalc_lengths(data.edit);
2533 PE_update_object(data.scene, data.scene_layer, data.ob, 1);
2534 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
2536 return OPERATOR_FINISHED;
2539 void PARTICLE_OT_subdivide(wmOperatorType *ot)
2542 ot->name = "Subdivide";
2543 ot->idname = "PARTICLE_OT_subdivide";
2544 ot->description = "Subdivide selected particles segments (adds keys)";
2547 ot->exec = subdivide_exec;
2548 ot->poll = PE_hair_poll;
2551 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2554 /************************ remove doubles opertor *********************/
2556 static int remove_doubles_exec(bContext *C, wmOperator *op)
2558 Scene *scene= CTX_data_scene(C);
2559 SceneLayer *sl = CTX_data_scene_layer(C);
2560 Object *ob= CTX_data_active_object(C);
2561 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
2562 ParticleSystem *psys = edit->psys;
2563 ParticleSystemModifierData *psmd;
2565 KDTreeNearest nearest[10];
2567 float mat[4][4], co[3], threshold= RNA_float_get(op->ptr, "threshold");
2568 int n, totn, removed, totremoved;
2570 if (psys->flag & PSYS_GLOBAL_HAIR)
2571 return OPERATOR_CANCELLED;
2574 psmd= psys_get_modifier(ob, psys);
2580 tree=BLI_kdtree_new(psys->totpart);
2582 /* insert particles into kd tree */
2583 LOOP_SELECTED_POINTS {
2584 psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat);
2585 copy_v3_v3(co, point->keys->co);
2587 BLI_kdtree_insert(tree, p, co);
2590 BLI_kdtree_balance(tree);
2592 /* tag particles to be removed */
2593 LOOP_SELECTED_POINTS {
2594 psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat);
2595 copy_v3_v3(co, point->keys->co);
2598 totn = BLI_kdtree_find_nearest_n(tree, co, nearest, 10);
2600 for (n=0; n<totn; n++) {
2601 /* this needs a custom threshold still */
2602 if (nearest[n].index > p && nearest[n].dist < threshold) {
2603 if (!(point->flag & PEP_TAG)) {
2604 point->flag |= PEP_TAG;
2611 BLI_kdtree_free(tree);
2613 /* remove tagged particles - don't do mirror here! */
2614 remove_tagged_particles(ob, psys, 0);
2615 totremoved += removed;
2618 if (totremoved == 0)
2619 return OPERATOR_CANCELLED;
2621 BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved);
2623 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
2624 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2626 return OPERATOR_FINISHED;
2629 void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
2632 ot->name = "Remove Doubles";
2633 ot->idname = "PARTICLE_OT_remove_doubles";
2634 ot->description = "Remove selected particles close enough of others";
2637 ot->exec = remove_doubles_exec;
2638 ot->poll = PE_hair_poll;
2641 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2644 RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX,
2645 "Merge Distance", "Threshold distance withing which particles are removed", 0.00001f, 0.1f);
2649 static int weight_set_exec(bContext *C, wmOperator *op)
2651 Scene *scene= CTX_data_scene(C);
2652 SceneLayer *sl = CTX_data_scene_layer(C);
2653 ParticleEditSettings *pset= PE_settings(scene);
2654 Object *ob= CTX_data_active_object(C);
2655 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
2656 ParticleSystem *psys = edit->psys;
2661 ParticleBrushData *brush= &pset->brush[pset->brushtype];
2662 float factor= RNA_float_get(op->ptr, "factor");
2664 weight= brush->strength;
2667 LOOP_SELECTED_POINTS {
2668 ParticleData *pa= psys->particles + p;
2670 LOOP_SELECTED_KEYS {
2672 hkey->weight= interpf(weight, hkey->weight, factor);
2676 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
2677 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2679 return OPERATOR_FINISHED;
2682 void PARTICLE_OT_weight_set(wmOperatorType *ot)
2685 ot->name = "Weight Set";
2686 ot->idname = "PARTICLE_OT_weight_set";
2687 ot->description = "Set the weight of selected keys";
2690 ot->exec = weight_set_exec;
2691 ot->poll = PE_hair_poll;
2694 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2696 RNA_def_float(ot->srna, "factor", 1, 0, 1, "Factor",
2697 "Interpolation factor between current brush weight, and keys' weights", 0, 1);
2700 /************************ cursor drawing *******************************/
2702 static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
2704 Scene *scene = CTX_data_scene(C);
2705 ParticleEditSettings *pset= PE_settings(scene);
2706 ParticleBrushData *brush;
2708 if (pset->brushtype < 0) {
2712 brush = &pset->brush[pset->brushtype];
2715 unsigned int pos = VertexFormat_add_attrib(immVertexFormat(), "pos", COMP_F32, 2, KEEP_FLOAT);
2716 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
2718 immUniformColor4ub(255, 255, 255, 128);
2720 glEnable(GL_LINE_SMOOTH);
2723 imm_draw_circle_wire(pos, (float)x, (float)y, pe_brush_size_get(scene, brush), 40);
2725 glDisable(GL_BLEND);
2726 glDisable(GL_LINE_SMOOTH);
2732 static void toggle_particle_cursor(bContext *C, int enable)
2734 ParticleEditSettings *pset= PE_settings(CTX_data_scene(C));
2736 if (pset->paintcursor && !enable) {
2737 WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
2738 pset->paintcursor = NULL;
2741 pset->paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), PE_poll_view3d, brush_drawcursor, NULL);
2744 /*************************** delete operator **************************/
2746 enum { DEL_PARTICLE, DEL_KEY };
2748 static EnumPropertyItem delete_type_items[] = {
2749 {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
2750 {DEL_KEY, "KEY", 0, "Key", ""},
2751 {0, NULL, 0, NULL, NULL}};
2753 static void set_delete_particle(PEData *data, int pa_index)
2755 PTCacheEdit *edit= data->edit;
2757 edit->points[pa_index].flag |= PEP_TAG;
2760 static void set_delete_particle_key(PEData *data, int pa_index, int key_index)
2762 PTCacheEdit *edit= data->edit;
2764 edit->points[pa_index].keys[key_index].flag |= PEK_TAG;
2767 static int delete_exec(bContext *C, wmOperator *op)
2770 int type= RNA_enum_get(op->ptr, "type");
2772 PE_set_data(C, &data);
2774 if (type == DEL_KEY) {
2775 foreach_selected_key(&data, set_delete_particle_key);
2776 remove_tagged_keys(data.ob, data.edit->psys);
2777 recalc_lengths(data.edit);
2779 else if (type == DEL_PARTICLE) {
2780 foreach_selected_point(&data, set_delete_particle);
2781 remove_tagged_particles(data.ob, data.edit->psys, pe_x_mirror(data.ob));
2782 recalc_lengths(data.edit);
2785 DEG_id_tag_update(&data.ob->id, OB_RECALC_DATA);
2786 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob);
2788 return OPERATOR_FINISHED;
2791 void PARTICLE_OT_delete(wmOperatorType *ot)
2794 ot->name = "Delete";
2795 ot->idname = "PARTICLE_OT_delete";
2796 ot->description = "Delete selected particles or keys";
2799 ot->exec = delete_exec;
2800 ot->invoke = WM_menu_invoke;
2801 ot->poll = PE_hair_poll;
2804 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2807 ot->prop = RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys");
2810 /*************************** mirror operator **************************/
2812 static void PE_mirror_x(Scene *scene, SceneLayer *sl, Object *ob, int tagged)
2814 Mesh *me= (Mesh *)(ob->data);
2815 ParticleSystemModifierData *psmd;
2816 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
2817 ParticleSystem *psys = edit->psys;
2818 ParticleData *pa, *newpa, *new_pars;
2819 PTCacheEditPoint *newpoint, *new_points;
2822 int *mirrorfaces = NULL;
2823 int rotation, totpart, newtotpart;
2825 if (psys->flag & PSYS_GLOBAL_HAIR)
2828 psmd= psys_get_modifier(ob, psys);
2829 if (!psmd->dm_final)
2832 const bool use_dm_final_indices = (psys->part->use_modifier_stack && !psmd->dm_final->deformedOnly);
2834 /* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */
2835 BKE_mesh_tessface_ensure(me);
2837 /* Note: In case psys uses DM tessface indices, we mirror final DM itself, not orig mesh. Avoids an (impossible)
2838 * dm -> orig -> dm tessface indices conversion... */
2839 mirrorfaces = mesh_get_x_mirror_faces(ob, NULL, use_dm_final_indices ? psmd->dm_final : NULL);
2841 if (!edit->mirror_cache)
2842 PE_update_mirror_cache(ob, psys);
2844 totpart= psys->totpart;
2845 newtotpart= psys->totpart;
2846 LOOP_VISIBLE_POINTS {
2847 pa = psys->particles + p;
2850 if (point_is_selected(point)) {
2851 if (edit->mirror_cache[p] != -1) {
2852 /* already has a mirror, don't need to duplicate */
2853 PE_mirror_particle(ob, psmd->dm_final, psys, pa, NULL);
2857 point->flag |= PEP_TAG;
2861 if ((point->flag & PEP_TAG) && mirrorfaces[pa->num*2] != -1)
2865 if (newtotpart != psys->totpart) {
2866 MFace *mtessface = use_dm_final_indices ? psmd->dm_final->getTessFaceArray(psmd->dm_final) : me->mface;
2868 /* allocate new arrays and copy existing */
2869 new_pars= MEM_callocN(newtotpart*sizeof(ParticleData), "ParticleData new");
2870 new_points= MEM_callocN(newtotpart*sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
2872 if (psys->particles) {
2873 memcpy(new_pars, psys->particles, totpart*sizeof(ParticleData));
2874 MEM_freeN(psys->particles);
2876 psys->particles= new_pars;
2879 memcpy(new_points, edit->points, totpart*sizeof(PTCacheEditPoint));
2880 MEM_freeN(edit->points);
2882 edit->points= new_points;
2884 if (edit->mirror_cache) {
2885 MEM_freeN(edit->mirror_cache);
2886 edit->mirror_cache= NULL;
2889 edit->totpoint= psys->totpart= newtotpart;
2891 /* create new elements */
2892 newpa= psys->particles + totpart;
2893 newpoint= edit->points + totpart;
2895 for (p=0, point=edit->points; p<totpart; p++, point++) {
2896 pa = psys->particles + p;
2897 const int pa_num = pa->num;
2899 if (point->flag & PEP_HIDE)
2902 if (!(point->flag & PEP_TAG) || mirrorfaces[pa_num * 2] == -1)
2908 if (pa->hair) newpa->hair= MEM_dupallocN(pa->hair);
2909 if (point->keys) newpoint->keys= MEM_dupallocN(point->keys);
2911 /* rotate weights according to vertex index rotation */
2912 rotation= mirrorfaces[pa_num * 2 + 1];
2913 newpa->fuv[0] = pa->fuv[2];
2914 newpa->fuv[1] = pa->fuv[1];
2915 newpa->fuv[2] = pa->fuv[0];
2916 newpa->fuv[3] = pa->fuv[3];
2917 while (rotation--) {
2918 if (mtessface[pa_num].v4) {
2919 SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3]);
2922 SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2]);
2926 /* assign face index */
2927 /* NOTE: mesh_get_x_mirror_faces generates -1 for non-found mirror, same as DMCACHE_NOTFOUND... */
2928 newpa->num = mirrorfaces[pa_num * 2];
2930 if (use_dm_final_indices) {
2931 newpa->num_dmcache = DMCACHE_ISCHILD;
2934 newpa->num_dmcache = psys_particle_dm_face_lookup(
2935 psmd->dm_final, psmd->dm_deformed, newpa->num, newpa->fuv, NULL);
2938 /* update edit key pointers */
2939 key= newpoint->keys;
2940 for (k=0, hkey=newpa->hair; k<newpa->totkey; k++, hkey++, key++) {
2942 key->time= &hkey->time;
2945 /* map key positions as mirror over x axis */
2946 PE_mirror_particle(ob, psmd->dm_final, psys, pa, newpa);
2954 point->flag &= ~PEP_TAG;
2957 MEM_freeN(mirrorfaces);
2960 static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
2962 Scene *scene= CTX_data_scene(C);
2963 SceneLayer *sl = CTX_data_scene_layer(C);
2964 Object *ob= CTX_data_active_object(C);
2965 PTCacheEdit *edit= PE_get_current(scene, sl, ob);
2967 PE_mirror_x(scene, sl, ob, 0);
2969 update_world_cos(ob, edit);
2970 WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
2971 DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
2973 return OPERATOR_FINISHED;
2976 void PARTICLE_OT_mirror(wmOperatorType *ot)
2979 ot->name = "Mirror";
2980 ot->idname = "PARTICLE_OT_mirror";
2981 ot->description = "Duplicate and mirror the selected particles along the local X axis";
2984 ot->exec = mirror_exec;
2985 ot->poll = PE_hair_poll;
2988 ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
2991 /************************* brush edit callbacks ********************/
2993 static void brush_comb(PEData *data, float UNUSED(mat[4][4]), float imat[4][4], int point_index, int key_index, PTCacheEditKey *key)
2995 ParticleEditSettings *pset= PE_settings(data->scene);
2998 if (pset->flag & PE_LOCK_FIRST && key_index == 0) return;
3000 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->combfac);
3002 copy_v3_v3(cvec, data->dvec);
3003 mul_mat3_m4_v3(imat, cvec);
3004 mul_v3_fl(cvec, fac);
3005 add_v3_v3(key->co, cvec);
3007 (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
3010 static void brush_cut(PEData *data, int pa_index)
3012 PTCacheEdit *edit = data->edit;
3013 ARegion *ar= data->vc.ar;
3014 Object *ob= data->ob;
3015 ParticleEditSettings *pset= PE_settings(data->scene);
3016 ParticleCacheKey *key= edit->pathcache[pa_index];
3017 float rad2, cut_time= 1.0;
3018 float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
3019 int k, cut, keys= (int)pow(2.0, (double)pset->draw_step);
3022 /* blunt scissors */
3023 if (BLI_frand() > data->cutfac) return;
3025 /* don't cut hidden */
3026 if (edit->points[pa_index].flag & PEP_HIDE)
3029 if (ED_view3d_project_int_global(ar, key->co, screen_co, V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK)
3032 rad2= data->rad * data->rad;
3036 x0 = (float)screen_co[0];
3037 x1 = (float)screen_co[1];
3039 o0= (float)data->mval[0];
3040 o1= (float)data->mval[1];
3045 /* check if root is inside circle */
3046 if (xo0*xo0 + xo1*xo1 < rad2 && key_test_depth(data, key->co, screen_co)) {
3051 /* calculate path time closest to root that was inside the circle */
3052 for (k=1, key++; k<=keys; k++, key++) {
3054 if ((ED_view3d_project_int_global(ar, key->co, screen_co, V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK) ||
3055 key_test_depth(data, key->co, screen_co) == 0)
3057 x0 = (float)screen_co[0];
3058 x1 = (float)screen_co[1];
3065 v0 = (float)screen_co[0] - x0;
3066 v1 = (float)screen_co[1] - x1;
3070 d= (v0*xo1 - v1*xo0);
3077 cut_time= -(v0*xo0 + v1*xo1 + d);
3079 if (cut_time > 0.0f) {
3082 if (cut_time < 1.0f) {
3083 cut_time += (float)(k-1);
3084 cut_time /= (float)keys;
3091 x0 = (float)screen_co[0];
3092 x1 = (float)screen_co[1];
3100 if (cut_time < 0.0f) {
3101 edit->points[pa_index].flag |= PEP_TAG;
3104 rekey_particle_to_time(data->scene, data->scene_layer, ob, pa_index, cut_time);
3105 edit->points[pa_index].flag |= PEP_EDIT_RECALC;
3110 static void brush_length(PEData *data, int point_index)
3112 PTCacheEdit *edit= data->edit;
3113 PTCacheEditPoint *point = edit->points + point_index;
3115 float dvec[3], pvec[3] = {0.0f, 0.0f, 0.0f};
3119 copy_v3_v3(pvec, key->co);
3122 sub_v3_v3v3(dvec, key->co, pvec);
3123 copy_v3_v3(pvec, key->co);
3124 mul_v3_fl(dvec, data->growfac);
3125 add_v3_v3v3(key->co, (key-1)->co, dvec);
3129 point->flag |= PEP_EDIT_RECALC;
3132 static void brush_puff(PEData *data, int point_index)
3134 PTCacheEdit *edit = data->edit;
3135 ParticleSystem *psys = edit->psys;
3136 PTCacheEditPoint *point = edit->points + point_index;
3138 float mat[4][4], imat[4][4];
3140 float onor_prev[3]; /* previous normal (particle-space) */
3141 float ofs_prev[3]; /* accumulate offset for puff_volume (particle-space) */
3142 float co_root[3], no_root[3]; /* root location and normal (global-space) */
3143 float co_prev[3], co[3]; /* track key coords as we loop (global-space) */
3144 float fac = 0.0f, length_accum = 0.0f;
3145 bool puff_volume = false;
3146 bool changed = false;
3151 ParticleEditSettings *pset= PE_settings(data->scene);
3152 ParticleBrushData *brush= &pset->brush[pset->brushtype];
3153 puff_volume = (brush->flag & PE_BRUSH_DATA_PUFF_VOLUME) != 0;
3156 if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
3157 psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat);
3158 invert_m4_m4(imat, mat);
3169 /* find root coordinate and normal on emitter */
3170 copy_v3_v3(co, key->co);
3172 mul_v3_m4v3(kco, data->ob->imat, co); /* use 'kco' as the object space version of worldspace 'co', ob->imat is set before calling */
3174 point_index= BLI_kdtree_find_nearest(edit->emitter_field, kco, NULL);
3175 if (point_index == -1) return;
3177 copy_v3_v3(co_root, co);
3178 copy_v3_v3(no_root, &edit->emitter_cosnos[point_index * 6 + 3]);
3179 mul_mat3_m4_v3(data->ob->obmat, no_root); /* normal into global-space */
3180 normalize_v3(no_root);
3183 copy_v3_v3(onor_prev, no_root);
3184 mul_mat3_m4_v3(imat, onor_prev); /* global-space into particle space */
3185 normalize_v3(onor_prev);
3188 fac= (float)pow((double)(1.0f - data->dist / data->rad), (double)data->pufffac);
3194 /* compute position as if hair was standing up straight.
3197 copy_v3_v3(co_prev, co);
3198 copy_v3_v3(co, key->co);
3200 length = len_v3v3(co_prev, co);
3201 length_accum += length;
3203 if ((data->select==0 || (key->flag & PEK_SELECT)) && !(key->flag & PEK_HIDE)) {
3204 float dco[3]; /* delta temp var */
3206 madd_v3_v3v3fl(kco, co_root, no_root, length_accum);
3208 /* blend between the current and straight position */
3209 sub_v3_v3v3(dco, kco, co);
3210 madd_v3_v3fl(co, dco, fac);
3211 /* keep the same distance from the root or we get glitches [#35406] */
3212 dist_ensure_v3_v3fl(co, co_root, length_accum);
3214 /* re-use dco to compare before and after translation and add to the offset */
3215 copy_v3_v3(dco, key->co);
3217 mul_v3_m4v3(key->co, imat, co);
3220 /* accumulate the total distance moved to apply to unselected
3221 * keys that come after */
3222 sub_v3_v3v3(ofs_prev, key->co, dco);
3230 /* this is simple but looks bad, adds annoying kinks */
3231 add_v3_v3(key->co, ofs);
3233 /* translate (not rotate) the rest of the hair if its not selected */
3235 #if 0 /* kindof works but looks worse then whats below */
3237 /* Move the unselected point on a vector based on the
3238 * hair direction and the offset */