Constraints: introduce wrapper functions to access target lists.

Instead of directly accessing constraint-specific callbacks
in code all over blender, introduce two wrappers to retrieve
and free the target list.

This incidentally revealed a place within the Collada exporter
in BCAnimationSampler.cpp that didn't clean up after retrieving
the targets, resulting in a small memory leak. Fixing this should
be the only functional change in this commit.

This was split off from D9732.

Differential Revision: https://developer.blender.org/D13844
This commit is contained in:
Alexander Gavrilov 2020-11-23 23:42:05 +03:00
parent 284a3431ae
commit d040e1da4f
14 changed files with 98 additions and 111 deletions

View File

@ -307,6 +307,25 @@ void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
void *ownerdata,
float mat[4][4],
float ctime);
/**
* Retrieves the list of all constraint targets, including the custom space target.
* Must be followed by a call to BKE_constraint_targets_flush to free memory.
*
* \param r_targets Pointer to the list to be initialized with target data.
* \returns the number of targets stored in the list.
*/
int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets);
/**
* Copies changed data from the list produced by BKE_constraint_targets_get back to the constraint
* data structures and frees memory.
*
* \param targets List of targets filled by BKE_constraint_targets_get.
* \param no_copy Only free memory without copying changes (read-only mode).
*/
void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy);
/**
* Get the list of targets required for solving a constraint.
*/

View File

@ -980,13 +980,10 @@ void BKE_pose_channels_remove(Object *ob,
else {
/* Maybe something the bone references is being removed instead? */
for (con = pchan->constraints.first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == ob) {
if (ct->subtarget[0]) {
@ -998,9 +995,7 @@ void BKE_pose_channels_remove(Object *ob,
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, 0);
}
BKE_constraint_targets_flush(con, &targets, 0);
}
}

View File

@ -6191,6 +6191,40 @@ bool BKE_constraint_is_nonlocal_in_liboverride(const Object *ob, const bConstrai
/* -------- Target-Matrix Stuff ------- */
int BKE_constraint_targets_get(struct bConstraint *con, struct ListBase *r_targets)
{
BLI_listbase_clear(r_targets);
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!cti) {
return 0;
}
int count = 0;
/* Constraint-specific targets. */
if (cti->get_constraint_targets) {
count = cti->get_constraint_targets(con, r_targets);
}
return count;
}
void BKE_constraint_targets_flush(struct bConstraint *con, struct ListBase *targets, bool no_copy)
{
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!cti) {
return;
}
/* Release the constraint-specific targets. */
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, targets, no_copy);
}
}
void BKE_constraint_target_matrix_get(struct Depsgraph *depsgraph,
Scene *scene,
bConstraint *con,

View File

@ -2483,21 +2483,16 @@ static void copy_object_pose(Object *obn, const Object *ob, const int flag)
* BKE_library_remap stuff, but...
* the flush_constraint_targets callback am not sure about, so will delay that for now. */
LISTBASE_FOREACH (bConstraint *, con, &chan->constraints) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {nullptr, nullptr};
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == ob) {
ct->tar = obn;
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, false);
}
BKE_constraint_targets_flush(con, &targets, false);
}
}
}
@ -5488,11 +5483,9 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
/* also update constraint targets */
LISTBASE_FOREACH (bConstraint *, con, &ob->constraints) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {nullptr, nullptr};
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar) {
BKE_object_modifier_update_subframe(
@ -5500,9 +5493,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
}
}
/* free temp targets */
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, false);
}
BKE_constraint_targets_flush(con, &targets, false);
}
}
}

View File

@ -1137,6 +1137,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
/* Add dependencies for each constraint in turn. */
for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {nullptr, nullptr};
/* Invalid constraint type. */
if (cti == nullptr) {
continue;
@ -1188,9 +1189,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(cache_key, constraint_op_key, cti->name);
}
}
else if (cti->get_constraint_targets) {
ListBase targets = {nullptr, nullptr};
cti->get_constraint_targets(con, &targets);
else if (BKE_constraint_targets_get(con, &targets)) {
LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) {
if (ct->tar == nullptr) {
continue;
@ -1300,9 +1299,7 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
add_relation(target_transform_key, constraint_op_key, cti->name);
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, true);
}
BKE_constraint_targets_flush(con, &targets, true);
}
}
}

View File

@ -1310,12 +1310,11 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
}
else {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
if ((cti && cti->get_constraint_targets) && (curcon->ui_expand_flag & (1 << 0))) {
ListBase targets = {NULL, NULL};
if ((curcon->ui_expand_flag & (1 << 0)) && BKE_constraint_targets_get(curcon, &targets)) {
bConstraintTarget *ct;
cti->get_constraint_targets(curcon, &targets);
for (ct = targets.first; ct; ct = ct->next) {
/* calculate target's matrix */
@ -1328,9 +1327,7 @@ static void OVERLAY_relationship_lines(OVERLAY_ExtraCallBuffers *cb,
OVERLAY_extra_line_dashed(cb, ct->matrix[3], ob->obmat[3], constraint_color);
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(curcon, &targets, 1);
}
BKE_constraint_targets_flush(curcon, &targets, 1);
}
}
}

View File

@ -375,13 +375,10 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
/* does this constraint have a subtarget in
* this armature?
*/
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(curcon, &targets);
if (BKE_constraint_targets_get(curcon, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if ((ct->tar == ob) && (ct->subtarget[0])) {
oldtarget = get_named_editbone(editbones, ct->subtarget);
@ -409,9 +406,7 @@ static void updateDuplicateSubtarget(EditBone *dup_bone,
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(curcon, &targets, 0);
}
BKE_constraint_targets_flush(curcon, &targets, 0);
}
}
}

View File

@ -109,13 +109,10 @@ static void constraint_bone_name_fix(Object *ob,
bConstraintTarget *ct;
for (curcon = conlist->first; curcon; curcon = curcon->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
ListBase targets = {NULL, NULL};
/* constraint targets */
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(curcon, &targets);
if (BKE_constraint_targets_get(curcon, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == ob) {
if (STREQ(ct->subtarget, oldname)) {
@ -124,9 +121,7 @@ static void constraint_bone_name_fix(Object *ob,
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(curcon, &targets, 0);
}
BKE_constraint_targets_flush(curcon, &targets, 0);
}
/* action constraints */

View File

@ -68,14 +68,11 @@ static void joined_armature_fix_links_constraints(Main *bmain,
bool changed = false;
for (con = lb->first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar == srcArm) {
if (ct->subtarget[0] == '\0') {
@ -90,9 +87,7 @@ static void joined_armature_fix_links_constraints(Main *bmain,
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, 0);
}
BKE_constraint_targets_flush(con, &targets, 0);
}
/* action constraint? (pose constraints only) */
@ -459,14 +454,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
if (ob->type == OB_ARMATURE) {
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (con = pchan->constraints.first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
/* Any targets which point to original armature
* are redirected to the new one only if:
@ -487,9 +479,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, 0);
}
BKE_constraint_targets_flush(con, &targets, 0);
}
}
}
@ -498,14 +488,11 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
/* fix object-level constraints */
if (ob != origArm) {
for (con = ob->constraints.first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
/* constraint targets */
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
/* any targets which point to original armature are redirected to the new one only if:
* - the target isn't origArm/newArm itself
@ -525,9 +512,7 @@ static void separated_armature_fix_links(Main *bmain, Object *origArm, Object *n
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, 0);
}
BKE_constraint_targets_flush(con, &targets, 0);
}
}
}

View File

@ -680,13 +680,10 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones) {
if (pchan->bone->flag & BONE_SELECTED) {
for (con = pchan->constraints.first; con; con = con->next) {
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
Object *ob = ct->tar;
@ -702,9 +699,7 @@ static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, 1);
}
BKE_constraint_targets_flush(con, &targets, 1);
}
}
}

View File

@ -245,13 +245,11 @@ static void set_constraint_nth_target(bConstraint *con,
const char subtarget[],
int index)
{
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
int num_targets, i;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
if (BKE_constraint_targets_get(con, &targets)) {
num_targets = BLI_listbase_count(&targets);
if (index < 0) {
@ -274,9 +272,7 @@ static void set_constraint_nth_target(bConstraint *con,
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, 0);
}
BKE_constraint_targets_flush(con, &targets, 0);
}
}
@ -289,7 +285,6 @@ static void set_constraint_nth_target(bConstraint *con,
static void test_constraint(
Main *bmain, Object *owner, bPoseChannel *pchan, bConstraint *con, int type)
{
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
bool check_targets = true;
@ -465,14 +460,7 @@ static void test_constraint(
}
/* Check targets for constraints */
if (check_targets && cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
/* constraints with empty target list that actually require targets */
if (!targets.first && ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
con->flag |= CONSTRAINT_DISABLE;
}
if (check_targets && BKE_constraint_targets_get(con, &targets)) {
/* disable and clear constraints targets that are incorrect */
for (ct = targets.first; ct; ct = ct->next) {
/* general validity checks (for those constraints that need this) */
@ -543,8 +531,12 @@ static void test_constraint(
}
/* free any temporary targets */
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, 0);
BKE_constraint_targets_flush(con, &targets, 0);
}
else if (check_targets) {
/* constraints with empty target list that actually require targets */
if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) {
con->flag |= CONSTRAINT_DISABLE;
}
}
}

View File

@ -225,24 +225,26 @@ bool BCAnimationSampler::is_animated_by_constraint(Object *ob,
for (con = (bConstraint *)conlist->first; con; con = con->next) {
ListBase targets = {nullptr, nullptr};
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
if (!bc_validateConstraints(con)) {
continue;
}
if (cti && cti->get_constraint_targets) {
if (BKE_constraint_targets_get(con, &targets)) {
bConstraintTarget *ct;
Object *obtar;
cti->get_constraint_targets(con, &targets);
bool found = false;
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
obtar = ct->tar;
if (obtar) {
if (animated_objects.find(obtar) != animated_objects.end()) {
return true;
found = true;
break;
}
}
}
BKE_constraint_targets_flush(con, &targets, true);
return found;
}
}
return false;

View File

@ -191,24 +191,19 @@ void SceneExporter::writeNode(Object *ob)
/* not ideal: add the target object name as another parameter.
* No real mapping in the `.dae`.
* Need support for multiple target objects also. */
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {nullptr, nullptr};
if (cti && cti->get_constraint_targets) {
ListBase targets = {nullptr, nullptr};
if (BKE_constraint_targets_get(con, &targets)) {
bConstraintTarget *ct;
Object *obtar;
cti->get_constraint_targets(con, &targets);
for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
obtar = ct->tar;
std::string tar_id((obtar) ? id_name(obtar) : "");
colladaNode.addExtraTechniqueChildParameter("blender", con_tag, "target_id", tar_id);
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, true);
}
BKE_constraint_targets_flush(con, &targets, true);
}
con = con->next;

View File

@ -598,22 +598,17 @@ static const EnumPropertyItem *rna_Constraint_target_space_itemf(bContext *UNUSE
bool *UNUSED(r_free))
{
bConstraint *con = (bConstraint *)ptr->data;
const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
ListBase targets = {NULL, NULL};
bConstraintTarget *ct;
if (cti && cti->get_constraint_targets) {
cti->get_constraint_targets(con, &targets);
if (BKE_constraint_targets_get(con, &targets)) {
for (ct = targets.first; ct; ct = ct->next) {
if (ct->tar && ct->tar->type == OB_ARMATURE) {
break;
}
}
if (cti->flush_constraint_targets) {
cti->flush_constraint_targets(con, &targets, 1);
}
BKE_constraint_targets_flush(con, &targets, 1);
if (ct) {
return target_space_pchan_items;