Fix #145753: Crash deleting a keyframe for another slot when tweaking
When deleting the last key of an F-Curve, the F-Curve itself also gets deleted. This is now done via the same code as deleting F-Curves from the channel list. Before this fix, a deletion function was used that's not capable of deleting from Actions in NLA strips, which is why it crashed. Pull Request: https://projects.blender.org/blender/blender/pulls/145929
This commit is contained in:
@@ -460,6 +460,15 @@ bool BKE_nlatracks_have_animated_strips(ListBase *tracks);
|
||||
*/
|
||||
void BKE_nlastrip_validate_fcurves(NlaStrip *strip);
|
||||
|
||||
/**
|
||||
* Delete the NLA-Strip's control F-Curve.
|
||||
*
|
||||
* This also ensures that the strip's flags are correctly updated.
|
||||
*
|
||||
* \return Whether the F-Curve was actually removed.
|
||||
*/
|
||||
bool BKE_nlastrip_controlcurve_remove(NlaStrip *strip, FCurve *fcurve);
|
||||
|
||||
/**
|
||||
* Check if the given RNA pointer + property combo should be handled by
|
||||
* NLA strip curves or not.
|
||||
|
||||
@@ -1862,6 +1862,23 @@ void BKE_nlastrip_validate_fcurves(NlaStrip *strip)
|
||||
}
|
||||
}
|
||||
|
||||
bool BKE_nlastrip_controlcurve_remove(NlaStrip *strip, FCurve *fcurve)
|
||||
{
|
||||
if (STREQ(fcurve->rna_path, "strip_time")) {
|
||||
strip->flag &= ~NLASTRIP_FLAG_USR_TIME;
|
||||
}
|
||||
else if (STREQ(fcurve->rna_path, "influence")) {
|
||||
strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
BLI_remlink(&strip->fcurves, fcurve);
|
||||
BKE_fcurve_free(fcurve);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BKE_nlastrip_has_curves_for_property(const PointerRNA *ptr, const PropertyRNA *prop)
|
||||
{
|
||||
/* sanity checks */
|
||||
|
||||
@@ -2905,6 +2905,54 @@ static bool animchannels_delete_containers(const bContext *C, bAnimContext *ac)
|
||||
return has_skipped_group;
|
||||
}
|
||||
|
||||
void ED_anim_ale_fcurve_delete(bAnimContext &ac, bAnimListElem &ale)
|
||||
{
|
||||
BLI_assert(ELEM(ale.type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE));
|
||||
|
||||
switch (ale.type) {
|
||||
case ANIMTYPE_FCURVE: {
|
||||
AnimData *adt = ale.adt;
|
||||
FCurve *fcu = static_cast<FCurve *>(ale.data);
|
||||
|
||||
BLI_assert_msg((fcu->driver != nullptr) == (ac.datatype == ANIMCONT_DRIVERS),
|
||||
"Expecting only driver F-Curves in the drivers editor");
|
||||
|
||||
if (ale.fcurve_owner_id && GS(ale.fcurve_owner_id->name) == ID_AC) {
|
||||
/* F-Curves can be owned by Actions assigned to NLA strips, which
|
||||
* `animrig::animdata_fcurve_delete()` (below) cannot handle. */
|
||||
BLI_assert_msg(!fcu->driver, "Drivers are not expected to be owned by Actions");
|
||||
blender::animrig::Action &action =
|
||||
reinterpret_cast<bAction *>(ale.fcurve_owner_id)->wrap();
|
||||
BLI_assert(!action.is_action_legacy());
|
||||
action_fcurve_remove(action, *fcu);
|
||||
}
|
||||
else if (fcu->driver || adt->action) {
|
||||
/* This function only works for drivers & directly-assigned Actions: */
|
||||
blender::animrig::animdata_fcurve_delete(adt, fcu);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_NLACURVE: {
|
||||
/* NLA Control Curve. */
|
||||
NlaStrip *strip = static_cast<NlaStrip *>(ale.owner);
|
||||
FCurve *fcu = static_cast<FCurve *>(ale.data);
|
||||
if (!BKE_nlastrip_controlcurve_remove(strip, fcu)) {
|
||||
printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n",
|
||||
fcu->rna_path);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
tag_update_animation_element(&ale);
|
||||
}
|
||||
|
||||
static wmOperatorStatus animchannels_delete_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
bAnimContext ac;
|
||||
@@ -2941,55 +2989,11 @@ static wmOperatorStatus animchannels_delete_exec(bContext *C, wmOperator * /*op*
|
||||
/* delete selected data channels */
|
||||
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
|
||||
switch (ale->type) {
|
||||
case ANIMTYPE_FCURVE: {
|
||||
/* F-Curves if we can identify its parent */
|
||||
AnimData *adt = ale->adt;
|
||||
FCurve *fcu = static_cast<FCurve *>(ale->data);
|
||||
|
||||
/* try to free F-Curve */
|
||||
BLI_assert_msg((fcu->driver != nullptr) == (ac.datatype == ANIMCONT_DRIVERS),
|
||||
"Expecting only driver F-Curves in the drivers editor");
|
||||
if (ale->fcurve_owner_id && GS(ale->fcurve_owner_id->name) == ID_AC) {
|
||||
/* F-Curves can be owned by Actions assigned to NLA strips, which
|
||||
* `animrig::animdata_fcurve_delete()` (below) cannot handle. */
|
||||
BLI_assert_msg(!fcu->driver, "Drivers are not expected to be owned by Actions");
|
||||
blender::animrig::Action &action =
|
||||
reinterpret_cast<bAction *>(ale->fcurve_owner_id)->wrap();
|
||||
BLI_assert(!action.is_action_legacy());
|
||||
action_fcurve_remove(action, *fcu);
|
||||
}
|
||||
else if (fcu->driver || adt->action) {
|
||||
/* This function only works for drivers & directly-assigned Actions: */
|
||||
blender::animrig::animdata_fcurve_delete(adt, fcu);
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
tag_update_animation_element(ale);
|
||||
case ANIMTYPE_FCURVE:
|
||||
case ANIMTYPE_NLACURVE:
|
||||
ED_anim_ale_fcurve_delete(ac, *ale);
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_NLACURVE: {
|
||||
/* NLA Control Curve - Deleting it should disable the corresponding setting... */
|
||||
NlaStrip *strip = static_cast<NlaStrip *>(ale->owner);
|
||||
FCurve *fcu = static_cast<FCurve *>(ale->data);
|
||||
|
||||
if (STREQ(fcu->rna_path, "strip_time")) {
|
||||
strip->flag &= ~NLASTRIP_FLAG_USR_TIME;
|
||||
}
|
||||
else if (STREQ(fcu->rna_path, "influence")) {
|
||||
strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
|
||||
}
|
||||
else {
|
||||
printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n",
|
||||
fcu->rna_path);
|
||||
}
|
||||
|
||||
/* unlink and free the F-Curve */
|
||||
BLI_remlink(&strip->fcurves, fcu);
|
||||
BKE_fcurve_free(fcu);
|
||||
tag_update_animation_element(ale);
|
||||
break;
|
||||
}
|
||||
case ANIMTYPE_GPLAYER: {
|
||||
/* Grease Pencil layer */
|
||||
bGPdata *gpd = reinterpret_cast<bGPdata *>(ale->id);
|
||||
|
||||
@@ -1231,6 +1231,14 @@ void ED_animedit_unlink_action(
|
||||
*/
|
||||
void ED_drivers_editor_init(bContext *C, ScrArea *area);
|
||||
|
||||
/**
|
||||
* Delete an F-Curve from its owner.
|
||||
*
|
||||
* This can delete an F-Curve from an Action (both directly assigned and via an
|
||||
* NLA strip), Drivers, and NLA control curves.
|
||||
*/
|
||||
void ED_anim_ale_fcurve_delete(bAnimContext &ac, bAnimListElem &ale);
|
||||
|
||||
/* ************************************************ */
|
||||
|
||||
enum eAnimvizCalcRange {
|
||||
|
||||
@@ -1144,15 +1144,11 @@ static bool delete_action_keys(bAnimContext *ac)
|
||||
changed = ED_masklayer_frames_delete((MaskLayer *)ale->data);
|
||||
}
|
||||
else {
|
||||
FCurve *fcu = (FCurve *)ale->key_data;
|
||||
AnimData *adt = ale->adt;
|
||||
|
||||
/* delete selected keyframes only */
|
||||
FCurve *fcu = static_cast<FCurve *>(ale->key_data);
|
||||
changed = BKE_fcurve_delete_keys_selected(fcu);
|
||||
|
||||
/* Only delete curve too if it won't be doing anything anymore */
|
||||
if (BKE_fcurve_is_empty(fcu)) {
|
||||
blender::animrig::animdata_fcurve_delete(adt, fcu);
|
||||
if (changed && BKE_fcurve_is_empty(fcu)) {
|
||||
ED_anim_ale_fcurve_delete(*ac, *ale);
|
||||
ale->key_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user