Fix T55645: broken particle Use Count option for instancing objects.

There is now a manual refresh button on the panel to update the list
of objects in case it changes, and it also gets refreshed when changing
the collection or toggling the use count option.

This is a bit more manual but the previous code of refreshing the
list while evaluating the depsgraph was unreliable.

This also fixes it to take properly take into account visibility, and
to work with linked collections for which index writing was missing.
This commit is contained in:
Brecht Van Lommel 2018-06-28 14:29:54 +02:00
parent ece72c9ec0
commit a59df21ad8
Notes: blender-bot 2023-02-14 11:34:30 +01:00
Referenced by issue #55645, Particle system option 'Use Count' doesnt list objects in the used collection any more
10 changed files with 151 additions and 105 deletions

View File

@ -1275,6 +1275,8 @@ class PARTICLE_PT_render_collection_use_count(ParticleButtonsPanel, Panel):
subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="")
subsub.operator("particle.dupliob_move_up", icon='TRIA_UP', text="")
subsub.operator("particle.dupliob_move_down", icon='TRIA_DOWN', text="")
subsub.separator()
subsub.operator("particle.dupliob_refresh", icon='FILE_REFRESH', text="")
weight = part.active_dupliweight
if weight:

View File

@ -309,6 +309,7 @@ bool psys_in_edit_mode(struct Depsgraph *depsgraph, struct ParticleSystem *psys)
bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, const bool use_render_params);
bool psys_check_edited(struct ParticleSystem *psys);
void psys_find_group_weights(struct ParticleSettings *part);
void psys_check_group_weights(struct ParticleSettings *part);
int psys_uses_gravity(struct ParticleSimulationData *sim);
void BKE_particlesettings_fluid_default_settings(struct ParticleSettings *part);

View File

@ -807,6 +807,10 @@ void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback call
}
}
}
for (ParticleDupliWeight *dw = psett->dupliweights.first; dw; dw = dw->next) {
CALLBACK_INVOKE(dw->ob, IDWALK_CB_NOP);
}
break;
}

View File

@ -836,7 +836,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0;
float (*obmat)[4];
int a, b, hair = 0;
int totpart, totchild, totcollection = 0 /*, pa_num */;
int totpart, totchild;
int no_draw_flag = PARS_UNEXIST;
@ -899,15 +899,26 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
RNG *rng = BLI_rng_new_srandom(31415926u + (unsigned int)psys->seed);
psys_check_group_weights(part);
psys->lattice_deform_data = psys_create_lattice_deform_data(&sim);
/* gather list of objects or single object */
int totcollection = 0;
if (part->ren_as == PART_DRAW_GR) {
if (part->draw & PART_DRAW_COUNT_GR) {
for (dw = part->dupliweights.first; dw; dw = dw->next)
totcollection += dw->count;
psys_find_group_weights(part);
for (dw = part->dupliweights.first; dw; dw = dw->next) {
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
{
if (dw->ob == object) {
totcollection += dw->count;
break;
}
}
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
}
else {
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
@ -923,14 +934,20 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
oblist = MEM_callocN((size_t)totcollection * sizeof(Object *), "dupcollection object list");
obcopylist = MEM_callocN((size_t)totcollection * sizeof(Object), "dupcollection copy list");
if (part->draw & PART_DRAW_COUNT_GR && totcollection) {
dw = part->dupliweights.first;
for (a = 0; a < totcollection; dw = dw->next) {
for (b = 0; b < dw->count; b++, a++) {
oblist[a] = dw->ob;
obcopylist[a] = *dw->ob;
if (part->draw & PART_DRAW_COUNT_GR) {
a = 0;
for (dw = part->dupliweights.first; dw; dw = dw->next) {
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(part->dup_group, object, mode)
{
if (dw->ob == object) {
for (b = 0; b < dw->count; b++, a++) {
oblist[a] = dw->ob;
obcopylist[a] = *dw->ob;
}
break;
}
}
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}
}
else {
@ -940,10 +957,6 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
oblist[a] = object;
obcopylist[a] = *object;
a++;
if (a >= totcollection) {
continue;
}
}
FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END;
}

View File

@ -350,73 +350,84 @@ bool psys_check_edited(ParticleSystem *psys)
return (psys->pointcache->edit && psys->pointcache->edit->edited);
}
void psys_find_group_weights(ParticleSettings *part)
{
/* Find object pointers based on index. If the collection is linked from
* another library linking may not have the object pointers available on
* file load, so we have to retrieve them later. See T49273. */
const ListBase dup_group_objects = BKE_collection_object_cache_get(part->dup_group);
for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
if (dw->ob == NULL) {
Base *base = BLI_findlink(&dup_group_objects, dw->index);
if (base != NULL) {
dw->ob = base->object;
}
}
}
}
void psys_check_group_weights(ParticleSettings *part)
{
ParticleDupliWeight *dw, *tdw;
int current = 0;
if (part->ren_as != PART_DRAW_GR || !part->dup_group) {
BLI_freelistN(&part->dupliweights);
return;
}
const ListBase dup_group_objects = BKE_collection_object_cache_get(part->dup_group);
if (dup_group_objects.first) {
/* First try to find NULL objects from their index,
* and remove all weights that don't have an object in the group. */
dw = part->dupliweights.first;
while (dw) {
if (dw->ob == NULL || !BKE_collection_has_object_recursive(part->dup_group, dw->ob)) {
Base *base = BLI_findlink(&dup_group_objects, dw->index);
if (base != NULL) {
dw->ob = base->object;
}
else {
tdw = dw->next;
BLI_freelinkN(&part->dupliweights, dw);
dw = tdw;
}
}
else {
dw = dw->next;
}
/* Find object pointers. */
psys_find_group_weights(part);
/* Remove NULL objects, that were removed from the collection. */
dw = part->dupliweights.first;
while (dw) {
if (dw->ob == NULL || !BKE_collection_has_object_recursive(part->dup_group, dw->ob)) {
tdw = dw->next;
BLI_freelinkN(&part->dupliweights, dw);
dw = tdw;
}
/* then add objects in the group to new list */
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object)
{
dw = part->dupliweights.first;
while (dw && dw->ob != object) {
dw = dw->next;
}
if (!dw) {
dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
dw->ob = object;
dw->count = 1;
BLI_addtail(&part->dupliweights, dw);
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
dw = part->dupliweights.first;
for (; dw; dw = dw->next) {
if (dw->flag & PART_DUPLIW_CURRENT) {
current = 1;
break;
}
}
if (!current) {
dw = part->dupliweights.first;
if (dw)
dw->flag |= PART_DUPLIW_CURRENT;
else {
dw = dw->next;
}
}
else {
BLI_freelistN(&part->dupliweights);
/* Add new objects in the collection. */
int index = 0;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(part->dup_group, object)
{
dw = part->dupliweights.first;
while (dw && dw->ob != object) {
dw = dw->next;
}
if (!dw) {
dw = MEM_callocN(sizeof(ParticleDupliWeight), "ParticleDupliWeight");
dw->ob = object;
dw->count = 1;
BLI_addtail(&part->dupliweights, dw);
}
dw->index = index++;
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
/* Ensure there is an element marked as current. */
int current = 0;
for (dw = part->dupliweights.first; dw; dw = dw->next) {
if (dw->flag & PART_DUPLIW_CURRENT) {
current = 1;
break;
}
}
if (!current) {
dw = part->dupliweights.first;
if (dw)
dw->flag |= PART_DUPLIW_CURRENT;
}
}
int psys_uses_gravity(ParticleSimulationData *sim)
{
return sim->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY && sim->psys->part && sim->psys->part->effector_weights->global_gravity != 0.0f;

View File

@ -4246,40 +4246,8 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
}
if (part->dupliweights.first && part->dup_group) {
ParticleDupliWeight *dw;
int index_ok = 0;
/* check for old files without indices (all indexes 0) */
if (BLI_listbase_is_single(&part->dupliweights)) {
/* special case for only one object in the group */
index_ok = 1;
}
else {
for (dw = part->dupliweights.first; dw; dw = dw->next) {
if (dw->index > 0) {
index_ok = 1;
break;
}
}
}
if (index_ok) {
/* if we have indexes, let's use them */
for (dw = part->dupliweights.first; dw; dw = dw->next) {
/* Do not try to restore pointer here, we have to search for group objects in another
* separated step.
* Reason is, the used group may be linked from another library, which has not yet
* been 'lib_linked'.
* Since dw->ob is not considered as an object user (it does not make objet directly linked),
* we may have no valid way to retrieve it yet.
* See T49273. */
dw->ob = NULL;
}
}
else {
/* otherwise try to get objects from own library (won't work on library linked groups) */
for (dw = part->dupliweights.first; dw; dw = dw->next) {
dw->ob = newlibadr(fd, part->id.lib, dw->ob);
}
for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
dw->ob = newlibadr(fd, part->id.lib, dw->ob);
}
}
else {
@ -9304,6 +9272,10 @@ static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSetting
}
}
}
for (ParticleDupliWeight *dw = part->dupliweights.first; dw; dw = dw->next) {
expand_doit(fd, mainvar, dw->ob);
}
}
static void expand_collection(FileData *fd, Main *mainvar, Collection *collection)

View File

@ -387,6 +387,35 @@ void PARTICLE_OT_target_move_down(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
/************************ refresh dupli objects *********************/
static int dupliob_refresh_exec(bContext *C, wmOperator *UNUSED(op))
{
PointerRNA ptr = CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem);
ParticleSystem *psys= ptr.data;
if (!psys)
return OPERATOR_CANCELLED;
psys_check_group_weights(psys->part);
DEG_id_tag_update(&psys->part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL);
return OPERATOR_FINISHED;
}
void PARTICLE_OT_dupliob_refresh(wmOperatorType *ot)
{
ot->name = "Refresh Dupli Objects";
ot->idname = "PARTICLE_OT_dupliob_refresh";
ot->description = "Refresh list of dupli objects and their weights";
ot->exec = dupliob_refresh_exec;
/* flags */
ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
}
/************************ move up particle dupliweight operator *********************/
static int dupliob_move_up_exec(bContext *C, wmOperator *UNUSED(op))
@ -405,6 +434,7 @@ static int dupliob_move_up_exec(bContext *C, wmOperator *UNUSED(op))
BLI_remlink(&part->dupliweights, dw);
BLI_insertlinkbefore(&part->dupliweights, dw->prev, dw);
DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL);
break;
}
@ -444,6 +474,7 @@ static int copy_particle_dupliob_exec(bContext *C, wmOperator *UNUSED(op))
dw->flag |= PART_DUPLIW_CURRENT;
BLI_addhead(&part->dupliweights, dw);
DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL);
break;
}
@ -490,6 +521,7 @@ static int remove_particle_dupliob_exec(bContext *C, wmOperator *UNUSED(op))
if (dw)
dw->flag |= PART_DUPLIW_CURRENT;
DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL);
return OPERATOR_FINISHED;
@ -527,6 +559,7 @@ static int dupliob_move_down_exec(bContext *C, wmOperator *UNUSED(op))
BLI_remlink(&part->dupliweights, dw);
BLI_insertlinkafter(&part->dupliweights, dw->next, dw);
DEG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE, NULL);
break;
}

View File

@ -95,6 +95,7 @@ void PARTICLE_OT_dupliob_copy(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_remove(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_move_up(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_move_down(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_refresh(struct wmOperatorType *ot);
/* particle_boids.c */
void BOID_OT_rule_add(struct wmOperatorType *ot);

View File

@ -85,6 +85,7 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_copy_particle_systems);
WM_operatortype_append(PARTICLE_OT_duplicate_particle_system);
WM_operatortype_append(PARTICLE_OT_dupliob_refresh);
WM_operatortype_append(PARTICLE_OT_dupliob_copy);
WM_operatortype_append(PARTICLE_OT_dupliob_remove);
WM_operatortype_append(PARTICLE_OT_dupliob_move_up);

View File

@ -607,6 +607,14 @@ static void rna_Particle_redo_dependency(Main *bmain, Scene *scene, PointerRNA *
rna_Particle_redo(bmain, scene, ptr);
}
static void rna_Particle_redo_count(Main *bmain, Scene *scene, PointerRNA *ptr)
{
ParticleSettings *part = (ParticleSettings *)ptr->data;
DEG_relations_tag_update(bmain);
psys_check_group_weights(part);
particle_recalc(bmain, scene, ptr, PSYS_RECALC_REDO);
}
static void rna_Particle_reset(Main *bmain, Scene *scene, PointerRNA *ptr)
{
particle_recalc(bmain, scene, ptr, PSYS_RECALC_RESET);
@ -2320,8 +2328,8 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_group_count", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_COUNT_GR);
RNA_def_property_ui_text(prop, "Use Count", "Use object multiple times in the same group");
RNA_def_property_update(prop, 0, "rna_Particle_redo");
RNA_def_property_ui_text(prop, "Use Count", "Use object multiple times in the same collecton");
RNA_def_property_update(prop, 0, "rna_Particle_redo_count");
prop = RNA_def_property(srna, "use_global_dupli", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_GLOBAL_OB);
@ -3085,7 +3093,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Collection");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Dupli Collection", "Show Objects in this collection in place of particles");
RNA_def_property_update(prop, 0, "rna_Particle_redo_dependency");
RNA_def_property_update(prop, 0, "rna_Particle_redo_count");
prop = RNA_def_property(srna, "dupli_weights", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "dupliweights", NULL);