Fix crash going to edit mode of particles with copy on write

We can not rely on edit->psys, it is not set for particle edit,
and there is some logic deeper inside which does different things
dependent on that.

We need to replace those checks with some some HAIR vs. PARTICLES
flag and always set psys pointer.
This commit is contained in:
Sergey Sharybin 2018-05-11 14:54:50 +02:00
parent af5428aa2b
commit aefd181b0b
7 changed files with 81 additions and 51 deletions

View File

@ -2886,19 +2886,28 @@ 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(Object *object, struct PTCacheEdit *edit)
Gwn_Batch *DRW_cache_particles_get_edit_strands(
Object *object,
ParticleSystem *psys,
struct PTCacheEdit *edit)
{
return DRW_particles_batch_cache_get_edit_strands(object, edit);
return DRW_particles_batch_cache_get_edit_strands(object, psys, edit);
}
Gwn_Batch *DRW_cache_particles_get_edit_inner_points(Object *object, struct PTCacheEdit *edit)
Gwn_Batch *DRW_cache_particles_get_edit_inner_points(
Object *object,
ParticleSystem *psys,
struct PTCacheEdit *edit)
{
return DRW_particles_batch_cache_get_edit_inner_points(object, edit);
return DRW_particles_batch_cache_get_edit_inner_points(object, psys, edit);
}
Gwn_Batch *DRW_cache_particles_get_edit_tip_points(Object *object, struct PTCacheEdit *edit)
Gwn_Batch *DRW_cache_particles_get_edit_tip_points(
Object *object,
ParticleSystem *psys,
struct PTCacheEdit *edit)
{
return DRW_particles_batch_cache_get_edit_tip_points(object, edit);
return DRW_particles_batch_cache_get_edit_tip_points(object, psys, 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 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_edit_strands(struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_cache_particles_get_edit_inner_points(struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_cache_particles_get_edit_tip_points(struct Object *object, struct ParticleSystem *psys, 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 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);
struct Gwn_Batch *DRW_particles_batch_cache_get_edit_strands(struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit);
struct Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(struct Object *object, struct ParticleSystem *psys, struct PTCacheEdit *edit);
#endif /* __DRAW_CACHE_IMPL_H__ */

View File

@ -597,25 +597,12 @@ Gwn_Batch *DRW_particles_batch_cache_get_dots(Object *object, ParticleSystem *ps
return cache->hairs;
}
/* TODO(sergey): Avoid linear lookup. */
static ParticleBatchCache *particle_batch_cache_get_edit(Object *object, PTCacheEdit *edit)
Gwn_Batch *DRW_particles_batch_cache_get_edit_strands(
Object *UNUSED(object),
ParticleSystem *psys,
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_edit(object, edit);
ParticleBatchCache *cache = particle_batch_cache_get(psys);
if (cache->hairs != NULL) {
return cache->hairs;
}
@ -691,9 +678,12 @@ static void particle_batch_cache_ensure_edit_inner_pos(
}
}
Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(Object *object, PTCacheEdit *edit)
Gwn_Batch *DRW_particles_batch_cache_get_edit_inner_points(
Object *UNUSED(object),
ParticleSystem *psys,
PTCacheEdit *edit)
{
ParticleBatchCache *cache = particle_batch_cache_get_edit(object, edit);
ParticleBatchCache *cache = particle_batch_cache_get(psys);
if (cache->edit_inner_points != NULL) {
return cache->edit_inner_points;
}
@ -752,9 +742,12 @@ static void particle_batch_cache_ensure_edit_tip_pos(
}
}
Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(Object *object, PTCacheEdit *edit)
Gwn_Batch *DRW_particles_batch_cache_get_edit_tip_points(
Object *UNUSED(object),
ParticleSystem *psys,
PTCacheEdit *edit)
{
ParticleBatchCache *cache = particle_batch_cache_get_edit(object, edit);
ParticleBatchCache *cache = particle_batch_cache_get(psys);
if (cache->edit_tip_points != NULL) {
return cache->edit_tip_points;
}

View File

@ -139,22 +139,17 @@ static void particle_cache_init(void *vedata)
DRW_shgroup_uniform_float(stl->g_data->tip_points_group, "outlineWidth", &outline_width, 1);
}
/* TODO(sergey): Avoid linear lookup. */
static void draw_update_ptcache_edit(Object *object_eval, PTCacheEdit *edit)
static void draw_update_ptcache_edit(Object *object_eval,
ParticleSystem *psys,
PTCacheEdit *edit)
{
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) {
/* NOTE: Get flag from particle system coming from drawing object.
* this is where depsgraph will be setting flags to.
*/
if (psys->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_eval);
@ -165,25 +160,26 @@ static void draw_update_ptcache_edit(Object *object_eval, PTCacheEdit *edit)
static void particle_edit_cache_populate(void *vedata,
Object *object,
ParticleSystem *psys,
PTCacheEdit *edit)
{
PARTICLE_StorageList *stl = ((PARTICLE_Data *)vedata)->stl;
const DRWContextState *draw_ctx = DRW_context_state_get();
draw_update_ptcache_edit(object, edit);
draw_update_ptcache_edit(object, psys, edit);
ParticleEditSettings *pset = PE_settings(draw_ctx->scene);
{
struct Gwn_Batch *strands =
DRW_cache_particles_get_edit_strands(object, edit);
DRW_cache_particles_get_edit_strands(object, psys, 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(object, edit);
DRW_cache_particles_get_edit_inner_points(object, psys, 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(object, edit);
DRW_cache_particles_get_edit_tip_points(object, psys, edit);
DRW_shgroup_call_add(stl->g_data->tip_points_group, points, NULL);
}
}
@ -197,7 +193,20 @@ static void particle_cache_populate(void *vedata, Object *object)
printf("Particle edit struct is NULL, not supposed to happen.\n");
return;
}
particle_edit_cache_populate(vedata, object, edit);
ParticleSystem *psys = object->particlesystem.first;
ParticleSystem *psys_orig = object_orig->particlesystem.first;
while (psys_orig != NULL) {
if (PE_get_current_from_psys(psys_orig) == edit) {
break;
}
psys = psys->next;
psys_orig = psys_orig->next;
}
if (psys == NULL) {
printf("Error getting evaluated particle system for edit.\n");
return;
}
particle_edit_cache_populate(vedata, object, psys, edit);
}
/* Optional: Post-cache_populate callback */

View File

@ -47,6 +47,7 @@ void PE_free_ptcache_edit(struct PTCacheEdit *edit);
int PE_start_edit(struct PTCacheEdit *edit);
/* access */
struct PTCacheEdit *PE_get_current_from_psys(struct ParticleSystem *psys);
struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob);
struct PTCacheEdit *PE_create_current(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);
void PE_current_changed(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob);

View File

@ -191,6 +191,24 @@ 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;
}
/* 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