Particle edit: Initial support of edit with copy-on-write

The idea is that edit mode structure is owned by original object,
and used for drawing. This is a bit confusing, especially since
path cache is also in that structure and needs evaluated object
to calculate cache.

In the future we should split edit data from visualization data,
but that's bigger refactor.
This commit is contained in:
Sergey Sharybin
2018-05-11 12:44:43 +02:00
parent ff3e9d0d90
commit d50821f145
9 changed files with 111 additions and 61 deletions

View File

@@ -2575,6 +2575,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re
}
void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params)
{
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ParticleCacheKey *ca, **cache = edit->pathcache;
ParticleEditSettings *pset = &scene->toolsettings->particle;
@@ -2582,8 +2583,19 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
PTCacheEditKey *ekey = NULL;
ParticleSystem *psys = edit->psys;
ParticleSystem *psys_eval = NULL;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
ParticleData *pa = psys ? psys->particles : NULL;
ParticleSystemModifierData *psmd_eval = NULL;
BLI_assert((ob->id.tag & LIB_TAG_COPY_ON_WRITE) == 0);
BLI_assert(psmd != NULL);
if (psmd != NULL) {
psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
psys_eval = psmd_eval->psys;
}
ParticleData *pa = psys_eval ? psys_eval->particles : NULL;
ParticleInterpolationData pind;
ParticleKey result;
@@ -2612,7 +2624,7 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
/* frs_sec = (psys || edit->pid.flag & PTCACHE_VEL_PER_SEC) ? 25.0f : 1.0f; */ /* UNUSED */
const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys != NULL) && (psys->particles != NULL);
const bool use_weight = (pset->brushtype == PE_BRUSH_WEIGHT) && (psys_eval != NULL) && (psys_eval->particles != NULL);
if (use_weight) {
; /* use weight painting colors now... */
@@ -2657,10 +2669,10 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
cache[i]->segments = segments;
/*--get the first data points--*/
init_particle_interpolation(ob, psys, pa, &pind);
init_particle_interpolation(ob_eval, psys_eval, pa, &pind);
if (psys) {
psys_mat_hair_to_global(ob, psmd->dm_final, psys->part->from, pa, hairmat);
if (psys_eval) {
psys_mat_hair_to_global(ob_eval, psmd_eval->dm_final, psys->part->from, pa, hairmat);
copy_v3_v3(rotmat[0], hairmat[2]);
copy_v3_v3(rotmat[1], hairmat[1]);
copy_v3_v3(rotmat[2], hairmat[0]);
@@ -2679,7 +2691,7 @@ void psys_cache_edit_paths(Depsgraph *depsgraph, Scene *scene, Object *ob, PTCac
time = (float)k / (float)segments;
t = birthtime + time * (dietime - birthtime);
result.time = -t;
do_particle_interpolation(psys, i, pa, t, &pind, &result);
do_particle_interpolation(psys_eval, i, pa, t, &pind, &result);
copy_v3_v3(ca->co, result.co);
/* non-hair points are already in global space */

View File

@@ -2886,19 +2886,19 @@ Gwn_Batch *DRW_cache_particles_get_dots(Object *object, ParticleSystem *psys)
return DRW_particles_batch_cache_get_dots(object, psys);
}
Gwn_Batch *DRW_cache_particles_get_edit_strands(struct PTCacheEdit *edit)
Gwn_Batch *DRW_cache_particles_get_edit_strands(Object *object, struct PTCacheEdit *edit)
{
return DRW_particles_batch_cache_get_edit_strands(edit);
return DRW_particles_batch_cache_get_edit_strands(object, edit);
}
Gwn_Batch *DRW_cache_particles_get_edit_inner_points(struct PTCacheEdit *edit)
Gwn_Batch *DRW_cache_particles_get_edit_inner_points(Object *object, struct PTCacheEdit *edit)
{
return DRW_particles_batch_cache_get_edit_inner_points(edit);
return DRW_particles_batch_cache_get_edit_inner_points(object, edit);
}
Gwn_Batch *DRW_cache_particles_get_edit_tip_points(struct PTCacheEdit *edit)
Gwn_Batch *DRW_cache_particles_get_edit_tip_points(Object *object, struct PTCacheEdit *edit)
{
return DRW_particles_batch_cache_get_edit_tip_points(edit);
return DRW_particles_batch_cache_get_edit_tip_points(object, edit);
}
Gwn_Batch *DRW_cache_particles_get_prim(int type)

View File

@@ -169,9 +169,9 @@ struct Gwn_Batch *DRW_cache_lattice_vert_overlay_get(struct Object *ob);
/* Particles */
struct Gwn_Batch *DRW_cache_particles_get_hair(struct ParticleSystem *psys, struct ModifierData *md);
struct Gwn_Batch *DRW_cache_particles_get_dots(struct Object *object, struct ParticleSystem *psys);
struct Gwn_Batch *DRW_cache_particles_get_edit_strands(struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_cache_particles_get_edit_inner_points(struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_cache_particles_get_edit_tip_points(struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_cache_particles_get_edit_strands(struct Object *object, struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_cache_particles_get_edit_inner_points(struct Object *object, struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_cache_particles_get_edit_tip_points(struct Object *object, struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_cache_particles_get_prim(int type);
/* Metaball */

View File

@@ -125,8 +125,8 @@ void DRW_mesh_cache_sculpt_coords_ensure(struct Mesh *me);
/* Particles */
struct Gwn_Batch *DRW_particles_batch_cache_get_hair(struct ParticleSystem *psys, struct ModifierData *md);
struct Gwn_Batch *DRW_particles_batch_cache_get_dots(struct Object *object, struct ParticleSystem *psys);
struct Gwn_Batch *DRW_particles_batch_cache_get_edit_strands(struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_particles_batch_cache_get_edit_strands(struct Object *object, struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(struct Object *object, struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *object, struct PTCacheEdit *edit);
#endif /* __DRAW_CACHE_IMPL_H__ */

View File

@@ -597,10 +597,25 @@ Gwn_Batch *DRW_particles_batch_cache_get_dots(Object *object, ParticleSystem *ps
return cache->hairs;
}
Gwn_Batch *DRW_particles_batch_cache_get_edit_strands(PTCacheEdit *edit)
/* TODO(sergey): Avoid linear lookup. */
static ParticleBatchCache *particle_batch_cache_get_edit(Object *object, PTCacheEdit *edit)
{
ParticleSystem *psys_orig = edit->psys;
for (ParticleSystem *psys_eval = object->particlesystem.first;
psys_eval != NULL;
psys_eval = psys_eval->next)
{
if (STREQ(psys_orig->name, psys_eval->name)) {
return particle_batch_cache_get(psys_eval);
}
}
return NULL;
}
Gwn_Batch *DRW_particles_batch_cache_get_edit_strands(Object *object, PTCacheEdit *edit)
{
ParticleSystem *psys = edit->psys;
ParticleBatchCache *cache = particle_batch_cache_get(psys);
ParticleBatchCache *cache = particle_batch_cache_get_edit(object, edit);
if (cache->hairs != NULL) {
return cache->hairs;
}
@@ -676,10 +691,9 @@ static void particle_batch_cache_ensure_edit_inner_pos(
}
}
Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(PTCacheEdit *edit)
Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(Object *object, PTCacheEdit *edit)
{
ParticleSystem *psys = edit->psys;
ParticleBatchCache *cache = particle_batch_cache_get(psys);
ParticleBatchCache *cache = particle_batch_cache_get_edit(object, edit);
if (cache->edit_inner_points != NULL) {
return cache->edit_inner_points;
}
@@ -692,7 +706,7 @@ Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(PTCacheEdit *edit)
}
static void ensure_edit_tip_points_count(const PTCacheEdit *edit,
ParticleBatchCache *cache)
ParticleBatchCache *cache)
{
if (cache->edit_tip_pos != NULL) {
return;
@@ -738,10 +752,9 @@ static void particle_batch_cache_ensure_edit_tip_pos(
}
}
Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(PTCacheEdit *edit)
Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(Object *object, PTCacheEdit *edit)
{
ParticleSystem *psys = edit->psys;
ParticleBatchCache *cache = particle_batch_cache_get(psys);
ParticleBatchCache *cache = particle_batch_cache_get_edit(object, edit);
if (cache->edit_tip_points != NULL) {
return cache->edit_tip_points;
}

View File

@@ -139,18 +139,30 @@ static void particle_cache_init(void *vedata)
DRW_shgroup_uniform_float(stl->g_data->tip_points_group, "outlineWidth", &outline_width, 1);
}
static void draw_update_ptcache_edit(Object *object, PTCacheEdit *edit)
/* TODO(sergey): Avoid linear lookup. */
static void draw_update_ptcache_edit(Object *object_eval, PTCacheEdit *edit)
{
if (edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED) {
if (edit->psys == NULL) {
return;
}
ParticleSystem *psys_eval;
for (psys_eval = object_eval->particlesystem.first;
psys_eval != NULL;
psys_eval = psys_eval->next)
{
if (STREQ(edit->psys->name, psys_eval->name)) {
break;
}
}
if (psys_eval->flag & PSYS_HAIR_UPDATED) {
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene_orig = (Scene *)DEG_get_original_id(&draw_ctx->scene->id);
Object *object_orig = DEG_get_original_object(object);
Object *object_orig = DEG_get_original_object(object_eval);
PE_update_object(draw_ctx->depsgraph, scene_orig, object_orig, 0);
}
BLI_assert(edit->pathcache != NULL);
}
static void particle_edit_cache_populate(void *vedata,
Object *object,
PTCacheEdit *edit)
@@ -160,35 +172,32 @@ static void particle_edit_cache_populate(void *vedata,
draw_update_ptcache_edit(object, edit);
ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
{
struct Gwn_Batch *strands = DRW_cache_particles_get_edit_strands(edit);
struct Gwn_Batch *strands =
DRW_cache_particles_get_edit_strands(object, edit);
DRW_shgroup_call_add(stl->g_data->strands_group, strands, NULL);
}
if (pset->selectmode == SCE_SELECT_POINT) {
struct Gwn_Batch *points = DRW_cache_particles_get_edit_inner_points(edit);
struct Gwn_Batch *points =
DRW_cache_particles_get_edit_inner_points(object, edit);
DRW_shgroup_call_add(stl->g_data->inner_points_group, points, NULL);
}
if (ELEM(pset->selectmode, SCE_SELECT_POINT, SCE_SELECT_END)) {
struct Gwn_Batch *points = DRW_cache_particles_get_edit_tip_points(edit);
struct Gwn_Batch *points =
DRW_cache_particles_get_edit_tip_points(object, edit);
DRW_shgroup_call_add(stl->g_data->tip_points_group, points, NULL);
}
}
static void particle_cache_populate(void *vedata, Object *object)
{
for (ParticleSystem *psys = object->particlesystem.first;
psys != NULL;
psys = psys->next)
{
if (!psys_check_enabled(object, psys, false)) {
continue;
}
PTCacheEdit *edit = PE_get_current_from_psys(psys);
if (edit == NULL) {
continue;
}
particle_edit_cache_populate(vedata, object, edit);
break;
const DRWContextState *draw_ctx = DRW_context_state_get();
Object *object_orig = DEG_get_original_object(object);
PTCacheEdit *edit = PE_get_current(draw_ctx->scene, object_orig);
if (edit == NULL) {
printf("Particle edit struct is NULL, not supposed to happen.\n");
return;
}
particle_edit_cache_populate(vedata, object, edit);
}
/* Optional: Post-cache_populate callback */

View File

@@ -85,6 +85,8 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "DEG_depsgraph_query.h"
#include "physics_intern.h"
#include "particle_edit_utildefines.h"
@@ -1185,19 +1187,27 @@ static void PE_update_selection(Depsgraph *depsgraph, Scene *scene, Object *ob,
DEG_id_tag_update(&ob->id, DEG_TAG_SELECT_UPDATE);
}
void update_world_cos(Object *ob, PTCacheEdit *edit)
void update_world_cos(Depsgraph *depsgraph, Object *ob, PTCacheEdit *edit)
{
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
ParticleSystem *psys_eval = NULL;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
ParticleSystemModifierData *psmd_eval = NULL;
POINT_P; KEY_K;
float hairmat[4][4];
if (psys==0 || psys->edit==0 || psmd->dm_final==NULL)
if (psmd != NULL) {
psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name);
psys_eval = psmd_eval->psys;
}
if (psys == 0 || psys->edit == 0 || psmd_eval->dm_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_eval, psmd_eval->dm_final, psys->part->from, psys_eval->particles+p, hairmat);
LOOP_KEYS {
copy_v3_v3(key->world_co, key->co);
@@ -1287,7 +1297,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla
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);
@@ -2970,7 +2980,7 @@ static int mirror_exec(bContext *C, wmOperator *UNUSED(op))
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);
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -3788,6 +3798,7 @@ static int brush_edit_init(bContext *C, wmOperator *op)
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;
@@ -3804,8 +3815,6 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (!PE_start_edit(edit))
return;
Depsgraph *depsgraph = CTX_data_depsgraph(C);
RNA_float_get_array(itemptr, "mouse", mousef);
mouse[0] = mousef[0];
mouse[1] = mousef[1];
@@ -3984,7 +3993,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
if (pset->brushtype == PE_BRUSH_ADD && pe_x_mirror(ob))
PE_mirror_x(scene, ob, 1);
update_world_cos(ob, edit);
update_world_cos(depsgraph, ob, edit);
psys_free_path_cache(NULL, edit);
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
@@ -4213,6 +4222,7 @@ static void shape_cut(PEData *data, int pa_index)
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);
@@ -4247,7 +4257,7 @@ 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);
DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
@@ -4332,14 +4342,20 @@ void PE_create_particle_edit(
Depsgraph *depsgraph, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
{
PTCacheEdit *edit;
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
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_eval && psmd_eval->dm_final) && !cache)
return;
if (cache && cache->flag & PTCACHE_DISK_CACHE)
@@ -4386,7 +4402,7 @@ void PE_create_particle_edit(
}
pa++;
}
update_world_cos(ob, edit);
update_world_cos(depsgraph, ob, edit);
}
else {
PTCacheMem *pm;

View File

@@ -946,7 +946,7 @@ static void copy_particle_edit(
pa++;
}
update_world_cos(ob, edit);
update_world_cos(depsgraph, ob, edit);
UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);

View File

@@ -75,7 +75,7 @@ void PE_create_particle_edit(
struct Object *ob, struct PointCache *cache, struct ParticleSystem *psys);
void recalc_lengths(struct PTCacheEdit *edit);
void recalc_emitter_field(struct Object *ob, struct ParticleSystem *psys);
void update_world_cos(struct Object *ob, struct PTCacheEdit *edit);
void update_world_cos(struct Depsgraph *depsgraph, struct Object *ob, struct PTCacheEdit *edit);
/* particle_object.c */
void OBJECT_OT_particle_system_add(struct wmOperatorType *ot);