Fix #100718: NLA Hold Forward Inconsistency

Fix #100718: NLA Hold Forward Inconsistency

Action Track with 'extrapolation=Hold Forward' behaves the same as 'Hold'.

For the Action Track, we now properly treat extrapolation Hold_Forward just like the rest of the NLA system.

Co-author Wayde Moss @wbmoss_dev
Pull Request: https://projects.blender.org/blender/blender/pulls/109182
This commit is contained in:
Nate Rupsis
2023-09-11 18:40:31 +02:00
committed by Nate Rupsis
parent 974edc5885
commit 9da88301ef
5 changed files with 78 additions and 15 deletions

View File

@@ -37,7 +37,7 @@ extern "C" {
*
* See https://wiki.blender.org/wiki/Process/Compatibility_Handling for details. */
#define BLENDER_FILE_MIN_VERSION 306
#define BLENDER_FILE_MIN_SUBVERSION 12
#define BLENDER_FILE_MIN_SUBVERSION 13
/** User readable version string. */
const char *BKE_blender_version_string(void);

View File

@@ -272,6 +272,12 @@ void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt);
* Check if there is any space in the given track to add a strip of the given length.
*/
bool BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
/**
* Check to see if there are any NLA strips in the NLA tracks.
*/
bool BKE_nlatrack_has_strips(ListBase *tracks);
/**
* Rearrange the strips in the track so that they are always in order
* (usually only needed after a strip has been moved).

View File

@@ -963,8 +963,23 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
/* loop over strips, checking if they fall within the range */
LISTBASE_FOREACH (NlaStrip *, strip, strips) {
/* Check if current time occurs within this strip. */
if (IN_RANGE_INCL(ctime, strip->start, strip->end) ||
(strip->flag & NLASTRIP_FLAG_NO_TIME_MAP)) {
/* This block leads to the Action Track and non-time-remapped tweak strip evaluation to respect
* the extrapolation modes. If in_range, these two tracks will always output NES_TIME_WITHIN so
* fcurve extrapolation isn't clamped to the keyframe bounds. */
bool in_range = IN_RANGE_INCL(ctime, strip->start, strip->end);
if (strip->flag & NLASTRIP_FLAG_NO_TIME_MAP) {
switch (strip->extendmode) {
case NLASTRIP_EXTEND_HOLD:
in_range = true;
break;
case NLASTRIP_EXTEND_HOLD_FORWARD:
in_range = ctime >= strip->start;
break;
}
}
if (in_range) {
/* this strip is active, so try to use it */
estrip = strip;
side = NES_TIME_WITHIN;
@@ -3217,16 +3232,10 @@ static void animsys_create_action_track_strip(const AnimData *adt,
r_action_strip->extendmode = adt->act_extendmode;
r_action_strip->influence = adt->act_influence;
/* NOTE: must set this, or else the default setting overrides,
* and this setting doesn't work. */
r_action_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
/* Unless `extendmode` is Nothing (might be useful for flattening NLA evaluation), disable range.
* Extend-mode Nothing and Hold will behave as normal. Hold Forward will behave just like Hold.
/* Must set NLASTRIP_FLAG_USR_INFLUENCE, or else the default setting overrides, and influence
* doesn't work.
*/
if (r_action_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
r_action_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
}
r_action_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
const bool tweaking = (adt->flag & ADT_NLA_EDIT_ON) != 0;
const bool soloing = (adt->flag & ADT_NLA_SOLO_TRACK) != 0;

View File

@@ -1221,6 +1221,24 @@ bool BKE_nlatrack_has_space(NlaTrack *nlt, float start, float end)
return BKE_nlastrips_has_space(&nlt->strips, start, end);
}
bool BKE_nlatrack_has_strips(ListBase *tracks)
{
/* sanity checks */
if (BLI_listbase_is_empty(tracks)) {
return false;
}
/* Check each track for NLA strips. */
LISTBASE_FOREACH (NlaTrack *, track, tracks) {
if (BLI_listbase_count(&track->strips) > 0) {
return true;
}
}
/* none found */
return false;
}
void BKE_nlatrack_sort_strips(NlaTrack *nlt)
{
/* sanity checks */

View File

@@ -69,6 +69,7 @@
#include "BKE_main_namemap.h"
#include "BKE_mesh.hh"
#include "BKE_modifier.h"
#include "BKE_nla.h"
#include "BKE_node.hh"
#include "BKE_screen.h"
#include "BKE_workspace.h"
@@ -1052,6 +1053,28 @@ static void version_geometry_nodes_extrude_smooth_propagation(bNodeTree &ntree)
}
}
/* Change the action strip (if a NLA strip is preset) to HOLD instead of HOLD FORWARD to maintain
* backwards compatibility.*/
static void version_nla_action_strip_hold(Main *bmain)
{
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
AnimData *adt = BKE_animdata_from_id(id);
/* We only want to preserve existing behavior if there's an action and 1 or more NLA strips. */
if (adt == nullptr || adt->action == nullptr ||
adt->act_extendmode != NLASTRIP_EXTEND_HOLD_FORWARD)
{
continue;
}
if (BKE_nlatrack_has_strips(&adt->nla_tracks)) {
adt->act_extendmode = NLASTRIP_EXTEND_HOLD;
}
FOREACH_MAIN_ID_END;
}
}
void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
{
if (MAIN_VERSION_FILE_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_FILE_ATLEAST(bmain, 300, 1)) {
@@ -1148,7 +1171,8 @@ void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
SOCK_OBJECT,
SOCK_COLLECTION,
SOCK_TEXTURE,
SOCK_MATERIAL)) {
SOCK_MATERIAL))
{
link->tosock = link->tosock->next;
}
}
@@ -1341,6 +1365,10 @@ void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
}
}
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 306, 13)) {
version_nla_action_strip_hold(bmain);
}
/**
* Versioning code until next subversion bump goes here.
*
@@ -2691,7 +2719,8 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 300, 17)) {
if (!DNA_struct_elem_find(
fd->filesdna, "View3DOverlay", "float", "normals_constant_screen_size")) {
fd->filesdna, "View3DOverlay", "float", "normals_constant_screen_size"))
{
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
@@ -2757,7 +2786,8 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 300, 18)) {
if (!DNA_struct_elem_find(
fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library_ref")) {
fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library_ref"))
{
LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
BKE_asset_library_reference_init_default(&workspace->asset_library_ref);
}