diff options
Diffstat (limited to 'source/blender/editors/physics/particle_edit.c')
-rw-r--r-- | source/blender/editors/physics/particle_edit.c | 1227 |
1 files changed, 800 insertions, 427 deletions
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index acfc3844b83..cfdeeffc434 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -46,40 +46,55 @@ #include "BLI_math.h" #include "BLI_lasso_2d.h" #include "BLI_listbase.h" +#include "BLI_string.h" #include "BLI_kdtree.h" #include "BLI_rand.h" +#include "BLI_task.h" #include "BLI_utildefines.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" #include "BKE_object.h" +#include "BKE_library.h" #include "BKE_main.h" #include "BKE_mesh.h" +#include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_report.h" +#include "BKE_scene.h" #include "BKE_bvhutils.h" #include "BKE_pointcache.h" +#include "DEG_depsgraph.h" + #include "BIF_gl.h" -#include "BIF_glutil.h" #include "ED_object.h" #include "ED_physics.h" #include "ED_mesh.h" #include "ED_particle.h" +#include "ED_screen.h" #include "ED_view3d.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" + #include "UI_resources.h" #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" +#include "WM_toolsystem.h" #include "RNA_access.h" #include "RNA_define.h" +#include "DEG_depsgraph_query.h" + +#include "PIL_time_utildefines.h" + #include "physics_intern.h" #include "particle_edit_utildefines.h" @@ -88,27 +103,25 @@ int PE_poll(bContext *C) { - Main *bmain = CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) + if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) { return 0; - - return (PE_get_current(bmain, scene, ob) != NULL); + } + return (PE_get_current(scene, ob) != NULL); } int PE_hair_poll(bContext *C) { - Main *bmain = CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); PTCacheEdit *edit; - if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) + if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT)) { return 0; - - edit= PE_get_current(bmain, scene, ob); + } + edit = PE_get_current(scene, ob); return (edit && edit->psys); } @@ -186,12 +199,55 @@ static float pe_brush_size_get(const Scene *UNUSED(scene), ParticleBrushData *br 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; +} + +/* NOTE: Similar to creation of edit, but only updates pointers in the + * existing struct. + */ +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++; + } +} /* 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(Main *bmain, Scene *scene, Object *ob, int create) +static PTCacheEdit *pe_get_current( + Depsgraph *depsgraph, Scene *scene, Object *ob, int create) { ParticleEditSettings *pset= PE_settings(scene); PTCacheEdit *edit = NULL; @@ -204,7 +260,7 @@ static PTCacheEdit *pe_get_current(Main *bmain, Scene *scene, Object *ob, int cr pset->scene = scene; pset->object = ob; - BKE_ptcache_ids_from_object(bmain, &pidlist, ob, NULL, 0); + 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)) { @@ -230,18 +286,21 @@ static PTCacheEdit *pe_get_current(Main *bmain, Scene *scene, Object *ob, int cr 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(bmain, scene, ob, pid->cache, NULL); + PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL); edit = pid->cache->edit; } else { - if (create && !psys->edit && psys->flag & PSYS_HAIR_DONE) - PE_create_particle_edit(bmain, scene, ob, NULL, psys); + 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(bmain, scene, ob, pid->cache, psys); + PE_create_particle_edit(depsgraph, scene, ob, pid->cache, psys); edit = pid->cache->edit; } @@ -252,7 +311,7 @@ static PTCacheEdit *pe_get_current(Main *bmain, Scene *scene, Object *ob, int cr 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(bmain, scene, ob, pid->cache, NULL); + PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL); } edit = pid->cache->edit; break; @@ -261,35 +320,44 @@ static PTCacheEdit *pe_get_current(Main *bmain, Scene *scene, Object *ob, int cr 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(bmain, scene, ob, pid->cache, NULL); + PE_create_particle_edit(depsgraph, scene, ob, pid->cache, NULL); } edit = pid->cache->edit; break; } } - if (edit) + 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(Main *bmain, Scene *scene, Object *ob) +PTCacheEdit *PE_get_current(Scene *scene, Object *ob) { - return pe_get_current(bmain, scene, ob, 0); + return pe_get_current(NULL, scene, ob, 0); } -PTCacheEdit *PE_create_current(Main *bmain, Scene *scene, Object *ob) +PTCacheEdit *PE_create_current(Depsgraph *depsgraph, Scene *scene, Object *ob) { - return pe_get_current(bmain, scene, ob, 1); + return pe_get_current(depsgraph, scene, ob, 1); } -void PE_current_changed(Main *bmain, Scene *scene, Object *ob) +void PE_current_changed(Depsgraph *depsgraph, Scene *scene, Object *ob) { - if (ob->mode == OB_MODE_PARTICLE_EDIT) - PE_create_current(bmain, 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) @@ -331,14 +399,18 @@ static int pe_x_mirror(Object *ob) typedef struct PEData { ViewContext vc; - bglMats mats; + const bContext *context; Main *bmain; Scene *scene; + ViewLayer *view_layer; Object *ob; - DerivedMesh *dm; + Mesh *mesh; PTCacheEdit *edit; BVHTreeFromMesh shape_bvh; + Depsgraph *depsgraph; + + RNG *rng; const int *mval; rcti *rect; @@ -369,9 +441,11 @@ static void PE_set_data(bContext *C, PEData *data) memset(data, 0, sizeof(*data)); data->bmain = CTX_data_main(C); - data->scene= CTX_data_scene(C); - data->ob= CTX_data_active_object(C); - data->edit= PE_get_current(data->bmain, data->scene, data->ob); + 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) @@ -379,8 +453,6 @@ static void PE_set_view3d_data(bContext *C, PEData *data) PE_set_data(C, data); ED_view3d_viewcontext_init(C, &data->vc); - /* note, the object argument means the modelview matrix does not account for the objects matrix, use viewmat rather than (obmat * viewmat) */ - view3d_get_transformation(data->vc.ar, data->vc.rv3d, NULL, &data->mats); if (V3D_IS_ZBUF(data->vc.v3d)) { if (data->vc.v3d->flag & V3D_INVALID_BACKBUF) { @@ -398,15 +470,15 @@ static void PE_set_view3d_data(bContext *C, PEData *data) static bool PE_create_shape_tree(PEData *data, Object *shapeob) { - DerivedMesh *dm = shapeob->derivedFinal; + Mesh *mesh = BKE_object_get_evaluated_mesh(data->depsgraph, shapeob); memset(&data->shape_bvh, 0, sizeof(data->shape_bvh)); - if (!dm) { + if (!mesh) { return false; } - return (bvhtree_from_mesh_get(&data->shape_bvh, dm, 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) @@ -414,13 +486,28 @@ static void PE_free_shape_tree(PEData *data) 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 ^= GET_UINT_FROM_POINTER(data->ob); + rng_seed ^= GET_UINT_FROM_POINTER(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; + } +} + /*************************** selection utilities *******************************/ static bool key_test_depth(PEData *data, const float co[3], const int screen_co[2]) { View3D *v3d= data->vc.v3d; ViewDepths *vd = data->vc.rv3d->depths; - double ux, uy, uz; float depth; /* nothing to do */ @@ -436,9 +523,6 @@ static bool key_test_depth(PEData *data, const float co[3], const int screen_co[ } #endif - gluProject(co[0], co[1], co[2], data->mats.modelview, data->mats.projection, - (GLint *)data->mats.viewport, &ux, &uy, &uz); - /* 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); @@ -448,7 +532,10 @@ static bool key_test_depth(PEData *data, const float co[3], const int screen_co[ else return 0; - if ((float)uz - 0.00001f > depth) + float win[3]; + ED_view3d_project(data->vc.ar, co, win); + + if (win[2] - 0.00001f > depth) return 0; else return 1; @@ -612,61 +699,87 @@ static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selecte } } -static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected) +typedef struct KeyIterData { + PEData *data; + PTCacheEdit *edit; + int selected; + ForKeyMatFunc 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 = NULL; - ParticleEditSettings *pset= PE_settings(data->scene); - POINT_P; KEY_K; + 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 (edit->psys) - psmd= psys_get_modifier(data->ob, edit->psys); - - /* 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) { - if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { - if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) { - psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat); - invert_m4_m4(imat, mat); - } - - func(data, mat, imat, p, point->totkey-1, key); + 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) { + if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { + 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); } } } - else { - /* do all keys */ - LOOP_VISIBLE_KEYS { - if (selected==0 || key->flag & PEK_SELECT) { - if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { - if (edit->psys && !(edit->psys->flag & PSYS_GLOBAL_HAIR)) { - psys_mat_hair_to_global(data->ob, psmd->dm_final, psys->part->from, psys->particles + p, mat); - invert_m4_m4(imat, mat); - } - - func(data, mat, imat, p, k, key); + } + else { + /* do all keys */ + PTCacheEditKey *key; + int k; + LOOP_VISIBLE_KEYS { + if (selected==0 || key->flag & PEK_SELECT) { + if (key_inside_circle(data, data->rad, KEY_WCO, &data->dist)) { + 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); } } } } } +static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc 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; + } + + 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); +} + static void foreach_selected_point(PEData *data, ForPointFunc func) { PTCacheEdit *edit = data->edit; @@ -730,7 +843,7 @@ static int count_selected_keys(Scene *scene, PTCacheEdit *edit) static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) { PTCacheEdit *edit; - ParticleSystemModifierData *psmd; + ParticleSystemModifierData *psmd_eval; KDTree *tree; KDTreeNearest nearest; HairKey *key; @@ -739,10 +852,10 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) int index, totpart; edit= psys->edit; - psmd= psys_get_modifier(ob, psys); + psmd_eval = edit->psmd_eval; totpart= psys->totpart; - if (!psmd->dm_final) + if (!psmd_eval->mesh_final) return; tree= BLI_kdtree_new(totpart); @@ -750,7 +863,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) /* insert particles into kd tree */ LOOP_PARTICLES { key = pa->hair; - psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat); + 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_insert(tree, p, co); @@ -764,7 +877,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) LOOP_PARTICLES { key = pa->hair; - psys_mat_hair_to_orco(ob, psmd->dm_final, psys->part->from, pa, mat); + 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]; @@ -790,7 +903,7 @@ static void PE_update_mirror_cache(Object *ob, ParticleSystem *psys) BLI_kdtree_free(tree); } -static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa) +static void PE_mirror_particle(Object *ob, Mesh *mesh, ParticleSystem *psys, ParticleData *pa, ParticleData *mpa) { HairKey *hkey, *mhkey; PTCacheEditPoint *point, *mpoint; @@ -841,8 +954,8 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys } /* mirror positions and tags */ - psys_mat_hair_to_orco(ob, dm, psys->part->from, pa, mat); - psys_mat_hair_to_orco(ob, dm, psys->part->from, mpa, mmat); + 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; @@ -870,16 +983,16 @@ static void PE_mirror_particle(Object *ob, DerivedMesh *dm, ParticleSystem *psys static void PE_apply_mirror(Object *ob, ParticleSystem *psys) { PTCacheEdit *edit; - ParticleSystemModifierData *psmd; + ParticleSystemModifierData *psmd_eval; POINT_P; if (!psys) return; edit= psys->edit; - psmd= psys_get_modifier(ob, psys); + psmd_eval= edit->psmd_eval; - if (!psmd->dm_final) + if (!psmd_eval->mesh_final) return; if (!edit->mirror_cache) @@ -892,7 +1005,7 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys) * to avoid doing mirror twice */ LOOP_POINTS { if (point->flag & PEP_EDIT_RECALC) { - PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL); + 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; @@ -909,110 +1022,152 @@ static void PE_apply_mirror(Object *ob, ParticleSystem *psys) /************************************************/ /* Edit Calculation */ /************************************************/ -/* 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); + +typedef struct DeflectEmitterIter { + Object *object; ParticleSystem *psys; - ParticleSystemModifierData *psmd; - POINT_P; KEY_K; + 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; - float hairimat[4][4], hairmat[4][4]; - 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; - - psys = edit->psys; - psmd = psys_get_modifier(ob, psys); - - if (!psmd->dm_final) - return; + 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_EDITED_POINTS { - psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles + p, hairmat); + LOOP_KEYS { + mul_m4_v3(hairmat, key->co); + } - 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_find_nearest(edit->emitter_field, key->co, NULL); - LOOP_KEYS { - if (k==0) { - dist_1st = len_v3v3((key+1)->co, key->co); - dist_1st *= dist * pset->emitterdist; - } - else { - index= BLI_kdtree_find_nearest(edit->emitter_field, key->co, NULL); - - vec=edit->emitter_cosnos +index*6; - nor=vec+3; + vec = edit->emitter_cosnos + index * 6; + nor = vec + 3; - sub_v3_v3v3(dvec, key->co, vec); + sub_v3_v3v3(dvec, key->co, vec); - dot=dot_v3v3(dvec, nor); - copy_v3_v3(dvec, nor); + 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 { + if (dot > 0.0f) { + if (dot < dist_1st) { normalize_v3(dvec); - mul_v3_fl(dvec, dist_1st-dot); + mul_v3_fl(dvec, dist_1st - dot); add_v3_v3(key->co, dvec); } - if (k==1) - dist_1st*=1.3333f; + } + 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); + invert_m4_m4(hairimat, hairmat); - LOOP_KEYS { - mul_m4_v3(hairimat, key->co); - } + LOOP_KEYS { + mul_m4_v3(hairimat, key->co); } } -/* force set distances between neighboring keys */ -static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit) -{ - ParticleEditSettings *pset=PE_settings(scene); - POINT_P; KEY_K; - float dv1[3]; +/* 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; - if (edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0) + if (edit == NULL || edit->psys == NULL || + (pset->flag & PE_DEFLECT_EMITTER) == 0 || + (edit->psys->flag & PSYS_GLOBAL_HAIR)) + { return; + } - if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) + psys = edit->psys; + + if (!edit->psmd_eval->mesh_final) { return; + } - LOOP_EDITED_POINTS { - LOOP_KEYS { - if (k) { - 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); - } + 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); +} + +typedef struct ApplyLengthsIterData { + 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); } } } -/* try to find a nice solution to keep distances between neighboring keys */ -static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit) + +/* force set distances between neighboring keys */ +static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit) { ParticleEditSettings *pset=PE_settings(scene); - POINT_P; - PTCacheEditKey *key; - int j, k; - 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}; if (edit==0 || (pset->flag & PE_KEEP_LENGTHS)==0) return; @@ -1020,43 +1175,91 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit) if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR) return; - LOOP_EDITED_POINTS { - for (j=1; j<point->totkey; j++) { - 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))); - } + ApplyLengthsIterData iter_data; + iter_data.edit = edit; - 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)); - } + 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); +} - if (k) { - add_v3_v3((key-1)->co, dv1); - } +typedef struct IterateLengthsIterData { + 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; + } - add_v3_v3v3(dv1, dv0, dv2); + 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; + } + + 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); +} + /* set current distances to be kept between neighbouting keys */ void recalc_lengths(PTCacheEdit *edit) { @@ -1074,14 +1277,14 @@ void recalc_lengths(PTCacheEdit *edit) } /* calculate a tree for finding nearest emitter's vertice */ -void recalc_emitter_field(Object *ob, ParticleSystem *psys) +void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), ParticleSystem *psys) { - DerivedMesh *dm=psys_get_modifier(ob, psys)->dm_final; - PTCacheEdit *edit= psys->edit; + PTCacheEdit *edit = psys->edit; + Mesh *mesh = edit->psmd_eval->mesh_final; float *vec, *nor; int i, totface /*, totvert*/; - if (!dm) + if (!mesh) return; if (edit->emitter_cosnos) @@ -1089,7 +1292,7 @@ void recalc_emitter_field(Object *ob, ParticleSystem *psys) BLI_kdtree_free(edit->emitter_field); - totface=dm->getNumTessFaces(dm); + totface = mesh->totface; /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/ edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float), "emitter cosnos"); @@ -1100,23 +1303,23 @@ void recalc_emitter_field(Object *ob, ParticleSystem *psys) nor=vec+3; for (i=0; i<totface; i++, vec+=6, nor+=6) { - MFace *mface=dm->getTessFaceData(dm, i, CD_MFACE); + MFace *mface = &mesh->mface[i]; MVert *mvert; - mvert=dm->getVertData(dm, mface->v1, CD_MVERT); + mvert = &mesh->mvert[mface->v1]; copy_v3_v3(vec, mvert->co); VECCOPY(nor, mvert->no); - mvert=dm->getVertData(dm, mface->v2, CD_MVERT); + mvert = &mesh->mvert[mface->v2]; add_v3_v3v3(vec, vec, mvert->co); VECADD(nor, nor, mvert->no); - mvert=dm->getVertData(dm, mface->v3, CD_MVERT); + mvert = &mesh->mvert[mface->v3]; add_v3_v3v3(vec, vec, mvert->co); VECADD(nor, nor, mvert->no); if (mface->v4) { - mvert=dm->getVertData(dm, mface->v4, CD_MVERT); + mvert = &mesh->mvert[mface->v4]; add_v3_v3v3(vec, vec, mvert->co); VECADD(nor, nor, mvert->no); @@ -1133,9 +1336,9 @@ void recalc_emitter_field(Object *ob, ParticleSystem *psys) BLI_kdtree_balance(edit->emitter_field); } -static void PE_update_selection(Main *bmain, Scene *scene, Object *ob, int useflag) +static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob, int useflag) { - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); HairKey *hkey; POINT_P; KEY_K; @@ -1154,27 +1357,29 @@ static void PE_update_selection(Main *bmain, Scene *scene, Object *ob, int usefl } } - psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering); + 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, DEG_TAG_SELECT_UPDATE); } -void update_world_cos(Object *ob, PTCacheEdit *edit) +void update_world_cos(Depsgraph *UNUSED(depsgraph), Object *ob, PTCacheEdit *edit) { ParticleSystem *psys = edit->psys; - ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); + ParticleSystemModifierData *psmd_eval = edit->psmd_eval; POINT_P; KEY_K; float hairmat[4][4]; - if (psys==0 || psys->edit==0 || psmd->dm_final==NULL) + 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->dm_final, psys->part->from, psys->particles+p, hairmat); + 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); @@ -1240,12 +1445,12 @@ static void update_velocities(PTCacheEdit *edit) } } -void PE_update_object(Main *bmain, Scene *scene, Object *ob, int useflag) +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(bmain, scene, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); POINT_P; if (!edit) @@ -1264,13 +1469,13 @@ void PE_update_object(Main *bmain, Scene *scene, Object *ob, int useflag) if (pe_x_mirror(ob)) PE_apply_mirror(ob, edit->psys); if (edit->psys) - update_world_cos(ob, edit); + 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(scene, ob, edit, CFRA, G.is_rendering); + psys_cache_edit_paths(depsgraph, scene, ob, edit, CFRA, G.is_rendering); /* disable update flag */ LOOP_POINTS { @@ -1379,10 +1584,10 @@ static void select_action_apply(PTCacheEditPoint *point, PTCacheEditKey *key, in static int pe_select_all_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Scene *scene= CTX_data_scene(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); POINT_P; KEY_K; int action = RNA_enum_get(op->ptr, "action"); @@ -1405,7 +1610,7 @@ static int pe_select_all_exec(bContext *C, wmOperator *op) } } - PE_update_selection(bmain, scene, ob, 1); + PE_update_selection(depsgraph, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -1432,11 +1637,10 @@ void PARTICLE_OT_select_all(wmOperatorType *ot) int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) { - Main *bmain = CTX_data_main(C); PEData data; Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); POINT_P; KEY_K; if (!PE_start_edit(edit)) @@ -1463,7 +1667,7 @@ int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselec else for_mouse_hit_keys(&data, toggle_key_select, 1); - PE_update_selection(bmain, scene, ob, 1); + PE_update_selection(data.depsgraph, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob); return OPERATOR_FINISHED; @@ -1504,7 +1708,7 @@ static int select_roots_exec(bContext *C, wmOperator *op) data.select_action = action; foreach_point(&data, select_root); - PE_update_selection(data.bmain, data.scene, data.ob, 1); + 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; @@ -1569,7 +1773,7 @@ static int select_tips_exec(bContext *C, wmOperator *op) data.select_action = action; foreach_point(&data, select_tip); - PE_update_selection(data.bmain, data.scene, data.ob, 1); + 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; @@ -1624,7 +1828,7 @@ static int select_random_exec(bContext *C, wmOperator *op) PE_set_data(C, &data); data.select_action = SEL_SELECT; - edit = PE_get_current(data.bmain, data.scene, data.ob); + edit = PE_get_current(data.scene, data.ob); rng = BLI_rng_new_srandom(seed); @@ -1649,7 +1853,7 @@ static int select_random_exec(bContext *C, wmOperator *op) BLI_rng_free(rng); - PE_update_selection(data.bmain, data.scene, data.ob, 1); + 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; @@ -1693,7 +1897,7 @@ static int select_linked_exec(bContext *C, wmOperator *op) data.select= !RNA_boolean_get(op->ptr, "deselect"); for_mouse_hit_keys(&data, select_keys, 1); /* nearest only */ - PE_update_selection(data.bmain, data.scene, data.ob, 1); + 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; @@ -1740,10 +1944,9 @@ void PE_deselect_all_visible(PTCacheEdit *edit) int PE_border_select(bContext *C, rcti *rect, bool select, bool extend) { - Main *bmain = CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); PEData data; if (!PE_start_edit(edit)) @@ -1758,7 +1961,7 @@ int PE_border_select(bContext *C, rcti *rect, bool select, bool extend) for_mouse_hit_keys(&data, select_key, 0); - PE_update_selection(bmain, scene, ob, 1); + PE_update_selection(data.depsgraph, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -1768,10 +1971,9 @@ int PE_border_select(bContext *C, rcti *rect, bool select, bool extend) int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad) { - Main *bmain = CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); PEData data; if (!PE_start_edit(edit)) @@ -1784,7 +1986,7 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad) for_mouse_hit_keys(&data, select_key, 0); - PE_update_selection(bmain, scene, ob, 1); + PE_update_selection(data.depsgraph, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -1794,14 +1996,13 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad) int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool extend, bool select) { - Main *bmain = CTX_data_main(C); 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(bmain, scene, ob); + PTCacheEdit *edit = PE_get_current(scene, ob); ParticleSystem *psys = edit->psys; - ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); + ParticleSystemModifierData *psmd_eval = edit->psmd_eval; POINT_P; KEY_K; float co[3], mat[4][4]; int screen_co[2]; @@ -1821,7 +2022,7 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool LOOP_VISIBLE_POINTS { if (edit->psys && !(psys->flag & PSYS_GLOBAL_HAIR)) - psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles + p, mat); + 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 { @@ -1873,7 +2074,7 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool } } - PE_update_selection(bmain, scene, ob, 1); + PE_update_selection(data.depsgraph, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -1883,12 +2084,14 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool static int hide_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Object *ob= CTX_data_active_object(C); Scene *scene= CTX_data_scene(C); - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + 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; @@ -1908,7 +2111,7 @@ static int hide_exec(bContext *C, wmOperator *op) } } - PE_update_selection(bmain, scene, ob, 1); + PE_update_selection(depsgraph, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -1936,10 +2139,10 @@ void PARTICLE_OT_hide(wmOperatorType *ot) static int reveal_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Object *ob= CTX_data_active_object(C); Scene *scene= CTX_data_scene(C); - PTCacheEdit *edit = PE_get_current(bmain, scene, ob); + 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; @@ -1954,7 +2157,7 @@ static int reveal_exec(bContext *C, wmOperator *op) } } - PE_update_selection(bmain, scene, ob, 1); + PE_update_selection(depsgraph, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, ob); return OPERATOR_FINISHED; @@ -2016,7 +2219,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op)) PE_set_data(C, &data); foreach_point(&data, select_less_keys); - PE_update_selection(data.bmain, data.scene, data.ob, 1); + 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; @@ -2078,7 +2281,7 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op)) PE_set_data(C, &data); foreach_point(&data, select_more_keys); - PE_update_selection(data.bmain, data.scene, data.ob, 1); + 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; @@ -2114,9 +2317,10 @@ static void rekey_particle(PEData *data, int pa_index) float dval, sta, end; int k; - 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; pa->flag |= PARS_REKEY; @@ -2175,7 +2379,7 @@ static int rekey_exec(bContext *C, wmOperator *op) foreach_selected_point(&data, rekey_particle); recalc_lengths(data.edit); - PE_update_object(data.bmain, data.scene, data.ob, 1); + 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; @@ -2200,11 +2404,11 @@ void PARTICLE_OT_rekey(wmOperatorType *ot) RNA_def_int(ot->srna, "keys_number", 2, 2, INT_MAX, "Number of Keys", "", 2, 100); } -static void rekey_particle_to_time(Main *bmain, 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(bmain, scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); ParticleSystem *psys; - ParticleSimulationData sim= {0}; + ParticleSimulationData sim = {0}; ParticleData *pa; ParticleKey state; HairKey *new_keys, *key; @@ -2215,9 +2419,10 @@ static void rekey_particle_to_time(Main *bmain, Scene *scene, Object *ob, int pa psys = edit->psys; - 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; @@ -2254,15 +2459,15 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror) ParticleData *pa, *npa=0, *new_pars=0; POINT_P; PTCacheEditPoint *npoint=0, *new_points=0; - ParticleSystemModifierData *psmd; + ParticleSystemModifierData *psmd_eval; int i, new_totpart= psys->totpart, removed= 0; if (mirror) { /* mirror tags */ - psmd= psys_get_modifier(ob, psys); + psmd_eval = edit->psmd_eval; LOOP_TAGGED_POINTS { - PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL); + PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL); } } @@ -2333,16 +2538,16 @@ static void remove_tagged_keys(Object *ob, ParticleSystem *psys) HairKey *hkey, *nhkey, *new_hkeys=0; POINT_P; KEY_K; PTCacheEditKey *nkey, *new_keys; - ParticleSystemModifierData *psmd; + ParticleSystemModifierData *psmd_eval; short new_totkey; if (pe_x_mirror(ob)) { /* mirror key tags */ - psmd= psys_get_modifier(ob, psys); + psmd_eval = psys_get_modifier(ob, psys); LOOP_POINTS { LOOP_TAGGED_KEYS { - PE_mirror_particle(ob, psmd->dm_final, psys, psys->particles + p, NULL); + PE_mirror_particle(ob, psmd_eval->mesh_final, psys, psys->particles + p, NULL); break; } } @@ -2432,9 +2637,10 @@ static void subdivide_particle(PEData *data, int pa_index) short totnewkey=0; float endtime; - 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) @@ -2506,7 +2712,7 @@ static int subdivide_exec(bContext *C, wmOperator *UNUSED(op)) foreach_point(&data, subdivide_particle); recalc_lengths(data.edit); - PE_update_object(data.bmain, data.scene, data.ob, 1); + 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; @@ -2531,12 +2737,11 @@ void PARTICLE_OT_subdivide(wmOperatorType *ot) static int remove_doubles_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); ParticleSystem *psys = edit->psys; - ParticleSystemModifierData *psmd; + ParticleSystemModifierData *psmd_eval; KDTree *tree; KDTreeNearest nearest[10]; POINT_P; @@ -2547,7 +2752,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; edit= psys->edit; - psmd= psys_get_modifier(ob, psys); + psmd_eval = edit->psmd_eval; totremoved= 0; do { @@ -2557,7 +2762,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) /* insert particles into kd tree */ LOOP_SELECTED_POINTS { - psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat); + 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_insert(tree, p, co); @@ -2567,7 +2772,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) /* tag particles to be removed */ LOOP_SELECTED_POINTS { - psys_mat_hair_to_object(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat); + 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); @@ -2596,7 +2801,7 @@ static int remove_doubles_exec(bContext *C, wmOperator *op) BKE_reportf(op->reports, RPT_INFO, "Removed %d double particles", totremoved); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); return OPERATOR_FINISHED; @@ -2624,11 +2829,10 @@ void PARTICLE_OT_remove_doubles(wmOperatorType *ot) static int weight_set_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Scene *scene= CTX_data_scene(C); ParticleEditSettings *pset= PE_settings(scene); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); ParticleSystem *psys = edit->psys; POINT_P; KEY_K; @@ -2649,7 +2853,7 @@ static int weight_set_exec(bContext *C, wmOperator *op) } } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); return OPERATOR_FINISHED; @@ -2681,24 +2885,27 @@ static void brush_drawcursor(bContext *C, int x, int y, void *UNUSED(customdata) ParticleEditSettings *pset= PE_settings(scene); ParticleBrushData *brush; - if (pset->brushtype < 0) + if (pset->brushtype < 0) { return; + } - brush= &pset->brush[pset->brushtype]; + brush = &pset->brush[pset->brushtype]; if (brush) { - glPushMatrix(); + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - glTranslatef((float)x, (float)y, 0.0f); + immUniformColor4ub(255, 255, 255, 128); - glColor4ub(255, 255, 255, 128); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - glutil_draw_lined_arc(0.0, M_PI*2.0, pe_brush_size_get(scene, brush), 40); + + imm_draw_circle_wire_2d(pos, (float)x, (float)y, pe_brush_size_get(scene, brush), 40); + glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - glPopMatrix(); + immUnbindProgram(); } } @@ -2755,7 +2962,7 @@ static int delete_exec(bContext *C, wmOperator *op) recalc_lengths(data.edit); } - DAG_id_tag_update(&data.ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&data.ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, data.ob); return OPERATOR_FINISHED; @@ -2782,11 +2989,12 @@ void PARTICLE_OT_delete(wmOperatorType *ot) /*************************** mirror operator **************************/ -static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged) +static void PE_mirror_x( + Scene *scene, Object *ob, int tagged) { Mesh *me= (Mesh *)(ob->data); - ParticleSystemModifierData *psmd; - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + ParticleSystemModifierData *psmd_eval; + PTCacheEdit *edit = PE_get_current(scene, ob); ParticleSystem *psys = edit->psys; ParticleData *pa, *newpa, *new_pars; PTCacheEditPoint *newpoint, *new_points; @@ -2798,18 +3006,18 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged) if (psys->flag & PSYS_GLOBAL_HAIR) return; - psmd= psys_get_modifier(ob, psys); - if (!psmd->dm_final) + psmd_eval = edit->psmd_eval; + if (!psmd_eval->mesh_final) return; - const bool use_dm_final_indices = (psys->part->use_modifier_stack && !psmd->dm_final->deformedOnly); + 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 DM tessface indices, we mirror final DM itself, not orig mesh. Avoids an (impossible) - * dm -> orig -> dm tessface indices conversion... */ - mirrorfaces = mesh_get_x_mirror_faces(ob, NULL, use_dm_final_indices ? psmd->dm_final : NULL); + /* 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); @@ -2823,7 +3031,7 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int 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->dm_final, psys, pa, NULL); + PE_mirror_particle(ob, psmd_eval->mesh_final, psys, pa, NULL); continue; } else @@ -2836,7 +3044,7 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged) } if (newtotpart != psys->totpart) { - MFace *mtessface = use_dm_final_indices ? psmd->dm_final->getTessFaceArray(psmd->dm_final) : me->mface; + 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"); @@ -2905,7 +3113,7 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged) } else { newpa->num_dmcache = psys_particle_dm_face_lookup( - psmd->dm_final, psmd->dm_deformed, newpa->num, newpa->fuv, NULL); + psmd_eval->mesh_final, psmd_eval->mesh_original, newpa->num, newpa->fuv, NULL); } /* update edit key pointers */ @@ -2916,7 +3124,7 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged) } /* map key positions as mirror over x axis */ - PE_mirror_particle(ob, psmd->dm_final, psys, pa, newpa); + PE_mirror_particle(ob, psmd_eval->mesh_final, psys, pa, newpa); newpa++; newpoint++; @@ -2932,16 +3140,15 @@ static void PE_mirror_x(Main *bmain, Scene *scene, Object *ob, int tagged) static int mirror_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); - PE_mirror_x(bmain, scene, ob, 0); + PE_mirror_x(scene, ob, 0); - update_world_cos(ob, edit); + update_world_cos(CTX_data_depsgraph(C), ob, edit); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); return OPERATOR_FINISHED; } @@ -2992,8 +3199,11 @@ static void brush_cut(PEData *data, int pa_index) 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_frand() > data->cutfac) return; + if (BLI_rng_get_float(data->rng) > data->cutfac) { + return; + } /* don't cut hidden */ if (edit->points[pa_index].flag & PEP_HIDE) @@ -3074,7 +3284,7 @@ static void brush_cut(PEData *data, int pa_index) edit->points[pa_index].flag |= PEP_TAG; } else { - rekey_particle_to_time(data->bmain, data->scene, ob, pa_index, cut_time); + rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time); edit->points[pa_index].flag |= PEP_EDIT_RECALC; } } @@ -3127,7 +3337,7 @@ static void brush_puff(PEData *data, int point_index) } if (psys && !(psys->flag & PSYS_GLOBAL_HAIR)) { - psys_mat_hair_to_global(data->ob, data->dm, psys->part->from, psys->particles + point_index, mat); + psys_mat_hair_to_global(data->ob, data->mesh, psys->part->from, psys->particles + point_index, mat); invert_m4_m4(imat, mat); } else { @@ -3322,12 +3532,12 @@ static void intersect_dm_quad_weights(const float v1[3], const float v2[3], cons } /* check intersection with a derivedmesh */ -static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, - 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) +static int particle_intersect_mesh(Depsgraph *depsgraph, Scene *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; @@ -3335,21 +3545,25 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, 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 (dm == NULL) { + if (mesh == NULL) { psys_disable_all(ob); - dm=mesh_get_derived_final(scene, ob, 0); + /* TODO(Sybren): port to Mesh when we have decided how to handle derivedFinal and derivedDeform */ + DerivedMesh *dm = mesh_get_derived_final(depsgraph, scene, ob, 0); if (dm == NULL) - dm=mesh_get_derived_deform(scene, ob, 0); + dm = mesh_get_derived_deform(depsgraph, scene, ob, 0); psys_enable_all(ob); if (dm == NULL) return 0; + + mesh = BKE_id_new_nomain(ID_ME, NULL); + DM_to_mesh(dm, mesh, ob, CD_MASK_EVERYTHING, false); } /* BMESH_ONLY, deform dm may not have tessface */ - DM_ensure_tessface(dm); + BKE_mesh_tessface_ensure(mesh); if (pa_minmax==0) { @@ -3362,9 +3576,9 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, copy_v3_v3(p_max, pa_minmax+3); } - totface=dm->getNumTessFaces(dm); - mface=dm->getTessFaceDataArray(dm, CD_MFACE); - mvert=dm->getVertDataArray(dm, CD_MVERT); + totface = mesh->totface; + mface = mesh->mface; + mvert = mesh->mvert; /* lets intersect the faces */ for (i=0; i<totface; i++, mface++) { @@ -3453,24 +3667,125 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, return intersect; } -static int brush_add(PEData *data, short number) +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; +} BrushAddCountIterData; + +typedef struct BrushAddCountIterTLSData { + 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(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); + } +} + +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; - DerivedMesh *dm; + Mesh *mesh; PTCacheEdit *edit = data->edit; ParticleSystem *psys= edit->psys; ParticleData *add_pars; - ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys); + ParticleSystemModifierData *psmd_eval = edit->psmd_eval; ParticleSimulationData sim= {0}; ParticleEditSettings *pset= PE_settings(scene); int i, k, n= 0, totpart= psys->totpart; - float mco[2]; - float dmx, dmy; - float co1[3], co2[3], min_d, imat[4][4]; + float co1[3], imat[4][4]; float framestep, timestep; short size= pset->brush[PE_BRUSH_ADD].size; - short size2= size*size; RNG *rng; invert_m4_m4(imat, ob->obmat); @@ -3482,67 +3797,66 @@ static int brush_add(PEData *data, short number) rng = BLI_rng_new_srandom(psys->seed+data->mval[0]+data->mval[1]); - sim.scene= scene; - sim.ob= ob; - sim.psys= psys; - sim.psmd= psmd; + sim.depsgraph = depsgraph; + sim.scene = scene; + sim.ob = ob; + sim.psys = psys; + sim.psmd = psmd_eval; - timestep= psys_get_timestep(&sim); + timestep = psys_get_timestep(&sim); - if (psys->part->use_modifier_stack || psmd->dm_final->deformedOnly) { - dm = psmd->dm_final; + if (psys->part->use_modifier_stack || psmd_eval->mesh_final->runtime.deformed_only) { + mesh = psmd_eval->mesh_final; } else { - dm = psmd->dm_deformed; + mesh = psmd_eval->mesh_original; } - BLI_assert(dm); - - for (i=0; i<number; i++) { - if (number>1) { - dmx = size; - dmy = size; - - /* rejection sampling to get points in circle */ - while (dmx*dmx + dmy*dmy > size2) { - dmx= (2.0f*BLI_rng_get_float(rng) - 1.0f)*size; - dmy= (2.0f*BLI_rng_get_float(rng) - 1.0f)*size; - } + BLI_assert(mesh); + + /* Calculate positions of new particles to add, based on brush interseciton + * with object. New particle data is assigned to a correponding 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 + * beginnign 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; } - else { - dmx = 0.0f; - dmy = 0.0f; - } - - mco[0] = data->mval[0] + dmx; - mco[1] = data->mval[1] + dmy; - ED_view3d_win_to_segment(data->vc.ar, data->vc.v3d, mco, co1, co2, true); - - mul_m4_v3(imat, co1); - mul_m4_v3(imat, co2); - min_d=2.0; - - /* warning, returns the derived mesh face */ - if (particle_intersect_dm(scene, ob, dm, 0, co1, co2, &min_d, &add_pars[n].num_dmcache, add_pars[n].fuv, 0, 0, 0, 0)) { - if (psys->part->use_modifier_stack && !psmd->dm_final->deformedOnly) { - add_pars[n].num = add_pars[n].num_dmcache; - add_pars[n].num_dmcache = DMCACHE_ISCHILD; - } - else if (dm == psmd->dm_deformed) { - /* Final DM is not same topology as orig mesh, we have to map num_dmcache to real final dm. */ - add_pars[n].num = add_pars[n].num_dmcache; - add_pars[n].num_dmcache = psys_particle_dm_face_lookup( - psmd->dm_final, psmd->dm_deformed, - add_pars[n].num, add_pars[n].fuv, NULL); - } - else { - add_pars[n].num = add_pars[n].num_dmcache; - } - - if (add_pars[n].num != DMCACHE_NOTFOUND) { - n++; - } + 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]; @@ -3573,7 +3887,7 @@ static int brush_add(PEData *data, short number) tree=BLI_kdtree_new(psys->totpart); for (i=0, pa=psys->particles; i<totpart; i++, pa++) { - psys_particle_on_dm(psmd->dm_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, cur_co, 0, 0, 0, 0, 0); + 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_insert(tree, i, cur_co); } @@ -3617,7 +3931,7 @@ static int brush_add(PEData *data, short number) int w, maxw; float maxd, totw=0.0, weight[3]; - psys_particle_on_dm(psmd->dm_final, psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co1, 0, 0, 0, 0, 0); + 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_find_nearest_n(tree, co1, ptn, 3); maxd= ptn[maxw-1].dist; @@ -3682,7 +3996,7 @@ static int brush_add(PEData *data, short number) } } for (k=0, hkey=pa->hair; k<pset->totaddkey; k++, hkey++) { - psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat); + 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); } @@ -3703,6 +4017,7 @@ static int brush_add(PEData *data, short number) typedef struct BrushEdit { Scene *scene; + ViewLayer *view_layer; Object *ob; PTCacheEdit *edit; @@ -3716,11 +4031,11 @@ typedef struct BrushEdit { static int brush_edit_init(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); Scene *scene= CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob= CTX_data_active_object(C); ParticleEditSettings *pset= PE_settings(scene); - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + PTCacheEdit *edit= PE_get_current(scene, ob); ARegion *ar= CTX_wm_region(C); BrushEdit *bedit; float min[3], max[3]; @@ -3730,7 +4045,7 @@ static int brush_edit_init(bContext *C, wmOperator *op) /* set the 'distance factor' for grabbing (used in comb etc) */ INIT_MINMAX(min, max); - PE_minmax(bmain, scene, min, max); + PE_minmax(scene, view_layer, min, max); mid_v3_v3v3(min, min, max); bedit= MEM_callocN(sizeof(BrushEdit), "BrushEdit"); @@ -3738,6 +4053,7 @@ static int brush_edit_init(bContext *C, wmOperator *op) op->customdata= bedit; bedit->scene= scene; + bedit->view_layer = view_layer; bedit->ob= ob; bedit->edit= edit; @@ -3745,19 +4061,20 @@ static int brush_edit_init(bContext *C, wmOperator *op) /* cache view depths and settings for re-use */ PE_set_view3d_data(C, &bedit->data); + PE_create_random_generator(&bedit->data); return 1; } static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) { - Main *bmain = CTX_data_main(C); 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= edit->psys ? psys_get_modifier(ob, edit->psys) : NULL; + ParticleSystemModifierData *psmd_eval = edit->psmd_eval; ParticleBrushData *brush= &pset->brush[pset->brushtype]; ARegion *ar= CTX_wm_region(C); float vec[3], mousef[2]; @@ -3793,7 +4110,8 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) 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; + 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); @@ -3871,7 +4189,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) case PE_BRUSH_PUFF: { if (edit->psys) { - data.dm= psmd->dm_final; + data.mesh = psmd_eval->mesh_final; data.mval= mval; data.rad= pe_brush_size_get(scene, brush); data.select= selected; @@ -3894,7 +4212,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) if (edit->psys && edit->psys->part->from==PART_FROM_FACE) { data.mval= mval; - added= brush_add(&data, brush->count); + added= brush_add(C, &data, brush->count); if (pset->flag & PE_KEEP_LENGTHS) recalc_lengths(edit); @@ -3927,7 +4245,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) case PE_BRUSH_WEIGHT: { if (edit->psys) { - data.dm= psmd->dm_final; + data.mesh = psmd_eval->mesh_final; data.mval= mval; data.rad= pe_brush_size_get(scene, brush); @@ -3944,21 +4262,24 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) 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(bmain, scene, ob, 1); + PE_mirror_x(scene, ob, 1); - update_world_cos(ob, edit); + update_world_cos(depsgraph, ob, edit); psys_free_path_cache(NULL, edit); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + else { + PE_update_object(depsgraph, scene, ob, 1); } - else - PE_update_object(bmain, scene, ob, 1); } if (edit->psys) { WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); + BKE_particle_batch_cache_dirty(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL); + DEG_id_tag_update(&ob->id, DEG_TAG_SELECT_UPDATE); } else { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); } @@ -3974,6 +4295,7 @@ static void brush_edit_exit(wmOperator *op) { BrushEdit *bedit= op->customdata; + PE_free_random_generator(&bedit->data); MEM_freeN(bedit); } @@ -4169,7 +4491,7 @@ static void shape_cut(PEData *data, int pa_index) edit->points[pa_index].flag |= PEP_TAG; } else { - rekey_particle_to_time(data->bmain, data->scene, ob, pa_index, cut_time); + rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time); edit->points[pa_index].flag |= PEP_EDIT_RECALC; } } @@ -4177,11 +4499,11 @@ static void shape_cut(PEData *data, int pa_index) static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); + 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(bmain, scene, ob); + 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; @@ -4212,18 +4534,21 @@ static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op)) recalc_lengths(edit); if (removed) { - update_world_cos(ob, edit); + update_world_cos(depsgraph, ob, edit); psys_free_path_cache(NULL, edit); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } + else { + PE_update_object(data.depsgraph, scene, ob, 1); } - else - PE_update_object(bmain, scene, ob, 1); if (edit->psys) { WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); + BKE_particle_batch_cache_dirty(edit->psys, BKE_PARTICLE_BATCH_DIRTY_ALL); + DEG_id_tag_update(&ob->id, DEG_TAG_SELECT_UPDATE); } else { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); } @@ -4252,12 +4577,12 @@ void PARTICLE_OT_shape_cut(wmOperatorType *ot) /************************ utilities ******************************/ -int PE_minmax(Main *bmain, Scene *scene, float min[3], float max[3]) +int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3]) { - Object *ob= OBACT; - PTCacheEdit *edit= PE_get_current(bmain, scene, ob); + Object *ob= OBACT(view_layer); + PTCacheEdit *edit= PE_get_current(scene, ob); ParticleSystem *psys; - ParticleSystemModifierData *psmd = NULL; + ParticleSystemModifierData *psmd_eval = NULL; POINT_P; KEY_K; float co[3], mat[4][4]; int ok= 0; @@ -4265,13 +4590,13 @@ int PE_minmax(Main *bmain, Scene *scene, float min[3], float max[3]) if (!edit) return ok; if ((psys = edit->psys)) - psmd= psys_get_modifier(ob, psys); + psmd_eval = edit->psmd_eval; else unit_m4(mat); LOOP_VISIBLE_POINTS { if (psys) - psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, psys->particles+p, mat); + 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); @@ -4291,18 +4616,43 @@ int PE_minmax(Main *bmain, Scene *scene, float min[3], float max[3]) /************************ particle edit toggle operator ************************/ +static struct ParticleSystem *psys_eval_get(Depsgraph *depsgraph, + Object *object, + ParticleSystem *psys) +{ + Object *object_eval = DEG_get_evaluated_object(depsgraph, object); + if (object_eval == object) { + return psys; + } + ParticleSystem *psys_eval = object_eval->particlesystem.first; + while (psys_eval != NULL) { + if (psys_eval->orig_psys == psys) { + return psys_eval; + } + psys_eval = psys_eval->next; + } + return psys_eval; +} + /* initialize needed data for bake edit */ -void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys) +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->dm_final) && !cache) + if (!(psys && psmd && psmd_eval->mesh_final) && !cache) return; if (cache && cache->flag & PTCACHE_DISK_CACHE) @@ -4314,6 +4664,9 @@ void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache * edit = (psys) ? psys->edit : cache->edit; if (!edit) { + ParticleSystem *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"); @@ -4321,8 +4674,11 @@ void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache * edit->totpoint = totpoint; if (psys && !cache) { - psys->edit= edit; + 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; @@ -4349,7 +4705,7 @@ void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache * } pa++; } - update_world_cos(ob, edit); + update_world_cos(depsgraph, ob, edit); } else { PTCacheMem *pm; @@ -4387,13 +4743,19 @@ void PE_create_particle_edit(Main *bmain, Scene *scene, Object *ob, PointCache * psys = NULL; } + /* Causes assert on startup. */ +#if 0 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)); +#endif recalc_lengths(edit); if (psys && !cache) - recalc_emitter_field(ob, psys); - PE_update_object(bmain, scene, ob, 1); + recalc_emitter_field(depsgraph, ob, psys); + + PE_update_object(depsgraph, scene, ob, 1); } } @@ -4415,7 +4777,8 @@ static int particle_edit_toggle_poll(bContext *C) static int particle_edit_toggle_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); + 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; @@ -4429,13 +4792,15 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op) if (!is_mode_set) { PTCacheEdit *edit; + ob->mode |= mode_flag; - edit= PE_create_current(bmain, 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) - recalc_emitter_field(ob, edit->psys); + 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); @@ -4446,7 +4811,13 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_OBJECT, NULL); } - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + // ED_workspace_object_mode_sync_from_object(wm, workspace, ob); + + DEG_id_tag_update(&ob->id, OB_RECALC_DATA | DEG_TAG_COPY_ON_WRITE); + + WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); + + WM_toolsystem_update_from_context_view3d(C); return OPERATOR_FINISHED; } @@ -4487,7 +4858,7 @@ static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op)) psys_reset(psys, PSYS_RESET_DEPSGRAPH); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } } else { /* some operation might have protected hair from editing so let's clear the flag */ @@ -4495,7 +4866,7 @@ static int clear_edited_exec(bContext *C, wmOperator *UNUSED(op)) psys->flag &= ~PSYS_GLOBAL_HAIR; psys->flag &= ~PSYS_EDITED; WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } return OPERATOR_FINISHED; @@ -4596,22 +4967,24 @@ static void scale_points_to_length(PTCacheEdit *edit, float length) static int unify_length_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); Object *ob = CTX_data_active_object(C); Scene *scene = CTX_data_scene(C); - PTCacheEdit *edit = PE_get_current(bmain, scene, ob); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + + 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); - PE_update_object(bmain, scene, ob, 1); + PE_update_object(depsgraph, scene, ob, 1); if (edit->psys) { WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob); } else { - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); } |