From 8c74c35ecb5b6416fcfc624e52c068ed90f48757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 30 Nov 2020 16:12:55 +0100 Subject: Fix T81628: Moving Python-made channels freezes Blender Fix various problems in the Action Group rearranging code. All fixes are necessary to resolve the bug. - Before groups are rearranged, the channels are moved into their respective groups (so no longer referenced by `action->channels`). A temporary group is made for ungrouped channels. The code made assumptions about the channels being in the same order as the groups; that assumption has been removed. - Looping over channels in an Action Group should stop when reaching the last channel, and not until `NULL`. - After all the reshuffling is done, the `action->channels` linked list wasn't terminated properly. Now `first.prev` and `last.next` are set to `NULL` to avoid infinite loops. --- .../blender/editors/animation/anim_channels_edit.c | 38 ++++++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) (limited to 'source/blender') diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 4c17d84b200..ba3796ad245 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -1213,15 +1213,29 @@ static void split_groups_action_temp(bAction *act, bActionGroup *tgrp) /* Separate F-Curves into lists per group */ LISTBASE_FOREACH (bActionGroup *, agrp, &act->groups) { - if (agrp->channels.first) { - fcu = agrp->channels.last; - act->curves.first = fcu->next; + FCurve *const group_fcurves_first = agrp->channels.first; + FCurve *const group_fcurves_last = agrp->channels.last; + if (group_fcurves_first == NULL) { + /* Empty group. */ + continue; + } - fcu = agrp->channels.first; - fcu->prev = NULL; + if (group_fcurves_first == act->curves.first) { + /* First of the action curves, update the start of the action curves. */ + BLI_assert(group_fcurves_first->prev == NULL); + act->curves.first = group_fcurves_last->next; + } + else { + group_fcurves_first->prev->next = group_fcurves_last->next; + } - fcu = agrp->channels.last; - fcu->next = NULL; + if (group_fcurves_last == act->curves.last) { + /* Last of the action curves, update the end of the action curves. */ + BLI_assert(group_fcurves_last->next == NULL); + act->curves.last = group_fcurves_first->prev; + } + else { + group_fcurves_last->next->prev = group_fcurves_first->prev; } } @@ -1277,12 +1291,22 @@ static void join_groups_action_temp(bAction *act) if (agrp->flag & AGRP_TEMP) { LISTBASE_FOREACH (FCurve *, fcu, &agrp->channels) { fcu->grp = NULL; + if (fcu == agrp->channels.last) { + break; + } } BLI_remlink(&act->groups, agrp); break; } } + + /* BLI_movelisttolist() doesn't touch first->prev and last->next pointers in its "dst" list. + * Ensure that after the reshuffling the list is properly terminated. */ + FCurve *act_fcurves_first = act->curves.first; + act_fcurves_first->prev = NULL; + FCurve *act_fcurves_last = act->curves.last; + act_fcurves_last->next = NULL; } /* Change the order of anim-channels within action -- cgit v1.2.3