diff options
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r-- | source/blender/blenkernel/intern/action.c | 38 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/action_test.cc | 144 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/anim_data.c | 32 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/ipo.c | 26 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 2 |
5 files changed, 196 insertions, 46 deletions
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 13ca5ecf23c..d55f023d209 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -497,9 +497,8 @@ void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve) } /* Reconstruct group channel pointers. - * Assumes that the channels are still in the proper order, i.e. that channels of the same group - * are adjacent in the act->channels list. It also assumes that the groups - * referred to by the FCurves are already in act->groups. + * Assumes that the groups referred to by the FCurves are already in act->groups. + * Reorders the main channel list to match group order. */ void BKE_action_groups_reconstruct(bAction *act) { @@ -514,23 +513,30 @@ void BKE_action_groups_reconstruct(bAction *act) BLI_listbase_clear(&group->channels); } - bActionGroup *grp; - bActionGroup *last_grp = NULL; - LISTBASE_FOREACH (FCurve *, fcurve, &act->curves) { - if (fcurve->grp == NULL) { - continue; - } + /* Sort the channels into the group lists, destroying the act->curves list. */ + ListBase ungrouped = {NULL, NULL}; - grp = fcurve->grp; - if (last_grp != grp) { - /* If this is the first time we see this group, this must be the first channel. */ - grp->channels.first = fcurve; + LISTBASE_FOREACH_MUTABLE (FCurve *, fcurve, &act->curves) { + if (fcurve->grp) { + BLI_assert(BLI_findindex(&act->groups, fcurve->grp) >= 0); + + BLI_addtail(&fcurve->grp->channels, fcurve); + } + else { + BLI_addtail(&ungrouped, fcurve); } + } + + /* Recombine into the main list. */ + BLI_listbase_clear(&act->curves); - /* This is the last channel, until it's overwritten by a later iteration. */ - grp->channels.last = fcurve; - last_grp = grp; + LISTBASE_FOREACH (bActionGroup *, group, &act->groups) { + /* Copy the list header to preserve the pointers in the group. */ + ListBase tmp = group->channels; + BLI_movelisttolist(&act->curves, &tmp); } + + BLI_movelisttolist(&act->curves, &ungrouped); } /* Remove the given channel from all groups */ diff --git a/source/blender/blenkernel/intern/action_test.cc b/source/blender/blenkernel/intern/action_test.cc new file mode 100644 index 00000000000..cd8751ec358 --- /dev/null +++ b/source/blender/blenkernel/intern/action_test.cc @@ -0,0 +1,144 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 Blender Foundation + * All rights reserved. + */ + +#include "BKE_action.h" + +#include "DNA_action_types.h" +#include "DNA_anim_types.h" + +#include "BLI_listbase.h" + +#include "testing/testing.h" + +namespace blender::bke::tests { + +TEST(action_groups, ReconstructGroupsWithReordering) +{ + // Construct an Action with three groups. + bAction action = {0}; + FCurve groupAcurve1 = {0}; + FCurve groupAcurve2 = {0}; + FCurve groupBcurve1 = {0}; + FCurve groupBcurve2 = {0}; + FCurve groupBcurve3 = {0}; + // Group C has no curves intentionally. + FCurve groupDcurve1 = {0}; + FCurve groupDcurve2 = {0}; + + groupAcurve1.rna_path = (char *)"groupAcurve1"; + groupAcurve2.rna_path = (char *)"groupAcurve2"; + groupBcurve1.rna_path = (char *)"groupBcurve1"; + groupBcurve2.rna_path = (char *)"groupBcurve2"; + groupDcurve1.rna_path = (char *)"groupDcurve1"; + groupBcurve3.rna_path = (char *)"groupBcurve3"; + groupDcurve2.rna_path = (char *)"groupDcurve2"; + + BLI_addtail(&action.curves, &groupAcurve1); + BLI_addtail(&action.curves, &groupAcurve2); + BLI_addtail(&action.curves, &groupBcurve1); + BLI_addtail(&action.curves, &groupBcurve2); + BLI_addtail(&action.curves, &groupDcurve1); + BLI_addtail(&action.curves, &groupBcurve3); // <-- The error that should be corrected. + BLI_addtail(&action.curves, &groupDcurve2); + + // Introduce another error type, by changing some `prev` pointers. + groupBcurve1.prev = NULL; + groupBcurve3.prev = &groupBcurve2; + groupDcurve1.prev = &groupBcurve3; + + bActionGroup groupA = {0}; + bActionGroup groupB = {0}; + bActionGroup groupC = {0}; + bActionGroup groupD = {0}; + strcpy(groupA.name, "groupA"); + strcpy(groupB.name, "groupB"); + strcpy(groupC.name, "groupC"); + strcpy(groupD.name, "groupD"); + + BLI_addtail(&action.groups, &groupA); + BLI_addtail(&action.groups, &groupB); + BLI_addtail(&action.groups, &groupC); + BLI_addtail(&action.groups, &groupD); + + groupAcurve1.grp = &groupA; + groupAcurve2.grp = &groupA; + groupBcurve1.grp = &groupB; + groupBcurve2.grp = &groupB; + groupBcurve3.grp = &groupB; + groupDcurve1.grp = &groupD; + groupDcurve2.grp = &groupD; + + groupA.channels.first = &groupAcurve1; + groupA.channels.last = &groupAcurve2; + groupB.channels.first = &groupBcurve1; + groupB.channels.last = &groupBcurve3; // The last channel in group B, after group C curve 1. + groupD.channels.first = &groupDcurve1; + groupD.channels.last = &groupDcurve2; + + EXPECT_EQ(groupA.channels.first, &groupAcurve1); + EXPECT_EQ(groupA.channels.last, &groupAcurve2); + EXPECT_EQ(groupB.channels.first, &groupBcurve1); + EXPECT_EQ(groupB.channels.last, &groupBcurve3); + EXPECT_EQ(groupC.channels.first, nullptr); + EXPECT_EQ(groupC.channels.last, nullptr); + EXPECT_EQ(groupD.channels.first, &groupDcurve1); + EXPECT_EQ(groupD.channels.last, &groupDcurve2); + + BKE_action_groups_reconstruct(&action); + + EXPECT_EQ(action.curves.first, &groupAcurve1); + EXPECT_EQ(action.curves.last, &groupDcurve2); + + EXPECT_EQ(groupA.prev, nullptr); + EXPECT_EQ(groupB.prev, &groupA); + EXPECT_EQ(groupC.prev, &groupB); + EXPECT_EQ(groupD.prev, &groupC); + + EXPECT_EQ(groupA.next, &groupB); + EXPECT_EQ(groupB.next, &groupC); + EXPECT_EQ(groupC.next, &groupD); + EXPECT_EQ(groupD.next, nullptr); + + EXPECT_EQ(groupA.channels.first, &groupAcurve1); + EXPECT_EQ(groupA.channels.last, &groupAcurve2); + EXPECT_EQ(groupB.channels.first, &groupBcurve1); + EXPECT_EQ(groupB.channels.last, &groupBcurve3); + EXPECT_EQ(groupC.channels.first, nullptr); + EXPECT_EQ(groupC.channels.last, nullptr); + EXPECT_EQ(groupD.channels.first, &groupDcurve1); + EXPECT_EQ(groupD.channels.last, &groupDcurve2); + + EXPECT_EQ(groupAcurve1.prev, nullptr); + EXPECT_EQ(groupAcurve2.prev, &groupAcurve1); + EXPECT_EQ(groupBcurve1.prev, &groupAcurve2); + EXPECT_EQ(groupBcurve2.prev, &groupBcurve1); + EXPECT_EQ(groupBcurve3.prev, &groupBcurve2); + EXPECT_EQ(groupDcurve1.prev, &groupBcurve3); + EXPECT_EQ(groupDcurve2.prev, &groupDcurve1); + + EXPECT_EQ(groupAcurve1.next, &groupAcurve2); + EXPECT_EQ(groupAcurve2.next, &groupBcurve1); + EXPECT_EQ(groupBcurve1.next, &groupBcurve2); + EXPECT_EQ(groupBcurve2.next, &groupBcurve3); + EXPECT_EQ(groupBcurve3.next, &groupDcurve1); + EXPECT_EQ(groupDcurve1.next, &groupDcurve2); + EXPECT_EQ(groupDcurve2.next, nullptr); +} + +} // namespace blender::bke::tests diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 4766fc6096b..7e4ab754500 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -89,16 +89,16 @@ bool id_can_have_animdata(const ID *id) return id_type_can_have_animdata(GS(id->name)); } -/* Get AnimData from the given ID-block. In order for this to work, we assume that - * the AnimData pointer is stored immediately after the given ID-block in the struct, - * as per IdAdtTemplate. +/** + * Get #AnimData from the given ID-block. */ AnimData *BKE_animdata_from_id(ID *id) { - /* only some ID-blocks have this info for now, so we cast the - * types that do to be of type IdAdtTemplate, and extract the - * AnimData that way - */ + /* In order for this to work, we assume that the #AnimData pointer is stored + * immediately after the given ID-block in the struct, as per IdAdtTemplate. */ + + /* Only some ID-blocks have this info for now, so we cast the types that do + * to be of type IdAdtTemplate, and add the AnimData to it using the template. */ if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; return iat->adt; @@ -106,16 +106,16 @@ AnimData *BKE_animdata_from_id(ID *id) return NULL; } -/* Add AnimData to the given ID-block. In order for this to work, we assume that - * the AnimData pointer is stored immediately after the given ID-block in the struct, - * as per IdAdtTemplate. Also note that +/** + * Ensure #AnimData exists in the given ID-block (when supported). */ -AnimData *BKE_animdata_add_id(ID *id) +AnimData *BKE_animdata_ensure_id(ID *id) { - /* Only some ID-blocks have this info for now, so we cast the - * types that do to be of type IdAdtTemplate, and add the AnimData - * to it using the template - */ + /* In order for this to work, we assume that the #AnimData pointer is stored + * immediately after the given ID-block in the struct, as per IdAdtTemplate. */ + + /* Only some ID-blocks have this info for now, so we cast the types that do + * to be of type IdAdtTemplate, and add the AnimData to it using the template. */ if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; @@ -667,7 +667,7 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa /* get animdata from src, and create for destination (if needed) */ srcAdt = BKE_animdata_from_id(srcID); - dstAdt = BKE_animdata_add_id(dstID); + dstAdt = BKE_animdata_ensure_id(dstID); if (ELEM(NULL, srcAdt, dstAdt)) { if (G.debug & G_DEBUG) { diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index a1f82b1dcb6..8a70f065e40 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -2087,7 +2087,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* check if object has any animation data */ if (ob->nlastrips.first) { /* Add AnimData block */ - BKE_animdata_add_id(id); + BKE_animdata_ensure_id(id); /* IPO first to take into any non-NLA'd Object Animation */ if (ob->ipo) { @@ -2109,7 +2109,7 @@ void do_versions_ipos_to_animato(Main *bmain) } else if ((ob->ipo) || (ob->action)) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Action first - so that Action name get conserved */ if (ob->action) { @@ -2133,7 +2133,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* check PoseChannels for constraints with local data */ if (ob->pose) { /* Verify if there's AnimData block */ - BKE_animdata_add_id(id); + BKE_animdata_ensure_id(id); for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { for (con = pchan->constraints.first; con; con = con->next) { @@ -2159,7 +2159,7 @@ void do_versions_ipos_to_animato(Main *bmain) */ if (con->ipo) { /* Verify if there's AnimData block, just in case */ - BKE_animdata_add_id(id); + BKE_animdata_ensure_id(id); /* although this was the constraint's local IPO, we still need to provide con * so that drivers can be added properly... @@ -2176,7 +2176,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* check constraint channels - we need to remove them anyway... */ if (ob->constraintChannels.first) { /* Verify if there's AnimData block */ - BKE_animdata_add_id(id); + BKE_animdata_ensure_id(id); for (conchan = ob->constraintChannels.first; conchan; conchan = conchann) { /* get pointer to next Constraint Channel */ @@ -2217,7 +2217,7 @@ void do_versions_ipos_to_animato(Main *bmain) */ if (key->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Shapekey data... */ ipo_to_animdata(bmain, id, key->ipo, NULL, NULL, NULL); @@ -2242,7 +2242,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (ma->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Material data... */ ipo_to_animdata(bmain, id, ma->ipo, NULL, NULL, NULL); @@ -2267,7 +2267,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (wo->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert World data... */ ipo_to_animdata(bmain, id, wo->ipo, NULL, NULL, NULL); @@ -2288,7 +2288,7 @@ void do_versions_ipos_to_animato(Main *bmain) if (ed && ed->seqbasep) { Sequence *seq; - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); SEQ_ALL_BEGIN (ed, seq) { IpoCurve *icu = (seq->ipo) ? seq->ipo->curve.first : NULL; @@ -2346,7 +2346,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (te->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Texture data... */ ipo_to_animdata(bmain, id, te->ipo, NULL, NULL, NULL); @@ -2371,7 +2371,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (ca->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Camera data... */ ipo_to_animdata(bmain, id, ca->ipo, NULL, NULL, NULL); @@ -2396,7 +2396,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (la->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Light data... */ ipo_to_animdata(bmain, id, la->ipo, NULL, NULL, NULL); @@ -2421,7 +2421,7 @@ void do_versions_ipos_to_animato(Main *bmain) /* we're only interested in the IPO */ if (cu->ipo) { /* Add AnimData block */ - AnimData *adt = BKE_animdata_add_id(id); + AnimData *adt = BKE_animdata_ensure_id(id); /* Convert Curve data... */ ipo_to_animdata(bmain, id, cu->ipo, NULL, NULL, NULL); diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 37c3d9017cd..d8b9b851865 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2813,7 +2813,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) /* add new animdata block */ if (!ob->adt) { - ob->adt = BKE_animdata_add_id(&ob->id); + ob->adt = BKE_animdata_ensure_id(&ob->id); } /* make a copy of all the drivers (for now), then correct any links that need fixing */ |