Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/physics/particle_edit.c')
-rw-r--r--source/blender/editors/physics/particle_edit.c8199
1 files changed, 4184 insertions, 4015 deletions
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index f2d9871a99d..627ffd68bbb 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -59,7 +59,6 @@
#include "DEG_depsgraph.h"
-
#include "ED_object.h"
#include "ED_physics.h"
#include "ED_mesh.h"
@@ -94,118 +93,117 @@
bool PE_poll(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
- if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) {
- return 0;
- }
- return (PE_get_current(scene, ob) != NULL);
+ if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) {
+ return 0;
+ }
+ return (PE_get_current(scene, ob) != NULL);
}
bool PE_hair_poll(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit;
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ PTCacheEdit *edit;
- if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) {
- return 0;
- }
- edit = PE_get_current(scene, ob);
+ if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) {
+ return 0;
+ }
+ edit = PE_get_current(scene, ob);
- return (edit && edit->psys);
+ return (edit && edit->psys);
}
bool PE_poll_view3d(bContext *C)
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
- return (PE_poll(C) &&
- (sa && sa->spacetype == SPACE_VIEW3D) &&
- (ar && ar->regiontype == RGN_TYPE_WINDOW));
+ return (PE_poll(C) && (sa && sa->spacetype == SPACE_VIEW3D) &&
+ (ar && ar->regiontype == RGN_TYPE_WINDOW));
}
void PE_free_ptcache_edit(PTCacheEdit *edit)
{
- POINT_P;
+ POINT_P;
- if (edit == 0) return;
+ if (edit == 0)
+ return;
- if (edit->points) {
- LOOP_POINTS {
- if (point->keys)
- MEM_freeN(point->keys);
- }
+ if (edit->points) {
+ LOOP_POINTS
+ {
+ if (point->keys)
+ MEM_freeN(point->keys);
+ }
- MEM_freeN(edit->points);
- }
+ MEM_freeN(edit->points);
+ }
- if (edit->mirror_cache)
- MEM_freeN(edit->mirror_cache);
+ if (edit->mirror_cache)
+ MEM_freeN(edit->mirror_cache);
- if (edit->emitter_cosnos) {
- MEM_freeN(edit->emitter_cosnos);
- edit->emitter_cosnos = 0;
- }
+ if (edit->emitter_cosnos) {
+ MEM_freeN(edit->emitter_cosnos);
+ edit->emitter_cosnos = 0;
+ }
- if (edit->emitter_field) {
- BLI_kdtree_3d_free(edit->emitter_field);
- edit->emitter_field = 0;
- }
+ if (edit->emitter_field) {
+ BLI_kdtree_3d_free(edit->emitter_field);
+ edit->emitter_field = 0;
+ }
- psys_free_path_cache(edit->psys, edit);
+ psys_free_path_cache(edit->psys, edit);
- MEM_freeN(edit);
+ MEM_freeN(edit);
}
/************************************************/
-/* Edit Mode Helpers */
+/* Edit Mode Helpers */
/************************************************/
int PE_start_edit(PTCacheEdit *edit)
{
- if (edit) {
- edit->edited = 1;
- if (edit->psys)
- edit->psys->flag |= PSYS_EDITED;
- return 1;
- }
+ if (edit) {
+ edit->edited = 1;
+ if (edit->psys)
+ edit->psys->flag |= PSYS_EDITED;
+ return 1;
+ }
- return 0;
+ return 0;
}
ParticleEditSettings *PE_settings(Scene *scene)
{
- return scene->toolsettings ? &scene->toolsettings->particle : NULL;
+ return scene->toolsettings ? &scene->toolsettings->particle : NULL;
}
static float pe_brush_size_get(const Scene *UNUSED(scene), ParticleBrushData *brush)
{
- // here we can enable unified brush size, needs more work...
- // UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- // float size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
+ // here we can enable unified brush size, needs more work...
+ // UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ // float size = (ups->flag & UNIFIED_PAINT_SIZE) ? ups->size : brush->size;
- return brush->size * U.pixelsize;
+ return brush->size * U.pixelsize;
}
PTCacheEdit *PE_get_current_from_psys(ParticleSystem *psys)
{
- if (psys->part && psys->part->type == PART_HAIR) {
- if ((psys->flag & PSYS_HAIR_DYNAMICS) != 0 &&
- (psys->pointcache->flag & PTCACHE_BAKED) != 0)
- {
- return psys->pointcache->edit;
- }
- else {
- return psys->edit;
- }
- }
- else if (psys->pointcache->flag & PTCACHE_BAKED) {
- return psys->pointcache->edit;
- }
- return NULL;
+ if (psys->part && psys->part->type == PART_HAIR) {
+ if ((psys->flag & PSYS_HAIR_DYNAMICS) != 0 && (psys->pointcache->flag & PTCACHE_BAKED) != 0) {
+ return psys->pointcache->edit;
+ }
+ else {
+ return psys->edit;
+ }
+ }
+ else if (psys->pointcache->flag & PTCACHE_BAKED) {
+ return psys->pointcache->edit;
+ }
+ return NULL;
}
/* NOTE: Similar to creation of edit, but only updates pointers in the
@@ -213,1678 +211,1722 @@ PTCacheEdit *PE_get_current_from_psys(ParticleSystem *psys)
*/
static void pe_update_hair_particle_edit_pointers(PTCacheEdit *edit)
{
- ParticleSystem *psys = edit->psys;
- ParticleData *pa = psys->particles;
- for (int p = 0; p < edit->totpoint; p++) {
- PTCacheEditPoint *point = &edit->points[p];
- HairKey *hair_key = pa->hair;
- for (int k = 0; k < point->totkey; k++) {
- PTCacheEditKey *key = &point->keys[k];
- key->co = hair_key->co;
- key->time = &hair_key->time;
- key->flag = hair_key->editflag;
- if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
- key->flag |= PEK_USE_WCO;
- hair_key->editflag |= PEK_USE_WCO;
- }
- hair_key++;
- }
- pa++;
- }
+ ParticleSystem *psys = edit->psys;
+ ParticleData *pa = psys->particles;
+ for (int p = 0; p < edit->totpoint; p++) {
+ PTCacheEditPoint *point = &edit->points[p];
+ HairKey *hair_key = pa->hair;
+ for (int k = 0; k < point->totkey; k++) {
+ PTCacheEditKey *key = &point->keys[k];
+ key->co = hair_key->co;
+ key->time = &hair_key->time;
+ key->flag = hair_key->editflag;
+ if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
+ key->flag |= PEK_USE_WCO;
+ hair_key->editflag |= PEK_USE_WCO;
+ }
+ hair_key++;
+ }
+ pa++;
+ }
}
/* always gets at least the first particlesystem even if PSYS_CURRENT flag is not set
*
* note: this function runs on poll, therefor it can runs many times a second
* keep it fast! */
-static PTCacheEdit *pe_get_current(
- Depsgraph *depsgraph, Scene *scene, Object *ob, int create)
-{
- ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = NULL;
- ListBase pidlist;
- PTCacheID *pid;
-
- if (pset == NULL || ob == NULL)
- return NULL;
-
- pset->scene = scene;
- pset->object = ob;
-
- BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
-
- /* in the case of only one editable thing, set pset->edittype accordingly */
- if (BLI_listbase_is_single(&pidlist)) {
- pid = pidlist.first;
- switch (pid->type) {
- case PTCACHE_TYPE_PARTICLES:
- pset->edittype = PE_TYPE_PARTICLES;
- break;
- case PTCACHE_TYPE_SOFTBODY:
- pset->edittype = PE_TYPE_SOFTBODY;
- break;
- case PTCACHE_TYPE_CLOTH:
- pset->edittype = PE_TYPE_CLOTH;
- break;
- }
- }
-
- for (pid = pidlist.first; pid; pid = pid->next) {
- if (pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) {
- ParticleSystem *psys = pid->calldata;
-
- if (psys->flag & PSYS_CURRENT) {
- if (psys->part && psys->part->type == PART_HAIR) {
- if (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
- if (create && !psys->pointcache->edit)
- PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
- edit = pid->cache->edit;
- }
- else {
- if (create && !psys->edit) {
- if (psys->flag & PSYS_HAIR_DONE) {
- PE_create_particle_edit(depsgraph, scene, ob, NULL, psys);
- }
- }
- edit = psys->edit;
- }
- }
- else {
- if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
- PE_create_particle_edit(depsgraph, scene, ob, pid->cache, psys);
- edit = pid->cache->edit;
- }
-
- break;
- }
- }
- else if (pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
- if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
- pset->flag |= PE_FADE_TIME;
- // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
- PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
- }
- edit = pid->cache->edit;
- break;
- }
- else if (pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
- if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
- pset->flag |= PE_FADE_TIME;
- // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
- PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
- }
- edit = pid->cache->edit;
- break;
- }
- }
-
- if (edit) {
- edit->pid = *pid;
- if (edit->flags & PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL) {
- if (edit->psys != NULL) {
- psys_copy_particles(edit->psys, edit->psys_eval);
- pe_update_hair_particle_edit_pointers(edit);
- }
- edit->flags &= ~PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL;
- }
- }
-
- BLI_freelistN(&pidlist);
-
- return edit;
+static PTCacheEdit *pe_get_current(Depsgraph *depsgraph, Scene *scene, Object *ob, int create)
+{
+ ParticleEditSettings *pset = PE_settings(scene);
+ PTCacheEdit *edit = NULL;
+ ListBase pidlist;
+ PTCacheID *pid;
+
+ if (pset == NULL || ob == NULL)
+ return NULL;
+
+ pset->scene = scene;
+ pset->object = ob;
+
+ BKE_ptcache_ids_from_object(&pidlist, ob, NULL, 0);
+
+ /* in the case of only one editable thing, set pset->edittype accordingly */
+ if (BLI_listbase_is_single(&pidlist)) {
+ pid = pidlist.first;
+ switch (pid->type) {
+ case PTCACHE_TYPE_PARTICLES:
+ pset->edittype = PE_TYPE_PARTICLES;
+ break;
+ case PTCACHE_TYPE_SOFTBODY:
+ pset->edittype = PE_TYPE_SOFTBODY;
+ break;
+ case PTCACHE_TYPE_CLOTH:
+ pset->edittype = PE_TYPE_CLOTH;
+ break;
+ }
+ }
+
+ for (pid = pidlist.first; pid; pid = pid->next) {
+ if (pset->edittype == PE_TYPE_PARTICLES && pid->type == PTCACHE_TYPE_PARTICLES) {
+ ParticleSystem *psys = pid->calldata;
+
+ if (psys->flag & PSYS_CURRENT) {
+ if (psys->part && psys->part->type == PART_HAIR) {
+ if (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
+ if (create && !psys->pointcache->edit)
+ PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
+ edit = pid->cache->edit;
+ }
+ else {
+ if (create && !psys->edit) {
+ if (psys->flag & PSYS_HAIR_DONE) {
+ PE_create_particle_edit(depsgraph, scene, ob, NULL, psys);
+ }
+ }
+ edit = psys->edit;
+ }
+ }
+ else {
+ if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
+ PE_create_particle_edit(depsgraph, scene, ob, pid->cache, psys);
+ edit = pid->cache->edit;
+ }
+
+ break;
+ }
+ }
+ else if (pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) {
+ if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
+ pset->flag |= PE_FADE_TIME;
+ // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
+ PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
+ }
+ edit = pid->cache->edit;
+ break;
+ }
+ else if (pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) {
+ if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
+ pset->flag |= PE_FADE_TIME;
+ // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
+ PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL);
+ }
+ edit = pid->cache->edit;
+ break;
+ }
+ }
+
+ if (edit) {
+ edit->pid = *pid;
+ if (edit->flags & PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL) {
+ if (edit->psys != NULL) {
+ psys_copy_particles(edit->psys, edit->psys_eval);
+ pe_update_hair_particle_edit_pointers(edit);
+ }
+ edit->flags &= ~PT_CACHE_EDIT_UPDATE_PARTICLE_FROM_EVAL;
+ }
+ }
+
+ BLI_freelistN(&pidlist);
+
+ return edit;
}
PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
{
- return pe_get_current(NULL, scene, ob, 0);
+ return pe_get_current(NULL, scene, ob, 0);
}
PTCacheEdit *PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- return pe_get_current(depsgraph, scene, ob, 1);
+ return pe_get_current(depsgraph, scene, ob, 1);
}
void PE_current_changed(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
- if (ob->mode == OB_MODE_PARTICLE_EDIT) {
- PE_create_current(depsgraph, scene, ob);
- }
+ if (ob->mode == OB_MODE_PARTICLE_EDIT) {
+ PE_create_current(depsgraph, scene, ob);
+ }
}
void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
{
- ParticleEditSettings *pset = PE_settings(scene);
- POINT_P; KEY_K;
-
-
- if (pset->flag & PE_FADE_TIME && pset->selectmode == SCE_SELECT_POINT) {
- LOOP_POINTS {
- LOOP_KEYS {
- if (fabsf(cfra - *key->time) < pset->fade_frames)
- key->flag &= ~PEK_HIDE;
- else {
- key->flag |= PEK_HIDE;
- //key->flag &= ~PEK_SELECT;
- }
- }
- }
- }
- else {
- LOOP_POINTS {
- LOOP_KEYS {
- key->flag &= ~PEK_HIDE;
- }
- }
- }
+ ParticleEditSettings *pset = PE_settings(scene);
+ POINT_P;
+ KEY_K;
+
+ if (pset->flag & PE_FADE_TIME && pset->selectmode == SCE_SELECT_POINT) {
+ LOOP_POINTS
+ {
+ LOOP_KEYS
+ {
+ if (fabsf(cfra - *key->time) < pset->fade_frames)
+ key->flag &= ~PEK_HIDE;
+ else {
+ key->flag |= PEK_HIDE;
+ //key->flag &= ~PEK_SELECT;
+ }
+ }
+ }
+ }
+ else {
+ LOOP_POINTS
+ {
+ LOOP_KEYS
+ {
+ key->flag &= ~PEK_HIDE;
+ }
+ }
+ }
}
static int pe_x_mirror(Object *ob)
{
- if (ob->type == OB_MESH)
- return (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X);
+ if (ob->type == OB_MESH)
+ return (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_X);
- return 0;
+ return 0;
}
/****************** common struct passed to callbacks ******************/
typedef struct PEData {
- ViewContext vc;
-
- const bContext *context;
- Main *bmain;
- Scene *scene;
- ViewLayer *view_layer;
- Object *ob;
- Mesh *mesh;
- PTCacheEdit *edit;
- BVHTreeFromMesh shape_bvh;
- Depsgraph *depsgraph;
-
- RNG *rng;
-
- const int *mval;
- const rcti *rect;
- float rad;
- float dval;
- int select;
- eSelectOp sel_op;
-
- float *dvec;
- float combfac;
- float pufffac;
- float cutfac;
- float smoothfac;
- float weightfac;
- float growfac;
- int totrekey;
-
- int invert;
- int tot;
- float vec[3];
-
- int select_action;
- int select_toggle_action;
- bool is_changed;
+ ViewContext vc;
+
+ const bContext *context;
+ Main *bmain;
+ Scene *scene;
+ ViewLayer *view_layer;
+ Object *ob;
+ Mesh *mesh;
+ PTCacheEdit *edit;
+ BVHTreeFromMesh shape_bvh;
+ Depsgraph *depsgraph;
+
+ RNG *rng;
+
+ const int *mval;
+ const rcti *rect;
+ float rad;
+ float dval;
+ int select;
+ eSelectOp sel_op;
+
+ float *dvec;
+ float combfac;
+ float pufffac;
+ float cutfac;
+ float smoothfac;
+ float weightfac;
+ float growfac;
+ int totrekey;
+
+ int invert;
+ int tot;
+ float vec[3];
+
+ int select_action;
+ int select_toggle_action;
+ bool is_changed;
} PEData;
static void PE_set_data(bContext *C, PEData *data)
{
- memset(data, 0, sizeof(*data));
+ memset(data, 0, sizeof(*data));
- data->context = C;
- data->bmain = CTX_data_main(C);
- data->scene = CTX_data_scene(C);
- data->view_layer = CTX_data_view_layer(C);
- data->ob = CTX_data_active_object(C);
- data->depsgraph = CTX_data_depsgraph(C);
- data->edit = PE_get_current(data->scene, data->ob);
+ data->context = C;
+ data->bmain = CTX_data_main(C);
+ data->scene = CTX_data_scene(C);
+ data->view_layer = CTX_data_view_layer(C);
+ data->ob = CTX_data_active_object(C);
+ data->depsgraph = CTX_data_depsgraph(C);
+ data->edit = PE_get_current(data->scene, data->ob);
}
static void PE_set_view3d_data(bContext *C, PEData *data)
{
- PE_set_data(C, data);
+ PE_set_data(C, data);
- ED_view3d_viewcontext_init(C, &data->vc);
+ ED_view3d_viewcontext_init(C, &data->vc);
- if (!XRAY_ENABLED(data->vc.v3d)) {
- if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
- /* needed or else the draw matrix can be incorrect */
- view3d_operator_needs_opengl(C);
+ if (!XRAY_ENABLED(data->vc.v3d)) {
+ if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) {
+ /* needed or else the draw matrix can be incorrect */
+ view3d_operator_needs_opengl(C);
- ED_view3d_backbuf_depth_validate(&data->vc);
- /* we may need to force an update here by setting the rv3d as dirty
- * for now it seems ok, but take care!:
- * rv3d->depths->dirty = 1; */
- ED_view3d_depth_update(data->vc.ar);
- }
- }
+ ED_view3d_backbuf_depth_validate(&data->vc);
+ /* we may need to force an update here by setting the rv3d as dirty
+ * for now it seems ok, but take care!:
+ * rv3d->depths->dirty = 1; */
+ ED_view3d_depth_update(data->vc.ar);
+ }
+ }
}
static bool PE_create_shape_tree(PEData *data, Object *shapeob)
{
- Mesh *mesh = BKE_object_get_evaluated_mesh(data->depsgraph, shapeob);
+ Mesh *mesh = BKE_object_get_evaluated_mesh(data->depsgraph, shapeob);
- memset(&data->shape_bvh, 0, sizeof(data->shape_bvh));
+ memset(&data->shape_bvh, 0, sizeof(data->shape_bvh));
- if (!mesh) {
- return false;
- }
+ if (!mesh) {
+ return false;
+ }
- return (BKE_bvhtree_from_mesh_get(&data->shape_bvh, mesh, BVHTREE_FROM_LOOPTRI, 4) != NULL);
+ return (BKE_bvhtree_from_mesh_get(&data->shape_bvh, mesh, BVHTREE_FROM_LOOPTRI, 4) != NULL);
}
static void PE_free_shape_tree(PEData *data)
{
- free_bvhtree_from_mesh(&data->shape_bvh);
+ free_bvhtree_from_mesh(&data->shape_bvh);
}
static void PE_create_random_generator(PEData *data)
{
- uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
- rng_seed ^= POINTER_AS_UINT(data->ob);
- rng_seed ^= POINTER_AS_UINT(data->edit);
- data->rng = BLI_rng_new(rng_seed);
+ uint rng_seed = (uint)(PIL_check_seconds_timer_i() & UINT_MAX);
+ rng_seed ^= POINTER_AS_UINT(data->ob);
+ rng_seed ^= POINTER_AS_UINT(data->edit);
+ data->rng = BLI_rng_new(rng_seed);
}
static void PE_free_random_generator(PEData *data)
{
- if (data->rng != NULL) {
- BLI_rng_free(data->rng);
- data->rng = NULL;
- }
+ if (data->rng != NULL) {
+ BLI_rng_free(data->rng);
+ data->rng = NULL;
+ }
}
/*************************** selection utilities *******************************/
static bool key_test_depth(const PEData *data, const float co[3], const int screen_co[2])
{
- View3D *v3d = data->vc.v3d;
- ViewDepths *vd = data->vc.rv3d->depths;
- float depth;
+ View3D *v3d = data->vc.v3d;
+ ViewDepths *vd = data->vc.rv3d->depths;
+ float depth;
- /* nothing to do */
- if (XRAY_ENABLED(v3d))
- return true;
+ /* nothing to do */
+ if (XRAY_ENABLED(v3d))
+ return true;
- /* used to calculate here but all callers have the screen_co already, so pass as arg */
+ /* used to calculate here but all callers have the screen_co already, so pass as arg */
#if 0
- if (ED_view3d_project_int_global(data->vc.ar, co, screen_co,
- V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK)
- {
- return 0;
- }
+ if (ED_view3d_project_int_global(data->vc.ar, co, screen_co,
+ V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_WIN | V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK)
+ {
+ return 0;
+ }
#endif
- /* check if screen_co is within bounds because brush_cut uses out of screen coords */
- if (screen_co[0] >= 0 && screen_co[0] < vd->w && screen_co[1] >= 0 && screen_co[1] < vd->h) {
- BLI_assert(vd && vd->depths);
- /* we know its not clipped */
- depth = vd->depths[screen_co[1] * vd->w + screen_co[0]];
- }
- else
- return 0;
+ /* check if screen_co is within bounds because brush_cut uses out of screen coords */
+ if (screen_co[0] >= 0 && screen_co[0] < vd->w && screen_co[1] >= 0 && screen_co[1] < vd->h) {
+ BLI_assert(vd && vd->depths);
+ /* we know its not clipped */
+ depth = vd->depths[screen_co[1] * vd->w + screen_co[0]];
+ }
+ else
+ return 0;
- float win[3];
- ED_view3d_project(data->vc.ar, co, win);
+ float win[3];
+ ED_view3d_project(data->vc.ar, co, win);
- if (win[2] - 0.00001f > depth)
- return 0;
- else
- return 1;
+ if (win[2] - 0.00001f > depth)
+ return 0;
+ else
+ return 1;
}
static bool key_inside_circle(const PEData *data, float rad, const float co[3], float *distance)
{
- float dx, dy, dist;
- int screen_co[2];
+ float dx, dy, dist;
+ int screen_co[2];
- /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
- if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK) {
- return 0;
- }
+ /* TODO, should this check V3D_PROJ_TEST_CLIP_BB too? */
+ if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) !=
+ V3D_PROJ_RET_OK) {
+ return 0;
+ }
- dx = data->mval[0] - screen_co[0];
- dy = data->mval[1] - screen_co[1];
- dist = sqrtf(dx * dx + dy * dy);
+ dx = data->mval[0] - screen_co[0];
+ dy = data->mval[1] - screen_co[1];
+ dist = sqrtf(dx * dx + dy * dy);
- if (dist > rad)
- return 0;
+ if (dist > rad)
+ return 0;
- if (key_test_depth(data, co, screen_co)) {
- if (distance)
- *distance = dist;
+ if (key_test_depth(data, co, screen_co)) {
+ if (distance)
+ *distance = dist;
- return 1;
- }
+ return 1;
+ }
- return 0;
+ return 0;
}
static bool key_inside_rect(PEData *data, const float co[3])
{
- int screen_co[2];
+ int screen_co[2];
- if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) != V3D_PROJ_RET_OK) {
- return 0;
- }
+ if (ED_view3d_project_int_global(data->vc.ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) !=
+ V3D_PROJ_RET_OK) {
+ return 0;
+ }
- if (screen_co[0] > data->rect->xmin && screen_co[0] < data->rect->xmax &&
- screen_co[1] > data->rect->ymin && screen_co[1] < data->rect->ymax)
- {
- return key_test_depth(data, co, screen_co);
- }
+ if (screen_co[0] > data->rect->xmin && screen_co[0] < data->rect->xmax &&
+ screen_co[1] > data->rect->ymin && screen_co[1] < data->rect->ymax) {
+ return key_test_depth(data, co, screen_co);
+ }
- return 0;
+ return 0;
}
static bool key_inside_test(PEData *data, const float co[3])
{
- if (data->mval)
- return key_inside_circle(data, data->rad, co, NULL);
- else
- return key_inside_rect(data, co);
+ if (data->mval)
+ return key_inside_circle(data, data->rad, co, NULL);
+ else
+ return key_inside_rect(data, co);
}
static bool point_is_selected(PTCacheEditPoint *point)
{
- KEY_K;
+ KEY_K;
- if (point->flag & PEP_HIDE)
- return 0;
+ if (point->flag & PEP_HIDE)
+ return 0;
- LOOP_SELECTED_KEYS {
- return 1;
- }
+ LOOP_SELECTED_KEYS
+ {
+ return 1;
+ }
- return 0;
+ return 0;
}
/*************************** iterators *******************************/
-typedef void (*ForPointFunc)(
- PEData *data,
- int point_index);
-typedef void (*ForHitPointFunc)(
- PEData *data,
- int point_index,
- float mouse_distance);
-
-typedef void (*ForKeyFunc)(
- PEData *data,
- int point_index,
- int key_index,
- bool is_inside);
-
-typedef void (*ForKeyMatFunc)(
- PEData *data,
- float mat[4][4],
- float imat[4][4],
- int point_index,
- int key_index,
- PTCacheEditKey *key);
-typedef void (*ForHitKeyMatFunc)(
- PEData *data,
- float mat[4][4],
- float imat[4][4],
- int point_index,
- int key_index,
- PTCacheEditKey *key,
- float mouse_distance);
+typedef void (*ForPointFunc)(PEData *data, int point_index);
+typedef void (*ForHitPointFunc)(PEData *data, int point_index, float mouse_distance);
+
+typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index, bool is_inside);
+
+typedef void (*ForKeyMatFunc)(PEData *data,
+ float mat[4][4],
+ float imat[4][4],
+ int point_index,
+ int key_index,
+ PTCacheEditKey *key);
+typedef void (*ForHitKeyMatFunc)(PEData *data,
+ float mat[4][4],
+ float imat[4][4],
+ int point_index,
+ int key_index,
+ PTCacheEditKey *key,
+ float mouse_distance);
enum eParticleSelectFlag {
- PSEL_NEAREST = (1 << 0),
- PSEL_ALL_KEYS = (1 << 1),
+ PSEL_NEAREST = (1 << 0),
+ PSEL_ALL_KEYS = (1 << 1),
};
static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum eParticleSelectFlag flag)
{
- ParticleEditSettings *pset = PE_settings(data->scene);
- PTCacheEdit *edit = data->edit;
- POINT_P; KEY_K;
- int nearest_point, nearest_key;
- float dist = data->rad;
-
- /* in path select mode we have no keys */
- if (pset->selectmode == SCE_SELECT_PATH)
- return;
-
- nearest_point = -1;
- nearest_key = -1;
-
- LOOP_VISIBLE_POINTS {
- if (pset->selectmode == SCE_SELECT_END) {
- if (point->totkey) {
- /* only do end keys */
- key = point->keys + point->totkey - 1;
-
- if (flag & PSEL_NEAREST) {
- if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
- nearest_point = p;
- nearest_key = point->totkey - 1;
- }
- }
- else {
- const bool is_inside = key_inside_test(data, KEY_WCO);
- if (is_inside || (flag & PSEL_ALL_KEYS)) {
- func(data, p, point->totkey - 1, is_inside);
- }
- }
- }
- }
- else {
- /* do all keys */
- LOOP_VISIBLE_KEYS {
- if (flag & PSEL_NEAREST) {
- if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
- nearest_point = p;
- nearest_key = k;
- }
- }
- else {
- const bool is_inside = key_inside_test(data, KEY_WCO);
- if (is_inside || (flag & PSEL_ALL_KEYS)) {
- func(data, p, k, is_inside);
- }
- }
- }
- }
- }
-
- /* do nearest only */
- if (flag & PSEL_NEAREST) {
- if (nearest_point != -1) {
- func(data, nearest_point, nearest_key, true);
- }
- }
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ PTCacheEdit *edit = data->edit;
+ POINT_P;
+ KEY_K;
+ int nearest_point, nearest_key;
+ float dist = data->rad;
+
+ /* in path select mode we have no keys */
+ if (pset->selectmode == SCE_SELECT_PATH)
+ return;
+
+ nearest_point = -1;
+ nearest_key = -1;
+
+ LOOP_VISIBLE_POINTS
+ {
+ if (pset->selectmode == SCE_SELECT_END) {
+ if (point->totkey) {
+ /* only do end keys */
+ key = point->keys + point->totkey - 1;
+
+ if (flag & PSEL_NEAREST) {
+ if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
+ nearest_point = p;
+ nearest_key = point->totkey - 1;
+ }
+ }
+ else {
+ const bool is_inside = key_inside_test(data, KEY_WCO);
+ if (is_inside || (flag & PSEL_ALL_KEYS)) {
+ func(data, p, point->totkey - 1, is_inside);
+ }
+ }
+ }
+ }
+ else {
+ /* do all keys */
+ LOOP_VISIBLE_KEYS
+ {
+ if (flag & PSEL_NEAREST) {
+ if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
+ nearest_point = p;
+ nearest_key = k;
+ }
+ }
+ else {
+ const bool is_inside = key_inside_test(data, KEY_WCO);
+ if (is_inside || (flag & PSEL_ALL_KEYS)) {
+ func(data, p, k, is_inside);
+ }
+ }
+ }
+ }
+ }
+
+ /* do nearest only */
+ if (flag & PSEL_NEAREST) {
+ if (nearest_point != -1) {
+ func(data, nearest_point, nearest_key, true);
+ }
+ }
}
static void foreach_mouse_hit_point(PEData *data, ForHitPointFunc func, int selected)
{
- ParticleEditSettings *pset = PE_settings(data->scene);
- PTCacheEdit *edit = data->edit;
- POINT_P; KEY_K;
-
- /* all is selected in path mode */
- if (pset->selectmode == SCE_SELECT_PATH)
- selected = 0;
-
- LOOP_VISIBLE_POINTS {
- if (pset->selectmode == SCE_SELECT_END) {
- if (point->totkey) {
- /* only do end keys */
- key = point->keys + point->totkey - 1;
-
- if (selected == 0 || key->flag & PEK_SELECT) {
- float mouse_distance;
- if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
- func(data, p, mouse_distance);
- }
- }
- }
- }
- else {
- /* do all keys */
- LOOP_VISIBLE_KEYS {
- if (selected == 0 || key->flag & PEK_SELECT) {
- float mouse_distance;
- if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
- func(data, p, mouse_distance);
- break;
- }
- }
- }
- }
- }
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ PTCacheEdit *edit = data->edit;
+ POINT_P;
+ KEY_K;
+
+ /* all is selected in path mode */
+ if (pset->selectmode == SCE_SELECT_PATH)
+ selected = 0;
+
+ LOOP_VISIBLE_POINTS
+ {
+ if (pset->selectmode == SCE_SELECT_END) {
+ if (point->totkey) {
+ /* only do end keys */
+ key = point->keys + point->totkey - 1;
+
+ if (selected == 0 || key->flag & PEK_SELECT) {
+ float mouse_distance;
+ if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
+ func(data, p, mouse_distance);
+ }
+ }
+ }
+ }
+ else {
+ /* do all keys */
+ LOOP_VISIBLE_KEYS
+ {
+ if (selected == 0 || key->flag & PEK_SELECT) {
+ float mouse_distance;
+ if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
+ func(data, p, mouse_distance);
+ break;
+ }
+ }
+ }
+ }
+ }
}
typedef struct KeyIterData {
- PEData *data;
- PTCacheEdit *edit;
- int selected;
- ForHitKeyMatFunc func;
+ PEData *data;
+ PTCacheEdit *edit;
+ int selected;
+ ForHitKeyMatFunc func;
} KeyIterData;
-static void foreach_mouse_hit_key_iter(
- void *__restrict iter_data_v,
- const int iter,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- KeyIterData *iter_data = (KeyIterData *)iter_data_v;
- PEData *data = iter_data->data;
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = &edit->points[iter];
- if (point->flag & PEP_HIDE) {
- return;
- }
- ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd_eval = iter_data->edit->psmd_eval;
- ParticleEditSettings *pset = PE_settings(data->scene);
- const int selected = iter_data->selected;
- float mat[4][4], imat[4][4];
- unit_m4(mat);
- unit_m4(imat);
- if (pset->selectmode == SCE_SELECT_END) {
- if (point->totkey) {
- /* only do end keys */
- PTCacheEditKey *key = point->keys + point->totkey - 1;
-
- if (selected == 0 || key->flag & PEK_SELECT) {
- float mouse_distance;
- if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
- if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, mat);
- invert_m4_m4(imat, mat);
- }
- iter_data->func(data, mat, imat, iter, point->totkey - 1, key, mouse_distance);
- }
- }
- }
- }
- else {
- /* do all keys */
- PTCacheEditKey *key;
- int k;
- LOOP_VISIBLE_KEYS {
- if (selected == 0 || key->flag & PEK_SELECT) {
- float mouse_distance;
- if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
- if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, mat);
- invert_m4_m4(imat, mat);
- }
- iter_data->func(data, mat, imat, iter, k, key, mouse_distance);
- }
- }
- }
- }
+static void foreach_mouse_hit_key_iter(void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ KeyIterData *iter_data = (KeyIterData *)iter_data_v;
+ PEData *data = iter_data->data;
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if (point->flag & PEP_HIDE) {
+ return;
+ }
+ ParticleSystem *psys = edit->psys;
+ ParticleSystemModifierData *psmd_eval = iter_data->edit->psmd_eval;
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ const int selected = iter_data->selected;
+ float mat[4][4], imat[4][4];
+ unit_m4(mat);
+ unit_m4(imat);
+ if (pset->selectmode == SCE_SELECT_END) {
+ if (point->totkey) {
+ /* only do end keys */
+ PTCacheEditKey *key = point->keys + point->totkey - 1;
+
+ if (selected == 0 || key->flag & PEK_SELECT) {
+ float mouse_distance;
+ if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
+ if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
+ psys_mat_hair_to_global(
+ data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, mat);
+ invert_m4_m4(imat, mat);
+ }
+ iter_data->func(data, mat, imat, iter, point->totkey - 1, key, mouse_distance);
+ }
+ }
+ }
+ }
+ else {
+ /* do all keys */
+ PTCacheEditKey *key;
+ int k;
+ LOOP_VISIBLE_KEYS
+ {
+ if (selected == 0 || key->flag & PEK_SELECT) {
+ float mouse_distance;
+ if (key_inside_circle(data, data->rad, KEY_WCO, &mouse_distance)) {
+ if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) {
+ psys_mat_hair_to_global(
+ data->ob, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, mat);
+ invert_m4_m4(imat, mat);
+ }
+ iter_data->func(data, mat, imat, iter, k, key, mouse_distance);
+ }
+ }
+ }
+ }
}
static void foreach_mouse_hit_key(PEData *data, ForHitKeyMatFunc func, int selected)
{
- PTCacheEdit *edit = data->edit;
- ParticleEditSettings *pset = PE_settings(data->scene);
- /* all is selected in path mode */
- if (pset->selectmode == SCE_SELECT_PATH) {
- selected = 0;
- }
+ PTCacheEdit *edit = data->edit;
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ /* all is selected in path mode */
+ if (pset->selectmode == SCE_SELECT_PATH) {
+ selected = 0;
+ }
- KeyIterData iter_data;
- iter_data.data = data;
- iter_data.edit = edit;
- iter_data.selected = selected;
- iter_data.func = func;
+ KeyIterData iter_data;
+ iter_data.data = data;
+ iter_data.edit = edit;
+ iter_data.selected = selected;
+ iter_data.func = func;
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(0, edit->totpoint, &iter_data, foreach_mouse_hit_key_iter, &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, foreach_mouse_hit_key_iter, &settings);
}
static void foreach_selected_point(PEData *data, ForPointFunc func)
{
- PTCacheEdit *edit = data->edit;
- POINT_P;
+ PTCacheEdit *edit = data->edit;
+ POINT_P;
- LOOP_SELECTED_POINTS {
- func(data, p);
- }
+ LOOP_SELECTED_POINTS
+ {
+ func(data, p);
+ }
}
static void foreach_selected_key(PEData *data, ForKeyFunc func)
{
- PTCacheEdit *edit = data->edit;
- POINT_P; KEY_K;
+ PTCacheEdit *edit = data->edit;
+ POINT_P;
+ KEY_K;
- LOOP_VISIBLE_POINTS {
- LOOP_SELECTED_KEYS {
- func(data, p, k, true);
- }
- }
+ LOOP_VISIBLE_POINTS
+ {
+ LOOP_SELECTED_KEYS
+ {
+ func(data, p, k, true);
+ }
+ }
}
static void foreach_point(PEData *data, ForPointFunc func)
{
- PTCacheEdit *edit = data->edit;
- POINT_P;
+ PTCacheEdit *edit = data->edit;
+ POINT_P;
- LOOP_POINTS {
- func(data, p);
- }
+ LOOP_POINTS
+ {
+ func(data, p);
+ }
}
static int count_selected_keys(Scene *scene, PTCacheEdit *edit)
{
- ParticleEditSettings *pset = PE_settings(scene);
- POINT_P; KEY_K;
- int sel = 0;
-
- LOOP_VISIBLE_POINTS {
- if (pset->selectmode == SCE_SELECT_POINT) {
- LOOP_SELECTED_KEYS {
- sel++;
- }
- }
- else if (pset->selectmode == SCE_SELECT_END) {
- if (point->totkey) {
- key = point->keys + point->totkey - 1;
- if (key->flag & PEK_SELECT)
- sel++;
- }
- }
- }
-
- return sel;
+ ParticleEditSettings *pset = PE_settings(scene);
+ POINT_P;
+ KEY_K;
+ int sel = 0;
+
+ LOOP_VISIBLE_POINTS
+ {
+ if (pset->selectmode == SCE_SELECT_POINT) {
+ LOOP_SELECTED_KEYS
+ {
+ sel++;
+ }
+ }
+ else if (pset->selectmode == SCE_SELECT_END) {
+ if (point->totkey) {
+ key = point->keys + point->totkey - 1;
+ if (key->flag & PEK_SELECT)
+ sel++;
+ }
+ }
+ }
+
+ return sel;
}
/************************************************/
-/* Particle Edit Mirroring */
+/* Particle Edit Mirroring */
/************************************************/
static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys)
{
- PTCacheEdit *edit;
- ParticleSystemModifierData *psmd_eval;
- KDTree_3d *tree;
- KDTreeNearest_3d nearest;
- HairKey *key;
- PARTICLE_P;
- float mat[4][4], co[3];
- int index, totpart;
-
- edit = psys->edit;
- psmd_eval = edit->psmd_eval;
- totpart = psys->totpart;
-
- if (!psmd_eval->mesh_final)
- return;
-
- tree = BLI_kdtree_3d_new(totpart);
-
- /* insert particles into kd tree */
- LOOP_PARTICLES {
- key = pa->hair;
- psys_mat_hair_to_orco(ob, psmd_eval->mesh_final, psys->part->from, pa, mat);
- copy_v3_v3(co, key->co);
- mul_m4_v3(mat, co);
- BLI_kdtree_3d_insert(tree, p, co);
- }
-
- BLI_kdtree_3d_balance(tree);
-
- /* lookup particles and set in mirror cache */
- if (!edit->mirror_cache)
- edit->mirror_cache = MEM_callocN(sizeof(int) * totpart, "PE mirror cache");
-
- LOOP_PARTICLES {
- key = pa->hair;
- psys_mat_hair_to_orco(ob, psmd_eval->mesh_final, psys->part->from, pa, mat);
- copy_v3_v3(co, key->co);
- mul_m4_v3(mat, co);
- co[0] = -co[0];
-
- index = BLI_kdtree_3d_find_nearest(tree, co, &nearest);
-
- /* this needs a custom threshold still, duplicated for editmode mirror */
- if (index != -1 && index != p && (nearest.dist <= 0.0002f))
- edit->mirror_cache[p] = index;
- else
- edit->mirror_cache[p] = -1;
- }
-
- /* make sure mirrors are in two directions */
- LOOP_PARTICLES {
- if (edit->mirror_cache[p]) {
- index = edit->mirror_cache[p];
- if (edit->mirror_cache[index] != p)
- edit->mirror_cache[p] = -1;
- }
- }
-
- BLI_kdtree_3d_free(tree);
-}
-
-static void PE_mirror_particle(Object *ob, Mesh *mesh, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
-{
- HairKey *hkey, *mhkey;
- PTCacheEditPoint *point, *mpoint;
- PTCacheEditKey *key, *mkey;
- PTCacheEdit *edit;
- float mat[4][4], mmat[4][4], immat[4][4];
- int i, mi, k;
-
- edit = psys->edit;
- i = pa - psys->particles;
-
- /* find mirrored particle if needed */
- if (!mpa) {
- if (!edit->mirror_cache)
- PE_update_mirror_cache(ob, psys);
-
- if (!edit->mirror_cache)
- return; /* something went wrong! */
-
- mi = edit->mirror_cache[i];
- if (mi == -1)
- return;
- mpa = psys->particles + mi;
- }
- else
- mi = mpa - psys->particles;
-
- point = edit->points + i;
- mpoint = edit->points + mi;
-
- /* make sure they have the same amount of keys */
- if (pa->totkey != mpa->totkey) {
- if (mpa->hair) MEM_freeN(mpa->hair);
- if (mpoint->keys) MEM_freeN(mpoint->keys);
-
- mpa->hair = MEM_dupallocN(pa->hair);
- mpa->totkey = pa->totkey;
- mpoint->keys = MEM_dupallocN(point->keys);
- mpoint->totkey = point->totkey;
-
- mhkey = mpa->hair;
- mkey = mpoint->keys;
- for (k = 0; k < mpa->totkey; k++, mkey++, mhkey++) {
- mkey->co = mhkey->co;
- mkey->time = &mhkey->time;
- mkey->flag &= ~PEK_SELECT;
- }
- }
-
- /* mirror positions and tags */
- psys_mat_hair_to_orco(ob, mesh, psys->part->from, pa, mat);
- psys_mat_hair_to_orco(ob, mesh, psys->part->from, mpa, mmat);
- invert_m4_m4(immat, mmat);
-
- hkey = pa->hair;
- mhkey = mpa->hair;
- key = point->keys;
- mkey = mpoint->keys;
- for (k = 0; k < pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
- copy_v3_v3(mhkey->co, hkey->co);
- mul_m4_v3(mat, mhkey->co);
- mhkey->co[0] = -mhkey->co[0];
- mul_m4_v3(immat, mhkey->co);
-
- if (key->flag & PEK_TAG)
- mkey->flag |= PEK_TAG;
-
- mkey->length = key->length;
- }
-
- if (point->flag & PEP_TAG)
- mpoint->flag |= PEP_TAG;
- if (point->flag & PEP_EDIT_RECALC)
- mpoint->flag |= PEP_EDIT_RECALC;
+ PTCacheEdit *edit;
+ ParticleSystemModifierData *psmd_eval;
+ KDTree_3d *tree;
+ KDTreeNearest_3d nearest;
+ HairKey *key;
+ PARTICLE_P;
+ float mat[4][4], co[3];
+ int index, totpart;
+
+ edit = psys->edit;
+ psmd_eval = edit->psmd_eval;
+ totpart = psys->totpart;
+
+ if (!psmd_eval->mesh_final)
+ return;
+
+ tree = BLI_kdtree_3d_new(totpart);
+
+ /* insert particles into kd tree */
+ LOOP_PARTICLES
+ {
+ key = pa->hair;
+ psys_mat_hair_to_orco(ob, psmd_eval->mesh_final, psys->part->from, pa, mat);
+ copy_v3_v3(co, key->co);
+ mul_m4_v3(mat, co);
+ BLI_kdtree_3d_insert(tree, p, co);
+ }
+
+ BLI_kdtree_3d_balance(tree);
+
+ /* lookup particles and set in mirror cache */
+ if (!edit->mirror_cache)
+ edit->mirror_cache = MEM_callocN(sizeof(int) * totpart, "PE mirror cache");
+
+ LOOP_PARTICLES
+ {
+ key = pa->hair;
+ psys_mat_hair_to_orco(ob, psmd_eval->mesh_final, psys->part->from, pa, mat);
+ copy_v3_v3(co, key->co);
+ mul_m4_v3(mat, co);
+ co[0] = -co[0];
+
+ index = BLI_kdtree_3d_find_nearest(tree, co, &nearest);
+
+ /* this needs a custom threshold still, duplicated for editmode mirror */
+ if (index != -1 && index != p && (nearest.dist <= 0.0002f))
+ edit->mirror_cache[p] = index;
+ else
+ edit->mirror_cache[p] = -1;
+ }
+
+ /* make sure mirrors are in two directions */
+ LOOP_PARTICLES
+ {
+ if (edit->mirror_cache[p]) {
+ index = edit->mirror_cache[p];
+ if (edit->mirror_cache[index] != p)
+ edit->mirror_cache[p] = -1;
+ }
+ }
+
+ BLI_kdtree_3d_free(tree);
+}
+
+static void PE_mirror_particle(
+ Object *ob, Mesh *mesh, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa)
+{
+ HairKey *hkey, *mhkey;
+ PTCacheEditPoint *point, *mpoint;
+ PTCacheEditKey *key, *mkey;
+ PTCacheEdit *edit;
+ float mat[4][4], mmat[4][4], immat[4][4];
+ int i, mi, k;
+
+ edit = psys->edit;
+ i = pa - psys->particles;
+
+ /* find mirrored particle if needed */
+ if (!mpa) {
+ if (!edit->mirror_cache)
+ PE_update_mirror_cache(ob, psys);
+
+ if (!edit->mirror_cache)
+ return; /* something went wrong! */
+
+ mi = edit->mirror_cache[i];
+ if (mi == -1)
+ return;
+ mpa = psys->particles + mi;
+ }
+ else
+ mi = mpa - psys->particles;
+
+ point = edit->points + i;
+ mpoint = edit->points + mi;
+
+ /* make sure they have the same amount of keys */
+ if (pa->totkey != mpa->totkey) {
+ if (mpa->hair)
+ MEM_freeN(mpa->hair);
+ if (mpoint->keys)
+ MEM_freeN(mpoint->keys);
+
+ mpa->hair = MEM_dupallocN(pa->hair);
+ mpa->totkey = pa->totkey;
+ mpoint->keys = MEM_dupallocN(point->keys);
+ mpoint->totkey = point->totkey;
+
+ mhkey = mpa->hair;
+ mkey = mpoint->keys;
+ for (k = 0; k < mpa->totkey; k++, mkey++, mhkey++) {
+ mkey->co = mhkey->co;
+ mkey->time = &mhkey->time;
+ mkey->flag &= ~PEK_SELECT;
+ }
+ }
+
+ /* mirror positions and tags */
+ psys_mat_hair_to_orco(ob, mesh, psys->part->from, pa, mat);
+ psys_mat_hair_to_orco(ob, mesh, psys->part->from, mpa, mmat);
+ invert_m4_m4(immat, mmat);
+
+ hkey = pa->hair;
+ mhkey = mpa->hair;
+ key = point->keys;
+ mkey = mpoint->keys;
+ for (k = 0; k < pa->totkey; k++, hkey++, mhkey++, key++, mkey++) {
+ copy_v3_v3(mhkey->co, hkey->co);
+ mul_m4_v3(mat, mhkey->co);
+ mhkey->co[0] = -mhkey->co[0];
+ mul_m4_v3(immat, mhkey->co);
+
+ if (key->flag & PEK_TAG)
+ mkey->flag |= PEK_TAG;
+
+ mkey->length = key->length;
+ }
+
+ if (point->flag & PEP_TAG)
+ mpoint->flag |= PEP_TAG;
+ if (point->flag & PEP_EDIT_RECALC)
+ mpoint->flag |= PEP_EDIT_RECALC;
}
static void PE_apply_mirror(Object *ob, ParticleSystem *psys)
{
- PTCacheEdit *edit;
- ParticleSystemModifierData *psmd_eval;
- POINT_P;
+ PTCacheEdit *edit;
+ ParticleSystemModifierData *psmd_eval;
+ POINT_P;
- if (!psys)
- return;
+ if (!psys)
+ return;
- edit = psys->edit;
- psmd_eval = edit->psmd_eval;
+ edit = psys->edit;
+ psmd_eval = edit->psmd_eval;
- if (!psmd_eval->mesh_final)
- return;
+ if (!psmd_eval->mesh_final)
+ return;
- if (!edit->mirror_cache)
- PE_update_mirror_cache(ob, psys);
+ if (!edit->mirror_cache)
+ PE_update_mirror_cache(ob, psys);
- if (!edit->mirror_cache)
- return; /* something went wrong */
+ if (!edit->mirror_cache)
+ return; /* something went wrong */
- /* we delay settings the PARS_EDIT_RECALC for mirrored particles
- * to avoid doing mirror twice */
- LOOP_POINTS {
- if (point->flag & PEP_EDIT_RECALC) {
- PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
+ /* we delay settings the PARS_EDIT_RECALC for mirrored particles
+ * to avoid doing mirror twice */
+ LOOP_POINTS
+ {
+ if (point->flag & PEP_EDIT_RECALC) {
+ PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
- if (edit->mirror_cache[p] != -1)
- edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
- }
- }
+ if (edit->mirror_cache[p] != -1)
+ edit->points[edit->mirror_cache[p]].flag &= ~PEP_EDIT_RECALC;
+ }
+ }
- LOOP_POINTS {
- if (point->flag & PEP_EDIT_RECALC)
- if (edit->mirror_cache[p] != -1)
- edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
- }
+ LOOP_POINTS
+ {
+ if (point->flag & PEP_EDIT_RECALC)
+ if (edit->mirror_cache[p] != -1)
+ edit->points[edit->mirror_cache[p]].flag |= PEP_EDIT_RECALC;
+ }
}
/************************************************/
-/* Edit Calculation */
+/* Edit Calculation */
/************************************************/
typedef struct DeflectEmitterIter {
- Object *object;
- ParticleSystem *psys;
- PTCacheEdit *edit;
- float dist;
- float emitterdist;
+ Object *object;
+ ParticleSystem *psys;
+ PTCacheEdit *edit;
+ float dist;
+ float emitterdist;
} DeflectEmitterIter;
-static void deflect_emitter_iter(
- void *__restrict iter_data_v,
- const int iter,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- DeflectEmitterIter *iter_data = (DeflectEmitterIter *)iter_data_v;
- PTCacheEdit *edit = iter_data->edit;
- PTCacheEditPoint *point = &edit->points[iter];
- if ((point->flag & PEP_EDIT_RECALC) == 0) {
- return;
- }
- Object *object = iter_data->object;
- ParticleSystem *psys = iter_data->psys;
- ParticleSystemModifierData *psmd_eval = iter_data->edit->psmd_eval;
- PTCacheEditKey *key;
- int k;
- float hairimat[4][4], hairmat[4][4];
- int index;
- float *vec, *nor, dvec[3], dot, dist_1st = 0.0f;
- const float dist = iter_data->dist;
- const float emitterdist = iter_data->emitterdist;
- psys_mat_hair_to_object(object,
- psmd_eval->mesh_final,
- psys->part->from,
- psys->particles + iter,
- hairmat);
-
- LOOP_KEYS {
- mul_m4_v3(hairmat, key->co);
- }
-
- LOOP_KEYS {
- if (k == 0) {
- dist_1st = len_v3v3((key + 1)->co, key->co);
- dist_1st *= dist * emitterdist;
- }
- else {
- index = BLI_kdtree_3d_find_nearest(edit->emitter_field, key->co, NULL);
-
- vec = edit->emitter_cosnos + index * 6;
- nor = vec + 3;
-
- sub_v3_v3v3(dvec, key->co, vec);
-
- dot = dot_v3v3(dvec, nor);
- copy_v3_v3(dvec, nor);
-
- if (dot > 0.0f) {
- if (dot < dist_1st) {
- normalize_v3(dvec);
- mul_v3_fl(dvec, dist_1st - dot);
- add_v3_v3(key->co, dvec);
- }
- }
- else {
- normalize_v3(dvec);
- mul_v3_fl(dvec, dist_1st - dot);
- add_v3_v3(key->co, dvec);
- }
- if (k == 1) {
- dist_1st *= 1.3333f;
- }
- }
- }
-
- invert_m4_m4(hairimat, hairmat);
-
- LOOP_KEYS {
- mul_m4_v3(hairimat, key->co);
- }
+static void deflect_emitter_iter(void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ DeflectEmitterIter *iter_data = (DeflectEmitterIter *)iter_data_v;
+ PTCacheEdit *edit = iter_data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if ((point->flag & PEP_EDIT_RECALC) == 0) {
+ return;
+ }
+ Object *object = iter_data->object;
+ ParticleSystem *psys = iter_data->psys;
+ ParticleSystemModifierData *psmd_eval = iter_data->edit->psmd_eval;
+ PTCacheEditKey *key;
+ int k;
+ float hairimat[4][4], hairmat[4][4];
+ int index;
+ float *vec, *nor, dvec[3], dot, dist_1st = 0.0f;
+ const float dist = iter_data->dist;
+ const float emitterdist = iter_data->emitterdist;
+ psys_mat_hair_to_object(
+ object, psmd_eval->mesh_final, psys->part->from, psys->particles + iter, hairmat);
+
+ LOOP_KEYS
+ {
+ mul_m4_v3(hairmat, key->co);
+ }
+
+ LOOP_KEYS
+ {
+ if (k == 0) {
+ dist_1st = len_v3v3((key + 1)->co, key->co);
+ dist_1st *= dist * emitterdist;
+ }
+ else {
+ index = BLI_kdtree_3d_find_nearest(edit->emitter_field, key->co, NULL);
+
+ vec = edit->emitter_cosnos + index * 6;
+ nor = vec + 3;
+
+ sub_v3_v3v3(dvec, key->co, vec);
+
+ dot = dot_v3v3(dvec, nor);
+ copy_v3_v3(dvec, nor);
+
+ if (dot > 0.0f) {
+ if (dot < dist_1st) {
+ normalize_v3(dvec);
+ mul_v3_fl(dvec, dist_1st - dot);
+ add_v3_v3(key->co, dvec);
+ }
+ }
+ else {
+ normalize_v3(dvec);
+ mul_v3_fl(dvec, dist_1st - dot);
+ add_v3_v3(key->co, dvec);
+ }
+ if (k == 1) {
+ dist_1st *= 1.3333f;
+ }
+ }
+ }
+
+ invert_m4_m4(hairimat, hairmat);
+
+ LOOP_KEYS
+ {
+ mul_m4_v3(hairimat, key->co);
+ }
}
/* tries to stop edited particles from going through the emitter's surface */
static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit)
{
- ParticleEditSettings *pset = PE_settings(scene);
- ParticleSystem *psys;
- const float dist = ED_view3d_select_dist_px() * 0.01f;
+ ParticleEditSettings *pset = PE_settings(scene);
+ ParticleSystem *psys;
+ const float dist = ED_view3d_select_dist_px() * 0.01f;
- if (edit == NULL || edit->psys == NULL ||
- (pset->flag & PE_DEFLECT_EMITTER) == 0 ||
- (edit->psys->flag & PSYS_GLOBAL_HAIR))
- {
- return;
- }
+ if (edit == NULL || edit->psys == NULL || (pset->flag & PE_DEFLECT_EMITTER) == 0 ||
+ (edit->psys->flag & PSYS_GLOBAL_HAIR)) {
+ return;
+ }
- psys = edit->psys;
+ psys = edit->psys;
- if (!edit->psmd_eval->mesh_final) {
- return;
- }
+ if (!edit->psmd_eval->mesh_final) {
+ return;
+ }
- DeflectEmitterIter iter_data;
- iter_data.object = ob;
- iter_data.psys = psys;
- iter_data.edit = edit;
- iter_data.dist = dist;
- iter_data.emitterdist = pset->emitterdist;
+ DeflectEmitterIter iter_data;
+ iter_data.object = ob;
+ iter_data.psys = psys;
+ iter_data.edit = edit;
+ iter_data.dist = dist;
+ iter_data.emitterdist = pset->emitterdist;
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(0, edit->totpoint, &iter_data, deflect_emitter_iter, &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, deflect_emitter_iter, &settings);
}
typedef struct ApplyLengthsIterData {
- PTCacheEdit *edit;
+ PTCacheEdit *edit;
} ApplyLengthsIterData;
-static void apply_lengths_iter(
- void *__restrict iter_data_v,
- const int iter,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- ApplyLengthsIterData *iter_data = (ApplyLengthsIterData *)iter_data_v;
- PTCacheEdit *edit = iter_data->edit;
- PTCacheEditPoint *point = &edit->points[iter];
- if ((point->flag & PEP_EDIT_RECALC) == 0) {
- return;
- }
- PTCacheEditKey *key;
- int k;
- LOOP_KEYS {
- if (k) {
- float dv1[3];
- sub_v3_v3v3(dv1, key->co, (key - 1)->co);
- normalize_v3(dv1);
- mul_v3_fl(dv1, (key - 1)->length);
- add_v3_v3v3(key->co, (key - 1)->co, dv1);
- }
- }
+static void apply_lengths_iter(void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ ApplyLengthsIterData *iter_data = (ApplyLengthsIterData *)iter_data_v;
+ PTCacheEdit *edit = iter_data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if ((point->flag & PEP_EDIT_RECALC) == 0) {
+ return;
+ }
+ PTCacheEditKey *key;
+ int k;
+ LOOP_KEYS
+ {
+ if (k) {
+ float dv1[3];
+ sub_v3_v3v3(dv1, key->co, (key - 1)->co);
+ normalize_v3(dv1);
+ mul_v3_fl(dv1, (key - 1)->length);
+ add_v3_v3v3(key->co, (key - 1)->co, dv1);
+ }
+ }
}
/* force set distances between neighboring keys */
static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit)
{
- ParticleEditSettings *pset = PE_settings(scene);
+ ParticleEditSettings *pset = PE_settings(scene);
- if (edit == 0 || (pset->flag & PE_KEEP_LENGTHS) == 0)
- return;
+ if (edit == 0 || (pset->flag & PE_KEEP_LENGTHS) == 0)
+ return;
- if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
- return;
+ if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
+ return;
- ApplyLengthsIterData iter_data;
- iter_data.edit = edit;
+ ApplyLengthsIterData iter_data;
+ iter_data.edit = edit;
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(0, edit->totpoint, &iter_data, apply_lengths_iter, &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, apply_lengths_iter, &settings);
}
typedef struct IterateLengthsIterData {
- PTCacheEdit *edit;
- ParticleEditSettings *pset;
+ PTCacheEdit *edit;
+ ParticleEditSettings *pset;
} IterateLengthsIterData;
-static void iterate_lengths_iter(
- void *__restrict iter_data_v,
- const int iter,
- const ParallelRangeTLS *__restrict UNUSED(tls))
-{
- IterateLengthsIterData *iter_data = (IterateLengthsIterData *)iter_data_v;
- PTCacheEdit *edit = iter_data->edit;
- PTCacheEditPoint *point = &edit->points[iter];
- if ((point->flag & PEP_EDIT_RECALC) == 0) {
- return;
- }
- ParticleEditSettings *pset = iter_data->pset;
- float tlen;
- float dv0[3] = {0.0f, 0.0f, 0.0f};
- float dv1[3] = {0.0f, 0.0f, 0.0f};
- float dv2[3] = {0.0f, 0.0f, 0.0f};
- for (int j = 1; j < point->totkey; j++) {
- PTCacheEditKey *key;
- int k;
- float mul = 1.0f / (float)point->totkey;
- if (pset->flag & PE_LOCK_FIRST) {
- key = point->keys + 1;
- k = 1;
- dv1[0] = dv1[1] = dv1[2] = 0.0;
- }
- else {
- key = point->keys;
- k = 0;
- dv0[0] = dv0[1] = dv0[2] = 0.0;
- }
-
- for (; k < point->totkey; k++, key++) {
- if (k) {
- sub_v3_v3v3(dv0, (key - 1)->co, key->co);
- tlen = normalize_v3(dv0);
- mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
- }
- if (k < point->totkey - 1) {
- sub_v3_v3v3(dv2, (key + 1)->co, key->co);
- tlen = normalize_v3(dv2);
- mul_v3_fl(dv2, mul * (tlen - key->length));
- }
- if (k) {
- add_v3_v3((key - 1)->co, dv1);
- }
- add_v3_v3v3(dv1, dv0, dv2);
- }
- }
+static void iterate_lengths_iter(void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict UNUSED(tls))
+{
+ IterateLengthsIterData *iter_data = (IterateLengthsIterData *)iter_data_v;
+ PTCacheEdit *edit = iter_data->edit;
+ PTCacheEditPoint *point = &edit->points[iter];
+ if ((point->flag & PEP_EDIT_RECALC) == 0) {
+ return;
+ }
+ ParticleEditSettings *pset = iter_data->pset;
+ float tlen;
+ float dv0[3] = {0.0f, 0.0f, 0.0f};
+ float dv1[3] = {0.0f, 0.0f, 0.0f};
+ float dv2[3] = {0.0f, 0.0f, 0.0f};
+ for (int j = 1; j < point->totkey; j++) {
+ PTCacheEditKey *key;
+ int k;
+ float mul = 1.0f / (float)point->totkey;
+ if (pset->flag & PE_LOCK_FIRST) {
+ key = point->keys + 1;
+ k = 1;
+ dv1[0] = dv1[1] = dv1[2] = 0.0;
+ }
+ else {
+ key = point->keys;
+ k = 0;
+ dv0[0] = dv0[1] = dv0[2] = 0.0;
+ }
+
+ for (; k < point->totkey; k++, key++) {
+ if (k) {
+ sub_v3_v3v3(dv0, (key - 1)->co, key->co);
+ tlen = normalize_v3(dv0);
+ mul_v3_fl(dv0, (mul * (tlen - (key - 1)->length)));
+ }
+ if (k < point->totkey - 1) {
+ sub_v3_v3v3(dv2, (key + 1)->co, key->co);
+ tlen = normalize_v3(dv2);
+ mul_v3_fl(dv2, mul * (tlen - key->length));
+ }
+ if (k) {
+ add_v3_v3((key - 1)->co, dv1);
+ }
+ add_v3_v3v3(dv1, dv0, dv2);
+ }
+ }
}
/* try to find a nice solution to keep distances between neighboring keys */
static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
{
- ParticleEditSettings *pset = PE_settings(scene);
- if (edit == 0 || (pset->flag & PE_KEEP_LENGTHS) == 0) {
- return;
- }
- if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) {
- return;
- }
+ ParticleEditSettings *pset = PE_settings(scene);
+ if (edit == 0 || (pset->flag & PE_KEEP_LENGTHS) == 0) {
+ return;
+ }
+ if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) {
+ return;
+ }
- IterateLengthsIterData iter_data;
- iter_data.edit = edit;
- iter_data.pset = pset;
+ IterateLengthsIterData iter_data;
+ iter_data.edit = edit;
+ iter_data.pset = pset;
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings);
}
/* set current distances to be kept between neighbouting keys */
void recalc_lengths(PTCacheEdit *edit)
{
- POINT_P; KEY_K;
+ POINT_P;
+ KEY_K;
- if (edit == 0)
- return;
+ if (edit == 0)
+ return;
- LOOP_EDITED_POINTS {
- key = point->keys;
- for (k = 0; k < point->totkey - 1; k++, key++) {
- key->length = len_v3v3(key->co, (key + 1)->co);
- }
- }
+ LOOP_EDITED_POINTS
+ {
+ key = point->keys;
+ for (k = 0; k < point->totkey - 1; k++, key++) {
+ key->length = len_v3v3(key->co, (key + 1)->co);
+ }
+ }
}
/* calculate a tree for finding nearest emitter's vertice */
void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), ParticleSystem *psys)
{
- PTCacheEdit *edit = psys->edit;
- Mesh *mesh = edit->psmd_eval->mesh_final;
- float *vec, *nor;
- int i, totface /*, totvert*/;
+ PTCacheEdit *edit = psys->edit;
+ Mesh *mesh = edit->psmd_eval->mesh_final;
+ float *vec, *nor;
+ int i, totface /*, totvert*/;
- if (!mesh)
- return;
+ if (!mesh)
+ return;
- if (edit->emitter_cosnos)
- MEM_freeN(edit->emitter_cosnos);
+ if (edit->emitter_cosnos)
+ MEM_freeN(edit->emitter_cosnos);
- BLI_kdtree_3d_free(edit->emitter_field);
+ BLI_kdtree_3d_free(edit->emitter_field);
- totface = mesh->totface;
- /*totvert=dm->getNumVerts(dm);*/ /*UNUSED*/
+ totface = mesh->totface;
+ /*totvert=dm->getNumVerts(dm);*/ /*UNUSED*/
- edit->emitter_cosnos = MEM_callocN(totface * 6 * sizeof(float), "emitter cosnos");
+ edit->emitter_cosnos = MEM_callocN(totface * 6 * sizeof(float), "emitter cosnos");
- edit->emitter_field = BLI_kdtree_3d_new(totface);
+ edit->emitter_field = BLI_kdtree_3d_new(totface);
- vec = edit->emitter_cosnos;
- nor = vec + 3;
+ vec = edit->emitter_cosnos;
+ nor = vec + 3;
- for (i = 0; i < totface; i++, vec += 6, nor += 6) {
- MFace *mface = &mesh->mface[i];
- MVert *mvert;
+ for (i = 0; i < totface; i++, vec += 6, nor += 6) {
+ MFace *mface = &mesh->mface[i];
+ MVert *mvert;
- mvert = &mesh->mvert[mface->v1];
- copy_v3_v3(vec, mvert->co);
- copy_v3fl_v3s(nor, mvert->no);
+ mvert = &mesh->mvert[mface->v1];
+ copy_v3_v3(vec, mvert->co);
+ copy_v3fl_v3s(nor, mvert->no);
- mvert = &mesh->mvert[mface->v2];
- add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ mvert = &mesh->mvert[mface->v2];
+ add_v3_v3v3(vec, vec, mvert->co);
+ add_v3fl_v3fl_v3s(nor, nor, mvert->no);
- mvert = &mesh->mvert[mface->v3];
- add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ mvert = &mesh->mvert[mface->v3];
+ add_v3_v3v3(vec, vec, mvert->co);
+ add_v3fl_v3fl_v3s(nor, nor, mvert->no);
- if (mface->v4) {
- mvert = &mesh->mvert[mface->v4];
- add_v3_v3v3(vec, vec, mvert->co);
- add_v3fl_v3fl_v3s(nor, nor, mvert->no);
+ if (mface->v4) {
+ mvert = &mesh->mvert[mface->v4];
+ add_v3_v3v3(vec, vec, mvert->co);
+ add_v3fl_v3fl_v3s(nor, nor, mvert->no);
- mul_v3_fl(vec, 0.25);
- }
- else {
- mul_v3_fl(vec, 1.0f / 3.0f);
- }
+ mul_v3_fl(vec, 0.25);
+ }
+ else {
+ mul_v3_fl(vec, 1.0f / 3.0f);
+ }
- normalize_v3(nor);
+ normalize_v3(nor);
- BLI_kdtree_3d_insert(edit->emitter_field, i, vec);
- }
+ BLI_kdtree_3d_insert(edit->emitter_field, i, vec);
+ }
- BLI_kdtree_3d_balance(edit->emitter_field);
+ BLI_kdtree_3d_balance(edit->emitter_field);
}
static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
{
- PTCacheEdit *edit = PE_get_current(scene, ob);
- HairKey *hkey;
- POINT_P; KEY_K;
-
- /* flag all particles to be updated if not using flag */
- if (!useflag)
- LOOP_POINTS {
- point->flag |= PEP_EDIT_RECALC;
- }
-
- /* flush edit key flag to hair key flag to preserve selection
- * on save */
- if (edit->psys) {
- LOOP_POINTS {
- hkey = edit->psys->particles[p].hair;
- LOOP_KEYS {
- hkey->editflag = key->flag;
- hkey++;
- }
- }
- }
-
- psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
-
-
- /* disable update flag */
- LOOP_POINTS {
- point->flag &= ~PEP_EDIT_RECALC;
- }
-
- DEG_id_tag_update(&ob->id, ID_RECALC_SELECT);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ HairKey *hkey;
+ POINT_P;
+ KEY_K;
+
+ /* flag all particles to be updated if not using flag */
+ if (!useflag)
+ LOOP_POINTS
+ {
+ point->flag |= PEP_EDIT_RECALC;
+ }
+
+ /* flush edit key flag to hair key flag to preserve selection
+ * on save */
+ if (edit->psys) {
+ LOOP_POINTS
+ {
+ hkey = edit->psys->particles[p].hair;
+ LOOP_KEYS
+ {
+ hkey->editflag = key->flag;
+ hkey++;
+ }
+ }
+ }
+
+ psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
+
+ /* disable update flag */
+ LOOP_POINTS
+ {
+ point->flag &= ~PEP_EDIT_RECALC;
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_SELECT);
}
void update_world_cos(Depsgraph *UNUSED(depsgraph), Object *ob, PTCacheEdit *edit)
{
- ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
- POINT_P; KEY_K;
- float hairmat[4][4];
-
- if (psys == 0 || psys->edit == 0 || psmd_eval->mesh_final == NULL)
- return;
-
- LOOP_POINTS {
- if (!(psys->flag & PSYS_GLOBAL_HAIR))
- psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, hairmat);
-
- LOOP_KEYS {
- copy_v3_v3(key->world_co, key->co);
- if (!(psys->flag & PSYS_GLOBAL_HAIR))
- mul_m4_v3(hairmat, key->world_co);
- }
- }
+ ParticleSystem *psys = edit->psys;
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
+ POINT_P;
+ KEY_K;
+ float hairmat[4][4];
+
+ if (psys == 0 || psys->edit == 0 || psmd_eval->mesh_final == NULL)
+ return;
+
+ LOOP_POINTS
+ {
+ if (!(psys->flag & PSYS_GLOBAL_HAIR))
+ psys_mat_hair_to_global(
+ ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, hairmat);
+
+ LOOP_KEYS
+ {
+ copy_v3_v3(key->world_co, key->co);
+ if (!(psys->flag & PSYS_GLOBAL_HAIR))
+ mul_m4_v3(hairmat, key->world_co);
+ }
+ }
}
static void update_velocities(PTCacheEdit *edit)
{
- /*TODO: get frs_sec properly */
- float vec1[3], vec2[3], frs_sec, dfra;
- POINT_P; KEY_K;
+ /*TODO: get frs_sec properly */
+ float vec1[3], vec2[3], frs_sec, dfra;
+ POINT_P;
+ KEY_K;
- /* hair doesn't use velocities */
- if (edit->psys || !edit->points || !edit->points->keys->vel)
- return;
+ /* hair doesn't use velocities */
+ if (edit->psys || !edit->points || !edit->points->keys->vel)
+ return;
- frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
+ frs_sec = edit->pid.flag & PTCACHE_VEL_PER_SEC ? 25.0f : 1.0f;
- LOOP_EDITED_POINTS {
- LOOP_KEYS {
- if (k == 0) {
- dfra = *(key + 1)->time - *key->time;
+ LOOP_EDITED_POINTS
+ {
+ LOOP_KEYS
+ {
+ if (k == 0) {
+ dfra = *(key + 1)->time - *key->time;
- if (dfra <= 0.0f)
- continue;
+ if (dfra <= 0.0f)
+ continue;
- sub_v3_v3v3(key->vel, (key + 1)->co, key->co);
+ sub_v3_v3v3(key->vel, (key + 1)->co, key->co);
- if (point->totkey > 2) {
- sub_v3_v3v3(vec1, (key + 1)->co, (key + 2)->co);
- project_v3_v3v3(vec2, vec1, key->vel);
- sub_v3_v3v3(vec2, vec1, vec2);
- madd_v3_v3fl(key->vel, vec2, 0.5f);
- }
- }
- else if (k == point->totkey - 1) {
- dfra = *key->time - *(key - 1)->time;
+ if (point->totkey > 2) {
+ sub_v3_v3v3(vec1, (key + 1)->co, (key + 2)->co);
+ project_v3_v3v3(vec2, vec1, key->vel);
+ sub_v3_v3v3(vec2, vec1, vec2);
+ madd_v3_v3fl(key->vel, vec2, 0.5f);
+ }
+ }
+ else if (k == point->totkey - 1) {
+ dfra = *key->time - *(key - 1)->time;
- if (dfra <= 0.0f)
- continue;
+ if (dfra <= 0.0f)
+ continue;
- sub_v3_v3v3(key->vel, key->co, (key - 1)->co);
+ sub_v3_v3v3(key->vel, key->co, (key - 1)->co);
- if (point->totkey > 2) {
- sub_v3_v3v3(vec1, (key - 2)->co, (key - 1)->co);
- project_v3_v3v3(vec2, vec1, key->vel);
- sub_v3_v3v3(vec2, vec1, vec2);
- madd_v3_v3fl(key->vel, vec2, 0.5f);
- }
- }
- else {
- dfra = *(key + 1)->time - *(key - 1)->time;
+ if (point->totkey > 2) {
+ sub_v3_v3v3(vec1, (key - 2)->co, (key - 1)->co);
+ project_v3_v3v3(vec2, vec1, key->vel);
+ sub_v3_v3v3(vec2, vec1, vec2);
+ madd_v3_v3fl(key->vel, vec2, 0.5f);
+ }
+ }
+ else {
+ dfra = *(key + 1)->time - *(key - 1)->time;
- if (dfra <= 0.0f)
- continue;
+ if (dfra <= 0.0f)
+ continue;
- sub_v3_v3v3(key->vel, (key + 1)->co, (key - 1)->co);
- }
- mul_v3_fl(key->vel, frs_sec / dfra);
- }
- }
+ sub_v3_v3v3(key->vel, (key + 1)->co, (key - 1)->co);
+ }
+ mul_v3_fl(key->vel, frs_sec / dfra);
+ }
+ }
}
void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag)
{
- /* use this to do partial particle updates, not usable when adding or
- * removing, then a full redo is necessary and calling this may crash */
- ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- POINT_P;
-
- if (!edit)
- return;
-
- /* flag all particles to be updated if not using flag */
- if (!useflag)
- LOOP_POINTS {
- point->flag |= PEP_EDIT_RECALC;
- }
-
- /* do post process on particle edit keys */
- pe_iterate_lengths(scene, edit);
- pe_deflect_emitter(scene, ob, edit);
- PE_apply_lengths(scene, edit);
- if (pe_x_mirror(ob))
- PE_apply_mirror(ob, edit->psys);
- if (edit->psys)
- update_world_cos(depsgraph, ob, edit);
- if (pset->flag & PE_AUTO_VELOCITY)
- update_velocities(edit);
- PE_hide_keys_time(scene, edit, CFRA);
-
- /* regenerate path caches */
- psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
-
- /* disable update flag */
- LOOP_POINTS {
- point->flag &= ~PEP_EDIT_RECALC;
- }
-
- if (edit->psys)
- edit->psys->flag &= ~PSYS_HAIR_UPDATED;
+ /* use this to do partial particle updates, not usable when adding or
+ * removing, then a full redo is necessary and calling this may crash */
+ ParticleEditSettings *pset = PE_settings(scene);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ POINT_P;
+
+ if (!edit)
+ return;
+
+ /* flag all particles to be updated if not using flag */
+ if (!useflag)
+ LOOP_POINTS
+ {
+ point->flag |= PEP_EDIT_RECALC;
+ }
+
+ /* do post process on particle edit keys */
+ pe_iterate_lengths(scene, edit);
+ pe_deflect_emitter(scene, ob, edit);
+ PE_apply_lengths(scene, edit);
+ if (pe_x_mirror(ob))
+ PE_apply_mirror(ob, edit->psys);
+ if (edit->psys)
+ update_world_cos(depsgraph, ob, edit);
+ if (pset->flag & PE_AUTO_VELOCITY)
+ update_velocities(edit);
+ PE_hide_keys_time(scene, edit, CFRA);
+
+ /* regenerate path caches */
+ psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering);
+
+ /* disable update flag */
+ LOOP_POINTS
+ {
+ point->flag &= ~PEP_EDIT_RECALC;
+ }
+
+ if (edit->psys)
+ edit->psys->flag &= ~PSYS_HAIR_UPDATED;
}
/************************************************/
-/* Edit Selections */
+/* Edit Selections */
/************************************************/
/*-----selection callbacks-----*/
static void select_key(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- PTCacheEditKey *key = point->keys + key_index;
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ PTCacheEditKey *key = point->keys + key_index;
- if (data->select)
- key->flag |= PEK_SELECT;
- else
- key->flag &= ~PEK_SELECT;
+ if (data->select)
+ key->flag |= PEK_SELECT;
+ else
+ key->flag &= ~PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- data->is_changed = true;
+ point->flag |= PEP_EDIT_RECALC;
+ data->is_changed = true;
}
static void select_key_op(PEData *data, int point_index, int key_index, bool is_inside)
{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- PTCacheEditKey *key = point->keys + key_index;
- const bool is_select = key->flag & PEK_SELECT;
- const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
- point->flag |= PEP_EDIT_RECALC;
- data->is_changed = true;
- }
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ PTCacheEditKey *key = point->keys + key_index;
+ const bool is_select = key->flag & PEK_SELECT;
+ const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
+ point->flag |= PEP_EDIT_RECALC;
+ data->is_changed = true;
+ }
}
-static void select_keys(PEData *data, int point_index, int UNUSED(key_index), bool UNUSED(is_inside))
+static void select_keys(PEData *data,
+ int point_index,
+ int UNUSED(key_index),
+ bool UNUSED(is_inside))
{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- KEY_K;
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ KEY_K;
- LOOP_KEYS {
- if (data->select)
- key->flag |= PEK_SELECT;
- else
- key->flag &= ~PEK_SELECT;
- }
+ LOOP_KEYS
+ {
+ if (data->select)
+ key->flag |= PEK_SELECT;
+ else
+ key->flag &= ~PEK_SELECT;
+ }
- point->flag |= PEP_EDIT_RECALC;
+ point->flag |= PEP_EDIT_RECALC;
}
static void extend_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- PTCacheEditKey *key = point->keys + key_index;
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ PTCacheEditKey *key = point->keys + key_index;
- if ((key->flag & PEK_SELECT) == 0) {
- key->flag |= PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- data->is_changed = true;
- }
+ if ((key->flag & PEK_SELECT) == 0) {
+ key->flag |= PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ data->is_changed = true;
+ }
}
-static void deselect_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
+static void deselect_key_select(PEData *data,
+ int point_index,
+ int key_index,
+ bool UNUSED(is_inside))
{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- PTCacheEditKey *key = point->keys + key_index;
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ PTCacheEditKey *key = point->keys + key_index;
- if ((key->flag & PEK_SELECT) != 0) {
- key->flag &= ~PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- data->is_changed = true;
- }
+ if ((key->flag & PEK_SELECT) != 0) {
+ key->flag &= ~PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ data->is_changed = true;
+ }
}
static void toggle_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside))
{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- PTCacheEditKey *key = point->keys + key_index;
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ PTCacheEditKey *key = point->keys + key_index;
- key->flag ^= PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- data->is_changed = true;
+ key->flag ^= PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ data->is_changed = true;
}
/************************ de select all operator ************************/
static bool select_action_apply(PTCacheEditPoint *point, PTCacheEditKey *key, int action)
{
- bool changed = false;
- switch (action) {
- case SEL_SELECT:
- if ((key->flag & PEK_SELECT) == 0) {
- key->flag |= PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- changed = true;
- }
- break;
- case SEL_DESELECT:
- if (key->flag & PEK_SELECT) {
- key->flag &= ~PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- changed = true;
- }
- break;
- case SEL_INVERT:
- if ((key->flag & PEK_SELECT) == 0) {
- key->flag |= PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- changed = true;
- }
- else {
- key->flag &= ~PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- changed = true;
- }
- break;
- }
- return changed;
+ bool changed = false;
+ switch (action) {
+ case SEL_SELECT:
+ if ((key->flag & PEK_SELECT) == 0) {
+ key->flag |= PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ changed = true;
+ }
+ break;
+ case SEL_DESELECT:
+ if (key->flag & PEK_SELECT) {
+ key->flag &= ~PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ changed = true;
+ }
+ break;
+ case SEL_INVERT:
+ if ((key->flag & PEK_SELECT) == 0) {
+ key->flag |= PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ changed = true;
+ }
+ else {
+ key->flag &= ~PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ changed = true;
+ }
+ break;
+ }
+ return changed;
}
static int pe_select_all_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- POINT_P; KEY_K;
- int action = RNA_enum_get(op->ptr, "action");
-
- if (action == SEL_TOGGLE) {
- action = SEL_SELECT;
- LOOP_VISIBLE_POINTS {
- LOOP_SELECTED_KEYS {
- action = SEL_DESELECT;
- break;
- }
-
- if (action == SEL_DESELECT)
- break;
- }
- }
-
- bool changed = false;
- LOOP_VISIBLE_POINTS {
- LOOP_VISIBLE_KEYS {
- changed |= select_action_apply(point, key, action);
- }
- }
-
- if (changed) {
- PE_update_selection(depsgraph, scene, ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
- }
- return OPERATOR_FINISHED;
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ POINT_P;
+ KEY_K;
+ int action = RNA_enum_get(op->ptr, "action");
+
+ if (action == SEL_TOGGLE) {
+ action = SEL_SELECT;
+ LOOP_VISIBLE_POINTS
+ {
+ LOOP_SELECTED_KEYS
+ {
+ action = SEL_DESELECT;
+ break;
+ }
+
+ if (action == SEL_DESELECT)
+ break;
+ }
+ }
+
+ bool changed = false;
+ LOOP_VISIBLE_POINTS
+ {
+ LOOP_VISIBLE_KEYS
+ {
+ changed |= select_action_apply(point, key, action);
+ }
+ }
+
+ if (changed) {
+ PE_update_selection(depsgraph, scene, ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
+ }
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_select_all(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "(De)select All";
- ot->idname = "PARTICLE_OT_select_all";
- ot->description = "(De)select all particles' keys";
+ /* identifiers */
+ ot->name = "(De)select All";
+ ot->idname = "PARTICLE_OT_select_all";
+ ot->description = "(De)select all particles' keys";
- /* api callbacks */
- ot->exec = pe_select_all_exec;
- ot->poll = PE_poll;
+ /* api callbacks */
+ ot->exec = pe_select_all_exec;
+ ot->poll = PE_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- WM_operator_properties_select_all(ot);
+ WM_operator_properties_select_all(ot);
}
/************************ pick select operator ************************/
bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
{
- PEData data;
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- POINT_P; KEY_K;
-
- if (!PE_start_edit(edit)) {
- return false;
- }
-
- if (!extend && !deselect && !toggle) {
- LOOP_VISIBLE_POINTS {
- LOOP_SELECTED_KEYS {
- key->flag &= ~PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- }
- }
- }
-
- PE_set_view3d_data(C, &data);
- data.mval = mval;
- data.rad = ED_view3d_select_dist_px();
-
- /* 1 = nearest only */
- if (extend) {
- for_mouse_hit_keys(&data, extend_key_select, PSEL_NEAREST);
- }
- else if (deselect) {
- for_mouse_hit_keys(&data, deselect_key_select, PSEL_NEAREST);
- }
- else {
- for_mouse_hit_keys(&data, toggle_key_select, PSEL_NEAREST);
- }
-
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, scene, ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
- }
-
- return true;
+ PEData data;
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ POINT_P;
+ KEY_K;
+
+ if (!PE_start_edit(edit)) {
+ return false;
+ }
+
+ if (!extend && !deselect && !toggle) {
+ LOOP_VISIBLE_POINTS
+ {
+ LOOP_SELECTED_KEYS
+ {
+ key->flag &= ~PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ }
+ }
+ }
+
+ PE_set_view3d_data(C, &data);
+ data.mval = mval;
+ data.rad = ED_view3d_select_dist_px();
+
+ /* 1 = nearest only */
+ if (extend) {
+ for_mouse_hit_keys(&data, extend_key_select, PSEL_NEAREST);
+ }
+ else if (deselect) {
+ for_mouse_hit_keys(&data, deselect_key_select, PSEL_NEAREST);
+ }
+ else {
+ for_mouse_hit_keys(&data, toggle_key_select, PSEL_NEAREST);
+ }
+
+ if (data.is_changed) {
+ PE_update_selection(data.depsgraph, scene, ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
+ }
+
+ return true;
}
/************************ select root operator ************************/
static void select_root(PEData *data, int point_index)
{
- PTCacheEditPoint *point = data->edit->points + point_index;
- PTCacheEditKey *key = point->keys;
+ PTCacheEditPoint *point = data->edit->points + point_index;
+ PTCacheEditKey *key = point->keys;
- if (point->flag & PEP_HIDE)
- return;
+ if (point->flag & PEP_HIDE)
+ return;
- if (data->select_action != SEL_TOGGLE) {
- data->is_changed = select_action_apply(point, key, data->select_action);
- }
- else if (key->flag & PEK_SELECT) {
- data->select_toggle_action = SEL_DESELECT;
- }
+ if (data->select_action != SEL_TOGGLE) {
+ data->is_changed = select_action_apply(point, key, data->select_action);
+ }
+ else if (key->flag & PEK_SELECT) {
+ data->select_toggle_action = SEL_DESELECT;
+ }
}
static int select_roots_exec(bContext *C, wmOperator *op)
{
- PEData data;
- int action = RNA_enum_get(op->ptr, "action");
+ PEData data;
+ int action = RNA_enum_get(op->ptr, "action");
- PE_set_data(C, &data);
+ PE_set_data(C, &data);
- if (action == SEL_TOGGLE) {
- data.select_action = SEL_TOGGLE;
- data.select_toggle_action = SEL_SELECT;
+ if (action == SEL_TOGGLE) {
+ data.select_action = SEL_TOGGLE;
+ data.select_toggle_action = SEL_SELECT;
- foreach_point(&data, select_root);
+ foreach_point(&data, select_root);
- action = data.select_toggle_action;
- }
+ action = data.select_toggle_action;
+ }
- data.select_action = action;
- foreach_point(&data, select_root);
+ data.select_action = action;
+ foreach_point(&data, select_root);
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
- }
- return OPERATOR_FINISHED;
+ if (data.is_changed) {
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
+ }
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_select_roots(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Roots";
- ot->idname = "PARTICLE_OT_select_roots";
- ot->description = "Select roots of all visible particles";
+ /* identifiers */
+ ot->name = "Select Roots";
+ ot->idname = "PARTICLE_OT_select_roots";
+ ot->description = "Select roots of all visible particles";
- /* api callbacks */
- ot->exec = select_roots_exec;
- ot->poll = PE_poll;
+ /* api callbacks */
+ ot->exec = select_roots_exec;
+ ot->poll = PE_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- WM_operator_properties_select_action(ot, SEL_SELECT, true);
+ /* properties */
+ WM_operator_properties_select_action(ot, SEL_SELECT, true);
}
/************************ select tip operator ************************/
static void select_tip(PEData *data, int point_index)
{
- PTCacheEditPoint *point = data->edit->points + point_index;
- PTCacheEditKey *key;
+ PTCacheEditPoint *point = data->edit->points + point_index;
+ PTCacheEditKey *key;
- if (point->totkey == 0) {
- return;
- }
+ if (point->totkey == 0) {
+ return;
+ }
- key = &point->keys[point->totkey - 1];
+ key = &point->keys[point->totkey - 1];
- if (point->flag & PEP_HIDE)
- return;
+ if (point->flag & PEP_HIDE)
+ return;
- if (data->select_action != SEL_TOGGLE) {
- data->is_changed = select_action_apply(point, key, data->select_action);
- }
- else if (key->flag & PEK_SELECT) {
- data->select_toggle_action = SEL_DESELECT;
- }
+ if (data->select_action != SEL_TOGGLE) {
+ data->is_changed = select_action_apply(point, key, data->select_action);
+ }
+ else if (key->flag & PEK_SELECT) {
+ data->select_toggle_action = SEL_DESELECT;
+ }
}
static int select_tips_exec(bContext *C, wmOperator *op)
{
- PEData data;
- int action = RNA_enum_get(op->ptr, "action");
+ PEData data;
+ int action = RNA_enum_get(op->ptr, "action");
- PE_set_data(C, &data);
+ PE_set_data(C, &data);
- if (action == SEL_TOGGLE) {
- data.select_action = SEL_TOGGLE;
- data.select_toggle_action = SEL_SELECT;
+ if (action == SEL_TOGGLE) {
+ data.select_action = SEL_TOGGLE;
+ data.select_toggle_action = SEL_SELECT;
- foreach_point(&data, select_tip);
+ foreach_point(&data, select_tip);
- action = data.select_toggle_action;
- }
+ action = data.select_toggle_action;
+ }
- data.select_action = action;
- foreach_point(&data, select_tip);
+ data.select_action = action;
+ foreach_point(&data, select_tip);
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
+ if (data.is_changed) {
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
}
void PARTICLE_OT_select_tips(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Tips";
- ot->idname = "PARTICLE_OT_select_tips";
- ot->description = "Select tips of all visible particles";
+ /* identifiers */
+ ot->name = "Select Tips";
+ ot->idname = "PARTICLE_OT_select_tips";
+ ot->description = "Select tips of all visible particles";
- /* api callbacks */
- ot->exec = select_tips_exec;
- ot->poll = PE_poll;
+ /* api callbacks */
+ ot->exec = select_tips_exec;
+ ot->poll = PE_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- WM_operator_properties_select_action(ot, SEL_SELECT, true);
+ /* properties */
+ WM_operator_properties_select_action(ot, SEL_SELECT, true);
}
/*********************** select random operator ************************/
@@ -1892,847 +1934,892 @@ void PARTICLE_OT_select_tips(wmOperatorType *ot)
enum { RAN_HAIR, RAN_POINTS };
static const EnumPropertyItem select_random_type_items[] = {
- {RAN_HAIR, "HAIR", 0, "Hair", ""},
- {RAN_POINTS, "POINTS", 0, "Points", ""},
- {0, NULL, 0, NULL, NULL},
+ {RAN_HAIR, "HAIR", 0, "Hair", ""},
+ {RAN_POINTS, "POINTS", 0, "Points", ""},
+ {0, NULL, 0, NULL, NULL},
};
static int select_random_exec(bContext *C, wmOperator *op)
{
- PEData data;
- int type;
-
- /* used by LOOP_VISIBLE_POINTS, LOOP_VISIBLE_KEYS and LOOP_KEYS */
- PTCacheEdit *edit;
- PTCacheEditPoint *point;
- PTCacheEditKey *key;
- int p;
- int k;
-
- const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
- const int seed = WM_operator_properties_select_random_seed_increment_get(op);
- const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
- RNG *rng;
-
- type = RNA_enum_get(op->ptr, "type");
-
- PE_set_data(C, &data);
- data.select_action = SEL_SELECT;
- edit = PE_get_current(data.scene, data.ob);
-
- rng = BLI_rng_new_srandom(seed);
-
- switch (type) {
- case RAN_HAIR:
- LOOP_VISIBLE_POINTS {
- int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
- LOOP_KEYS {
- data.is_changed |= select_action_apply(point, key, flag);
- }
- }
- break;
- case RAN_POINTS:
- LOOP_VISIBLE_POINTS {
- LOOP_VISIBLE_KEYS {
- int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
- data.is_changed |= select_action_apply(point, key, flag);
- }
- }
- break;
- }
-
- BLI_rng_free(rng);
-
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
- }
- return OPERATOR_FINISHED;
+ PEData data;
+ int type;
+
+ /* used by LOOP_VISIBLE_POINTS, LOOP_VISIBLE_KEYS and LOOP_KEYS */
+ PTCacheEdit *edit;
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
+ int p;
+ int k;
+
+ const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f;
+ const int seed = WM_operator_properties_select_random_seed_increment_get(op);
+ const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
+ RNG *rng;
+
+ type = RNA_enum_get(op->ptr, "type");
+
+ PE_set_data(C, &data);
+ data.select_action = SEL_SELECT;
+ edit = PE_get_current(data.scene, data.ob);
+
+ rng = BLI_rng_new_srandom(seed);
+
+ switch (type) {
+ case RAN_HAIR:
+ LOOP_VISIBLE_POINTS
+ {
+ int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
+ LOOP_KEYS
+ {
+ data.is_changed |= select_action_apply(point, key, flag);
+ }
+ }
+ break;
+ case RAN_POINTS:
+ LOOP_VISIBLE_POINTS
+ {
+ LOOP_VISIBLE_KEYS
+ {
+ int flag = ((BLI_rng_get_float(rng) < randfac) == select) ? SEL_SELECT : SEL_DESELECT;
+ data.is_changed |= select_action_apply(point, key, flag);
+ }
+ }
+ break;
+ }
+
+ BLI_rng_free(rng);
+
+ if (data.is_changed) {
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
+ }
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_select_random(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Random";
- ot->idname = "PARTICLE_OT_select_random";
- ot->description = "Select a randomly distributed set of hair or points";
+ /* identifiers */
+ ot->name = "Select Random";
+ ot->idname = "PARTICLE_OT_select_random";
+ ot->description = "Select a randomly distributed set of hair or points";
- /* api callbacks */
- ot->exec = select_random_exec;
- ot->poll = PE_poll;
+ /* api callbacks */
+ ot->exec = select_random_exec;
+ ot->poll = PE_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- WM_operator_properties_select_random(ot);
- ot->prop = RNA_def_enum(ot->srna, "type", select_random_type_items, RAN_HAIR,
- "Type", "Select either hair or points");
+ /* properties */
+ WM_operator_properties_select_random(ot);
+ ot->prop = RNA_def_enum(ot->srna,
+ "type",
+ select_random_type_items,
+ RAN_HAIR,
+ "Type",
+ "Select either hair or points");
}
/************************ select linked operator ************************/
static int select_linked_exec(bContext *C, wmOperator *op)
{
- PEData data;
- int mval[2];
- int location[2];
+ PEData data;
+ int mval[2];
+ int location[2];
- RNA_int_get_array(op->ptr, "location", location);
- mval[0] = location[0];
- mval[1] = location[1];
+ RNA_int_get_array(op->ptr, "location", location);
+ mval[0] = location[0];
+ mval[1] = location[1];
- PE_set_view3d_data(C, &data);
- data.mval = mval;
- data.rad = 75.0f;
- data.select = !RNA_boolean_get(op->ptr, "deselect");
+ PE_set_view3d_data(C, &data);
+ data.mval = mval;
+ data.rad = 75.0f;
+ data.select = !RNA_boolean_get(op->ptr, "deselect");
- for_mouse_hit_keys(&data, select_keys, PSEL_NEAREST);
- PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
+ for_mouse_hit_keys(&data, select_keys, PSEL_NEAREST);
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- RNA_int_set_array(op->ptr, "location", event->mval);
- return select_linked_exec(C, op);
+ RNA_int_set_array(op->ptr, "location", event->mval);
+ return select_linked_exec(C, op);
}
void PARTICLE_OT_select_linked(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Linked";
- ot->idname = "PARTICLE_OT_select_linked";
- ot->description = "Select nearest particle from mouse pointer";
+ /* identifiers */
+ ot->name = "Select Linked";
+ ot->idname = "PARTICLE_OT_select_linked";
+ ot->description = "Select nearest particle from mouse pointer";
- /* api callbacks */
- ot->exec = select_linked_exec;
- ot->invoke = select_linked_invoke;
- ot->poll = PE_poll_view3d;
+ /* api callbacks */
+ ot->exec = select_linked_exec;
+ ot->invoke = select_linked_invoke;
+ ot->poll = PE_poll_view3d;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them");
- RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
+ /* properties */
+ RNA_def_boolean(
+ ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them");
+ RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
}
/************************ box select operator ************************/
bool PE_deselect_all_visible_ex(PTCacheEdit *edit)
{
- bool changed = false;
- POINT_P; KEY_K;
+ bool changed = false;
+ POINT_P;
+ KEY_K;
- LOOP_VISIBLE_POINTS {
- LOOP_SELECTED_KEYS {
- if ((key->flag & PEK_SELECT) != 0) {
- key->flag &= ~PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC;
- changed = true;
- }
- }
- }
- return changed;
+ LOOP_VISIBLE_POINTS
+ {
+ LOOP_SELECTED_KEYS
+ {
+ if ((key->flag & PEK_SELECT) != 0) {
+ key->flag &= ~PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC;
+ changed = true;
+ }
+ }
+ }
+ return changed;
}
bool PE_deselect_all_visible(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- if (!PE_start_edit(edit)) {
- return false;
- }
- return PE_deselect_all_visible_ex(edit);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ if (!PE_start_edit(edit)) {
+ return false;
+ }
+ return PE_deselect_all_visible_ex(edit);
}
bool PE_box_select(bContext *C, const rcti *rect, const int sel_op)
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- PEData data;
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ PEData data;
- if (!PE_start_edit(edit)) {
- return false;
- }
+ if (!PE_start_edit(edit)) {
+ return false;
+ }
- PE_set_view3d_data(C, &data);
- data.rect = rect;
- data.sel_op = sel_op;
+ PE_set_view3d_data(C, &data);
+ data.rect = rect;
+ data.sel_op = sel_op;
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- data.is_changed = PE_deselect_all_visible_ex(edit);
- }
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ data.is_changed = PE_deselect_all_visible_ex(edit);
+ }
- if (BLI_rcti_is_empty(rect)) {
- /* pass */
- }
- else {
- for_mouse_hit_keys(&data, select_key_op, PSEL_ALL_KEYS);
- }
+ if (BLI_rcti_is_empty(rect)) {
+ /* pass */
+ }
+ else {
+ for_mouse_hit_keys(&data, select_key_op, PSEL_ALL_KEYS);
+ }
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, scene, ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
- }
- return data.is_changed;
+ if (data.is_changed) {
+ PE_update_selection(data.depsgraph, scene, ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
+ }
+ return data.is_changed;
}
/************************ circle select operator ************************/
bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float rad)
{
- BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- PEData data;
+ BLI_assert(ELEM(sel_op, SEL_OP_SET, SEL_OP_ADD, SEL_OP_SUB));
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ PEData data;
- if (!PE_start_edit(edit)) {
- return false;
- }
+ if (!PE_start_edit(edit)) {
+ return false;
+ }
- const bool select = (sel_op != SEL_OP_SUB);
+ const bool select = (sel_op != SEL_OP_SUB);
- PE_set_view3d_data(C, &data);
- data.mval = mval;
- data.rad = rad;
- data.select = select;
+ PE_set_view3d_data(C, &data);
+ data.mval = mval;
+ data.rad = rad;
+ data.select = select;
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- data.is_changed = PE_deselect_all_visible_ex(edit);
- }
- for_mouse_hit_keys(&data, select_key, 0);
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, scene, ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
- }
- return data.is_changed;
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ data.is_changed = PE_deselect_all_visible_ex(edit);
+ }
+ for_mouse_hit_keys(&data, select_key, 0);
+ if (data.is_changed) {
+ PE_update_selection(data.depsgraph, scene, ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
+ }
+ return data.is_changed;
}
/************************ lasso select operator ************************/
int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op)
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- ARegion *ar = CTX_wm_region(C);
- ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
- POINT_P; KEY_K;
- float co[3], mat[4][4];
- int screen_co[2];
-
- PEData data;
-
- unit_m4(mat);
-
- if (!PE_start_edit(edit))
- return OPERATOR_CANCELLED;
-
- /* only for depths */
- PE_set_view3d_data(C, &data);
-
- if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
- data.is_changed |= PE_deselect_all_visible_ex(edit);
- }
-
- LOOP_VISIBLE_POINTS {
- if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
- psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
-
- if (pset->selectmode == SCE_SELECT_POINT) {
- LOOP_KEYS {
- copy_v3_v3(co, key->co);
- mul_m4_v3(mat, co);
- const bool is_select = key->flag & PEK_SELECT;
- const bool is_inside = (
- (ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
- key_test_depth(&data, co, screen_co));
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
- point->flag |= PEP_EDIT_RECALC;
- data.is_changed = true;
- }
- }
- }
- else if (pset->selectmode == SCE_SELECT_END) {
- if (point->totkey) {
- key = point->keys + point->totkey - 1;
- copy_v3_v3(co, key->co);
- mul_m4_v3(mat, co);
- const bool is_select = key->flag & PEK_SELECT;
- const bool is_inside = (
- (ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) &&
- BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
- key_test_depth(&data, co, screen_co));
- const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
- if (sel_op_result != -1) {
- SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
- point->flag |= PEP_EDIT_RECALC;
- data.is_changed = true;
- }
- }
- }
- }
-
- if (data.is_changed) {
- PE_update_selection(data.depsgraph, scene, ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ARegion *ar = CTX_wm_region(C);
+ ParticleEditSettings *pset = PE_settings(scene);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ ParticleSystem *psys = edit->psys;
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
+ POINT_P;
+ KEY_K;
+ float co[3], mat[4][4];
+ int screen_co[2];
+
+ PEData data;
+
+ unit_m4(mat);
+
+ if (!PE_start_edit(edit))
+ return OPERATOR_CANCELLED;
+
+ /* only for depths */
+ PE_set_view3d_data(C, &data);
+
+ if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
+ data.is_changed |= PE_deselect_all_visible_ex(edit);
+ }
+
+ LOOP_VISIBLE_POINTS
+ {
+ if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR))
+ psys_mat_hair_to_global(
+ ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
+
+ if (pset->selectmode == SCE_SELECT_POINT) {
+ LOOP_KEYS
+ {
+ copy_v3_v3(co, key->co);
+ mul_m4_v3(mat, co);
+ const bool is_select = key->flag & PEK_SELECT;
+ const bool is_inside =
+ ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) ==
+ V3D_PROJ_RET_OK) &&
+ BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
+ key_test_depth(&data, co, screen_co));
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
+ point->flag |= PEP_EDIT_RECALC;
+ data.is_changed = true;
+ }
+ }
+ }
+ else if (pset->selectmode == SCE_SELECT_END) {
+ if (point->totkey) {
+ key = point->keys + point->totkey - 1;
+ copy_v3_v3(co, key->co);
+ mul_m4_v3(mat, co);
+ const bool is_select = key->flag & PEK_SELECT;
+ const bool is_inside =
+ ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) ==
+ V3D_PROJ_RET_OK) &&
+ BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) &&
+ key_test_depth(&data, co, screen_co));
+ const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
+ if (sel_op_result != -1) {
+ SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
+ point->flag |= PEP_EDIT_RECALC;
+ data.is_changed = true;
+ }
+ }
+ }
+ }
+
+ if (data.is_changed) {
+ PE_update_selection(data.depsgraph, scene, ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
}
/*************************** hide operator **************************/
static int hide_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
-
- PTCacheEdit *edit = PE_get_current(scene, ob);
- POINT_P; KEY_K;
-
-
- if (RNA_enum_get(op->ptr, "unselected")) {
- LOOP_UNSELECTED_POINTS {
- point->flag |= PEP_HIDE;
- point->flag |= PEP_EDIT_RECALC;
-
- LOOP_KEYS {
- key->flag &= ~PEK_SELECT;
- }
- }
- }
- else {
- LOOP_SELECTED_POINTS {
- point->flag |= PEP_HIDE;
- point->flag |= PEP_EDIT_RECALC;
-
- LOOP_KEYS {
- key->flag &= ~PEK_SELECT;
- }
- }
- }
-
- PE_update_selection(depsgraph, scene, ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
-
- return OPERATOR_FINISHED;
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ POINT_P;
+ KEY_K;
+
+ if (RNA_enum_get(op->ptr, "unselected")) {
+ LOOP_UNSELECTED_POINTS
+ {
+ point->flag |= PEP_HIDE;
+ point->flag |= PEP_EDIT_RECALC;
+
+ LOOP_KEYS
+ {
+ key->flag &= ~PEK_SELECT;
+ }
+ }
+ }
+ else {
+ LOOP_SELECTED_POINTS
+ {
+ point->flag |= PEP_HIDE;
+ point->flag |= PEP_EDIT_RECALC;
+
+ LOOP_KEYS
+ {
+ key->flag &= ~PEK_SELECT;
+ }
+ }
+ }
+
+ PE_update_selection(depsgraph, scene, ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_hide(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Hide Selected";
- ot->idname = "PARTICLE_OT_hide";
- ot->description = "Hide selected particles";
+ /* identifiers */
+ ot->name = "Hide Selected";
+ ot->idname = "PARTICLE_OT_hide";
+ ot->description = "Hide selected particles";
- /* api callbacks */
- ot->exec = hide_exec;
- ot->poll = PE_poll;
+ /* api callbacks */
+ ot->exec = hide_exec;
+ ot->poll = PE_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
}
/*************************** reveal operator **************************/
static int reveal_exec(bContext *C, wmOperator *op)
{
- Object *ob = CTX_data_active_object(C);
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- const bool select = RNA_boolean_get(op->ptr, "select");
- POINT_P; KEY_K;
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ const bool select = RNA_boolean_get(op->ptr, "select");
+ POINT_P;
+ KEY_K;
- LOOP_POINTS {
- if (point->flag & PEP_HIDE) {
- point->flag &= ~PEP_HIDE;
- point->flag |= PEP_EDIT_RECALC;
+ LOOP_POINTS
+ {
+ if (point->flag & PEP_HIDE) {
+ point->flag &= ~PEP_HIDE;
+ point->flag |= PEP_EDIT_RECALC;
- LOOP_KEYS {
- SET_FLAG_FROM_TEST(key->flag, select, PEK_SELECT);
- }
- }
- }
+ LOOP_KEYS
+ {
+ SET_FLAG_FROM_TEST(key->flag, select, PEK_SELECT);
+ }
+ }
+ }
- PE_update_selection(depsgraph, scene, ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
+ PE_update_selection(depsgraph, scene, ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_reveal(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Reveal";
- ot->idname = "PARTICLE_OT_reveal";
- ot->description = "Show hidden particles";
+ /* identifiers */
+ ot->name = "Reveal";
+ ot->idname = "PARTICLE_OT_reveal";
+ ot->description = "Show hidden particles";
- /* api callbacks */
- ot->exec = reveal_exec;
- ot->poll = PE_poll;
+ /* api callbacks */
+ ot->exec = reveal_exec;
+ ot->poll = PE_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* props */
- RNA_def_boolean(ot->srna, "select", true, "Select", "");
+ /* props */
+ RNA_def_boolean(ot->srna, "select", true, "Select", "");
}
/************************ select less operator ************************/
static void select_less_keys(PEData *data, int point_index)
{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- KEY_K;
-
- LOOP_SELECTED_KEYS {
- if (k == 0) {
- if (((key + 1)->flag & PEK_SELECT) == 0)
- key->flag |= PEK_TAG;
- }
- else if (k == point->totkey - 1) {
- if (((key - 1)->flag & PEK_SELECT) == 0)
- key->flag |= PEK_TAG;
- }
- else {
- if ((((key - 1)->flag & (key + 1)->flag) & PEK_SELECT) == 0)
- key->flag |= PEK_TAG;
- }
- }
-
- LOOP_KEYS {
- if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT)) {
- key->flag &= ~(PEK_TAG | PEK_SELECT);
- point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
- data->is_changed = true;
- }
- }
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ KEY_K;
+
+ LOOP_SELECTED_KEYS
+ {
+ if (k == 0) {
+ if (((key + 1)->flag & PEK_SELECT) == 0)
+ key->flag |= PEK_TAG;
+ }
+ else if (k == point->totkey - 1) {
+ if (((key - 1)->flag & PEK_SELECT) == 0)
+ key->flag |= PEK_TAG;
+ }
+ else {
+ if ((((key - 1)->flag & (key + 1)->flag) & PEK_SELECT) == 0)
+ key->flag |= PEK_TAG;
+ }
+ }
+
+ LOOP_KEYS
+ {
+ if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT)) {
+ key->flag &= ~(PEK_TAG | PEK_SELECT);
+ point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
+ data->is_changed = true;
+ }
+ }
}
static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
{
- PEData data;
+ PEData data;
- PE_set_data(C, &data);
- foreach_point(&data, select_less_keys);
+ PE_set_data(C, &data);
+ foreach_point(&data, select_less_keys);
- PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_select_less(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select Less";
- ot->idname = "PARTICLE_OT_select_less";
- ot->description = "Deselect boundary selected keys of each particle";
+ /* identifiers */
+ ot->name = "Select Less";
+ ot->idname = "PARTICLE_OT_select_less";
+ ot->description = "Deselect boundary selected keys of each particle";
- /* api callbacks */
- ot->exec = select_less_exec;
- ot->poll = PE_poll;
+ /* api callbacks */
+ ot->exec = select_less_exec;
+ ot->poll = PE_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/************************ select more operator ************************/
static void select_more_keys(PEData *data, int point_index)
{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- KEY_K;
-
- LOOP_KEYS {
- if (key->flag & PEK_SELECT) continue;
-
- if (k == 0) {
- if ((key + 1)->flag & PEK_SELECT)
- key->flag |= PEK_TAG;
- }
- else if (k == point->totkey - 1) {
- if ((key - 1)->flag & PEK_SELECT)
- key->flag |= PEK_TAG;
- }
- else {
- if (((key - 1)->flag | (key + 1)->flag) & PEK_SELECT)
- key->flag |= PEK_TAG;
- }
- }
-
- LOOP_KEYS {
- if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT) == 0) {
- key->flag &= ~PEK_TAG;
- key->flag |= PEK_SELECT;
- point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
- data->is_changed = true;
- }
- }
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ KEY_K;
+
+ LOOP_KEYS
+ {
+ if (key->flag & PEK_SELECT)
+ continue;
+
+ if (k == 0) {
+ if ((key + 1)->flag & PEK_SELECT)
+ key->flag |= PEK_TAG;
+ }
+ else if (k == point->totkey - 1) {
+ if ((key - 1)->flag & PEK_SELECT)
+ key->flag |= PEK_TAG;
+ }
+ else {
+ if (((key - 1)->flag | (key + 1)->flag) & PEK_SELECT)
+ key->flag |= PEK_TAG;
+ }
+ }
+
+ LOOP_KEYS
+ {
+ if ((key->flag & PEK_TAG) && (key->flag & PEK_SELECT) == 0) {
+ key->flag &= ~PEK_TAG;
+ key->flag |= PEK_SELECT;
+ point->flag |= PEP_EDIT_RECALC; /* redraw selection only */
+ data->is_changed = true;
+ }
+ }
}
static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
{
- PEData data;
+ PEData data;
- PE_set_data(C, &data);
- foreach_point(&data, select_more_keys);
+ PE_set_data(C, &data);
+ foreach_point(&data, select_more_keys);
- PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_select_more(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Select More";
- ot->idname = "PARTICLE_OT_select_more";
- ot->description = "Select keys linked to boundary selected keys of each particle";
+ /* identifiers */
+ ot->name = "Select More";
+ ot->idname = "PARTICLE_OT_select_more";
+ ot->description = "Select keys linked to boundary selected keys of each particle";
- /* api callbacks */
- ot->exec = select_more_exec;
- ot->poll = PE_poll;
+ /* api callbacks */
+ ot->exec = select_more_exec;
+ ot->poll = PE_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/************************ rekey operator ************************/
static void rekey_particle(PEData *data, int pa_index)
{
- PTCacheEdit *edit = data->edit;
- ParticleSystem *psys = edit->psys;
- ParticleSimulationData sim = {0};
- ParticleData *pa = psys->particles + pa_index;
- PTCacheEditPoint *point = edit->points + pa_index;
- ParticleKey state;
- HairKey *key, *new_keys, *okey;
- PTCacheEditKey *ekey;
- float dval, sta, end;
- int k;
-
- sim.depsgraph = data->depsgraph;
- sim.scene = data->scene;
- sim.ob = data->ob;
- sim.psys = edit->psys;
-
- pa->flag |= PARS_REKEY;
-
- key = new_keys = MEM_callocN(data->totrekey * sizeof(HairKey), "Hair re-key keys");
-
- okey = pa->hair;
- /* root and tip stay the same */
- copy_v3_v3(key->co, okey->co);
- copy_v3_v3((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co);
-
- sta = key->time = okey->time;
- end = (key + data->totrekey - 1)->time = (okey + pa->totkey - 1)->time;
- dval = (end - sta) / (float)(data->totrekey - 1);
-
- /* interpolate new keys from old ones */
- for (k = 1, key++; k < data->totrekey - 1; k++, key++) {
- state.time = (float)k / (float)(data->totrekey - 1);
- psys_get_particle_on_path(&sim, pa_index, &state, 0);
- copy_v3_v3(key->co, state.co);
- key->time = sta + k * dval;
- }
-
- /* replace keys */
- if (pa->hair)
- MEM_freeN(pa->hair);
- pa->hair = new_keys;
-
- point->totkey = pa->totkey = data->totrekey;
-
-
- if (point->keys)
- MEM_freeN(point->keys);
- ekey = point->keys = MEM_callocN(pa->totkey * sizeof(PTCacheEditKey), "Hair re-key edit keys");
-
- for (k = 0, key = pa->hair; k < pa->totkey; k++, key++, ekey++) {
- ekey->co = key->co;
- ekey->time = &key->time;
- ekey->flag |= PEK_SELECT;
- if (!(psys->flag & PSYS_GLOBAL_HAIR))
- ekey->flag |= PEK_USE_WCO;
- }
-
- pa->flag &= ~PARS_REKEY;
- point->flag |= PEP_EDIT_RECALC;
+ PTCacheEdit *edit = data->edit;
+ ParticleSystem *psys = edit->psys;
+ ParticleSimulationData sim = {0};
+ ParticleData *pa = psys->particles + pa_index;
+ PTCacheEditPoint *point = edit->points + pa_index;
+ ParticleKey state;
+ HairKey *key, *new_keys, *okey;
+ PTCacheEditKey *ekey;
+ float dval, sta, end;
+ int k;
+
+ sim.depsgraph = data->depsgraph;
+ sim.scene = data->scene;
+ sim.ob = data->ob;
+ sim.psys = edit->psys;
+
+ pa->flag |= PARS_REKEY;
+
+ key = new_keys = MEM_callocN(data->totrekey * sizeof(HairKey), "Hair re-key keys");
+
+ okey = pa->hair;
+ /* root and tip stay the same */
+ copy_v3_v3(key->co, okey->co);
+ copy_v3_v3((key + data->totrekey - 1)->co, (okey + pa->totkey - 1)->co);
+
+ sta = key->time = okey->time;
+ end = (key + data->totrekey - 1)->time = (okey + pa->totkey - 1)->time;
+ dval = (end - sta) / (float)(data->totrekey - 1);
+
+ /* interpolate new keys from old ones */
+ for (k = 1, key++; k < data->totrekey - 1; k++, key++) {
+ state.time = (float)k / (float)(data->totrekey - 1);
+ psys_get_particle_on_path(&sim, pa_index, &state, 0);
+ copy_v3_v3(key->co, state.co);
+ key->time = sta + k * dval;
+ }
+
+ /* replace keys */
+ if (pa->hair)
+ MEM_freeN(pa->hair);
+ pa->hair = new_keys;
+
+ point->totkey = pa->totkey = data->totrekey;
+
+ if (point->keys)
+ MEM_freeN(point->keys);
+ ekey = point->keys = MEM_callocN(pa->totkey * sizeof(PTCacheEditKey), "Hair re-key edit keys");
+
+ for (k = 0, key = pa->hair; k < pa->totkey; k++, key++, ekey++) {
+ ekey->co = key->co;
+ ekey->time = &key->time;
+ ekey->flag |= PEK_SELECT;
+ if (!(psys->flag & PSYS_GLOBAL_HAIR))
+ ekey->flag |= PEK_USE_WCO;
+ }
+
+ pa->flag &= ~PARS_REKEY;
+ point->flag |= PEP_EDIT_RECALC;
}
static int rekey_exec(bContext *C, wmOperator *op)
{
- PEData data;
+ PEData data;
- PE_set_data(C, &data);
+ PE_set_data(C, &data);
- data.dval = 1.0f / (float)(data.totrekey - 1);
- data.totrekey = RNA_int_get(op->ptr, "keys_number");
+ data.dval = 1.0f / (float)(data.totrekey - 1);
+ data.totrekey = RNA_int_get(op->ptr, "keys_number");
- foreach_selected_point(&data, rekey_particle);
+ foreach_selected_point(&data, rekey_particle);
- recalc_lengths(data.edit);
- PE_update_object(data.depsgraph, data.scene, data.ob, 1);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
+ recalc_lengths(data.edit);
+ PE_update_object(data.depsgraph, data.scene, data.ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_rekey(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Rekey";
- ot->idname = "PARTICLE_OT_rekey";
- ot->description = "Change the number of keys of selected particles (root and tip keys included)";
+ /* identifiers */
+ ot->name = "Rekey";
+ ot->idname = "PARTICLE_OT_rekey";
+ ot->description = "Change the number of keys of selected particles (root and tip keys included)";
- /* api callbacks */
- ot->exec = rekey_exec;
- ot->invoke = WM_operator_props_popup;
- ot->poll = PE_hair_poll;
+ /* api callbacks */
+ ot->exec = rekey_exec;
+ ot->invoke = WM_operator_props_popup;
+ ot->poll = PE_hair_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- RNA_def_int(ot->srna, "keys_number", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
+ /* properties */
+ RNA_def_int(ot->srna, "keys_number", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
}
-static void rekey_particle_to_time(const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
+static void rekey_particle_to_time(
+ const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
{
- PTCacheEdit *edit = PE_get_current(scene, ob);
- ParticleSystem *psys;
- ParticleSimulationData sim = {0};
- ParticleData *pa;
- ParticleKey state;
- HairKey *new_keys, *key;
- PTCacheEditKey *ekey;
- int k;
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ ParticleSystem *psys;
+ ParticleSimulationData sim = {0};
+ ParticleData *pa;
+ ParticleKey state;
+ HairKey *new_keys, *key;
+ PTCacheEditKey *ekey;
+ int k;
- if (!edit || !edit->psys) return;
+ if (!edit || !edit->psys)
+ return;
- psys = edit->psys;
+ psys = edit->psys;
- sim.depsgraph = CTX_data_depsgraph(C);
- sim.scene = scene;
- sim.ob = ob;
- sim.psys = psys;
+ sim.depsgraph = CTX_data_depsgraph(C);
+ sim.scene = scene;
+ sim.ob = ob;
+ sim.psys = psys;
- pa = psys->particles + pa_index;
+ pa = psys->particles + pa_index;
- pa->flag |= PARS_REKEY;
+ pa->flag |= PARS_REKEY;
- key = new_keys = MEM_dupallocN(pa->hair);
+ key = new_keys = MEM_dupallocN(pa->hair);
- /* interpolate new keys from old ones (roots stay the same) */
- for (k = 1, key++; k < pa->totkey; k++, key++) {
- state.time = path_time * (float)k / (float)(pa->totkey - 1);
- psys_get_particle_on_path(&sim, pa_index, &state, 0);
- copy_v3_v3(key->co, state.co);
- }
+ /* interpolate new keys from old ones (roots stay the same) */
+ for (k = 1, key++; k < pa->totkey; k++, key++) {
+ state.time = path_time * (float)k / (float)(pa->totkey - 1);
+ psys_get_particle_on_path(&sim, pa_index, &state, 0);
+ copy_v3_v3(key->co, state.co);
+ }
- /* replace hair keys */
- if (pa->hair)
- MEM_freeN(pa->hair);
- pa->hair = new_keys;
+ /* replace hair keys */
+ if (pa->hair)
+ MEM_freeN(pa->hair);
+ pa->hair = new_keys;
- /* update edit pointers */
- for (k = 0, key = pa->hair, ekey = edit->points[pa_index].keys; k < pa->totkey; k++, key++, ekey++) {
- ekey->co = key->co;
- ekey->time = &key->time;
- }
+ /* update edit pointers */
+ for (k = 0, key = pa->hair, ekey = edit->points[pa_index].keys; k < pa->totkey;
+ k++, key++, ekey++) {
+ ekey->co = key->co;
+ ekey->time = &key->time;
+ }
- pa->flag &= ~PARS_REKEY;
+ pa->flag &= ~PARS_REKEY;
}
/************************* utilities **************************/
static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror)
{
- PTCacheEdit *edit = psys->edit;
- ParticleData *pa, *npa = 0, *new_pars = 0;
- POINT_P;
- PTCacheEditPoint *npoint = 0, *new_points = 0;
- ParticleSystemModifierData *psmd_eval;
- int i, new_totpart = psys->totpart, removed = 0;
-
- if (mirror) {
- /* mirror tags */
- psmd_eval = edit->psmd_eval;
-
- LOOP_TAGGED_POINTS {
- PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
- }
- }
-
- LOOP_TAGGED_POINTS {
- new_totpart--;
- removed++;
- }
-
- if (new_totpart != psys->totpart) {
- if (new_totpart) {
- npa = new_pars = MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
- npoint = new_points = MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array");
-
- if (ELEM(NULL, new_pars, new_points)) {
- /* allocation error! */
- if (new_pars)
- MEM_freeN(new_pars);
- if (new_points)
- MEM_freeN(new_points);
- return 0;
- }
- }
-
- pa = psys->particles;
- point = edit->points;
- for (i = 0; i < psys->totpart; i++, pa++, point++) {
- if (point->flag & PEP_TAG) {
- if (point->keys)
- MEM_freeN(point->keys);
- if (pa->hair)
- MEM_freeN(pa->hair);
- }
- else {
- memcpy(npa, pa, sizeof(ParticleData));
- memcpy(npoint, point, sizeof(PTCacheEditPoint));
- npa++;
- npoint++;
- }
- }
-
- if (psys->particles) MEM_freeN(psys->particles);
- psys->particles = new_pars;
-
- if (edit->points) MEM_freeN(edit->points);
- edit->points = new_points;
-
- if (edit->mirror_cache) {
- MEM_freeN(edit->mirror_cache);
- edit->mirror_cache = NULL;
- }
-
- if (psys->child) {
- MEM_freeN(psys->child);
- psys->child = NULL;
- psys->totchild = 0;
- }
-
- edit->totpoint = psys->totpart = new_totpart;
- }
-
- return removed;
+ PTCacheEdit *edit = psys->edit;
+ ParticleData *pa, *npa = 0, *new_pars = 0;
+ POINT_P;
+ PTCacheEditPoint *npoint = 0, *new_points = 0;
+ ParticleSystemModifierData *psmd_eval;
+ int i, new_totpart = psys->totpart, removed = 0;
+
+ if (mirror) {
+ /* mirror tags */
+ psmd_eval = edit->psmd_eval;
+
+ LOOP_TAGGED_POINTS
+ {
+ PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
+ }
+ }
+
+ LOOP_TAGGED_POINTS
+ {
+ new_totpart--;
+ removed++;
+ }
+
+ if (new_totpart != psys->totpart) {
+ if (new_totpart) {
+ npa = new_pars = MEM_callocN(new_totpart * sizeof(ParticleData), "ParticleData array");
+ npoint = new_points = MEM_callocN(new_totpart * sizeof(PTCacheEditPoint),
+ "PTCacheEditKey array");
+
+ if (ELEM(NULL, new_pars, new_points)) {
+ /* allocation error! */
+ if (new_pars)
+ MEM_freeN(new_pars);
+ if (new_points)
+ MEM_freeN(new_points);
+ return 0;
+ }
+ }
+
+ pa = psys->particles;
+ point = edit->points;
+ for (i = 0; i < psys->totpart; i++, pa++, point++) {
+ if (point->flag & PEP_TAG) {
+ if (point->keys)
+ MEM_freeN(point->keys);
+ if (pa->hair)
+ MEM_freeN(pa->hair);
+ }
+ else {
+ memcpy(npa, pa, sizeof(ParticleData));
+ memcpy(npoint, point, sizeof(PTCacheEditPoint));
+ npa++;
+ npoint++;
+ }
+ }
+
+ if (psys->particles)
+ MEM_freeN(psys->particles);
+ psys->particles = new_pars;
+
+ if (edit->points)
+ MEM_freeN(edit->points);
+ edit->points = new_points;
+
+ if (edit->mirror_cache) {
+ MEM_freeN(edit->mirror_cache);
+ edit->mirror_cache = NULL;
+ }
+
+ if (psys->child) {
+ MEM_freeN(psys->child);
+ psys->child = NULL;
+ psys->totchild = 0;
+ }
+
+ edit->totpoint = psys->totpart = new_totpart;
+ }
+
+ return removed;
}
static void remove_tagged_keys(Object *ob, ParticleSystem *psys)
{
- PTCacheEdit *edit = psys->edit;
- ParticleData *pa;
- HairKey *hkey, *nhkey, *new_hkeys = 0;
- POINT_P; KEY_K;
- PTCacheEditKey *nkey, *new_keys;
- ParticleSystemModifierData *psmd_eval;
- short new_totkey;
-
- if (pe_x_mirror(ob)) {
- /* mirror key tags */
- psmd_eval = psys_get_modifier(ob, psys);
-
- LOOP_POINTS {
- LOOP_TAGGED_KEYS {
- PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
- break;
- }
- }
- }
-
- LOOP_POINTS {
- new_totkey = point->totkey;
- LOOP_TAGGED_KEYS {
- new_totkey--;
- }
- /* we can't have elements with less than two keys*/
- if (new_totkey < 2)
- point->flag |= PEP_TAG;
- }
- remove_tagged_particles(ob, psys, pe_x_mirror(ob));
-
- LOOP_POINTS {
- pa = psys->particles + p;
- new_totkey = pa->totkey;
-
- LOOP_TAGGED_KEYS {
- new_totkey--;
- }
-
- if (new_totkey != pa->totkey) {
- nhkey = new_hkeys = MEM_callocN(new_totkey * sizeof(HairKey), "HairKeys");
- nkey = new_keys = MEM_callocN(new_totkey * sizeof(PTCacheEditKey), "particle edit keys");
-
- hkey = pa->hair;
- LOOP_KEYS {
- while (key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
- key++;
- hkey++;
- }
-
- if (hkey < pa->hair + pa->totkey) {
- copy_v3_v3(nhkey->co, hkey->co);
- nhkey->editflag = hkey->editflag;
- nhkey->time = hkey->time;
- nhkey->weight = hkey->weight;
-
- nkey->co = nhkey->co;
- nkey->time = &nhkey->time;
- /* these can be copied from old edit keys */
- nkey->flag = key->flag;
- nkey->ftime = key->ftime;
- nkey->length = key->length;
- copy_v3_v3(nkey->world_co, key->world_co);
- }
- nkey++;
- nhkey++;
- hkey++;
- }
-
- if (pa->hair)
- MEM_freeN(pa->hair);
-
- if (point->keys)
- MEM_freeN(point->keys);
-
- pa->hair = new_hkeys;
- point->keys = new_keys;
-
- point->totkey = pa->totkey = new_totkey;
-
- /* flag for recalculating length */
- point->flag |= PEP_EDIT_RECALC;
- }
- }
+ PTCacheEdit *edit = psys->edit;
+ ParticleData *pa;
+ HairKey *hkey, *nhkey, *new_hkeys = 0;
+ POINT_P;
+ KEY_K;
+ PTCacheEditKey *nkey, *new_keys;
+ ParticleSystemModifierData *psmd_eval;
+ short new_totkey;
+
+ if (pe_x_mirror(ob)) {
+ /* mirror key tags */
+ psmd_eval = psys_get_modifier(ob, psys);
+
+ LOOP_POINTS
+ {
+ LOOP_TAGGED_KEYS
+ {
+ PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL);
+ break;
+ }
+ }
+ }
+
+ LOOP_POINTS
+ {
+ new_totkey = point->totkey;
+ LOOP_TAGGED_KEYS
+ {
+ new_totkey--;
+ }
+ /* we can't have elements with less than two keys*/
+ if (new_totkey < 2)
+ point->flag |= PEP_TAG;
+ }
+ remove_tagged_particles(ob, psys, pe_x_mirror(ob));
+
+ LOOP_POINTS
+ {
+ pa = psys->particles + p;
+ new_totkey = pa->totkey;
+
+ LOOP_TAGGED_KEYS
+ {
+ new_totkey--;
+ }
+
+ if (new_totkey != pa->totkey) {
+ nhkey = new_hkeys = MEM_callocN(new_totkey * sizeof(HairKey), "HairKeys");
+ nkey = new_keys = MEM_callocN(new_totkey * sizeof(PTCacheEditKey), "particle edit keys");
+
+ hkey = pa->hair;
+ LOOP_KEYS
+ {
+ while (key->flag & PEK_TAG && hkey < pa->hair + pa->totkey) {
+ key++;
+ hkey++;
+ }
+
+ if (hkey < pa->hair + pa->totkey) {
+ copy_v3_v3(nhkey->co, hkey->co);
+ nhkey->editflag = hkey->editflag;
+ nhkey->time = hkey->time;
+ nhkey->weight = hkey->weight;
+
+ nkey->co = nhkey->co;
+ nkey->time = &nhkey->time;
+ /* these can be copied from old edit keys */
+ nkey->flag = key->flag;
+ nkey->ftime = key->ftime;
+ nkey->length = key->length;
+ copy_v3_v3(nkey->world_co, key->world_co);
+ }
+ nkey++;
+ nhkey++;
+ hkey++;
+ }
+
+ if (pa->hair)
+ MEM_freeN(pa->hair);
+
+ if (point->keys)
+ MEM_freeN(point->keys);
+
+ pa->hair = new_hkeys;
+ point->keys = new_keys;
+
+ point->totkey = pa->totkey = new_totkey;
+
+ /* flag for recalculating length */
+ point->flag |= PEP_EDIT_RECALC;
+ }
+ }
}
/************************ subdivide opertor *********************/
@@ -2740,308 +2827,326 @@ static void remove_tagged_keys(Object *ob, ParticleSystem *psys)
/* works like normal edit mode subdivide, inserts keys between neighboring selected keys */
static void subdivide_particle(PEData *data, int pa_index)
{
- PTCacheEdit *edit = data->edit;
- ParticleSystem *psys = edit->psys;
- ParticleSimulationData sim = {0};
- ParticleData *pa = psys->particles + pa_index;
- PTCacheEditPoint *point = edit->points + pa_index;
- ParticleKey state;
- HairKey *key, *nkey, *new_keys;
- PTCacheEditKey *ekey, *nekey, *new_ekeys;
+ PTCacheEdit *edit = data->edit;
+ ParticleSystem *psys = edit->psys;
+ ParticleSimulationData sim = {0};
+ ParticleData *pa = psys->particles + pa_index;
+ PTCacheEditPoint *point = edit->points + pa_index;
+ ParticleKey state;
+ HairKey *key, *nkey, *new_keys;
+ PTCacheEditKey *ekey, *nekey, *new_ekeys;
- int k;
- short totnewkey = 0;
- float endtime;
+ int k;
+ short totnewkey = 0;
+ float endtime;
- sim.depsgraph = data->depsgraph;
- sim.scene = data->scene;
- sim.ob = data->ob;
- sim.psys = edit->psys;
+ sim.depsgraph = data->depsgraph;
+ sim.scene = data->scene;
+ sim.ob = data->ob;
+ sim.psys = edit->psys;
- for (k = 0, ekey = point->keys; k < pa->totkey - 1; k++, ekey++) {
- if (ekey->flag & PEK_SELECT && (ekey + 1)->flag & PEK_SELECT)
- totnewkey++;
- }
+ for (k = 0, ekey = point->keys; k < pa->totkey - 1; k++, ekey++) {
+ if (ekey->flag & PEK_SELECT && (ekey + 1)->flag & PEK_SELECT)
+ totnewkey++;
+ }
- if (totnewkey == 0) return;
+ if (totnewkey == 0)
+ return;
- pa->flag |= PARS_REKEY;
+ pa->flag |= PARS_REKEY;
- nkey = new_keys = MEM_callocN((pa->totkey + totnewkey) * (sizeof(HairKey)), "Hair subdivide keys");
- nekey = new_ekeys = MEM_callocN((pa->totkey + totnewkey) * (sizeof(PTCacheEditKey)), "Hair subdivide edit keys");
+ nkey = new_keys = MEM_callocN((pa->totkey + totnewkey) * (sizeof(HairKey)),
+ "Hair subdivide keys");
+ nekey = new_ekeys = MEM_callocN((pa->totkey + totnewkey) * (sizeof(PTCacheEditKey)),
+ "Hair subdivide edit keys");
- key = pa->hair;
- endtime = key[pa->totkey - 1].time;
+ key = pa->hair;
+ endtime = key[pa->totkey - 1].time;
- for (k = 0, ekey = point->keys; k < pa->totkey - 1; k++, key++, ekey++) {
+ for (k = 0, ekey = point->keys; k < pa->totkey - 1; k++, key++, ekey++) {
- memcpy(nkey, key, sizeof(HairKey));
- memcpy(nekey, ekey, sizeof(PTCacheEditKey));
+ memcpy(nkey, key, sizeof(HairKey));
+ memcpy(nekey, ekey, sizeof(PTCacheEditKey));
- nekey->co = nkey->co;
- nekey->time = &nkey->time;
+ nekey->co = nkey->co;
+ nekey->time = &nkey->time;
- nkey++;
- nekey++;
+ nkey++;
+ nekey++;
- if (ekey->flag & PEK_SELECT && (ekey + 1)->flag & PEK_SELECT) {
- nkey->time = (key->time + (key + 1)->time) * 0.5f;
- state.time = (endtime != 0.0f) ? nkey->time / endtime : 0.0f;
- psys_get_particle_on_path(&sim, pa_index, &state, 0);
- copy_v3_v3(nkey->co, state.co);
+ if (ekey->flag & PEK_SELECT && (ekey + 1)->flag & PEK_SELECT) {
+ nkey->time = (key->time + (key + 1)->time) * 0.5f;
+ state.time = (endtime != 0.0f) ? nkey->time / endtime : 0.0f;
+ psys_get_particle_on_path(&sim, pa_index, &state, 0);
+ copy_v3_v3(nkey->co, state.co);
- nekey->co = nkey->co;
- nekey->time = &nkey->time;
- nekey->flag |= PEK_SELECT;
- if (!(psys->flag & PSYS_GLOBAL_HAIR))
- nekey->flag |= PEK_USE_WCO;
+ nekey->co = nkey->co;
+ nekey->time = &nkey->time;
+ nekey->flag |= PEK_SELECT;
+ if (!(psys->flag & PSYS_GLOBAL_HAIR))
+ nekey->flag |= PEK_USE_WCO;
- nekey++;
- nkey++;
- }
- }
- /*tip still not copied*/
- memcpy(nkey, key, sizeof(HairKey));
- memcpy(nekey, ekey, sizeof(PTCacheEditKey));
+ nekey++;
+ nkey++;
+ }
+ }
+ /*tip still not copied*/
+ memcpy(nkey, key, sizeof(HairKey));
+ memcpy(nekey, ekey, sizeof(PTCacheEditKey));
- nekey->co = nkey->co;
- nekey->time = &nkey->time;
+ nekey->co = nkey->co;
+ nekey->time = &nkey->time;
- if (pa->hair)
- MEM_freeN(pa->hair);
- pa->hair = new_keys;
+ if (pa->hair)
+ MEM_freeN(pa->hair);
+ pa->hair = new_keys;
- if (point->keys)
- MEM_freeN(point->keys);
- point->keys = new_ekeys;
+ if (point->keys)
+ MEM_freeN(point->keys);
+ point->keys = new_ekeys;
- point->totkey = pa->totkey = pa->totkey + totnewkey;
- point->flag |= PEP_EDIT_RECALC;
- pa->flag &= ~PARS_REKEY;
+ point->totkey = pa->totkey = pa->totkey + totnewkey;
+ point->flag |= PEP_EDIT_RECALC;
+ pa->flag &= ~PARS_REKEY;
}
static int subdivide_exec(bContext *C, wmOperator *UNUSED(op))
{
- PEData data;
+ PEData data;
- PE_set_data(C, &data);
- foreach_point(&data, subdivide_particle);
+ PE_set_data(C, &data);
+ foreach_point(&data, subdivide_particle);
- recalc_lengths(data.edit);
- PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
- PE_update_object(data.depsgraph, data.scene, data.ob, 1);
- DEG_id_tag_update(&data.ob->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
+ recalc_lengths(data.edit);
+ PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
+ PE_update_object(data.depsgraph, data.scene, data.ob, 1);
+ DEG_id_tag_update(&data.ob->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_subdivide(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Subdivide";
- ot->idname = "PARTICLE_OT_subdivide";
- ot->description = "Subdivide selected particles segments (adds keys)";
+ /* identifiers */
+ ot->name = "Subdivide";
+ ot->idname = "PARTICLE_OT_subdivide";
+ ot->description = "Subdivide selected particles segments (adds keys)";
- /* api callbacks */
- ot->exec = subdivide_exec;
- ot->poll = PE_hair_poll;
+ /* api callbacks */
+ ot->exec = subdivide_exec;
+ ot->poll = PE_hair_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/************************ remove doubles opertor *********************/
static int remove_doubles_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd_eval;
- KDTree_3d *tree;
- KDTreeNearest_3d nearest[10];
- POINT_P;
- float mat[4][4], co[3], threshold = RNA_float_get(op->ptr, "threshold");
- int n, totn, removed, totremoved;
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ ParticleSystem *psys = edit->psys;
+ ParticleSystemModifierData *psmd_eval;
+ KDTree_3d *tree;
+ KDTreeNearest_3d nearest[10];
+ POINT_P;
+ float mat[4][4], co[3], threshold = RNA_float_get(op->ptr, "threshold");
+ int n, totn, removed, totremoved;
- if (psys->flag & PSYS_GLOBAL_HAIR)
- return OPERATOR_CANCELLED;
+ if (psys->flag & PSYS_GLOBAL_HAIR)
+ return OPERATOR_CANCELLED;
- edit = psys->edit;
- psmd_eval = edit->psmd_eval;
- totremoved = 0;
+ edit = psys->edit;
+ psmd_eval = edit->psmd_eval;
+ totremoved = 0;
- do {
- removed = 0;
+ do {
+ removed = 0;
- tree = BLI_kdtree_3d_new(psys->totpart);
+ tree = BLI_kdtree_3d_new(psys->totpart);
- /* insert particles into kd tree */
- LOOP_SELECTED_POINTS {
- psys_mat_hair_to_object(ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
- copy_v3_v3(co, point->keys->co);
- mul_m4_v3(mat, co);
- BLI_kdtree_3d_insert(tree, p, co);
- }
+ /* insert particles into kd tree */
+ LOOP_SELECTED_POINTS
+ {
+ psys_mat_hair_to_object(
+ ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
+ copy_v3_v3(co, point->keys->co);
+ mul_m4_v3(mat, co);
+ BLI_kdtree_3d_insert(tree, p, co);
+ }
- BLI_kdtree_3d_balance(tree);
+ BLI_kdtree_3d_balance(tree);
- /* tag particles to be removed */
- LOOP_SELECTED_POINTS {
- psys_mat_hair_to_object(ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
- copy_v3_v3(co, point->keys->co);
- mul_m4_v3(mat, co);
+ /* tag particles to be removed */
+ LOOP_SELECTED_POINTS
+ {
+ psys_mat_hair_to_object(
+ ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
+ copy_v3_v3(co, point->keys->co);
+ mul_m4_v3(mat, co);
- totn = BLI_kdtree_3d_find_nearest_n(tree, co, nearest, 10);
+ totn = BLI_kdtree_3d_find_nearest_n(tree, co, nearest, 10);
- for (n = 0; n < totn; n++) {
- /* this needs a custom threshold still */
- if (nearest[n].index > p && nearest[n].dist < threshold) {
- if (!(point->flag & PEP_TAG)) {
- point->flag |= PEP_TAG;
- removed++;
- }
- }
- }
- }
+ for (n = 0; n < totn; n++) {
+ /* this needs a custom threshold still */
+ if (nearest[n].index > p && nearest[n].dist < threshold) {
+ if (!(point->flag & PEP_TAG)) {
+ point->flag |= PEP_TAG;
+ removed++;
+ }
+ }
+ }
+ }
- BLI_kdtree_3d_free(tree);
+ BLI_kdtree_3d_free(tree);
- /* remove tagged particles - don't do mirror here! */
- remove_tagged_particles(ob, psys, 0);
- totremoved += removed;
- } while (removed);
+ /* remove tagged particles - don't do mirror here! */
+ remove_tagged_particles(ob, psys, 0);
+ totremoved += removed;
+ } while (removed);
- if (totremoved == 0)
- return OPERATOR_CANCELLED;
+ if (totremoved == 0)
+ return OPERATOR_CANCELLED;
- BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved);
+ BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_remove_doubles(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Remove Doubles";
- ot->idname = "PARTICLE_OT_remove_doubles";
- ot->description = "Remove selected particles close enough of others";
+ /* identifiers */
+ ot->name = "Remove Doubles";
+ ot->idname = "PARTICLE_OT_remove_doubles";
+ ot->description = "Remove selected particles close enough of others";
- /* api callbacks */
- ot->exec = remove_doubles_exec;
- ot->poll = PE_hair_poll;
+ /* api callbacks */
+ ot->exec = remove_doubles_exec;
+ ot->poll = PE_hair_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- RNA_def_float(ot->srna, "threshold", 0.0002f, 0.0f, FLT_MAX,
- "Merge Distance", "Threshold distance within which particles are removed", 0.00001f, 0.1f);
+ /* properties */
+ RNA_def_float(ot->srna,
+ "threshold",
+ 0.0002f,
+ 0.0f,
+ FLT_MAX,
+ "Merge Distance",
+ "Threshold distance within which particles are removed",
+ 0.00001f,
+ 0.1f);
}
-
static int weight_set_exec(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ParticleEditSettings *pset = PE_settings(scene);
- Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- ParticleSystem *psys = edit->psys;
- POINT_P;
- KEY_K;
- HairKey *hkey;
- float weight;
- ParticleBrushData *brush = &pset->brush[pset->brushtype];
- float factor = RNA_float_get(op->ptr, "factor");
+ Scene *scene = CTX_data_scene(C);
+ ParticleEditSettings *pset = PE_settings(scene);
+ Object *ob = CTX_data_active_object(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ ParticleSystem *psys = edit->psys;
+ POINT_P;
+ KEY_K;
+ HairKey *hkey;
+ float weight;
+ ParticleBrushData *brush = &pset->brush[pset->brushtype];
+ float factor = RNA_float_get(op->ptr, "factor");
- weight = brush->strength;
- edit = psys->edit;
+ weight = brush->strength;
+ edit = psys->edit;
- LOOP_SELECTED_POINTS {
- ParticleData *pa = psys->particles + p;
+ LOOP_SELECTED_POINTS
+ {
+ ParticleData *pa = psys->particles + p;
- LOOP_SELECTED_KEYS {
- hkey = pa->hair + k;
- hkey->weight = interpf(weight, hkey->weight, factor);
- }
- }
+ LOOP_SELECTED_KEYS
+ {
+ hkey = pa->hair + k;
+ hkey->weight = interpf(weight, hkey->weight, factor);
+ }
+ }
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_weight_set(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Weight Set";
- ot->idname = "PARTICLE_OT_weight_set";
- ot->description = "Set the weight of selected keys";
+ /* identifiers */
+ ot->name = "Weight Set";
+ ot->idname = "PARTICLE_OT_weight_set";
+ ot->description = "Set the weight of selected keys";
- /* api callbacks */
- ot->exec = weight_set_exec;
- ot->poll = PE_hair_poll;
+ /* api callbacks */
+ ot->exec = weight_set_exec;
+ ot->poll = PE_hair_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_float(ot->srna, "factor", 1, 0, 1, "Factor",
- "Interpolation factor between current brush weight, and keys' weights", 0, 1);
+ RNA_def_float(ot->srna,
+ "factor",
+ 1,
+ 0,
+ 1,
+ "Factor",
+ "Interpolation factor between current brush weight, and keys' weights",
+ 0,
+ 1);
}
/************************ cursor drawing *******************************/
static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata))
{
- Scene *scene = CTX_data_scene(C);
- ParticleEditSettings *pset = PE_settings(scene);
- ParticleBrushData *brush;
+ Scene *scene = CTX_data_scene(C);
+ ParticleEditSettings *pset = PE_settings(scene);
+ ParticleBrushData *brush;
- if (!WM_toolsystem_active_tool_is_brush(C)) {
- return;
- }
+ if (!WM_toolsystem_active_tool_is_brush(C)) {
+ return;
+ }
- brush = &pset->brush[pset->brushtype];
+ brush = &pset->brush[pset->brushtype];
- if (brush) {
- uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ if (brush) {
+ uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4ub(255, 255, 255, 128);
+ immUniformColor4ub(255, 255, 255, 128);
- GPU_line_smooth(true);
- GPU_blend(true);
+ GPU_line_smooth(true);
+ GPU_blend(true);
- imm_draw_circle_wire_2d(pos, (float)x, (float)y, pe_brush_size_get(scene, brush), 40);
+ imm_draw_circle_wire_2d(pos, (float)x, (float)y, pe_brush_size_get(scene, brush), 40);
- GPU_blend(false);
- GPU_line_smooth(false);
+ GPU_blend(false);
+ GPU_line_smooth(false);
- immUnbindProgram();
- }
+ immUnbindProgram();
+ }
}
static void toggle_particle_cursor(bContext *C, int enable)
{
- ParticleEditSettings *pset = PE_settings(CTX_data_scene(C));
+ ParticleEditSettings *pset = PE_settings(CTX_data_scene(C));
- if (pset->paintcursor && !enable) {
- WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
- pset->paintcursor = NULL;
- }
- else if (enable)
- pset->paintcursor = WM_paint_cursor_activate(
- CTX_wm_manager(C),
- SPACE_VIEW3D, RGN_TYPE_WINDOW,
- PE_poll_view3d,
- brush_drawcursor,
- NULL);
+ if (pset->paintcursor && !enable) {
+ WM_paint_cursor_end(CTX_wm_manager(C), pset->paintcursor);
+ pset->paintcursor = NULL;
+ }
+ else if (enable)
+ pset->paintcursor = WM_paint_cursor_activate(
+ CTX_wm_manager(C), SPACE_VIEW3D, RGN_TYPE_WINDOW, PE_poll_view3d, brush_drawcursor, NULL);
}
/*************************** delete operator **************************/
@@ -3049,2126 +3154,2190 @@ static void toggle_particle_cursor(bContext *C, int enable)
enum { DEL_PARTICLE, DEL_KEY };
static const EnumPropertyItem delete_type_items[] = {
- {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
- {DEL_KEY, "KEY", 0, "Key", ""},
- {0, NULL, 0, NULL, NULL},
+ {DEL_PARTICLE, "PARTICLE", 0, "Particle", ""},
+ {DEL_KEY, "KEY", 0, "Key", ""},
+ {0, NULL, 0, NULL, NULL},
};
static void set_delete_particle(PEData *data, int pa_index)
{
- PTCacheEdit *edit = data->edit;
+ PTCacheEdit *edit = data->edit;
- edit->points[pa_index].flag |= PEP_TAG;
+ edit->points[pa_index].flag |= PEP_TAG;
}
-static void set_delete_particle_key(PEData *data, int pa_index, int key_index, bool UNUSED(is_inside))
+static void set_delete_particle_key(PEData *data,
+ int pa_index,
+ int key_index,
+ bool UNUSED(is_inside))
{
- PTCacheEdit *edit = data->edit;
+ PTCacheEdit *edit = data->edit;
- edit->points[pa_index].keys[key_index].flag |= PEK_TAG;
+ edit->points[pa_index].keys[key_index].flag |= PEK_TAG;
}
static int delete_exec(bContext *C, wmOperator *op)
{
- PEData data;
- int type = RNA_enum_get(op->ptr, "type");
+ PEData data;
+ int type = RNA_enum_get(op->ptr, "type");
- PE_set_data(C, &data);
+ PE_set_data(C, &data);
- if (type == DEL_KEY) {
- foreach_selected_key(&data, set_delete_particle_key);
- remove_tagged_keys(data.ob, data.edit->psys);
- recalc_lengths(data.edit);
- }
- else if (type == DEL_PARTICLE) {
- foreach_selected_point(&data, set_delete_particle);
- remove_tagged_particles(data.ob, data.edit->psys, pe_x_mirror(data.ob));
- recalc_lengths(data.edit);
- }
+ if (type == DEL_KEY) {
+ foreach_selected_key(&data, set_delete_particle_key);
+ remove_tagged_keys(data.ob, data.edit->psys);
+ recalc_lengths(data.edit);
+ }
+ else if (type == DEL_PARTICLE) {
+ foreach_selected_point(&data, set_delete_particle);
+ remove_tagged_particles(data.ob, data.edit->psys, pe_x_mirror(data.ob));
+ recalc_lengths(data.edit);
+ }
- DEG_id_tag_update(&data.ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
+ DEG_id_tag_update(&data.ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, data.ob);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_delete(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Delete";
- ot->idname = "PARTICLE_OT_delete";
- ot->description = "Delete selected particles or keys";
+ /* identifiers */
+ ot->name = "Delete";
+ ot->idname = "PARTICLE_OT_delete";
+ ot->description = "Delete selected particles or keys";
- /* api callbacks */
- ot->exec = delete_exec;
- ot->invoke = WM_menu_invoke;
- ot->poll = PE_hair_poll;
+ /* api callbacks */
+ ot->exec = delete_exec;
+ ot->invoke = WM_menu_invoke;
+ ot->poll = PE_hair_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", delete_type_items, DEL_PARTICLE, "Type", "Delete a full particle or only keys");
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna,
+ "type",
+ delete_type_items,
+ DEL_PARTICLE,
+ "Type",
+ "Delete a full particle or only keys");
}
/*************************** mirror operator **************************/
-static void PE_mirror_x(
- Scene *scene, Object *ob, int tagged)
-{
- Mesh *me = (Mesh *)(ob->data);
- ParticleSystemModifierData *psmd_eval;
- PTCacheEdit *edit = PE_get_current(scene, ob);
- ParticleSystem *psys = edit->psys;
- ParticleData *pa, *newpa, *new_pars;
- PTCacheEditPoint *newpoint, *new_points;
- POINT_P; KEY_K;
- HairKey *hkey;
- int *mirrorfaces = NULL;
- int rotation, totpart, newtotpart;
-
- if (psys->flag & PSYS_GLOBAL_HAIR)
- return;
-
- psmd_eval = edit->psmd_eval;
- if (!psmd_eval->mesh_final)
- return;
-
- const bool use_dm_final_indices = (psys->part->use_modifier_stack && !psmd_eval->mesh_final->runtime.deformed_only);
-
- /* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */
- BKE_mesh_tessface_ensure(me);
-
- /* Note: In case psys uses Mesh tessface indices, we mirror final Mesh itself, not orig mesh. Avoids an (impossible)
- * mesh -> orig -> mesh tessface indices conversion... */
- mirrorfaces = mesh_get_x_mirror_faces(ob, NULL, use_dm_final_indices ? psmd_eval->mesh_final : NULL);
-
- if (!edit->mirror_cache)
- PE_update_mirror_cache(ob, psys);
-
- totpart = psys->totpart;
- newtotpart = psys->totpart;
- LOOP_VISIBLE_POINTS {
- pa = psys->particles + p;
-
- if (!tagged) {
- if (point_is_selected(point)) {
- if (edit->mirror_cache[p] != -1) {
- /* already has a mirror, don't need to duplicate */
- PE_mirror_particle(ob, psmd_eval->mesh_final, psys, pa, NULL);
- continue;
- }
- else
- point->flag |= PEP_TAG;
- }
- }
-
- if ((point->flag & PEP_TAG) && mirrorfaces[pa->num * 2] != -1)
- newtotpart++;
- }
-
- if (newtotpart != psys->totpart) {
- MFace *mtessface = use_dm_final_indices ? psmd_eval->mesh_final->mface : me->mface;
-
- /* allocate new arrays and copy existing */
- new_pars = MEM_callocN(newtotpart * sizeof(ParticleData), "ParticleData new");
- new_points = MEM_callocN(newtotpart * sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
-
- if (psys->particles) {
- memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
- MEM_freeN(psys->particles);
- }
- psys->particles = new_pars;
-
- if (edit->points) {
- memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint));
- MEM_freeN(edit->points);
- }
- edit->points = new_points;
-
- if (edit->mirror_cache) {
- MEM_freeN(edit->mirror_cache);
- edit->mirror_cache = NULL;
- }
-
- edit->totpoint = psys->totpart = newtotpart;
-
- /* create new elements */
- newpa = psys->particles + totpart;
- newpoint = edit->points + totpart;
-
- for (p = 0, point = edit->points; p < totpart; p++, point++) {
- pa = psys->particles + p;
- const int pa_num = pa->num;
-
- if (point->flag & PEP_HIDE)
- continue;
-
- if (!(point->flag & PEP_TAG) || mirrorfaces[pa_num * 2] == -1)
- continue;
-
- /* duplicate */
- *newpa = *pa;
- *newpoint = *point;
- if (pa->hair) newpa->hair = MEM_dupallocN(pa->hair);
- if (point->keys) newpoint->keys = MEM_dupallocN(point->keys);
-
- /* rotate weights according to vertex index rotation */
- rotation = mirrorfaces[pa_num * 2 + 1];
- newpa->fuv[0] = pa->fuv[2];
- newpa->fuv[1] = pa->fuv[1];
- newpa->fuv[2] = pa->fuv[0];
- newpa->fuv[3] = pa->fuv[3];
- while (rotation--) {
- if (mtessface[pa_num].v4) {
- SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3]);
- }
- else {
- SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2]);
- }
- }
-
- /* assign face index */
- /* NOTE: mesh_get_x_mirror_faces generates -1 for non-found mirror, same as DMCACHE_NOTFOUND... */
- newpa->num = mirrorfaces[pa_num * 2];
-
- if (use_dm_final_indices) {
- newpa->num_dmcache = DMCACHE_ISCHILD;
- }
- else {
- newpa->num_dmcache = psys_particle_dm_face_lookup(
- psmd_eval->mesh_final, psmd_eval->mesh_original, newpa->num, newpa->fuv, NULL);
- }
-
- /* update edit key pointers */
- key = newpoint->keys;
- for (k = 0, hkey = newpa->hair; k < newpa->totkey; k++, hkey++, key++) {
- key->co = hkey->co;
- key->time = &hkey->time;
- }
-
- /* map key positions as mirror over x axis */
- PE_mirror_particle(ob, psmd_eval->mesh_final, psys, pa, newpa);
-
- newpa++;
- newpoint++;
- }
- }
-
- LOOP_POINTS {
- point->flag &= ~PEP_TAG;
- }
-
- MEM_freeN(mirrorfaces);
+static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
+{
+ Mesh *me = (Mesh *)(ob->data);
+ ParticleSystemModifierData *psmd_eval;
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ ParticleSystem *psys = edit->psys;
+ ParticleData *pa, *newpa, *new_pars;
+ PTCacheEditPoint *newpoint, *new_points;
+ POINT_P;
+ KEY_K;
+ HairKey *hkey;
+ int *mirrorfaces = NULL;
+ int rotation, totpart, newtotpart;
+
+ if (psys->flag & PSYS_GLOBAL_HAIR)
+ return;
+
+ psmd_eval = edit->psmd_eval;
+ if (!psmd_eval->mesh_final)
+ return;
+
+ const bool use_dm_final_indices = (psys->part->use_modifier_stack &&
+ !psmd_eval->mesh_final->runtime.deformed_only);
+
+ /* NOTE: this is not nice to use tessfaces but hard to avoid since pa->num uses tessfaces */
+ BKE_mesh_tessface_ensure(me);
+
+ /* Note: In case psys uses Mesh tessface indices, we mirror final Mesh itself, not orig mesh. Avoids an (impossible)
+ * mesh -> orig -> mesh tessface indices conversion... */
+ mirrorfaces = mesh_get_x_mirror_faces(
+ ob, NULL, use_dm_final_indices ? psmd_eval->mesh_final : NULL);
+
+ if (!edit->mirror_cache)
+ PE_update_mirror_cache(ob, psys);
+
+ totpart = psys->totpart;
+ newtotpart = psys->totpart;
+ LOOP_VISIBLE_POINTS
+ {
+ pa = psys->particles + p;
+
+ if (!tagged) {
+ if (point_is_selected(point)) {
+ if (edit->mirror_cache[p] != -1) {
+ /* already has a mirror, don't need to duplicate */
+ PE_mirror_particle(ob, psmd_eval->mesh_final, psys, pa, NULL);
+ continue;
+ }
+ else
+ point->flag |= PEP_TAG;
+ }
+ }
+
+ if ((point->flag & PEP_TAG) && mirrorfaces[pa->num * 2] != -1)
+ newtotpart++;
+ }
+
+ if (newtotpart != psys->totpart) {
+ MFace *mtessface = use_dm_final_indices ? psmd_eval->mesh_final->mface : me->mface;
+
+ /* allocate new arrays and copy existing */
+ new_pars = MEM_callocN(newtotpart * sizeof(ParticleData), "ParticleData new");
+ new_points = MEM_callocN(newtotpart * sizeof(PTCacheEditPoint), "PTCacheEditPoint new");
+
+ if (psys->particles) {
+ memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
+ MEM_freeN(psys->particles);
+ }
+ psys->particles = new_pars;
+
+ if (edit->points) {
+ memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint));
+ MEM_freeN(edit->points);
+ }
+ edit->points = new_points;
+
+ if (edit->mirror_cache) {
+ MEM_freeN(edit->mirror_cache);
+ edit->mirror_cache = NULL;
+ }
+
+ edit->totpoint = psys->totpart = newtotpart;
+
+ /* create new elements */
+ newpa = psys->particles + totpart;
+ newpoint = edit->points + totpart;
+
+ for (p = 0, point = edit->points; p < totpart; p++, point++) {
+ pa = psys->particles + p;
+ const int pa_num = pa->num;
+
+ if (point->flag & PEP_HIDE)
+ continue;
+
+ if (!(point->flag & PEP_TAG) || mirrorfaces[pa_num * 2] == -1)
+ continue;
+
+ /* duplicate */
+ *newpa = *pa;
+ *newpoint = *point;
+ if (pa->hair)
+ newpa->hair = MEM_dupallocN(pa->hair);
+ if (point->keys)
+ newpoint->keys = MEM_dupallocN(point->keys);
+
+ /* rotate weights according to vertex index rotation */
+ rotation = mirrorfaces[pa_num * 2 + 1];
+ newpa->fuv[0] = pa->fuv[2];
+ newpa->fuv[1] = pa->fuv[1];
+ newpa->fuv[2] = pa->fuv[0];
+ newpa->fuv[3] = pa->fuv[3];
+ while (rotation--) {
+ if (mtessface[pa_num].v4) {
+ SHIFT4(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2], newpa->fuv[3]);
+ }
+ else {
+ SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2]);
+ }
+ }
+
+ /* assign face index */
+ /* NOTE: mesh_get_x_mirror_faces generates -1 for non-found mirror, same as DMCACHE_NOTFOUND... */
+ newpa->num = mirrorfaces[pa_num * 2];
+
+ if (use_dm_final_indices) {
+ newpa->num_dmcache = DMCACHE_ISCHILD;
+ }
+ else {
+ newpa->num_dmcache = psys_particle_dm_face_lookup(
+ psmd_eval->mesh_final, psmd_eval->mesh_original, newpa->num, newpa->fuv, NULL);
+ }
+
+ /* update edit key pointers */
+ key = newpoint->keys;
+ for (k = 0, hkey = newpa->hair; k < newpa->totkey; k++, hkey++, key++) {
+ key->co = hkey->co;
+ key->time = &hkey->time;
+ }
+
+ /* map key positions as mirror over x axis */
+ PE_mirror_particle(ob, psmd_eval->mesh_final, psys, pa, newpa);
+
+ newpa++;
+ newpoint++;
+ }
+ }
+
+ LOOP_POINTS
+ {
+ point->flag &= ~PEP_TAG;
+ }
+
+ MEM_freeN(mirrorfaces);
}
static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
{
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
- PE_mirror_x(scene, ob, 0);
+ PE_mirror_x(scene, ob, 0);
- update_world_cos(CTX_data_depsgraph(C), ob, edit);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ update_world_cos(CTX_data_depsgraph(C), ob, edit);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_mirror(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Mirror";
- ot->idname = "PARTICLE_OT_mirror";
- ot->description = "Duplicate and mirror the selected particles along the local X axis";
+ /* identifiers */
+ ot->name = "Mirror";
+ ot->idname = "PARTICLE_OT_mirror";
+ ot->description = "Duplicate and mirror the selected particles along the local X axis";
- /* api callbacks */
- ot->exec = mirror_exec;
- ot->poll = PE_hair_poll;
+ /* api callbacks */
+ ot->exec = mirror_exec;
+ ot->poll = PE_hair_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/************************* brush edit callbacks ********************/
-static void brush_comb(
- PEData *data,
- float UNUSED(mat[4][4]),
- float imat[4][4],
- int point_index,
- int key_index,
- PTCacheEditKey *key,
- float mouse_distance)
+static void brush_comb(PEData *data,
+ float UNUSED(mat[4][4]),
+ float imat[4][4],
+ int point_index,
+ int key_index,
+ PTCacheEditKey *key,
+ float mouse_distance)
{
- ParticleEditSettings *pset = PE_settings(data->scene);
- float cvec[3], fac;
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ float cvec[3], fac;
- if (pset->flag & PE_LOCK_FIRST && key_index == 0) return;
+ if (pset->flag & PE_LOCK_FIRST && key_index == 0)
+ return;
- fac = (float)pow((double)(1.0f - mouse_distance / data->rad), (double)data->combfac);
+ fac = (float)pow((double)(1.0f - mouse_distance / data->rad), (double)data->combfac);
- copy_v3_v3(cvec, data->dvec);
- mul_mat3_m4_v3(imat, cvec);
- mul_v3_fl(cvec, fac);
- add_v3_v3(key->co, cvec);
+ copy_v3_v3(cvec, data->dvec);
+ mul_mat3_m4_v3(imat, cvec);
+ mul_v3_fl(cvec, fac);
+ add_v3_v3(key->co, cvec);
- (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
+ (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
}
static void brush_cut(PEData *data, int pa_index)
{
- PTCacheEdit *edit = data->edit;
- ARegion *ar = data->vc.ar;
- Object *ob = data->ob;
- ParticleEditSettings *pset = PE_settings(data->scene);
- ParticleCacheKey *key = edit->pathcache[pa_index];
- float rad2, cut_time = 1.0;
- float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
- int k, cut, keys = (int)pow(2.0, (double)pset->draw_step);
- int screen_co[2];
+ PTCacheEdit *edit = data->edit;
+ ARegion *ar = data->vc.ar;
+ Object *ob = data->ob;
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ ParticleCacheKey *key = edit->pathcache[pa_index];
+ float rad2, cut_time = 1.0;
+ float x0, x1, v0, v1, o0, o1, xo0, xo1, d, dv;
+ int k, cut, keys = (int)pow(2.0, (double)pset->draw_step);
+ int screen_co[2];
- BLI_assert(data->rng != NULL);
- /* blunt scissors */
- if (BLI_rng_get_float(data->rng) > data->cutfac) {
- return;
- }
+ BLI_assert(data->rng != NULL);
+ /* blunt scissors */
+ if (BLI_rng_get_float(data->rng) > data->cutfac) {
+ return;
+ }
- /* don't cut hidden */
- if (edit->points[pa_index].flag & PEP_HIDE)
- return;
+ /* don't cut hidden */
+ if (edit->points[pa_index].flag & PEP_HIDE)
+ return;
- if (ED_view3d_project_int_global(ar, key->co, screen_co, V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK)
- return;
+ if (ED_view3d_project_int_global(ar, key->co, screen_co, V3D_PROJ_TEST_CLIP_NEAR) !=
+ V3D_PROJ_RET_OK)
+ return;
- rad2 = data->rad * data->rad;
+ rad2 = data->rad * data->rad;
- cut = 0;
+ cut = 0;
- x0 = (float)screen_co[0];
- x1 = (float)screen_co[1];
+ x0 = (float)screen_co[0];
+ x1 = (float)screen_co[1];
- o0 = (float)data->mval[0];
- o1 = (float)data->mval[1];
+ o0 = (float)data->mval[0];
+ o1 = (float)data->mval[1];
- xo0 = x0 - o0;
- xo1 = x1 - o1;
+ xo0 = x0 - o0;
+ xo1 = x1 - o1;
- /* check if root is inside circle */
- if (xo0 * xo0 + xo1 * xo1 < rad2 && key_test_depth(data, key->co, screen_co)) {
- cut_time = -1.0f;
- cut = 1;
- }
- else {
- /* calculate path time closest to root that was inside the circle */
- for (k = 1, key++; k <= keys; k++, key++) {
+ /* check if root is inside circle */
+ if (xo0 * xo0 + xo1 * xo1 < rad2 && key_test_depth(data, key->co, screen_co)) {
+ cut_time = -1.0f;
+ cut = 1;
+ }
+ else {
+ /* calculate path time closest to root that was inside the circle */
+ for (k = 1, key++; k <= keys; k++, key++) {
- if ((ED_view3d_project_int_global(ar, key->co, screen_co, V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK) ||
- key_test_depth(data, key->co, screen_co) == 0)
- {
- x0 = (float)screen_co[0];
- x1 = (float)screen_co[1];
+ if ((ED_view3d_project_int_global(ar, key->co, screen_co, V3D_PROJ_TEST_CLIP_NEAR) !=
+ V3D_PROJ_RET_OK) ||
+ key_test_depth(data, key->co, screen_co) == 0) {
+ x0 = (float)screen_co[0];
+ x1 = (float)screen_co[1];
- xo0 = x0 - o0;
- xo1 = x1 - o1;
- continue;
- }
+ xo0 = x0 - o0;
+ xo1 = x1 - o1;
+ continue;
+ }
- v0 = (float)screen_co[0] - x0;
- v1 = (float)screen_co[1] - x1;
+ v0 = (float)screen_co[0] - x0;
+ v1 = (float)screen_co[1] - x1;
- dv = v0 * v0 + v1 * v1;
+ dv = v0 * v0 + v1 * v1;
- d = (v0 * xo1 - v1 * xo0);
+ d = (v0 * xo1 - v1 * xo0);
- d = dv * rad2 - d * d;
+ d = dv * rad2 - d * d;
- if (d > 0.0f) {
- d = sqrtf(d);
+ if (d > 0.0f) {
+ d = sqrtf(d);
- cut_time = -(v0 * xo0 + v1 * xo1 + d);
+ cut_time = -(v0 * xo0 + v1 * xo1 + d);
- if (cut_time > 0.0f) {
- cut_time /= dv;
+ if (cut_time > 0.0f) {
+ cut_time /= dv;
- if (cut_time < 1.0f) {
- cut_time += (float)(k - 1);
- cut_time /= (float)keys;
- cut = 1;
- break;
- }
- }
- }
+ if (cut_time < 1.0f) {
+ cut_time += (float)(k - 1);
+ cut_time /= (float)keys;
+ cut = 1;
+ break;
+ }
+ }
+ }
- x0 = (float)screen_co[0];
- x1 = (float)screen_co[1];
+ x0 = (float)screen_co[0];
+ x1 = (float)screen_co[1];
- xo0 = x0 - o0;
- xo1 = x1 - o1;
- }
- }
+ xo0 = x0 - o0;
+ xo1 = x1 - o1;
+ }
+ }
- if (cut) {
- if (cut_time < 0.0f) {
- edit->points[pa_index].flag |= PEP_TAG;
- }
- else {
- rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
- edit->points[pa_index].flag |= PEP_EDIT_RECALC;
- }
- }
+ if (cut) {
+ if (cut_time < 0.0f) {
+ edit->points[pa_index].flag |= PEP_TAG;
+ }
+ else {
+ rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
+ edit->points[pa_index].flag |= PEP_EDIT_RECALC;
+ }
+ }
}
static void brush_length(PEData *data, int point_index, float UNUSED(mouse_distance))
{
- PTCacheEdit *edit = data->edit;
- PTCacheEditPoint *point = edit->points + point_index;
- KEY_K;
- float dvec[3], pvec[3] = {0.0f, 0.0f, 0.0f};
+ PTCacheEdit *edit = data->edit;
+ PTCacheEditPoint *point = edit->points + point_index;
+ KEY_K;
+ float dvec[3], pvec[3] = {0.0f, 0.0f, 0.0f};
- LOOP_KEYS {
- if (k == 0) {
- copy_v3_v3(pvec, key->co);
- }
- else {
- sub_v3_v3v3(dvec, key->co, pvec);
- copy_v3_v3(pvec, key->co);
- mul_v3_fl(dvec, data->growfac);
- add_v3_v3v3(key->co, (key - 1)->co, dvec);
- }
- }
+ LOOP_KEYS
+ {
+ if (k == 0) {
+ copy_v3_v3(pvec, key->co);
+ }
+ else {
+ sub_v3_v3v3(dvec, key->co, pvec);
+ copy_v3_v3(pvec, key->co);
+ mul_v3_fl(dvec, data->growfac);
+ add_v3_v3v3(key->co, (key - 1)->co, dvec);
+ }
+ }
- point->flag |= PEP_EDIT_RECALC;
+ point->flag |= PEP_EDIT_RECALC;
}
static void brush_puff(PEData *data, int point_index, float mouse_distance)
{
- PTCacheEdit *edit = data->edit;
- ParticleSystem *psys = edit->psys;
- PTCacheEditPoint *point = edit->points + point_index;
- KEY_K;
- float mat[4][4], imat[4][4];
-
- float onor_prev[3]; /* previous normal (particle-space) */
- float ofs_prev[3]; /* accumulate offset for puff_volume (particle-space) */
- float co_root[3], no_root[3]; /* root location and normal (global-space) */
- float co_prev[3], co[3]; /* track key coords as we loop (global-space) */
- float fac = 0.0f, length_accum = 0.0f;
- bool puff_volume = false;
- bool changed = false;
-
- zero_v3(ofs_prev);
-
- {
- ParticleEditSettings *pset = PE_settings(data->scene);
- ParticleBrushData *brush = &pset->brush[pset->brushtype];
- puff_volume = (brush->flag & PE_BRUSH_DATA_PUFF_VOLUME) != 0;
- }
-
- if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
- psys_mat_hair_to_global(data->ob, data->mesh, psys->part->from, psys->particles + point_index, mat);
- invert_m4_m4(imat, mat);
- }
- else {
- unit_m4(mat);
- unit_m4(imat);
- }
-
- LOOP_KEYS {
- float kco[3];
-
- if (k == 0) {
- /* find root coordinate and normal on emitter */
- copy_v3_v3(co, key->co);
- mul_m4_v3(mat, co);
-
- /* use 'kco' as the object space version of worldspace 'co',
- * ob->imat is set before calling */
- mul_v3_m4v3(kco, data->ob->imat, co);
-
- point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL);
- if (point_index == -1) return;
-
- copy_v3_v3(co_root, co);
- copy_v3_v3(no_root, &edit->emitter_cosnos[point_index * 6 + 3]);
- mul_mat3_m4_v3(data->ob->obmat, no_root); /* normal into global-space */
- normalize_v3(no_root);
-
- if (puff_volume) {
- copy_v3_v3(onor_prev, no_root);
- mul_mat3_m4_v3(imat, onor_prev); /* global-space into particle space */
- normalize_v3(onor_prev);
- }
-
- fac = (float)pow((double)(1.0f - mouse_distance / data->rad), (double)data->pufffac);
- fac *= 0.025f;
- if (data->invert)
- fac = -fac;
- }
- else {
- /* compute position as if hair was standing up straight.
- * */
- float length;
- copy_v3_v3(co_prev, co);
- copy_v3_v3(co, key->co);
- mul_m4_v3(mat, co);
- length = len_v3v3(co_prev, co);
- length_accum += length;
-
- if ((data->select == 0 || (key->flag & PEK_SELECT)) && !(key->flag & PEK_HIDE)) {
- float dco[3]; /* delta temp var */
-
- madd_v3_v3v3fl(kco, co_root, no_root, length_accum);
-
- /* blend between the current and straight position */
- sub_v3_v3v3(dco, kco, co);
- madd_v3_v3fl(co, dco, fac);
- /* keep the same distance from the root or we get glitches [#35406] */
- dist_ensure_v3_v3fl(co, co_root, length_accum);
-
- /* re-use dco to compare before and after translation and add to the offset */
- copy_v3_v3(dco, key->co);
-
- mul_v3_m4v3(key->co, imat, co);
-
- if (puff_volume) {
- /* accumulate the total distance moved to apply to unselected
- * keys that come after */
- sub_v3_v3v3(ofs_prev, key->co, dco);
- }
- changed = true;
- }
- else {
-
- if (puff_volume) {
+ PTCacheEdit *edit = data->edit;
+ ParticleSystem *psys = edit->psys;
+ PTCacheEditPoint *point = edit->points + point_index;
+ KEY_K;
+ float mat[4][4], imat[4][4];
+
+ float onor_prev[3]; /* previous normal (particle-space) */
+ float ofs_prev[3]; /* accumulate offset for puff_volume (particle-space) */
+ float co_root[3], no_root[3]; /* root location and normal (global-space) */
+ float co_prev[3], co[3]; /* track key coords as we loop (global-space) */
+ float fac = 0.0f, length_accum = 0.0f;
+ bool puff_volume = false;
+ bool changed = false;
+
+ zero_v3(ofs_prev);
+
+ {
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ ParticleBrushData *brush = &pset->brush[pset->brushtype];
+ puff_volume = (brush->flag & PE_BRUSH_DATA_PUFF_VOLUME) != 0;
+ }
+
+ if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) {
+ psys_mat_hair_to_global(
+ data->ob, data->mesh, psys->part->from, psys->particles + point_index, mat);
+ invert_m4_m4(imat, mat);
+ }
+ else {
+ unit_m4(mat);
+ unit_m4(imat);
+ }
+
+ LOOP_KEYS
+ {
+ float kco[3];
+
+ if (k == 0) {
+ /* find root coordinate and normal on emitter */
+ copy_v3_v3(co, key->co);
+ mul_m4_v3(mat, co);
+
+ /* use 'kco' as the object space version of worldspace 'co',
+ * ob->imat is set before calling */
+ mul_v3_m4v3(kco, data->ob->imat, co);
+
+ point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL);
+ if (point_index == -1)
+ return;
+
+ copy_v3_v3(co_root, co);
+ copy_v3_v3(no_root, &edit->emitter_cosnos[point_index * 6 + 3]);
+ mul_mat3_m4_v3(data->ob->obmat, no_root); /* normal into global-space */
+ normalize_v3(no_root);
+
+ if (puff_volume) {
+ copy_v3_v3(onor_prev, no_root);
+ mul_mat3_m4_v3(imat, onor_prev); /* global-space into particle space */
+ normalize_v3(onor_prev);
+ }
+
+ fac = (float)pow((double)(1.0f - mouse_distance / data->rad), (double)data->pufffac);
+ fac *= 0.025f;
+ if (data->invert)
+ fac = -fac;
+ }
+ else {
+ /* compute position as if hair was standing up straight.
+ * */
+ float length;
+ copy_v3_v3(co_prev, co);
+ copy_v3_v3(co, key->co);
+ mul_m4_v3(mat, co);
+ length = len_v3v3(co_prev, co);
+ length_accum += length;
+
+ if ((data->select == 0 || (key->flag & PEK_SELECT)) && !(key->flag & PEK_HIDE)) {
+ float dco[3]; /* delta temp var */
+
+ madd_v3_v3v3fl(kco, co_root, no_root, length_accum);
+
+ /* blend between the current and straight position */
+ sub_v3_v3v3(dco, kco, co);
+ madd_v3_v3fl(co, dco, fac);
+ /* keep the same distance from the root or we get glitches [#35406] */
+ dist_ensure_v3_v3fl(co, co_root, length_accum);
+
+ /* re-use dco to compare before and after translation and add to the offset */
+ copy_v3_v3(dco, key->co);
+
+ mul_v3_m4v3(key->co, imat, co);
+
+ if (puff_volume) {
+ /* accumulate the total distance moved to apply to unselected
+ * keys that come after */
+ sub_v3_v3v3(ofs_prev, key->co, dco);
+ }
+ changed = true;
+ }
+ else {
+
+ if (puff_volume) {
#if 0
- /* this is simple but looks bad, adds annoying kinks */
- add_v3_v3(key->co, ofs);
+ /* this is simple but looks bad, adds annoying kinks */
+ add_v3_v3(key->co, ofs);
#else
- /* translate (not rotate) the rest of the hair if its not selected */
- {
-#if 0 /* kindof works but looks worse then what's below */
-
- /* Move the unselected point on a vector based on the
- * hair direction and the offset */
- float c1[3], c2[3];
- sub_v3_v3v3(dco, lastco, co);
- mul_mat3_m4_v3(imat, dco); /* into particle space */
-
- /* move the point along a vector perpendicular to the
- * hairs direction, reduces odd kinks, */
- cross_v3_v3v3(c1, ofs, dco);
- cross_v3_v3v3(c2, c1, dco);
- normalize_v3(c2);
- mul_v3_fl(c2, len_v3(ofs));
- add_v3_v3(key->co, c2);
-#else
- /* Move the unselected point on a vector based on the
- * the normal of the closest geometry */
- float oco[3], onor[3];
- copy_v3_v3(oco, key->co);
- mul_m4_v3(mat, oco);
-
- /* use 'kco' as the object space version of worldspace 'co',
- * ob->imat is set before calling */
- mul_v3_m4v3(kco, data->ob->imat, oco);
-
- point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL);
- if (point_index != -1) {
- copy_v3_v3(onor, &edit->emitter_cosnos[point_index * 6 + 3]);
- mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */
- mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */
- normalize_v3(onor);
- }
- else {
- copy_v3_v3(onor, onor_prev);
- }
-
- if (!is_zero_v3(ofs_prev)) {
- mul_v3_fl(onor, len_v3(ofs_prev));
-
- add_v3_v3(key->co, onor);
- }
-
- copy_v3_v3(onor_prev, onor);
-#endif
- }
+ /* translate (not rotate) the rest of the hair if its not selected */
+ {
+# if 0 /* kindof works but looks worse then what's below */
+
+ /* Move the unselected point on a vector based on the
+ * hair direction and the offset */
+ float c1[3], c2[3];
+ sub_v3_v3v3(dco, lastco, co);
+ mul_mat3_m4_v3(imat, dco); /* into particle space */
+
+ /* move the point along a vector perpendicular to the
+ * hairs direction, reduces odd kinks, */
+ cross_v3_v3v3(c1, ofs, dco);
+ cross_v3_v3v3(c2, c1, dco);
+ normalize_v3(c2);
+ mul_v3_fl(c2, len_v3(ofs));
+ add_v3_v3(key->co, c2);
+# else
+ /* Move the unselected point on a vector based on the
+ * the normal of the closest geometry */
+ float oco[3], onor[3];
+ copy_v3_v3(oco, key->co);
+ mul_m4_v3(mat, oco);
+
+ /* use 'kco' as the object space version of worldspace 'co',
+ * ob->imat is set before calling */
+ mul_v3_m4v3(kco, data->ob->imat, oco);
+
+ point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL);
+ if (point_index != -1) {
+ copy_v3_v3(onor, &edit->emitter_cosnos[point_index * 6 + 3]);
+ mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */
+ mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */
+ normalize_v3(onor);
+ }
+ else {
+ copy_v3_v3(onor, onor_prev);
+ }
+
+ if (!is_zero_v3(ofs_prev)) {
+ mul_v3_fl(onor, len_v3(ofs_prev));
+
+ add_v3_v3(key->co, onor);
+ }
+
+ copy_v3_v3(onor_prev, onor);
+# endif
+ }
#endif
- }
- }
- }
- }
+ }
+ }
+ }
+ }
- if (changed)
- point->flag |= PEP_EDIT_RECALC;
+ if (changed)
+ point->flag |= PEP_EDIT_RECALC;
}
-
-static void BKE_brush_weight_get(
- PEData *data,
- float UNUSED(mat[4][4]),
- float UNUSED(imat[4][4]),
- int point_index,
- int key_index,
- PTCacheEditKey *UNUSED(key),
- float UNUSED(mouse_distance))
+static void BKE_brush_weight_get(PEData *data,
+ float UNUSED(mat[4][4]),
+ float UNUSED(imat[4][4]),
+ int point_index,
+ int key_index,
+ PTCacheEditKey *UNUSED(key),
+ float UNUSED(mouse_distance))
{
- /* roots have full weight always */
- if (key_index) {
- PTCacheEdit *edit = data->edit;
- ParticleSystem *psys = edit->psys;
+ /* roots have full weight always */
+ if (key_index) {
+ PTCacheEdit *edit = data->edit;
+ ParticleSystem *psys = edit->psys;
- ParticleData *pa = psys->particles + point_index;
- pa->hair[key_index].weight = data->weightfac;
+ ParticleData *pa = psys->particles + point_index;
+ pa->hair[key_index].weight = data->weightfac;
- (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
- }
+ (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
+ }
}
-static void brush_smooth_get(
- PEData *data,
- float mat[4][4],
- float UNUSED(imat[4][4]),
- int UNUSED(point_index),
- int key_index,
- PTCacheEditKey *key,
- float UNUSED(mouse_distance))
+static void brush_smooth_get(PEData *data,
+ float mat[4][4],
+ float UNUSED(imat[4][4]),
+ int UNUSED(point_index),
+ int key_index,
+ PTCacheEditKey *key,
+ float UNUSED(mouse_distance))
{
- if (key_index) {
- float dvec[3];
+ if (key_index) {
+ float dvec[3];
- sub_v3_v3v3(dvec, key->co, (key - 1)->co);
- mul_mat3_m4_v3(mat, dvec);
- add_v3_v3(data->vec, dvec);
- data->tot++;
- }
+ sub_v3_v3v3(dvec, key->co, (key - 1)->co);
+ mul_mat3_m4_v3(mat, dvec);
+ add_v3_v3(data->vec, dvec);
+ data->tot++;
+ }
}
-static void brush_smooth_do(
- PEData *data,
- float UNUSED(mat[4][4]),
- float imat[4][4],
- int point_index,
- int key_index,
- PTCacheEditKey *key,
- float UNUSED(mouse_distance))
+static void brush_smooth_do(PEData *data,
+ float UNUSED(mat[4][4]),
+ float imat[4][4],
+ int point_index,
+ int key_index,
+ PTCacheEditKey *key,
+ float UNUSED(mouse_distance))
{
- float vec[3], dvec[3];
+ float vec[3], dvec[3];
- if (key_index) {
- copy_v3_v3(vec, data->vec);
- mul_mat3_m4_v3(imat, vec);
+ if (key_index) {
+ copy_v3_v3(vec, data->vec);
+ mul_mat3_m4_v3(imat, vec);
- sub_v3_v3v3(dvec, key->co, (key - 1)->co);
+ sub_v3_v3v3(dvec, key->co, (key - 1)->co);
- sub_v3_v3v3(dvec, vec, dvec);
- mul_v3_fl(dvec, data->smoothfac);
+ sub_v3_v3v3(dvec, vec, dvec);
+ mul_v3_fl(dvec, data->smoothfac);
- add_v3_v3(key->co, dvec);
- }
+ add_v3_v3(key->co, dvec);
+ }
- (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
+ (data->edit->points + point_index)->flag |= PEP_EDIT_RECALC;
}
/* convert from triangle barycentric weights to quad mean value weights */
-static void intersect_dm_quad_weights(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float w[4])
+static void intersect_dm_quad_weights(
+ const float v1[3], const float v2[3], const float v3[3], const float v4[3], float w[4])
{
- float co[3], vert[4][3];
+ float co[3], vert[4][3];
- copy_v3_v3(vert[0], v1);
- copy_v3_v3(vert[1], v2);
- copy_v3_v3(vert[2], v3);
- copy_v3_v3(vert[3], v4);
+ copy_v3_v3(vert[0], v1);
+ copy_v3_v3(vert[1], v2);
+ copy_v3_v3(vert[2], v3);
+ copy_v3_v3(vert[3], v4);
- co[0] = v1[0] * w[0] + v2[0] * w[1] + v3[0] * w[2] + v4[0] * w[3];
- co[1] = v1[1] * w[0] + v2[1] * w[1] + v3[1] * w[2] + v4[1] * w[3];
- co[2] = v1[2] * w[0] + v2[2] * w[1] + v3[2] * w[2] + v4[2] * w[3];
+ co[0] = v1[0] * w[0] + v2[0] * w[1] + v3[0] * w[2] + v4[0] * w[3];
+ co[1] = v1[1] * w[0] + v2[1] * w[1] + v3[1] * w[2] + v4[1] * w[3];
+ co[2] = v1[2] * w[0] + v2[2] * w[1] + v3[2] * w[2] + v4[2] * w[3];
- interp_weights_poly_v3(w, vert, 4, co);
+ interp_weights_poly_v3(w, vert, 4, co);
}
/** Check intersection with an evaluated mesh. */
-static int particle_intersect_mesh(Depsgraph *depsgraph, Scene *UNUSED(scene), Object *ob, Mesh *mesh,
+static int particle_intersect_mesh(Depsgraph *depsgraph,
+ Scene *UNUSED(scene),
+ Object *ob,
+ Mesh *mesh,
float *vert_cos,
- const float co1[3], const float co2[3],
- float *min_d, int *min_face, float *min_w,
- float *face_minmax, float *pa_minmax,
- float radius, float *ipoint)
-{
- MFace *mface = NULL;
- MVert *mvert = NULL;
- int i, totface, intersect = 0;
- float cur_d, cur_uv[2], v1[3], v2[3], v3[3], v4[3], min[3], max[3], p_min[3], p_max[3];
- float cur_ipoint[3];
-
- if (mesh == NULL) {
- psys_disable_all(ob);
-
- Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
-
- mesh = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
- if (mesh == NULL) {
- mesh = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
- }
-
- psys_enable_all(ob);
-
- if (mesh == NULL) {
- return 0;
- }
- }
-
- /* BMESH_ONLY, deform dm may not have tessface */
- BKE_mesh_tessface_ensure(mesh);
-
-
- if (pa_minmax == 0) {
- INIT_MINMAX(p_min, p_max);
- minmax_v3v3_v3(p_min, p_max, co1);
- minmax_v3v3_v3(p_min, p_max, co2);
- }
- else {
- copy_v3_v3(p_min, pa_minmax);
- copy_v3_v3(p_max, pa_minmax + 3);
- }
-
- totface = mesh->totface;
- mface = mesh->mface;
- mvert = mesh->mvert;
-
- /* lets intersect the faces */
- for (i = 0; i < totface; i++, mface++) {
- if (vert_cos) {
- copy_v3_v3(v1, vert_cos + 3 * mface->v1);
- copy_v3_v3(v2, vert_cos + 3 * mface->v2);
- copy_v3_v3(v3, vert_cos + 3 * mface->v3);
- if (mface->v4)
- copy_v3_v3(v4, vert_cos + 3 * mface->v4);
- }
- else {
- copy_v3_v3(v1, mvert[mface->v1].co);
- copy_v3_v3(v2, mvert[mface->v2].co);
- copy_v3_v3(v3, mvert[mface->v3].co);
- if (mface->v4)
- copy_v3_v3(v4, mvert[mface->v4].co);
- }
-
- if (face_minmax == 0) {
- INIT_MINMAX(min, max);
- DO_MINMAX(v1, min, max);
- DO_MINMAX(v2, min, max);
- DO_MINMAX(v3, min, max);
- if (mface->v4)
- DO_MINMAX(v4, min, max);
- if (isect_aabb_aabb_v3(min, max, p_min, p_max) == 0)
- continue;
- }
- else {
- copy_v3_v3(min, face_minmax + 6 * i);
- copy_v3_v3(max, face_minmax + 6 * i + 3);
- if (isect_aabb_aabb_v3(min, max, p_min, p_max) == 0)
- continue;
- }
-
- if (radius > 0.0f) {
- if (isect_sweeping_sphere_tri_v3(co1, co2, radius, v2, v3, v1, &cur_d, cur_ipoint)) {
- if (cur_d < *min_d) {
- *min_d = cur_d;
- copy_v3_v3(ipoint, cur_ipoint);
- *min_face = i;
- intersect = 1;
- }
- }
- if (mface->v4) {
- if (isect_sweeping_sphere_tri_v3(co1, co2, radius, v4, v1, v3, &cur_d, cur_ipoint)) {
- if (cur_d < *min_d) {
- *min_d = cur_d;
- copy_v3_v3(ipoint, cur_ipoint);
- *min_face = i;
- intersect = 1;
- }
- }
- }
- }
- else {
- if (isect_line_segment_tri_v3(co1, co2, v1, v2, v3, &cur_d, cur_uv)) {
- if (cur_d < *min_d) {
- *min_d = cur_d;
- min_w[0] = 1.0f - cur_uv[0] - cur_uv[1];
- min_w[1] = cur_uv[0];
- min_w[2] = cur_uv[1];
- min_w[3] = 0.0f;
- if (mface->v4)
- intersect_dm_quad_weights(v1, v2, v3, v4, min_w);
- *min_face = i;
- intersect = 1;
- }
- }
- if (mface->v4) {
- if (isect_line_segment_tri_v3(co1, co2, v1, v3, v4, &cur_d, cur_uv)) {
- if (cur_d < *min_d) {
- *min_d = cur_d;
- min_w[0] = 1.0f - cur_uv[0] - cur_uv[1];
- min_w[1] = 0.0f;
- min_w[2] = cur_uv[0];
- min_w[3] = cur_uv[1];
- intersect_dm_quad_weights(v1, v2, v3, v4, min_w);
- *min_face = i;
- intersect = 1;
- }
- }
- }
- }
- }
- return intersect;
+ const float co1[3],
+ const float co2[3],
+ float *min_d,
+ int *min_face,
+ float *min_w,
+ float *face_minmax,
+ float *pa_minmax,
+ float radius,
+ float *ipoint)
+{
+ MFace *mface = NULL;
+ MVert *mvert = NULL;
+ int i, totface, intersect = 0;
+ float cur_d, cur_uv[2], v1[3], v2[3], v3[3], v4[3], min[3], max[3], p_min[3], p_max[3];
+ float cur_ipoint[3];
+
+ if (mesh == NULL) {
+ psys_disable_all(ob);
+
+ Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+
+ mesh = mesh_get_eval_final(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
+ if (mesh == NULL) {
+ mesh = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
+ }
+
+ psys_enable_all(ob);
+
+ if (mesh == NULL) {
+ return 0;
+ }
+ }
+
+ /* BMESH_ONLY, deform dm may not have tessface */
+ BKE_mesh_tessface_ensure(mesh);
+
+ if (pa_minmax == 0) {
+ INIT_MINMAX(p_min, p_max);
+ minmax_v3v3_v3(p_min, p_max, co1);
+ minmax_v3v3_v3(p_min, p_max, co2);
+ }
+ else {
+ copy_v3_v3(p_min, pa_minmax);
+ copy_v3_v3(p_max, pa_minmax + 3);
+ }
+
+ totface = mesh->totface;
+ mface = mesh->mface;
+ mvert = mesh->mvert;
+
+ /* lets intersect the faces */
+ for (i = 0; i < totface; i++, mface++) {
+ if (vert_cos) {
+ copy_v3_v3(v1, vert_cos + 3 * mface->v1);
+ copy_v3_v3(v2, vert_cos + 3 * mface->v2);
+ copy_v3_v3(v3, vert_cos + 3 * mface->v3);
+ if (mface->v4)
+ copy_v3_v3(v4, vert_cos + 3 * mface->v4);
+ }
+ else {
+ copy_v3_v3(v1, mvert[mface->v1].co);
+ copy_v3_v3(v2, mvert[mface->v2].co);
+ copy_v3_v3(v3, mvert[mface->v3].co);
+ if (mface->v4)
+ copy_v3_v3(v4, mvert[mface->v4].co);
+ }
+
+ if (face_minmax == 0) {
+ INIT_MINMAX(min, max);
+ DO_MINMAX(v1, min, max);
+ DO_MINMAX(v2, min, max);
+ DO_MINMAX(v3, min, max);
+ if (mface->v4)
+ DO_MINMAX(v4, min, max);
+ if (isect_aabb_aabb_v3(min, max, p_min, p_max) == 0)
+ continue;
+ }
+ else {
+ copy_v3_v3(min, face_minmax + 6 * i);
+ copy_v3_v3(max, face_minmax + 6 * i + 3);
+ if (isect_aabb_aabb_v3(min, max, p_min, p_max) == 0)
+ continue;
+ }
+
+ if (radius > 0.0f) {
+ if (isect_sweeping_sphere_tri_v3(co1, co2, radius, v2, v3, v1, &cur_d, cur_ipoint)) {
+ if (cur_d < *min_d) {
+ *min_d = cur_d;
+ copy_v3_v3(ipoint, cur_ipoint);
+ *min_face = i;
+ intersect = 1;
+ }
+ }
+ if (mface->v4) {
+ if (isect_sweeping_sphere_tri_v3(co1, co2, radius, v4, v1, v3, &cur_d, cur_ipoint)) {
+ if (cur_d < *min_d) {
+ *min_d = cur_d;
+ copy_v3_v3(ipoint, cur_ipoint);
+ *min_face = i;
+ intersect = 1;
+ }
+ }
+ }
+ }
+ else {
+ if (isect_line_segment_tri_v3(co1, co2, v1, v2, v3, &cur_d, cur_uv)) {
+ if (cur_d < *min_d) {
+ *min_d = cur_d;
+ min_w[0] = 1.0f - cur_uv[0] - cur_uv[1];
+ min_w[1] = cur_uv[0];
+ min_w[2] = cur_uv[1];
+ min_w[3] = 0.0f;
+ if (mface->v4)
+ intersect_dm_quad_weights(v1, v2, v3, v4, min_w);
+ *min_face = i;
+ intersect = 1;
+ }
+ }
+ if (mface->v4) {
+ if (isect_line_segment_tri_v3(co1, co2, v1, v3, v4, &cur_d, cur_uv)) {
+ if (cur_d < *min_d) {
+ *min_d = cur_d;
+ min_w[0] = 1.0f - cur_uv[0] - cur_uv[1];
+ min_w[1] = 0.0f;
+ min_w[2] = cur_uv[0];
+ min_w[3] = cur_uv[1];
+ intersect_dm_quad_weights(v1, v2, v3, v4, min_w);
+ *min_face = i;
+ intersect = 1;
+ }
+ }
+ }
+ }
+ }
+ return intersect;
}
typedef struct BrushAddCountIterData {
- Depsgraph *depsgraph;
- Scene *scene;
- Object *object;
- Mesh *mesh;
- PEData *data;
- int number;
- short size;
- float imat[4][4];
- ParticleData *add_pars;
- int num_added;
+ Depsgraph *depsgraph;
+ Scene *scene;
+ Object *object;
+ Mesh *mesh;
+ PEData *data;
+ int number;
+ short size;
+ float imat[4][4];
+ ParticleData *add_pars;
+ int num_added;
} BrushAddCountIterData;
typedef struct BrushAddCountIterTLSData {
- RNG *rng;
- int num_added;
+ RNG *rng;
+ int num_added;
} BrushAddCountIterTLSData;
-static void brush_add_count_iter(
- void *__restrict iter_data_v,
- const int iter,
- const ParallelRangeTLS *__restrict tls_v)
-{
- BrushAddCountIterData *iter_data = (BrushAddCountIterData *)iter_data_v;
- Depsgraph *depsgraph = iter_data->depsgraph;
- PEData *data = iter_data->data;
- PTCacheEdit *edit = data->edit;
- ParticleSystem *psys = edit->psys;
- ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
- ParticleData *add_pars = iter_data->add_pars;
- BrushAddCountIterTLSData *tls = tls_v->userdata_chunk;
- const int number = iter_data->number;
- const short size = iter_data->size;
- const short size2 = size * size;
- float dmx, dmy;
- if (number > 1) {
- dmx = size;
- dmy = size;
- if (tls->rng == NULL) {
- tls->rng = BLI_rng_new_srandom(
- psys->seed + data->mval[0] + data->mval[1] + tls_v->thread_id);
- }
- /* rejection sampling to get points in circle */
- while (dmx * dmx + dmy * dmy > size2) {
- dmx = (2.0f * BLI_rng_get_float(tls->rng) - 1.0f) * size;
- dmy = (2.0f * BLI_rng_get_float(tls->rng) - 1.0f) * size;
- }
- }
- else {
- dmx = 0.0f;
- dmy = 0.0f;
- }
-
- float mco[2];
- mco[0] = data->mval[0] + dmx;
- mco[1] = data->mval[1] + dmy;
-
- float co1[3], co2[3];
- ED_view3d_win_to_segment_clipped(depsgraph, data->vc.ar, data->vc.v3d, mco, co1, co2, true);
-
- mul_m4_v3(iter_data->imat, co1);
- mul_m4_v3(iter_data->imat, co2);
- float min_d = 2.0;
-
- /* warning, returns the derived mesh face */
- BLI_assert(iter_data->mesh != NULL);
- if (particle_intersect_mesh(depsgraph, iter_data->scene, iter_data->object, iter_data->mesh,
- 0, co1, co2,
- &min_d,
- &add_pars[iter].num_dmcache,
- add_pars[iter].fuv,
- 0, 0, 0, 0))
- {
- if (psys->part->use_modifier_stack && !psmd_eval->mesh_final->runtime.deformed_only) {
- add_pars[iter].num = add_pars[iter].num_dmcache;
- add_pars[iter].num_dmcache = DMCACHE_ISCHILD;
- }
- else if (iter_data->mesh == psmd_eval->mesh_original) {
- /* Final DM is not same topology as orig mesh, we have to map num_dmcache to real final dm. */
- add_pars[iter].num = add_pars[iter].num_dmcache;
- add_pars[iter].num_dmcache = psys_particle_dm_face_lookup(
- psmd_eval->mesh_final, psmd_eval->mesh_original,
- add_pars[iter].num, add_pars[iter].fuv, NULL);
- }
- else {
- add_pars[iter].num = add_pars[iter].num_dmcache;
- }
- if (add_pars[iter].num != DMCACHE_NOTFOUND) {
- tls->num_added++;
- }
- }
+static void brush_add_count_iter(void *__restrict iter_data_v,
+ const int iter,
+ const ParallelRangeTLS *__restrict tls_v)
+{
+ BrushAddCountIterData *iter_data = (BrushAddCountIterData *)iter_data_v;
+ Depsgraph *depsgraph = iter_data->depsgraph;
+ PEData *data = iter_data->data;
+ PTCacheEdit *edit = data->edit;
+ ParticleSystem *psys = edit->psys;
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
+ ParticleData *add_pars = iter_data->add_pars;
+ BrushAddCountIterTLSData *tls = tls_v->userdata_chunk;
+ const int number = iter_data->number;
+ const short size = iter_data->size;
+ const short size2 = size * size;
+ float dmx, dmy;
+ if (number > 1) {
+ dmx = size;
+ dmy = size;
+ if (tls->rng == NULL) {
+ tls->rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1] +
+ tls_v->thread_id);
+ }
+ /* rejection sampling to get points in circle */
+ while (dmx * dmx + dmy * dmy > size2) {
+ dmx = (2.0f * BLI_rng_get_float(tls->rng) - 1.0f) * size;
+ dmy = (2.0f * BLI_rng_get_float(tls->rng) - 1.0f) * size;
+ }
+ }
+ else {
+ dmx = 0.0f;
+ dmy = 0.0f;
+ }
+
+ float mco[2];
+ mco[0] = data->mval[0] + dmx;
+ mco[1] = data->mval[1] + dmy;
+
+ float co1[3], co2[3];
+ ED_view3d_win_to_segment_clipped(depsgraph, data->vc.ar, data->vc.v3d, mco, co1, co2, true);
+
+ mul_m4_v3(iter_data->imat, co1);
+ mul_m4_v3(iter_data->imat, co2);
+ float min_d = 2.0;
+
+ /* warning, returns the derived mesh face */
+ BLI_assert(iter_data->mesh != NULL);
+ if (particle_intersect_mesh(depsgraph,
+ iter_data->scene,
+ iter_data->object,
+ iter_data->mesh,
+ 0,
+ co1,
+ co2,
+ &min_d,
+ &add_pars[iter].num_dmcache,
+ add_pars[iter].fuv,
+ 0,
+ 0,
+ 0,
+ 0)) {
+ if (psys->part->use_modifier_stack && !psmd_eval->mesh_final->runtime.deformed_only) {
+ add_pars[iter].num = add_pars[iter].num_dmcache;
+ add_pars[iter].num_dmcache = DMCACHE_ISCHILD;
+ }
+ else if (iter_data->mesh == psmd_eval->mesh_original) {
+ /* Final DM is not same topology as orig mesh, we have to map num_dmcache to real final dm. */
+ add_pars[iter].num = add_pars[iter].num_dmcache;
+ add_pars[iter].num_dmcache = psys_particle_dm_face_lookup(psmd_eval->mesh_final,
+ psmd_eval->mesh_original,
+ add_pars[iter].num,
+ add_pars[iter].fuv,
+ NULL);
+ }
+ else {
+ add_pars[iter].num = add_pars[iter].num_dmcache;
+ }
+ if (add_pars[iter].num != DMCACHE_NOTFOUND) {
+ tls->num_added++;
+ }
+ }
}
static void brush_add_count_iter_finalize(void *__restrict userdata_v,
void *__restrict userdata_chunk_v)
{
- BrushAddCountIterData *iter_data = (BrushAddCountIterData *)userdata_v;
- BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)userdata_chunk_v;
- iter_data->num_added += tls->num_added;
- if (tls->rng != NULL) {
- BLI_rng_free(tls->rng);
- }
+ BrushAddCountIterData *iter_data = (BrushAddCountIterData *)userdata_v;
+ BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)userdata_chunk_v;
+ iter_data->num_added += tls->num_added;
+ if (tls->rng != NULL) {
+ BLI_rng_free(tls->rng);
+ }
}
static int brush_add(const bContext *C, PEData *data, short number)
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = data->scene;
- Object *ob = data->ob;
- Mesh *mesh;
- PTCacheEdit *edit = data->edit;
- ParticleSystem *psys = edit->psys;
- ParticleData *add_pars;
- ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
- ParticleSimulationData sim = {0};
- ParticleEditSettings *pset = PE_settings(scene);
- int i, k, n = 0, totpart = psys->totpart;
- float co1[3], imat[4][4];
- float framestep, timestep;
- short size = pset->brush[PE_BRUSH_ADD].size;
- RNG *rng;
-
- invert_m4_m4(imat, ob->obmat);
-
- if (psys->flag & PSYS_GLOBAL_HAIR)
- return 0;
-
- add_pars = MEM_callocN(number * sizeof(ParticleData), "ParticleData add");
-
- rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1]);
-
- sim.depsgraph = depsgraph;
- sim.scene = scene;
- sim.ob = ob;
- sim.psys = psys;
- sim.psmd = psmd_eval;
-
- timestep = psys_get_timestep(&sim);
-
- if (psys->part->use_modifier_stack || psmd_eval->mesh_final->runtime.deformed_only) {
- mesh = psmd_eval->mesh_final;
- }
- else {
- mesh = psmd_eval->mesh_original;
- }
- BLI_assert(mesh);
-
- /* Calculate positions of new particles to add, based on brush intersection
- * with object. New particle data is assigned to a corresponding to check
- * index element of add_pars array. This means, that add_pars is a sparse
- * array.
- */
- BrushAddCountIterData iter_data;
- iter_data.depsgraph = depsgraph;
- iter_data.scene = scene;
- iter_data.object = ob;
- iter_data.mesh = mesh;
- iter_data.data = data;
- iter_data.number = number;
- iter_data.size = size;
- iter_data.add_pars = add_pars;
- iter_data.num_added = 0;
- copy_m4_m4(iter_data.imat, imat);
-
- BrushAddCountIterTLSData tls = {NULL};
-
- ParallelRangeSettings settings;
- BLI_parallel_range_settings_defaults(&settings);
- settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
- settings.userdata_chunk = &tls;
- settings.userdata_chunk_size = sizeof(BrushAddCountIterTLSData);
- settings.func_finalize = brush_add_count_iter_finalize;
- BLI_task_parallel_range(0, number, &iter_data, brush_add_count_iter, &settings);
-
- /* Convert add_parse to a dense array, where all new particles are in the
- * beginning of the array.
- */
- n = iter_data.num_added;
- for (int current_iter = 0, new_index = 0; current_iter < number; current_iter++) {
- if (add_pars[current_iter].num == DMCACHE_NOTFOUND) {
- continue;
- }
- if (new_index != current_iter) {
- new_index++;
- continue;
- }
- memcpy(add_pars + new_index, add_pars + current_iter, sizeof(ParticleData));
- new_index++;
- }
-
- /* TODO(sergey): Consider multi-threading this part as well. */
- if (n) {
- int newtotpart = totpart + n;
- float hairmat[4][4], cur_co[3];
- KDTree_3d *tree = 0;
- ParticleData *pa, *new_pars = MEM_callocN(newtotpart * sizeof(ParticleData), "ParticleData new");
- PTCacheEditPoint *point, *new_points = MEM_callocN(newtotpart * sizeof(PTCacheEditPoint), "PTCacheEditPoint array new");
- PTCacheEditKey *key;
- HairKey *hkey;
-
- /* save existing elements */
- memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
- memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint));
-
- /* change old arrays to new ones */
- if (psys->particles) MEM_freeN(psys->particles);
- psys->particles = new_pars;
-
- if (edit->points) MEM_freeN(edit->points);
- edit->points = new_points;
-
- if (edit->mirror_cache) {
- MEM_freeN(edit->mirror_cache);
- edit->mirror_cache = NULL;
- }
-
- /* create tree for interpolation */
- if (pset->flag & PE_INTERPOLATE_ADDED && psys->totpart) {
- tree = BLI_kdtree_3d_new(psys->totpart);
-
- for (i = 0, pa = psys->particles; i < totpart; i++, pa++) {
- psys_particle_on_dm(psmd_eval->mesh_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, cur_co, 0, 0, 0, 0);
- BLI_kdtree_3d_insert(tree, i, cur_co);
- }
-
- BLI_kdtree_3d_balance(tree);
- }
-
- edit->totpoint = psys->totpart = newtotpart;
-
- /* create new elements */
- pa = psys->particles + totpart;
- point = edit->points + totpart;
-
- for (i = totpart; i < newtotpart; i++, pa++, point++) {
- memcpy(pa, add_pars + i - totpart, sizeof(ParticleData));
- pa->hair = MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add");
- key = point->keys = MEM_callocN(pset->totaddkey * sizeof(PTCacheEditKey), "PTCacheEditKey add");
- point->totkey = pa->totkey = pset->totaddkey;
-
- for (k = 0, hkey = pa->hair; k < pa->totkey; k++, hkey++, key++) {
- key->co = hkey->co;
- key->time = &hkey->time;
-
- if (!(psys->flag & PSYS_GLOBAL_HAIR))
- key->flag |= PEK_USE_WCO;
- }
-
- pa->size = 1.0f;
- initialize_particle(&sim, pa);
- reset_particle(&sim, pa, 0.0, 1.0);
- point->flag |= PEP_EDIT_RECALC;
- if (pe_x_mirror(ob))
- point->flag |= PEP_TAG; /* signal for duplicate */
-
- framestep = pa->lifetime / (float)(pset->totaddkey - 1);
-
- if (tree) {
- ParticleData *ppa;
- HairKey *thkey;
- ParticleKey key3[3];
- KDTreeNearest_3d ptn[3];
- int w, maxw;
- float maxd, totw = 0.0, weight[3];
-
- psys_particle_on_dm(psmd_eval->mesh_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, 0);
- maxw = BLI_kdtree_3d_find_nearest_n(tree, co1, ptn, 3);
-
- maxd = ptn[maxw - 1].dist;
-
- for (w = 0; w < maxw; w++) {
- weight[w] = (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
- totw += weight[w];
- }
- for (; w < 3; w++) {
- weight[w] = 0.0f;
- }
-
- if (totw > 0.0f) {
- for (w = 0; w < maxw; w++)
- weight[w] /= totw;
- }
- else {
- for (w = 0; w < maxw; w++)
- weight[w] = 1.0f / maxw;
- }
-
- ppa = psys->particles + ptn[0].index;
-
- for (k = 0; k < pset->totaddkey; k++) {
- thkey = (HairKey *)pa->hair + k;
- thkey->time = pa->time + k * framestep;
-
- key3[0].time = thkey->time / 100.0f;
- psys_get_particle_on_path(&sim, ptn[0].index, key3, 0);
- mul_v3_fl(key3[0].co, weight[0]);
-
- /* TODO: interpolating the weight would be nicer */
- thkey->weight = (ppa->hair + MIN2(k, ppa->totkey - 1))->weight;
-
- if (maxw > 1) {
- key3[1].time = key3[0].time;
- psys_get_particle_on_path(&sim, ptn[1].index, &key3[1], 0);
- mul_v3_fl(key3[1].co, weight[1]);
- add_v3_v3(key3[0].co, key3[1].co);
-
- if (maxw > 2) {
- key3[2].time = key3[0].time;
- psys_get_particle_on_path(&sim, ptn[2].index, &key3[2], 0);
- mul_v3_fl(key3[2].co, weight[2]);
- add_v3_v3(key3[0].co, key3[2].co);
- }
- }
-
- if (k == 0)
- sub_v3_v3v3(co1, pa->state.co, key3[0].co);
-
- add_v3_v3v3(thkey->co, key3[0].co, co1);
-
- thkey->time = key3[0].time;
- }
- }
- else {
- for (k = 0, hkey = pa->hair; k < pset->totaddkey; k++, hkey++) {
- madd_v3_v3v3fl(hkey->co, pa->state.co, pa->state.vel, k * framestep * timestep);
- hkey->time += k * framestep;
- hkey->weight = 1.f - (float)k / (float)(pset->totaddkey - 1);
- }
- }
- for (k = 0, hkey = pa->hair; k < pset->totaddkey; k++, hkey++) {
- psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, pa, hairmat);
- invert_m4_m4(imat, hairmat);
- mul_m4_v3(imat, hkey->co);
- }
- }
-
- if (tree)
- BLI_kdtree_3d_free(tree);
- }
-
- MEM_freeN(add_pars);
-
- BLI_rng_free(rng);
-
- return n;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = data->scene;
+ Object *ob = data->ob;
+ Mesh *mesh;
+ PTCacheEdit *edit = data->edit;
+ ParticleSystem *psys = edit->psys;
+ ParticleData *add_pars;
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
+ ParticleSimulationData sim = {0};
+ ParticleEditSettings *pset = PE_settings(scene);
+ int i, k, n = 0, totpart = psys->totpart;
+ float co1[3], imat[4][4];
+ float framestep, timestep;
+ short size = pset->brush[PE_BRUSH_ADD].size;
+ RNG *rng;
+
+ invert_m4_m4(imat, ob->obmat);
+
+ if (psys->flag & PSYS_GLOBAL_HAIR)
+ return 0;
+
+ add_pars = MEM_callocN(number * sizeof(ParticleData), "ParticleData add");
+
+ rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1]);
+
+ sim.depsgraph = depsgraph;
+ sim.scene = scene;
+ sim.ob = ob;
+ sim.psys = psys;
+ sim.psmd = psmd_eval;
+
+ timestep = psys_get_timestep(&sim);
+
+ if (psys->part->use_modifier_stack || psmd_eval->mesh_final->runtime.deformed_only) {
+ mesh = psmd_eval->mesh_final;
+ }
+ else {
+ mesh = psmd_eval->mesh_original;
+ }
+ BLI_assert(mesh);
+
+ /* Calculate positions of new particles to add, based on brush intersection
+ * with object. New particle data is assigned to a corresponding to check
+ * index element of add_pars array. This means, that add_pars is a sparse
+ * array.
+ */
+ BrushAddCountIterData iter_data;
+ iter_data.depsgraph = depsgraph;
+ iter_data.scene = scene;
+ iter_data.object = ob;
+ iter_data.mesh = mesh;
+ iter_data.data = data;
+ iter_data.number = number;
+ iter_data.size = size;
+ iter_data.add_pars = add_pars;
+ iter_data.num_added = 0;
+ copy_m4_m4(iter_data.imat, imat);
+
+ BrushAddCountIterTLSData tls = {NULL};
+
+ ParallelRangeSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC;
+ settings.userdata_chunk = &tls;
+ settings.userdata_chunk_size = sizeof(BrushAddCountIterTLSData);
+ settings.func_finalize = brush_add_count_iter_finalize;
+ BLI_task_parallel_range(0, number, &iter_data, brush_add_count_iter, &settings);
+
+ /* Convert add_parse to a dense array, where all new particles are in the
+ * beginning of the array.
+ */
+ n = iter_data.num_added;
+ for (int current_iter = 0, new_index = 0; current_iter < number; current_iter++) {
+ if (add_pars[current_iter].num == DMCACHE_NOTFOUND) {
+ continue;
+ }
+ if (new_index != current_iter) {
+ new_index++;
+ continue;
+ }
+ memcpy(add_pars + new_index, add_pars + current_iter, sizeof(ParticleData));
+ new_index++;
+ }
+
+ /* TODO(sergey): Consider multi-threading this part as well. */
+ if (n) {
+ int newtotpart = totpart + n;
+ float hairmat[4][4], cur_co[3];
+ KDTree_3d *tree = 0;
+ ParticleData *pa,
+ *new_pars = MEM_callocN(newtotpart * sizeof(ParticleData), "ParticleData new");
+ PTCacheEditPoint *point, *new_points = MEM_callocN(newtotpart * sizeof(PTCacheEditPoint),
+ "PTCacheEditPoint array new");
+ PTCacheEditKey *key;
+ HairKey *hkey;
+
+ /* save existing elements */
+ memcpy(new_pars, psys->particles, totpart * sizeof(ParticleData));
+ memcpy(new_points, edit->points, totpart * sizeof(PTCacheEditPoint));
+
+ /* change old arrays to new ones */
+ if (psys->particles)
+ MEM_freeN(psys->particles);
+ psys->particles = new_pars;
+
+ if (edit->points)
+ MEM_freeN(edit->points);
+ edit->points = new_points;
+
+ if (edit->mirror_cache) {
+ MEM_freeN(edit->mirror_cache);
+ edit->mirror_cache = NULL;
+ }
+
+ /* create tree for interpolation */
+ if (pset->flag & PE_INTERPOLATE_ADDED && psys->totpart) {
+ tree = BLI_kdtree_3d_new(psys->totpart);
+
+ for (i = 0, pa = psys->particles; i < totpart; i++, pa++) {
+ psys_particle_on_dm(psmd_eval->mesh_final,
+ psys->part->from,
+ pa->num,
+ pa->num_dmcache,
+ pa->fuv,
+ pa->foffset,
+ cur_co,
+ 0,
+ 0,
+ 0,
+ 0);
+ BLI_kdtree_3d_insert(tree, i, cur_co);
+ }
+
+ BLI_kdtree_3d_balance(tree);
+ }
+
+ edit->totpoint = psys->totpart = newtotpart;
+
+ /* create new elements */
+ pa = psys->particles + totpart;
+ point = edit->points + totpart;
+
+ for (i = totpart; i < newtotpart; i++, pa++, point++) {
+ memcpy(pa, add_pars + i - totpart, sizeof(ParticleData));
+ pa->hair = MEM_callocN(pset->totaddkey * sizeof(HairKey), "BakeKey key add");
+ key = point->keys = MEM_callocN(pset->totaddkey * sizeof(PTCacheEditKey),
+ "PTCacheEditKey add");
+ point->totkey = pa->totkey = pset->totaddkey;
+
+ for (k = 0, hkey = pa->hair; k < pa->totkey; k++, hkey++, key++) {
+ key->co = hkey->co;
+ key->time = &hkey->time;
+
+ if (!(psys->flag & PSYS_GLOBAL_HAIR))
+ key->flag |= PEK_USE_WCO;
+ }
+
+ pa->size = 1.0f;
+ initialize_particle(&sim, pa);
+ reset_particle(&sim, pa, 0.0, 1.0);
+ point->flag |= PEP_EDIT_RECALC;
+ if (pe_x_mirror(ob))
+ point->flag |= PEP_TAG; /* signal for duplicate */
+
+ framestep = pa->lifetime / (float)(pset->totaddkey - 1);
+
+ if (tree) {
+ ParticleData *ppa;
+ HairKey *thkey;
+ ParticleKey key3[3];
+ KDTreeNearest_3d ptn[3];
+ int w, maxw;
+ float maxd, totw = 0.0, weight[3];
+
+ psys_particle_on_dm(psmd_eval->mesh_final,
+ psys->part->from,
+ pa->num,
+ pa->num_dmcache,
+ pa->fuv,
+ pa->foffset,
+ co1,
+ 0,
+ 0,
+ 0,
+ 0);
+ maxw = BLI_kdtree_3d_find_nearest_n(tree, co1, ptn, 3);
+
+ maxd = ptn[maxw - 1].dist;
+
+ for (w = 0; w < maxw; w++) {
+ weight[w] = (float)pow(2.0, (double)(-6.0f * ptn[w].dist / maxd));
+ totw += weight[w];
+ }
+ for (; w < 3; w++) {
+ weight[w] = 0.0f;
+ }
+
+ if (totw > 0.0f) {
+ for (w = 0; w < maxw; w++)
+ weight[w] /= totw;
+ }
+ else {
+ for (w = 0; w < maxw; w++)
+ weight[w] = 1.0f / maxw;
+ }
+
+ ppa = psys->particles + ptn[0].index;
+
+ for (k = 0; k < pset->totaddkey; k++) {
+ thkey = (HairKey *)pa->hair + k;
+ thkey->time = pa->time + k * framestep;
+
+ key3[0].time = thkey->time / 100.0f;
+ psys_get_particle_on_path(&sim, ptn[0].index, key3, 0);
+ mul_v3_fl(key3[0].co, weight[0]);
+
+ /* TODO: interpolating the weight would be nicer */
+ thkey->weight = (ppa->hair + MIN2(k, ppa->totkey - 1))->weight;
+
+ if (maxw > 1) {
+ key3[1].time = key3[0].time;
+ psys_get_particle_on_path(&sim, ptn[1].index, &key3[1], 0);
+ mul_v3_fl(key3[1].co, weight[1]);
+ add_v3_v3(key3[0].co, key3[1].co);
+
+ if (maxw > 2) {
+ key3[2].time = key3[0].time;
+ psys_get_particle_on_path(&sim, ptn[2].index, &key3[2], 0);
+ mul_v3_fl(key3[2].co, weight[2]);
+ add_v3_v3(key3[0].co, key3[2].co);
+ }
+ }
+
+ if (k == 0)
+ sub_v3_v3v3(co1, pa->state.co, key3[0].co);
+
+ add_v3_v3v3(thkey->co, key3[0].co, co1);
+
+ thkey->time = key3[0].time;
+ }
+ }
+ else {
+ for (k = 0, hkey = pa->hair; k < pset->totaddkey; k++, hkey++) {
+ madd_v3_v3v3fl(hkey->co, pa->state.co, pa->state.vel, k * framestep * timestep);
+ hkey->time += k * framestep;
+ hkey->weight = 1.f - (float)k / (float)(pset->totaddkey - 1);
+ }
+ }
+ for (k = 0, hkey = pa->hair; k < pset->totaddkey; k++, hkey++) {
+ psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, pa, hairmat);
+ invert_m4_m4(imat, hairmat);
+ mul_m4_v3(imat, hkey->co);
+ }
+ }
+
+ if (tree)
+ BLI_kdtree_3d_free(tree);
+ }
+
+ MEM_freeN(add_pars);
+
+ BLI_rng_free(rng);
+
+ return n;
}
/************************* brush edit operator ********************/
typedef struct BrushEdit {
- Scene *scene;
- ViewLayer *view_layer;
- Object *ob;
- PTCacheEdit *edit;
+ Scene *scene;
+ ViewLayer *view_layer;
+ Object *ob;
+ PTCacheEdit *edit;
- int first;
- int lastmouse[2];
- float zfac;
+ int first;
+ int lastmouse[2];
+ float zfac;
- /* optional cached view settings to avoid setting on every mousemove */
- PEData data;
+ /* optional cached view settings to avoid setting on every mousemove */
+ PEData data;
} BrushEdit;
static int brush_edit_init(bContext *C, wmOperator *op)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Object *ob = CTX_data_active_object(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- ARegion *ar = CTX_wm_region(C);
- BrushEdit *bedit;
- float min[3], max[3];
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ Object *ob = CTX_data_active_object(C);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ ARegion *ar = CTX_wm_region(C);
+ BrushEdit *bedit;
+ float min[3], max[3];
- if (!WM_toolsystem_active_tool_is_brush(C)) {
- return 0;
- }
+ if (!WM_toolsystem_active_tool_is_brush(C)) {
+ return 0;
+ }
- /* set the 'distance factor' for grabbing (used in comb etc) */
- INIT_MINMAX(min, max);
- PE_minmax(scene, view_layer, min, max);
- mid_v3_v3v3(min, min, max);
+ /* set the 'distance factor' for grabbing (used in comb etc) */
+ INIT_MINMAX(min, max);
+ PE_minmax(scene, view_layer, min, max);
+ mid_v3_v3v3(min, min, max);
- bedit = MEM_callocN(sizeof(BrushEdit), "BrushEdit");
- bedit->first = 1;
- op->customdata = bedit;
+ bedit = MEM_callocN(sizeof(BrushEdit), "BrushEdit");
+ bedit->first = 1;
+ op->customdata = bedit;
- bedit->scene = scene;
- bedit->view_layer = view_layer;
- bedit->ob = ob;
- bedit->edit = edit;
+ bedit->scene = scene;
+ bedit->view_layer = view_layer;
+ bedit->ob = ob;
+ bedit->edit = edit;
- bedit->zfac = ED_view3d_calc_zfac(ar->regiondata, min, NULL);
+ bedit->zfac = ED_view3d_calc_zfac(ar->regiondata, min, NULL);
- /* cache view depths and settings for re-use */
- PE_set_view3d_data(C, &bedit->data);
- PE_create_random_generator(&bedit->data);
+ /* cache view depths and settings for re-use */
+ PE_set_view3d_data(C, &bedit->data);
+ PE_create_random_generator(&bedit->data);
- return 1;
+ return 1;
}
static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
{
- BrushEdit *bedit = op->customdata;
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = bedit->scene;
- Object *ob = bedit->ob;
- PTCacheEdit *edit = bedit->edit;
- ParticleEditSettings *pset = PE_settings(scene);
- ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
- ParticleBrushData *brush = &pset->brush[pset->brushtype];
- ARegion *ar = CTX_wm_region(C);
- float vec[3], mousef[2];
- int mval[2];
- int flip, mouse[2], removed = 0, added = 0, selected = 0, tot_steps = 1, step = 1;
- float dx, dy, dmax;
- int lock_root = pset->flag & PE_LOCK_FIRST;
-
- if (!PE_start_edit(edit))
- return;
-
- RNA_float_get_array(itemptr, "mouse", mousef);
- mouse[0] = mousef[0];
- mouse[1] = mousef[1];
- flip = RNA_boolean_get(itemptr, "pen_flip");
-
- if (bedit->first) {
- bedit->lastmouse[0] = mouse[0];
- bedit->lastmouse[1] = mouse[1];
- }
-
- dx = mouse[0] - bedit->lastmouse[0];
- dy = mouse[1] - bedit->lastmouse[1];
-
- mval[0] = mouse[0];
- mval[1] = mouse[1];
-
-
- /* disable locking temporatily for disconnected hair */
- if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
- pset->flag &= ~PE_LOCK_FIRST;
-
- if (((pset->brushtype == PE_BRUSH_ADD) ?
- (sqrtf(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0)) || bedit->first)
- {
- PEData data = bedit->data;
- data.context = C; // TODO(mai): why isnt this set in bedit->data?
-
- view3d_operator_needs_opengl(C);
- selected = (short)count_selected_keys(scene, edit);
-
- dmax = max_ff(fabsf(dx), fabsf(dy));
- tot_steps = dmax / (0.2f * pe_brush_size_get(scene, brush)) + 1;
-
- dx /= (float)tot_steps;
- dy /= (float)tot_steps;
-
- for (step = 1; step <= tot_steps; step++) {
- mval[0] = bedit->lastmouse[0] + step * dx;
- mval[1] = bedit->lastmouse[1] + step * dy;
-
- switch (pset->brushtype) {
- case PE_BRUSH_COMB:
- {
- const float mval_f[2] = {dx, dy};
- data.mval = mval;
- data.rad = pe_brush_size_get(scene, brush);
-
- data.combfac = (brush->strength - 0.5f) * 2.0f;
- if (data.combfac < 0.0f)
- data.combfac = 1.0f - 9.0f * data.combfac;
- else
- data.combfac = 1.0f - data.combfac;
-
- invert_m4_m4(ob->imat, ob->obmat);
-
- ED_view3d_win_to_delta(ar, mval_f, vec, bedit->zfac);
- data.dvec = vec;
-
- foreach_mouse_hit_key(&data, brush_comb, selected);
- break;
- }
- case PE_BRUSH_CUT:
- {
- if (edit->psys && edit->pathcache) {
- data.mval = mval;
- data.rad = pe_brush_size_get(scene, brush);
- data.cutfac = brush->strength;
-
- if (selected)
- foreach_selected_point(&data, brush_cut);
- else
- foreach_point(&data, brush_cut);
-
- removed = remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob));
- if (pset->flag & PE_KEEP_LENGTHS)
- recalc_lengths(edit);
- }
- else
- removed = 0;
-
- break;
- }
- case PE_BRUSH_LENGTH:
- {
- data.mval = mval;
-
- data.rad = pe_brush_size_get(scene, brush);
- data.growfac = brush->strength / 50.0f;
-
- if (brush->invert ^ flip)
- data.growfac = 1.0f - data.growfac;
- else
- data.growfac = 1.0f + data.growfac;
-
- foreach_mouse_hit_point(&data, brush_length, selected);
-
- if (pset->flag & PE_KEEP_LENGTHS)
- recalc_lengths(edit);
- break;
- }
- case PE_BRUSH_PUFF:
- {
- if (edit->psys) {
- data.mesh = psmd_eval->mesh_final;
- data.mval = mval;
- data.rad = pe_brush_size_get(scene, brush);
- data.select = selected;
-
- data.pufffac = (brush->strength - 0.5f) * 2.0f;
- if (data.pufffac < 0.0f)
- data.pufffac = 1.0f - 9.0f * data.pufffac;
- else
- data.pufffac = 1.0f - data.pufffac;
-
- data.invert = (brush->invert ^ flip);
- invert_m4_m4(ob->imat, ob->obmat);
-
- foreach_mouse_hit_point(&data, brush_puff, selected);
- }
- break;
- }
- case PE_BRUSH_ADD:
- {
- if (edit->psys && edit->psys->part->from == PART_FROM_FACE) {
- data.mval = mval;
-
- added = brush_add(C, &data, brush->count);
-
- if (pset->flag & PE_KEEP_LENGTHS)
- recalc_lengths(edit);
- }
- else
- added = 0;
- break;
- }
- case PE_BRUSH_SMOOTH:
- {
- data.mval = mval;
- data.rad = pe_brush_size_get(scene, brush);
-
- data.vec[0] = data.vec[1] = data.vec[2] = 0.0f;
- data.tot = 0;
-
- data.smoothfac = brush->strength;
-
- invert_m4_m4(ob->imat, ob->obmat);
-
- foreach_mouse_hit_key(&data, brush_smooth_get, selected);
-
- if (data.tot) {
- mul_v3_fl(data.vec, 1.0f / (float)data.tot);
- foreach_mouse_hit_key(&data, brush_smooth_do, selected);
- }
-
- break;
- }
- case PE_BRUSH_WEIGHT:
- {
- if (edit->psys) {
- data.mesh = psmd_eval->mesh_final;
- data.mval = mval;
- data.rad = pe_brush_size_get(scene, brush);
-
- data.weightfac = brush->strength; /* note that this will never be zero */
-
- foreach_mouse_hit_key(&data, BKE_brush_weight_get, selected);
- }
-
- break;
- }
- }
- if ((pset->flag & PE_KEEP_LENGTHS) == 0)
- recalc_lengths(edit);
-
- if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) {
- if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob))
- PE_mirror_x(scene, ob, 1);
-
- update_world_cos(depsgraph, ob, edit);
- psys_free_path_cache(NULL, edit);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- else {
- PE_update_object(depsgraph, scene, ob, 1);
- }
- }
-
- if (edit->psys) {
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
- DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO);
- }
- else {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
- }
-
- bedit->lastmouse[0] = mouse[0];
- bedit->lastmouse[1] = mouse[1];
- bedit->first = 0;
- }
-
- pset->flag |= lock_root;
+ BrushEdit *bedit = op->customdata;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = bedit->scene;
+ Object *ob = bedit->ob;
+ PTCacheEdit *edit = bedit->edit;
+ ParticleEditSettings *pset = PE_settings(scene);
+ ParticleSystemModifierData *psmd_eval = edit->psmd_eval;
+ ParticleBrushData *brush = &pset->brush[pset->brushtype];
+ ARegion *ar = CTX_wm_region(C);
+ float vec[3], mousef[2];
+ int mval[2];
+ int flip, mouse[2], removed = 0, added = 0, selected = 0, tot_steps = 1, step = 1;
+ float dx, dy, dmax;
+ int lock_root = pset->flag & PE_LOCK_FIRST;
+
+ if (!PE_start_edit(edit))
+ return;
+
+ RNA_float_get_array(itemptr, "mouse", mousef);
+ mouse[0] = mousef[0];
+ mouse[1] = mousef[1];
+ flip = RNA_boolean_get(itemptr, "pen_flip");
+
+ if (bedit->first) {
+ bedit->lastmouse[0] = mouse[0];
+ bedit->lastmouse[1] = mouse[1];
+ }
+
+ dx = mouse[0] - bedit->lastmouse[0];
+ dy = mouse[1] - bedit->lastmouse[1];
+
+ mval[0] = mouse[0];
+ mval[1] = mouse[1];
+
+ /* disable locking temporatily for disconnected hair */
+ if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
+ pset->flag &= ~PE_LOCK_FIRST;
+
+ if (((pset->brushtype == PE_BRUSH_ADD) ?
+ (sqrtf(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) :
+ (dx != 0 || dy != 0)) ||
+ bedit->first) {
+ PEData data = bedit->data;
+ data.context = C; // TODO(mai): why isnt this set in bedit->data?
+
+ view3d_operator_needs_opengl(C);
+ selected = (short)count_selected_keys(scene, edit);
+
+ dmax = max_ff(fabsf(dx), fabsf(dy));
+ tot_steps = dmax / (0.2f * pe_brush_size_get(scene, brush)) + 1;
+
+ dx /= (float)tot_steps;
+ dy /= (float)tot_steps;
+
+ for (step = 1; step <= tot_steps; step++) {
+ mval[0] = bedit->lastmouse[0] + step * dx;
+ mval[1] = bedit->lastmouse[1] + step * dy;
+
+ switch (pset->brushtype) {
+ case PE_BRUSH_COMB: {
+ const float mval_f[2] = {dx, dy};
+ data.mval = mval;
+ data.rad = pe_brush_size_get(scene, brush);
+
+ data.combfac = (brush->strength - 0.5f) * 2.0f;
+ if (data.combfac < 0.0f)
+ data.combfac = 1.0f - 9.0f * data.combfac;
+ else
+ data.combfac = 1.0f - data.combfac;
+
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ ED_view3d_win_to_delta(ar, mval_f, vec, bedit->zfac);
+ data.dvec = vec;
+
+ foreach_mouse_hit_key(&data, brush_comb, selected);
+ break;
+ }
+ case PE_BRUSH_CUT: {
+ if (edit->psys && edit->pathcache) {
+ data.mval = mval;
+ data.rad = pe_brush_size_get(scene, brush);
+ data.cutfac = brush->strength;
+
+ if (selected)
+ foreach_selected_point(&data, brush_cut);
+ else
+ foreach_point(&data, brush_cut);
+
+ removed = remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob));
+ if (pset->flag & PE_KEEP_LENGTHS)
+ recalc_lengths(edit);
+ }
+ else
+ removed = 0;
+
+ break;
+ }
+ case PE_BRUSH_LENGTH: {
+ data.mval = mval;
+
+ data.rad = pe_brush_size_get(scene, brush);
+ data.growfac = brush->strength / 50.0f;
+
+ if (brush->invert ^ flip)
+ data.growfac = 1.0f - data.growfac;
+ else
+ data.growfac = 1.0f + data.growfac;
+
+ foreach_mouse_hit_point(&data, brush_length, selected);
+
+ if (pset->flag & PE_KEEP_LENGTHS)
+ recalc_lengths(edit);
+ break;
+ }
+ case PE_BRUSH_PUFF: {
+ if (edit->psys) {
+ data.mesh = psmd_eval->mesh_final;
+ data.mval = mval;
+ data.rad = pe_brush_size_get(scene, brush);
+ data.select = selected;
+
+ data.pufffac = (brush->strength - 0.5f) * 2.0f;
+ if (data.pufffac < 0.0f)
+ data.pufffac = 1.0f - 9.0f * data.pufffac;
+ else
+ data.pufffac = 1.0f - data.pufffac;
+
+ data.invert = (brush->invert ^ flip);
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ foreach_mouse_hit_point(&data, brush_puff, selected);
+ }
+ break;
+ }
+ case PE_BRUSH_ADD: {
+ if (edit->psys && edit->psys->part->from == PART_FROM_FACE) {
+ data.mval = mval;
+
+ added = brush_add(C, &data, brush->count);
+
+ if (pset->flag & PE_KEEP_LENGTHS)
+ recalc_lengths(edit);
+ }
+ else
+ added = 0;
+ break;
+ }
+ case PE_BRUSH_SMOOTH: {
+ data.mval = mval;
+ data.rad = pe_brush_size_get(scene, brush);
+
+ data.vec[0] = data.vec[1] = data.vec[2] = 0.0f;
+ data.tot = 0;
+
+ data.smoothfac = brush->strength;
+
+ invert_m4_m4(ob->imat, ob->obmat);
+
+ foreach_mouse_hit_key(&data, brush_smooth_get, selected);
+
+ if (data.tot) {
+ mul_v3_fl(data.vec, 1.0f / (float)data.tot);
+ foreach_mouse_hit_key(&data, brush_smooth_do, selected);
+ }
+
+ break;
+ }
+ case PE_BRUSH_WEIGHT: {
+ if (edit->psys) {
+ data.mesh = psmd_eval->mesh_final;
+ data.mval = mval;
+ data.rad = pe_brush_size_get(scene, brush);
+
+ data.weightfac = brush->strength; /* note that this will never be zero */
+
+ foreach_mouse_hit_key(&data, BKE_brush_weight_get, selected);
+ }
+
+ break;
+ }
+ }
+ if ((pset->flag & PE_KEEP_LENGTHS) == 0)
+ recalc_lengths(edit);
+
+ if (ELEM(pset->brushtype, PE_BRUSH_ADD, PE_BRUSH_CUT) && (added || removed)) {
+ if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob))
+ PE_mirror_x(scene, ob, 1);
+
+ update_world_cos(depsgraph, ob, edit);
+ psys_free_path_cache(NULL, edit);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ else {
+ PE_update_object(depsgraph, scene, ob, 1);
+ }
+ }
+
+ if (edit->psys) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO);
+ }
+ else {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ }
+
+ bedit->lastmouse[0] = mouse[0];
+ bedit->lastmouse[1] = mouse[1];
+ bedit->first = 0;
+ }
+
+ pset->flag |= lock_root;
}
static void brush_edit_exit(wmOperator *op)
{
- BrushEdit *bedit = op->customdata;
+ BrushEdit *bedit = op->customdata;
- PE_free_random_generator(&bedit->data);
- MEM_freeN(bedit);
+ PE_free_random_generator(&bedit->data);
+ MEM_freeN(bedit);
}
static int brush_edit_exec(bContext *C, wmOperator *op)
{
- if (!brush_edit_init(C, op))
- return OPERATOR_CANCELLED;
+ if (!brush_edit_init(C, op))
+ return OPERATOR_CANCELLED;
- RNA_BEGIN(op->ptr, itemptr, "stroke")
- {
- brush_edit_apply(C, op, &itemptr);
- }
- RNA_END;
+ RNA_BEGIN (op->ptr, itemptr, "stroke") {
+ brush_edit_apply(C, op, &itemptr);
+ }
+ RNA_END;
- brush_edit_exit(op);
+ brush_edit_exit(op);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static void brush_edit_apply_event(bContext *C, wmOperator *op, const wmEvent *event)
{
- PointerRNA itemptr;
- float mouse[2];
+ PointerRNA itemptr;
+ float mouse[2];
- copy_v2fl_v2i(mouse, event->mval);
+ copy_v2fl_v2i(mouse, event->mval);
- /* fill in stroke */
- RNA_collection_add(op->ptr, "stroke", &itemptr);
+ /* fill in stroke */
+ RNA_collection_add(op->ptr, "stroke", &itemptr);
- RNA_float_set_array(&itemptr, "mouse", mouse);
- RNA_boolean_set(&itemptr, "pen_flip", event->shift != false); // XXX hardcoded
+ RNA_float_set_array(&itemptr, "mouse", mouse);
+ RNA_boolean_set(&itemptr, "pen_flip", event->shift != false); // XXX hardcoded
- /* apply */
- brush_edit_apply(C, op, &itemptr);
+ /* apply */
+ brush_edit_apply(C, op, &itemptr);
}
static int brush_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- if (!brush_edit_init(C, op))
- return OPERATOR_CANCELLED;
+ if (!brush_edit_init(C, op))
+ return OPERATOR_CANCELLED;
- brush_edit_apply_event(C, op, event);
+ brush_edit_apply_event(C, op, event);
- WM_event_add_modal_handler(C, op);
+ WM_event_add_modal_handler(C, op);
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
static int brush_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- switch (event->type) {
- case LEFTMOUSE:
- case MIDDLEMOUSE:
- case RIGHTMOUSE: // XXX hardcoded
- if (event->val == KM_RELEASE) {
- brush_edit_exit(op);
- return OPERATOR_FINISHED;
- }
- break;
- case MOUSEMOVE:
- brush_edit_apply_event(C, op, event);
- break;
- }
+ switch (event->type) {
+ case LEFTMOUSE:
+ case MIDDLEMOUSE:
+ case RIGHTMOUSE: // XXX hardcoded
+ if (event->val == KM_RELEASE) {
+ brush_edit_exit(op);
+ return OPERATOR_FINISHED;
+ }
+ break;
+ case MOUSEMOVE:
+ brush_edit_apply_event(C, op, event);
+ break;
+ }
- return OPERATOR_RUNNING_MODAL;
+ return OPERATOR_RUNNING_MODAL;
}
static void brush_edit_cancel(bContext *UNUSED(C), wmOperator *op)
{
- brush_edit_exit(op);
+ brush_edit_exit(op);
}
void PARTICLE_OT_brush_edit(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Brush Edit";
- ot->idname = "PARTICLE_OT_brush_edit";
- ot->description = "Apply a stroke of brush to the particles";
+ /* identifiers */
+ ot->name = "Brush Edit";
+ ot->idname = "PARTICLE_OT_brush_edit";
+ ot->description = "Apply a stroke of brush to the particles";
- /* api callbacks */
- ot->exec = brush_edit_exec;
- ot->invoke = brush_edit_invoke;
- ot->modal = brush_edit_modal;
- ot->cancel = brush_edit_cancel;
- ot->poll = PE_poll_view3d;
+ /* api callbacks */
+ ot->exec = brush_edit_exec;
+ ot->invoke = brush_edit_invoke;
+ ot->modal = brush_edit_modal;
+ ot->cancel = brush_edit_cancel;
+ ot->poll = PE_poll_view3d;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
- /* properties */
- PropertyRNA *prop;
- prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
- RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ /* properties */
+ PropertyRNA *prop;
+ prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/*********************** cut shape ***************************/
static bool shape_cut_poll(bContext *C)
{
- if (PE_hair_poll(C)) {
- Scene *scene = CTX_data_scene(C);
- ParticleEditSettings *pset = PE_settings(scene);
+ if (PE_hair_poll(C)) {
+ Scene *scene = CTX_data_scene(C);
+ ParticleEditSettings *pset = PE_settings(scene);
- if (pset->shape_object && (pset->shape_object->type == OB_MESH)) {
- return true;
- }
- }
+ if (pset->shape_object && (pset->shape_object->type == OB_MESH)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
typedef struct PointInsideBVH {
- BVHTreeFromMesh bvhdata;
- int num_hits;
+ BVHTreeFromMesh bvhdata;
+ int num_hits;
} PointInsideBVH;
-static void point_inside_bvh_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+static void point_inside_bvh_cb(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
{
- PointInsideBVH *data = userdata;
+ PointInsideBVH *data = userdata;
- data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit);
+ data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit);
- if (hit->index != -1)
- ++data->num_hits;
+ if (hit->index != -1)
+ ++data->num_hits;
}
/* true if the point is inside the shape mesh */
static bool shape_cut_test_point(PEData *data, ParticleCacheKey *key)
{
- BVHTreeFromMesh *shape_bvh = &data->shape_bvh;
- const float dir[3] = {1.0f, 0.0f, 0.0f};
- PointInsideBVH userdata;
+ BVHTreeFromMesh *shape_bvh = &data->shape_bvh;
+ const float dir[3] = {1.0f, 0.0f, 0.0f};
+ PointInsideBVH userdata;
- userdata.bvhdata = data->shape_bvh;
- userdata.num_hits = 0;
+ userdata.bvhdata = data->shape_bvh;
+ userdata.num_hits = 0;
- BLI_bvhtree_ray_cast_all(
- shape_bvh->tree, key->co, dir, 0.0f, BVH_RAYCAST_DIST_MAX,
- point_inside_bvh_cb, &userdata);
+ BLI_bvhtree_ray_cast_all(
+ shape_bvh->tree, key->co, dir, 0.0f, BVH_RAYCAST_DIST_MAX, point_inside_bvh_cb, &userdata);
- /* for any point inside a watertight mesh the number of hits is uneven */
- return (userdata.num_hits % 2) == 1;
+ /* for any point inside a watertight mesh the number of hits is uneven */
+ return (userdata.num_hits % 2) == 1;
}
static void shape_cut(PEData *data, int pa_index)
{
- PTCacheEdit *edit = data->edit;
- Object *ob = data->ob;
- ParticleEditSettings *pset = PE_settings(data->scene);
- ParticleCacheKey *key;
-
- bool cut;
- float cut_time = 1.0;
- int k, totkeys = 1 << pset->draw_step;
-
- /* don't cut hidden */
- if (edit->points[pa_index].flag & PEP_HIDE)
- return;
-
- cut = false;
-
- /* check if root is inside the cut shape */
- key = edit->pathcache[pa_index];
- if (!shape_cut_test_point(data, key)) {
- cut_time = -1.0f;
- cut = true;
- }
- else {
- for (k = 0; k < totkeys; k++, key++) {
- BVHTreeRayHit hit;
- float dir[3];
- float len;
-
- sub_v3_v3v3(dir, (key + 1)->co, key->co);
- len = normalize_v3(dir);
-
- memset(&hit, 0, sizeof(hit));
- hit.index = -1;
- hit.dist = len;
- BLI_bvhtree_ray_cast(data->shape_bvh.tree, key->co, dir, 0.0f, &hit, data->shape_bvh.raycast_callback, &data->shape_bvh);
- if (hit.index >= 0) {
- if (hit.dist < len) {
- cut_time = (hit.dist / len + (float)k) / (float)totkeys;
- cut = true;
- break;
- }
- }
- }
- }
-
- if (cut) {
- if (cut_time < 0.0f) {
- edit->points[pa_index].flag |= PEP_TAG;
- }
- else {
- rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
- edit->points[pa_index].flag |= PEP_EDIT_RECALC;
- }
- }
+ PTCacheEdit *edit = data->edit;
+ Object *ob = data->ob;
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ ParticleCacheKey *key;
+
+ bool cut;
+ float cut_time = 1.0;
+ int k, totkeys = 1 << pset->draw_step;
+
+ /* don't cut hidden */
+ if (edit->points[pa_index].flag & PEP_HIDE)
+ return;
+
+ cut = false;
+
+ /* check if root is inside the cut shape */
+ key = edit->pathcache[pa_index];
+ if (!shape_cut_test_point(data, key)) {
+ cut_time = -1.0f;
+ cut = true;
+ }
+ else {
+ for (k = 0; k < totkeys; k++, key++) {
+ BVHTreeRayHit hit;
+ float dir[3];
+ float len;
+
+ sub_v3_v3v3(dir, (key + 1)->co, key->co);
+ len = normalize_v3(dir);
+
+ memset(&hit, 0, sizeof(hit));
+ hit.index = -1;
+ hit.dist = len;
+ BLI_bvhtree_ray_cast(data->shape_bvh.tree,
+ key->co,
+ dir,
+ 0.0f,
+ &hit,
+ data->shape_bvh.raycast_callback,
+ &data->shape_bvh);
+ if (hit.index >= 0) {
+ if (hit.dist < len) {
+ cut_time = (hit.dist / len + (float)k) / (float)totkeys;
+ cut = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (cut) {
+ if (cut_time < 0.0f) {
+ edit->points[pa_index].flag |= PEP_TAG;
+ }
+ else {
+ rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
+ edit->points[pa_index].flag |= PEP_EDIT_RECALC;
+ }
+ }
}
static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
{
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- ParticleEditSettings *pset = PE_settings(scene);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- Object *shapeob = pset->shape_object;
- int selected = count_selected_keys(scene, edit);
- int lock_root = pset->flag & PE_LOCK_FIRST;
-
- if (!PE_start_edit(edit))
- return OPERATOR_CANCELLED;
-
- /* disable locking temporatily for disconnected hair */
- if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
- pset->flag &= ~PE_LOCK_FIRST;
-
- if (edit->psys && edit->pathcache) {
- PEData data;
- int removed;
-
- PE_set_data(C, &data);
- if (!PE_create_shape_tree(&data, shapeob)) {
- /* shapeob may not have faces... */
- return OPERATOR_CANCELLED;
- }
-
- if (selected)
- foreach_selected_point(&data, shape_cut);
- else
- foreach_point(&data, shape_cut);
-
- removed = remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob));
- recalc_lengths(edit);
-
- if (removed) {
- update_world_cos(depsgraph, ob, edit);
- psys_free_path_cache(NULL, edit);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- else {
- PE_update_object(data.depsgraph, scene, ob, 1);
- }
-
- if (edit->psys) {
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
- DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO);
- }
- else {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
- }
-
- PE_free_shape_tree(&data);
- }
-
- pset->flag |= lock_root;
-
- return OPERATOR_FINISHED;
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ParticleEditSettings *pset = PE_settings(scene);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ Object *shapeob = pset->shape_object;
+ int selected = count_selected_keys(scene, edit);
+ int lock_root = pset->flag & PE_LOCK_FIRST;
+
+ if (!PE_start_edit(edit))
+ return OPERATOR_CANCELLED;
+
+ /* disable locking temporatily for disconnected hair */
+ if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
+ pset->flag &= ~PE_LOCK_FIRST;
+
+ if (edit->psys && edit->pathcache) {
+ PEData data;
+ int removed;
+
+ PE_set_data(C, &data);
+ if (!PE_create_shape_tree(&data, shapeob)) {
+ /* shapeob may not have faces... */
+ return OPERATOR_CANCELLED;
+ }
+
+ if (selected)
+ foreach_selected_point(&data, shape_cut);
+ else
+ foreach_point(&data, shape_cut);
+
+ removed = remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob));
+ recalc_lengths(edit);
+
+ if (removed) {
+ update_world_cos(depsgraph, ob, edit);
+ psys_free_path_cache(NULL, edit);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ else {
+ PE_update_object(data.depsgraph, scene, ob, 1);
+ }
+
+ if (edit->psys) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ BKE_particle_batch_cache_dirty_tag(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL);
+ DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO);
+ }
+ else {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ }
+
+ PE_free_shape_tree(&data);
+ }
+
+ pset->flag |= lock_root;
+
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_shape_cut(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Shape Cut";
- ot->idname = "PARTICLE_OT_shape_cut";
- ot->description = "Cut hair to conform to the set shape object";
+ /* identifiers */
+ ot->name = "Shape Cut";
+ ot->idname = "PARTICLE_OT_shape_cut";
+ ot->description = "Cut hair to conform to the set shape object";
- /* api callbacks */
- ot->exec = shape_cut_exec;
- ot->poll = shape_cut_poll;
+ /* api callbacks */
+ ot->exec = shape_cut_exec;
+ ot->poll = shape_cut_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/************************ utilities ******************************/
int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
{
- Object *ob = OBACT(view_layer);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- ParticleSystem *psys;
- ParticleSystemModifierData *psmd_eval = NULL;
- POINT_P; KEY_K;
- float co[3], mat[4][4];
- int ok = 0;
-
- if (!edit) return ok;
-
- if ((psys = edit->psys))
- psmd_eval = edit->psmd_eval;
- else
- unit_m4(mat);
-
- LOOP_VISIBLE_POINTS {
- if (psys)
- psys_mat_hair_to_global(ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
-
- LOOP_SELECTED_KEYS {
- copy_v3_v3(co, key->co);
- mul_m4_v3(mat, co);
- DO_MINMAX(co, min, max);
- ok = 1;
- }
- }
-
- if (!ok) {
- BKE_object_minmax(ob, min, max, true);
- ok = 1;
- }
-
- return ok;
+ Object *ob = OBACT(view_layer);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ ParticleSystem *psys;
+ ParticleSystemModifierData *psmd_eval = NULL;
+ POINT_P;
+ KEY_K;
+ float co[3], mat[4][4];
+ int ok = 0;
+
+ if (!edit)
+ return ok;
+
+ if ((psys = edit->psys))
+ psmd_eval = edit->psmd_eval;
+ else
+ unit_m4(mat);
+
+ LOOP_VISIBLE_POINTS
+ {
+ if (psys)
+ psys_mat_hair_to_global(
+ ob, psmd_eval->mesh_final, psys->part->from, psys->particles + p, mat);
+
+ LOOP_SELECTED_KEYS
+ {
+ copy_v3_v3(co, key->co);
+ mul_m4_v3(mat, co);
+ DO_MINMAX(co, min, max);
+ ok = 1;
+ }
+ }
+
+ if (!ok) {
+ BKE_object_minmax(ob, min, max, true);
+ ok = 1;
+ }
+
+ return ok;
}
/************************ particle edit toggle operator ************************/
/* initialize needed data for bake edit */
void PE_create_particle_edit(
- Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
-{
- Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
- PTCacheEdit *edit;
- ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
- ParticleSystemModifierData *psmd_eval = NULL;
- POINT_P; KEY_K;
- ParticleData *pa = NULL;
- HairKey *hkey;
- int totpoint;
-
- if (psmd != NULL) {
- psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
- }
-
- /* no psmd->dm happens in case particle system modifier is not enabled */
- if (!(psys && psmd && psmd_eval->mesh_final) && !cache)
- return;
-
- if (cache && cache->flag & PTCACHE_DISK_CACHE)
- return;
-
- if (psys == NULL && (cache && BLI_listbase_is_empty(&cache->mem_cache)))
- return;
-
- edit = (psys) ? psys->edit : cache->edit;
-
- if (!edit) {
- ParticleSystem *psys_eval = NULL;
- if (psys) {
- psys_eval = psys_eval_get(depsgraph, ob, psys);
- psys_copy_particles(psys, psys_eval);
- }
-
- totpoint = psys ? psys->totpart : (int)((PTCacheMem *)cache->mem_cache.first)->totpoint;
-
- edit = MEM_callocN(sizeof(PTCacheEdit), "PE_create_particle_edit");
- edit->points = MEM_callocN(totpoint * sizeof(PTCacheEditPoint), "PTCacheEditPoints");
- edit->totpoint = totpoint;
-
- if (psys && !cache) {
- edit->psmd = psmd;
- edit->psmd_eval = psmd_eval;
- psys->edit = edit;
- edit->psys = psys;
- edit->psys_eval = psys_eval;
-
- psys->free_edit = PE_free_ptcache_edit;
-
- edit->pathcache = NULL;
- BLI_listbase_clear(&edit->pathcachebufs);
-
- pa = psys->particles;
- LOOP_POINTS {
- point->totkey = pa->totkey;
- point->keys = MEM_callocN(point->totkey * sizeof(PTCacheEditKey), "ParticleEditKeys");
- point->flag |= PEP_EDIT_RECALC;
-
- hkey = pa->hair;
- LOOP_KEYS {
- key->co = hkey->co;
- key->time = &hkey->time;
- key->flag = hkey->editflag;
- if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
- key->flag |= PEK_USE_WCO;
- hkey->editflag |= PEK_USE_WCO;
- }
-
- hkey++;
- }
- pa++;
- }
- update_world_cos(depsgraph, ob, edit);
- }
- else {
- PTCacheMem *pm;
- int totframe = 0;
-
- cache->edit = edit;
- cache->free_edit = PE_free_ptcache_edit;
- edit->psys = NULL;
-
- for (pm = cache->mem_cache.first; pm; pm = pm->next)
- totframe++;
-
- for (pm = cache->mem_cache.first; pm; pm = pm->next) {
- LOOP_POINTS {
- if (BKE_ptcache_mem_pointers_seek(p, pm) == 0)
- continue;
-
- if (!point->totkey) {
- key = point->keys = MEM_callocN(totframe * sizeof(PTCacheEditKey), "ParticleEditKeys");
- point->flag |= PEP_EDIT_RECALC;
- }
- else
- key = point->keys + point->totkey;
-
- key->co = pm->cur[BPHYS_DATA_LOCATION];
- key->vel = pm->cur[BPHYS_DATA_VELOCITY];
- key->rot = pm->cur[BPHYS_DATA_ROTATION];
- key->ftime = (float)pm->frame;
- key->time = &key->ftime;
- BKE_ptcache_mem_pointers_incr(pm);
-
- point->totkey++;
- }
- }
- psys = NULL;
- }
-
- /* Causes assert on startup. */
+ Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
+{
+ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
+ PTCacheEdit *edit;
+ ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
+ ParticleSystemModifierData *psmd_eval = NULL;
+ POINT_P;
+ KEY_K;
+ ParticleData *pa = NULL;
+ HairKey *hkey;
+ int totpoint;
+
+ if (psmd != NULL) {
+ psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
+ }
+
+ /* no psmd->dm happens in case particle system modifier is not enabled */
+ if (!(psys && psmd && psmd_eval->mesh_final) && !cache)
+ return;
+
+ if (cache && cache->flag & PTCACHE_DISK_CACHE)
+ return;
+
+ if (psys == NULL && (cache && BLI_listbase_is_empty(&cache->mem_cache)))
+ return;
+
+ edit = (psys) ? psys->edit : cache->edit;
+
+ if (!edit) {
+ ParticleSystem *psys_eval = NULL;
+ if (psys) {
+ psys_eval = psys_eval_get(depsgraph, ob, psys);
+ psys_copy_particles(psys, psys_eval);
+ }
+
+ totpoint = psys ? psys->totpart : (int)((PTCacheMem *)cache->mem_cache.first)->totpoint;
+
+ edit = MEM_callocN(sizeof(PTCacheEdit), "PE_create_particle_edit");
+ edit->points = MEM_callocN(totpoint * sizeof(PTCacheEditPoint), "PTCacheEditPoints");
+ edit->totpoint = totpoint;
+
+ if (psys && !cache) {
+ edit->psmd = psmd;
+ edit->psmd_eval = psmd_eval;
+ psys->edit = edit;
+ edit->psys = psys;
+ edit->psys_eval = psys_eval;
+
+ psys->free_edit = PE_free_ptcache_edit;
+
+ edit->pathcache = NULL;
+ BLI_listbase_clear(&edit->pathcachebufs);
+
+ pa = psys->particles;
+ LOOP_POINTS
+ {
+ point->totkey = pa->totkey;
+ point->keys = MEM_callocN(point->totkey * sizeof(PTCacheEditKey), "ParticleEditKeys");
+ point->flag |= PEP_EDIT_RECALC;
+
+ hkey = pa->hair;
+ LOOP_KEYS
+ {
+ key->co = hkey->co;
+ key->time = &hkey->time;
+ key->flag = hkey->editflag;
+ if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
+ key->flag |= PEK_USE_WCO;
+ hkey->editflag |= PEK_USE_WCO;
+ }
+
+ hkey++;
+ }
+ pa++;
+ }
+ update_world_cos(depsgraph, ob, edit);
+ }
+ else {
+ PTCacheMem *pm;
+ int totframe = 0;
+
+ cache->edit = edit;
+ cache->free_edit = PE_free_ptcache_edit;
+ edit->psys = NULL;
+
+ for (pm = cache->mem_cache.first; pm; pm = pm->next)
+ totframe++;
+
+ for (pm = cache->mem_cache.first; pm; pm = pm->next) {
+ LOOP_POINTS
+ {
+ if (BKE_ptcache_mem_pointers_seek(p, pm) == 0)
+ continue;
+
+ if (!point->totkey) {
+ key = point->keys = MEM_callocN(totframe * sizeof(PTCacheEditKey), "ParticleEditKeys");
+ point->flag |= PEP_EDIT_RECALC;
+ }
+ else
+ key = point->keys + point->totkey;
+
+ key->co = pm->cur[BPHYS_DATA_LOCATION];
+ key->vel = pm->cur[BPHYS_DATA_VELOCITY];
+ key->rot = pm->cur[BPHYS_DATA_ROTATION];
+ key->ftime = (float)pm->frame;
+ key->time = &key->ftime;
+ BKE_ptcache_mem_pointers_incr(pm);
+
+ point->totkey++;
+ }
+ }
+ psys = NULL;
+ }
+
+ /* Causes assert on startup. */
#if 0
- UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
- UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);
+ UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
+ UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);
#else
- memset(edit->sel_col, 0xff, sizeof(edit->sel_col));
- memset(edit->nosel_col, 0x00, sizeof(edit->nosel_col));
+ memset(edit->sel_col, 0xff, sizeof(edit->sel_col));
+ memset(edit->nosel_col, 0x00, sizeof(edit->nosel_col));
#endif
- recalc_lengths(edit);
- if (psys && !cache)
- recalc_emitter_field(depsgraph, ob, psys);
+ recalc_lengths(edit);
+ if (psys && !cache)
+ recalc_emitter_field(depsgraph, ob, psys);
- PE_update_object(depsgraph, scene, ob, 1);
- }
+ PE_update_object(depsgraph, scene, ob, 1);
+ }
}
static bool particle_edit_toggle_poll(bContext *C)
{
- Object *ob = CTX_data_active_object(C);
+ Object *ob = CTX_data_active_object(C);
- if (ob == NULL || ob->type != OB_MESH)
- return 0;
- if (!ob->data || ID_IS_LINKED(ob->data))
- return 0;
- if (CTX_data_edit_object(C))
- return 0;
+ if (ob == NULL || ob->type != OB_MESH)
+ return 0;
+ if (!ob->data || ID_IS_LINKED(ob->data))
+ return 0;
+ if (CTX_data_edit_object(C))
+ return 0;
- return (ob->particlesystem.first ||
- modifiers_findByType(ob, eModifierType_Cloth) ||
- modifiers_findByType(ob, eModifierType_Softbody));
+ return (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) ||
+ modifiers_findByType(ob, eModifierType_Softbody));
}
static void free_all_psys_edit(Object *object)
{
- for (ParticleSystem *psys = object->particlesystem.first;
- psys != NULL;
- psys = psys->next)
- {
- if (psys->edit != NULL) {
- BLI_assert(psys->free_edit != NULL);
- psys->free_edit(psys->edit);
- psys->free_edit = NULL;
- psys->edit = NULL;
- }
- }
+ for (ParticleSystem *psys = object->particlesystem.first; psys != NULL; psys = psys->next) {
+ if (psys->edit != NULL) {
+ BLI_assert(psys->free_edit != NULL);
+ psys->free_edit(psys->edit);
+ psys->free_edit = NULL;
+ psys->edit = NULL;
+ }
+ }
}
static int particle_edit_toggle_exec(bContext *C, wmOperator *op)
{
- struct wmMsgBus *mbus = CTX_wm_message_bus(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
- const int mode_flag = OB_MODE_PARTICLE_EDIT;
- const bool is_mode_set = (ob->mode & mode_flag) != 0;
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ const int mode_flag = OB_MODE_PARTICLE_EDIT;
+ const bool is_mode_set = (ob->mode & mode_flag) != 0;
- if (!is_mode_set) {
- if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
- return OPERATOR_CANCELLED;
- }
- }
+ if (!is_mode_set) {
+ if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
+ return OPERATOR_CANCELLED;
+ }
+ }
- if (!is_mode_set) {
- PTCacheEdit *edit;
+ if (!is_mode_set) {
+ PTCacheEdit *edit;
- ob->mode |= mode_flag;
+ ob->mode |= mode_flag;
- edit = PE_create_current(depsgraph, scene, ob);
+ edit = PE_create_current(depsgraph, scene, ob);
- /* Mesh may have changed since last entering editmode.
- * note, this may have run before if the edit data was just created,
- * so could avoid this and speed up a little. */
- if (edit && edit->psys) {
- /* Make sure pointer to the evaluated modifier data is up to date,
- * with possible changes applied when object was outside of the
- * edit mode. */
- Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
- edit->psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(
- object_eval, edit->psmd->modifier.name);
- recalc_emitter_field(depsgraph, ob, edit->psys);
- }
+ /* Mesh may have changed since last entering editmode.
+ * note, this may have run before if the edit data was just created,
+ * so could avoid this and speed up a little. */
+ if (edit && edit->psys) {
+ /* Make sure pointer to the evaluated modifier data is up to date,
+ * with possible changes applied when object was outside of the
+ * edit mode. */
+ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
+ edit->psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(
+ object_eval, edit->psmd->modifier.name);
+ recalc_emitter_field(depsgraph, ob, edit->psys);
+ }
- toggle_particle_cursor(C, 1);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_PARTICLE, NULL);
- }
- else {
- ob->mode &= ~mode_flag;
- toggle_particle_cursor(C, 0);
- free_all_psys_edit(ob);
- WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
- }
+ toggle_particle_cursor(C, 1);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_PARTICLE, NULL);
+ }
+ else {
+ ob->mode &= ~mode_flag;
+ toggle_particle_cursor(C, 0);
+ free_all_psys_edit(ob);
+ WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL);
+ }
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
- WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
+ WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
- WM_toolsystem_update_from_context_view3d(C);
+ WM_toolsystem_update_from_context_view3d(C);
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_particle_edit_toggle(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Particle Edit Toggle";
- ot->idname = "PARTICLE_OT_particle_edit_toggle";
- ot->description = "Toggle particle edit mode";
+ /* identifiers */
+ ot->name = "Particle Edit Toggle";
+ ot->idname = "PARTICLE_OT_particle_edit_toggle";
+ ot->description = "Toggle particle edit mode";
- /* api callbacks */
- ot->exec = particle_edit_toggle_exec;
- ot->poll = particle_edit_toggle_poll;
+ /* api callbacks */
+ ot->exec = particle_edit_toggle_exec;
+ ot->poll = particle_edit_toggle_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-
/************************ set editable operator ************************/
static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
- ParticleSystem *psys = psys_get_current(ob);
+ Object *ob = CTX_data_active_object(C);
+ ParticleSystem *psys = psys_get_current(ob);
- if (psys->edit) {
- if (psys->edit->edited || 1) {
- PE_free_ptcache_edit(psys->edit);
+ if (psys->edit) {
+ if (psys->edit->edited || 1) {
+ PE_free_ptcache_edit(psys->edit);
- psys->edit = NULL;
- psys->free_edit = NULL;
+ psys->edit = NULL;
+ psys->free_edit = NULL;
- psys->recalc |= ID_RECALC_PSYS_RESET;
- psys->flag &= ~PSYS_GLOBAL_HAIR;
- psys->flag &= ~PSYS_EDITED;
+ psys->recalc |= ID_RECALC_PSYS_RESET;
+ psys->flag &= ~PSYS_GLOBAL_HAIR;
+ psys->flag &= ~PSYS_EDITED;
- psys_reset(psys, PSYS_RESET_DEPSGRAPH);
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
- }
- else { /* some operation might have protected hair from editing so let's clear the flag */
- psys->recalc |= ID_RECALC_PSYS_RESET;
- psys->flag &= ~PSYS_GLOBAL_HAIR;
- psys->flag &= ~PSYS_EDITED;
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- }
+ psys_reset(psys, PSYS_RESET_DEPSGRAPH);
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
+ }
+ else { /* some operation might have protected hair from editing so let's clear the flag */
+ psys->recalc |= ID_RECALC_PSYS_RESET;
+ psys->flag &= ~PSYS_GLOBAL_HAIR;
+ psys->flag &= ~PSYS_EDITED;
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ }
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
static int clear_edited_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- return WM_operator_confirm_message(C, op, "Lose changes done in particle mode? (no undo)");
+ return WM_operator_confirm_message(C, op, "Lose changes done in particle mode? (no undo)");
}
void PARTICLE_OT_edited_clear(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Clear Edited";
- ot->idname = "PARTICLE_OT_edited_clear";
- ot->description = "Undo all edition performed on the particle system";
+ /* identifiers */
+ ot->name = "Clear Edited";
+ ot->idname = "PARTICLE_OT_edited_clear";
+ ot->description = "Undo all edition performed on the particle system";
- /* api callbacks */
- ot->exec = clear_edited_exec;
- ot->poll = particle_edit_toggle_poll;
- ot->invoke = clear_edited_invoke;
+ /* api callbacks */
+ ot->exec = clear_edited_exec;
+ ot->poll = particle_edit_toggle_poll;
+ ot->invoke = clear_edited_invoke;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/************************ Unify length operator ************************/
static float calculate_point_length(PTCacheEditPoint *point)
{
- float length = 0.0f;
- KEY_K;
- LOOP_KEYS {
- if (k > 0) {
- length += len_v3v3((key - 1)->co, key->co);
- }
- }
- return length;
+ float length = 0.0f;
+ KEY_K;
+ LOOP_KEYS
+ {
+ if (k > 0) {
+ length += len_v3v3((key - 1)->co, key->co);
+ }
+ }
+ return length;
}
static float calculate_average_length(PTCacheEdit *edit)
{
- int num_selected = 0;
- float total_length = 0;
- POINT_P;
- LOOP_SELECTED_POINTS {
- total_length += calculate_point_length(point);
- ++num_selected;
- }
- if (num_selected == 0) {
- return 0.0f;
- }
- return total_length / num_selected;
+ int num_selected = 0;
+ float total_length = 0;
+ POINT_P;
+ LOOP_SELECTED_POINTS
+ {
+ total_length += calculate_point_length(point);
+ ++num_selected;
+ }
+ if (num_selected == 0) {
+ return 0.0f;
+ }
+ return total_length / num_selected;
}
static void scale_point_factor(PTCacheEditPoint *point, float factor)
{
- float orig_prev_co[3], prev_co[3];
- KEY_K;
- LOOP_KEYS {
- if (k == 0) {
- copy_v3_v3(orig_prev_co, key->co);
- copy_v3_v3(prev_co, key->co);
- }
- else {
- float new_co[3];
- float delta[3];
-
- sub_v3_v3v3(delta, key->co, orig_prev_co);
- mul_v3_fl(delta, factor);
- add_v3_v3v3(new_co, prev_co, delta);
-
- copy_v3_v3(orig_prev_co, key->co);
- copy_v3_v3(key->co, new_co);
- copy_v3_v3(prev_co, key->co);
- }
- }
- point->flag |= PEP_EDIT_RECALC;
+ float orig_prev_co[3], prev_co[3];
+ KEY_K;
+ LOOP_KEYS
+ {
+ if (k == 0) {
+ copy_v3_v3(orig_prev_co, key->co);
+ copy_v3_v3(prev_co, key->co);
+ }
+ else {
+ float new_co[3];
+ float delta[3];
+
+ sub_v3_v3v3(delta, key->co, orig_prev_co);
+ mul_v3_fl(delta, factor);
+ add_v3_v3v3(new_co, prev_co, delta);
+
+ copy_v3_v3(orig_prev_co, key->co);
+ copy_v3_v3(key->co, new_co);
+ copy_v3_v3(prev_co, key->co);
+ }
+ }
+ point->flag |= PEP_EDIT_RECALC;
}
static void scale_point_to_length(PTCacheEditPoint *point, float length)
{
- const float point_length = calculate_point_length(point);
- if (point_length != 0.0f) {
- const float factor = length / point_length;
- scale_point_factor(point, factor);
- }
+ const float point_length = calculate_point_length(point);
+ if (point_length != 0.0f) {
+ const float factor = length / point_length;
+ scale_point_factor(point, factor);
+ }
}
static void scale_points_to_length(PTCacheEdit *edit, float length)
{
- POINT_P;
- LOOP_SELECTED_POINTS {
- scale_point_to_length(point, length);
- }
- recalc_lengths(edit);
+ POINT_P;
+ LOOP_SELECTED_POINTS
+ {
+ scale_point_to_length(point, length);
+ }
+ recalc_lengths(edit);
}
static int unify_length_exec(bContext *C, wmOperator *UNUSED(op))
{
- Object *ob = CTX_data_active_object(C);
- Scene *scene = CTX_data_scene(C);
- Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
- PTCacheEdit *edit = PE_get_current(scene, ob);
- float average_length = calculate_average_length(edit);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ float average_length = calculate_average_length(edit);
- if (average_length == 0.0f) {
- return OPERATOR_CANCELLED;
- }
- scale_points_to_length(edit, average_length);
+ if (average_length == 0.0f) {
+ return OPERATOR_CANCELLED;
+ }
+ scale_points_to_length(edit, average_length);
- PE_update_object(depsgraph, scene, ob, 1);
- if (edit->psys) {
- WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
- }
- else {
- DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
- }
+ PE_update_object(depsgraph, scene, ob, 1);
+ if (edit->psys) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob);
+ }
+ else {
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+ }
- return OPERATOR_FINISHED;
+ return OPERATOR_FINISHED;
}
void PARTICLE_OT_unify_length(struct wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Unify Length";
- ot->idname = "PARTICLE_OT_unify_length";
- ot->description = "Make selected hair the same length";
+ /* identifiers */
+ ot->name = "Unify Length";
+ ot->idname = "PARTICLE_OT_unify_length";
+ ot->description = "Make selected hair the same length";
- /* api callbacks */
- ot->exec = unify_length_exec;
- ot->poll = PE_poll_view3d;
+ /* api callbacks */
+ ot->exec = unify_length_exec;
+ ot->poll = PE_poll_view3d;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}