Skip to content

Commit

Permalink
Track View Fix: Implement the public override of the externally used …
Browse files Browse the repository at this point in the history
…method, thus removing asserts (issue #14801). (#18495)

* Implement missing public method SetValue(...). Add unit tests.

Signed-off-by: Aleks Starykh <[email protected]>

* Descriptive name for a local variable

Signed-off-by: Aleks Starykh <[email protected]>

---------

Signed-off-by: Aleks Starykh <[email protected]>
  • Loading branch information
Aleks-Starykh-TR authored Nov 23, 2024
1 parent 05a6061 commit 3aba99a
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 2 deletions.
144 changes: 142 additions & 2 deletions Gems/Maestro/Code/Source/Cinematics/AssetBlendTrack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,11 +273,151 @@ void CAssetBlendTrack::GetValue(float time, Maestro::AssetBlends<AZ::Data::Asset
value = m_assetBlend;
}

void CAssetBlendTrack::SetKeysAtTime(float time, const Maestro::AssetBlends<AZ::Data::AssetData>& value)
{
ClearKeys();
for (const auto& blend : value.m_assetBlends)
{
if (!blend.m_assetId.IsValid())
{
continue; // filter out blends for invalid AssetIds
}

AZ::IAssetBlendKey key;
key.m_assetId = blend.m_assetId;
key.m_description.clear(); // could be parsed to asset filename after requesting AssetData by Id
key.m_blendInTime = blend.m_blendInTime;
key.m_blendOutTime = blend.m_blendOutTime;
// IKey (key.flags nullified in ctor)
key.time = time + blend.m_time;

// Check that the key for the asset is unique in time-line
bool isUnique = true;
for (const auto& previousKey : m_keys)
{
if ((previousKey.m_assetId == key.m_assetId) &&
(fabs(previousKey.time - key.time) < AZ::Constants::Tolerance))
{
isUnique = false;
break;
}
}
if (isUnique)
{
m_keys.push_back(key);
}
}

SortKeys(); // sorting by key.time

m_lastTime = time;
m_currKey = 0;
m_fMinKeyValue = 0;
m_fMaxKeyValue = 0;
const auto keysCount = m_keys.size();
for (size_t i = 0; i < keysCount; ++i)
{
auto& key = m_keys[i];
// Try to restore values for ITimeRangeKey - not all values can be restored, information on duration and looping is missing
key.m_startTime = key.time;
if (keysCount > 1 && i < keysCount - 1) // not the last key ?
{
key.m_duration = m_keys[i + 1].time - key.time; // prolong to the next key
}
else
{
key.m_duration = key.m_blendInTime + key.m_blendOutTime + AZ::Constants::Tolerance; // set at least enough time to fade in/out
}
key.m_endTime = key.m_startTime + key.m_duration;
key.m_speed = 1;
key.m_bLoop = false;

// Accumulate values for TAnimTrack<AZ::IAssetBlendKey>
m_fMinKeyValue = (key.time < m_fMinKeyValue) ? key.time : m_fMinKeyValue;
m_fMaxKeyValue = (key.time > m_fMaxKeyValue) ? key.time : m_fMaxKeyValue;
key.m_bLoop = i < keysCount - 1 && key.m_endTime < m_keys[i + 1].m_startTime;
}
// TAnimTrack<AZ::IAssetBlendKey>
if (keysCount == 0)
{
m_timeRange.start = 0.f;
m_timeRange.end = 0.f;
}
else
{
m_timeRange.start = time;
m_timeRange.end = m_keys.back().m_endTime;
}
}

void CAssetBlendTrack::FilterBlends(const Maestro::AssetBlends<AZ::Data::AssetData>& value, Maestro::AssetBlends<AZ::Data::AssetData>& filteredValue) const
{
filteredValue.m_assetBlends.clear();
for (const auto& nextBlend : value.m_assetBlends)
{
if (nextBlend.m_assetId.IsValid())
{
bool isUnique = true;
for (const auto& previousBlend : filteredValue.m_assetBlends)
{
if ((previousBlend.m_assetId == nextBlend.m_assetId) &&
(fabs(previousBlend.m_time - nextBlend.m_time) < AZ::Constants::Tolerance))
{
isUnique = false;
break;
}
}
if (isUnique)
{
filteredValue.m_assetBlends.push_back(nextBlend);
}
}
}
}

void CAssetBlendTrack::ClearKeys()
{
// TAnimTrack
m_keys.clear();
m_currKey = 0;
m_lastTime = -1;
m_timeRange.Clear();
m_bModified = 0;
m_fMinKeyValue = 0;
m_fMaxKeyValue = 0;
}

//////////////////////////////////////////////////////////////////////////
void CAssetBlendTrack::SetValue(float time, const Maestro::AssetBlends<AZ::Data::AssetData>& value, bool bDefault)
{
if (bDefault)
{
SetDefaultValue(time, value);
return;
}
SetKeysAtTime(time, value);
}

//////////////////////////////////////////////////////////////////////////
void CAssetBlendTrack::SetDefaultValue(const Maestro::AssetBlends<AZ::Data::AssetData>& defaultValue)
{
m_defaultValue = defaultValue;
Invalidate();
SetDefaultValue(0.f, defaultValue);
}

//////////////////////////////////////////////////////////////////////////
void CAssetBlendTrack::SetDefaultValue(float time, const Maestro::AssetBlends<AZ::Data::AssetData>& defaultValue)
{
Maestro::AssetBlends<AZ::Data::AssetData> fileteredValue;
FilterBlends(defaultValue, fileteredValue);
m_defaultValue = fileteredValue;

SetKeysAtTime(time, fileteredValue);
}

//////////////////////////////////////////////////////////////////////////
void CAssetBlendTrack::GetDefaultValue(Maestro::AssetBlends<AZ::Data::AssetData>& defaultValue) const
{
defaultValue = m_defaultValue;
}

//////////////////////////////////////////////////////////////////////////
Expand Down
7 changes: 7 additions & 0 deletions Gems/Maestro/Code/Source/Cinematics/AssetBlendTrack.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,21 @@ class CAssetBlendTrack

AnimValueType GetValueType() override;
void GetValue(float time, Maestro::AssetBlends<AZ::Data::AssetData>& value) override;
void SetValue(float time, const Maestro::AssetBlends<AZ::Data::AssetData>& value, bool bDefault = false) override;

//////////////////////////////////////////////////////////////////////////
void SetDefaultValue(const Maestro::AssetBlends<AZ::Data::AssetData>& defaultValue);
void SetDefaultValue(float time, const Maestro::AssetBlends<AZ::Data::AssetData>& defaultValue);
void GetDefaultValue(Maestro::AssetBlends<AZ::Data::AssetData>& defaultValue) const;

float GetEndTime() const;

static void Reflect(AZ::ReflectContext* context);

private:
void SetKeysAtTime(float time, const Maestro::AssetBlends<AZ::Data::AssetData>& value);
void ClearKeys();
void FilterBlends(const Maestro::AssetBlends<AZ::Data::AssetData>& value, Maestro::AssetBlends<AZ::Data::AssetData>& filteredValue) const;

// Internal transient state, not serialized.
Maestro::AssetBlends<AZ::Data::AssetData> m_assetBlend;
Expand Down
70 changes: 70 additions & 0 deletions Gems/Maestro/Code/Source/Cinematics/Tests/AssetBlendTrackTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace AssetBlendTrackTest
const AZ::Data::AssetId KEY1_ASSET_ID = AZ::Data::AssetId(AZ::Uuid("{86CE36B5-D996-4CEF-943E-3F12008694E1}"), 1);
const AZ::Data::AssetId KEY2_ASSET_ID = AZ::Data::AssetId(AZ::Uuid("{94D54D20-BACC-4A60-8A03-0DC9B5033E03}"), 2);
const AZ::Data::AssetId KEY3_ASSET_ID = AZ::Data::AssetId(AZ::Uuid("{94D54D20-BACC-4A60-8A03-0DC9B5033E03}"), 3);
const AZ::Data::AssetId ZERO_ASSET_ID = AZ::Data::AssetId();

/////////////////////////////////////////////////////////////////////////////////////
// Testing sub-class
Expand All @@ -31,6 +32,23 @@ namespace AssetBlendTrackTest
void CreateAssetBlendTestKeys();

CAssetBlendTrack m_assetBlendTrack;

AZStd::vector<Maestro::AssetBlend> m_vectorBlends8EvaluatingTo6 = {
// m_assetId, m_time, m_blendInTime, m_blendOutTime
Maestro::AssetBlend(KEY1_ASSET_ID, 0.0f, 0.1f, 0.1f),
Maestro::AssetBlend(KEY1_ASSET_ID, 0.0f, 0.1f, 0.1f), // item is to be filtered out due to the ambiguous key time
Maestro::AssetBlend(ZERO_ASSET_ID, 0.5f, 0.1f, 0.1f), // item is to be filtered out due to the invalid asset Id
Maestro::AssetBlend(KEY1_ASSET_ID, 0.5f, 0.1f, 0.1f),
Maestro::AssetBlend(KEY2_ASSET_ID, 1.0f, 0.1f, 0.1f),
Maestro::AssetBlend(KEY2_ASSET_ID, 1.5f, 0.1f, 0.1f),
Maestro::AssetBlend(KEY3_ASSET_ID, 2.5f, 0.3f, 0.3f), // item is to be sorted down, its duration cannot be determined other than 0.3f + 0.3f + tolerance
Maestro::AssetBlend(KEY3_ASSET_ID, 2.0f, 0.1f, 0.1f)
};

Maestro::AssetBlends<AZ::Data::AssetData> m_AssetBlends8EvaluatingTo6 = {
m_vectorBlends8EvaluatingTo6 // AZStd::vector<AssetBlend> m_assetBlends
};

};

/////////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -92,6 +110,58 @@ namespace AssetBlendTrackTest
ASSERT_EQ(value.m_assetBlends.at(0).m_assetId, KEY3_ASSET_ID) << "Expected KEY3_ASSET_ID at time 3.0f.";
};

TEST_F(CAssetBlendTrackTest, SetValue_EmptyBlends_ExpectNoKeys)
{
Maestro::AssetBlends<AZ::Data::AssetData> emptyAssetBlends;

m_assetBlendTrack.SetValue(0.f, emptyAssetBlends, false);
ASSERT_EQ(m_assetBlendTrack.GetNumKeys(), 0) << "Expected no keys.";

CreateAssetBlendTestKeys();
m_assetBlendTrack.SetValue(0.f, emptyAssetBlends, true);
ASSERT_EQ(m_assetBlendTrack.GetNumKeys(), 0) << "Expected no keys.";

CreateAssetBlendTestKeys();
m_assetBlendTrack.SetDefaultValue(emptyAssetBlends);
ASSERT_EQ(m_assetBlendTrack.GetNumKeys(), 0) << "Expected no keys.";
}

TEST_F(CAssetBlendTrackTest, SetValue_Default_8Blends_Expect6Keys)
{
constexpr float timeOffset = 1.0f;
m_assetBlendTrack.SetValue(timeOffset, m_AssetBlends8EvaluatingTo6, true); // save default blends and then reconstruct keys from these

Maestro::AssetBlends<AZ::Data::AssetData> resultingDefaultBlends;
m_assetBlendTrack.GetDefaultValue(resultingDefaultBlends);
// Invalid elements (with invalid AssetId) and ambiguous elements (with the repeating AssetId and time key) are filtered out
ASSERT_EQ(resultingDefaultBlends.m_assetBlends.size(), 6) << "Expected 6 blends, 2 of 8 were to be filtered out.";

// Setting blends reconstructs keys accordingly, filtering out invalid and ambiguous elements
auto numKeys = m_assetBlendTrack.GetNumKeys();
ASSERT_EQ(numKeys, 6) << "Expected 6 keys, 2 of 8 blends were to be filtered out.";

AZ::IAssetBlendKey key;
m_assetBlendTrack.GetKey(4, &key);
ASSERT_LE(fabs(key.time - 2.0f - timeOffset), AZ::Constants::FloatEpsilon) << "Wrong key time.";
ASSERT_LE(fabs(key.m_duration - 0.5f), AZ::Constants::FloatEpsilon) << "Wrong key duration.";
m_assetBlendTrack.GetKey(5, &key); // last key
ASSERT_LE(fabs(key.time - 2.5f - timeOffset), AZ::Constants::FloatEpsilon) << "Wrong key time.";
ASSERT_LE(fabs(key.m_duration - 0.6f), AZ::Constants::Tolerance + AZ::Constants::FloatEpsilon);
ASSERT_LE(fabs(m_assetBlendTrack.GetEndTime() - key.m_endTime), AZ::Constants::FloatEpsilon) << "Wrong sequence end time.";

m_assetBlendTrack.SetValue(0.f, m_AssetBlends8EvaluatingTo6, false); // reconstruct current keys from given blends

// Setting blends reconstructs keys accordingly, filtering out invalid and ambiguous elements
numKeys = m_assetBlendTrack.GetNumKeys();
ASSERT_EQ(numKeys, 6) << "Expected 6 keys, 2 of 8 possible keys were to be filtered out.";

m_assetBlendTrack.GetKey(4, &key);
ASSERT_LE(fabs(key.time - 2.0f), AZ::Constants::FloatEpsilon) << "Wrong key time.";
ASSERT_LE(fabs(key.m_duration - 0.5f), AZ::Constants::FloatEpsilon) << "Wrong key duration.";
m_assetBlendTrack.GetKey(5, &key); // last key
ASSERT_LE(fabs(key.time - 2.5f), AZ::Constants::FloatEpsilon) << "Wrong key time.";
ASSERT_LE(fabs(m_assetBlendTrack.GetEndTime() - key.m_endTime), AZ::Constants::FloatEpsilon) << "Wrong sequence end time.";
}
}; // namespace AssetBlendTrackTest

#endif // !defined(_RELEASE)

0 comments on commit 3aba99a

Please sign in to comment.