You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/LyShine/Code/Source/Animation/AnimSplineTrack_Vec2Special...

407 lines
13 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <LyShine/UiBase.h>
template <>
inline TUiAnimSplineTrack<Vec2>::TUiAnimSplineTrack()
: m_refCount(0)
{
AllocSpline();
m_flags = 0;
m_defaultValue = Vec2(0, 0);
m_fMinKeyValue = 0.0f;
m_fMaxKeyValue = 0.0f;
m_bCustomColorSet = false;
}
template <>
inline void TUiAnimSplineTrack<Vec2>::GetValue(float time, float& value)
{
if (GetNumKeys() == 0)
{
value = m_defaultValue.y;
}
else
{
Spline::ValueType tmp;
m_spline->Interpolate(time, tmp);
value = tmp[0];
}
}
template <>
inline EUiAnimCurveType TUiAnimSplineTrack<Vec2>::GetCurveType() { return eUiAnimCurveType_BezierFloat; }
template <>
inline EUiAnimValue TUiAnimSplineTrack<Vec2>::GetValueType() { return eUiAnimValue_Float; }
template <>
inline void TUiAnimSplineTrack<Vec2>::SetValue(float time, const float& value, bool bDefault)
{
if (!bDefault)
{
I2DBezierKey key;
key.value = Vec2(time, value);
SetKeyAtTime(time, &key);
}
else
{
m_defaultValue = Vec2(time, value);
}
}
template <>
inline void TUiAnimSplineTrack<Vec2>::GetKey(int index, IKey* key) const
{
assert(index >= 0 && index < GetNumKeys());
assert(key != 0);
Spline::key_type& k = m_spline->key(index);
I2DBezierKey* bezierkey = (I2DBezierKey*)key;
bezierkey->time = k.time;
bezierkey->flags = k.flags;
bezierkey->value = k.value;
}
template <>
inline void TUiAnimSplineTrack<Vec2>::SetKey(int index, IKey* key)
{
assert(index >= 0 && index < GetNumKeys());
assert(key != 0);
Spline::key_type& k = m_spline->key(index);
I2DBezierKey* bezierkey = (I2DBezierKey*)key;
k.time = bezierkey->time;
k.flags = bezierkey->flags;
k.value = bezierkey->value;
UpdateTrackValueRange(k.value.y);
Invalidate();
}
//! Create key at given time, and return its index.
template <>
inline int TUiAnimSplineTrack<Vec2>::CreateKey(float time)
{
float value;
int nkey = GetNumKeys();
if (nkey > 0)
{
GetValue(time, value);
}
else
{
value = m_defaultValue.y;
}
UpdateTrackValueRange(value);
Spline::ValueType tmp;
tmp[0] = value;
tmp[1] = 0;
return m_spline->InsertKey(time, tmp);
}
template <>
inline int TUiAnimSplineTrack<Vec2>::CopyKey(IUiAnimTrack* pFromTrack, int nFromKey)
{
// This small time offset is applied to prevent the generation of singular tangents.
float timeOffset = 0.01f;
I2DBezierKey key;
pFromTrack->GetKey(nFromKey, &key);
float t = key.time + timeOffset;
int newIndex = CreateKey(t);
key.time = key.value.x = t;
SetKey(newIndex, &key);
return newIndex;
}
template <>
inline bool TUiAnimSplineTrack<Vec2>::Serialize([[maybe_unused]] IUiAnimationSystem* uiAnimationSystem, XmlNodeRef& xmlNode, bool bLoading, bool bLoadEmptyTracks)
{
if (bLoading)
{
int num = xmlNode->getChildCount();
int flags = m_flags;
xmlNode->getAttr("Flags", flags);
xmlNode->getAttr("defaultValue", m_defaultValue);
SetFlags(flags);
xmlNode->getAttr("HasCustomColor", m_bCustomColorSet);
if (m_bCustomColorSet)
{
unsigned int abgr;
xmlNode->getAttr("CustomColor", abgr);
m_customColor = ColorB(abgr);
}
SetNumKeys(num);
for (int i = 0; i < num; i++)
{
I2DBezierKey key; // Must be inside loop.
XmlNodeRef keyNode = xmlNode->getChild(i);
if (!keyNode->getAttr("time", key.time))
{
CryLog("[UI_ANIMATION:TUiAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing time information.");
return false;
}
if (!keyNode->getAttr("value", key.value))
{
CryLog("[UI_ANIMATION:TUiAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing value information.");
return false;
}
//assert(key.time == key.value.x);
keyNode->getAttr("flags", key.flags);
SetKey(i, &key);
// In-/Out-tangent
if (!keyNode->getAttr("ds", m_spline->key(i).ds))
{
CryLog("[UI_ANIMATION:TUiAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing ds spline information.");
return false;
}
if (!keyNode->getAttr("dd", m_spline->key(i).dd))
{
CryLog("[UI_ANIMATION:TUiAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:dd spline information.");
return false;
}
}
if ((!num) && (!bLoadEmptyTracks))
{
return false;
}
}
else
{
int num = GetNumKeys();
xmlNode->setAttr("Flags", GetFlags());
xmlNode->setAttr("defaultValue", m_defaultValue);
xmlNode->setAttr("HasCustomColor", m_bCustomColorSet);
if (m_bCustomColorSet)
{
xmlNode->setAttr("CustomColor", m_customColor.pack_abgr8888());
}
I2DBezierKey key;
for (int i = 0; i < num; i++)
{
GetKey(i, &key);
XmlNodeRef keyNode = xmlNode->newChild("Key");
assert(key.time == key.value.x);
keyNode->setAttr("time", key.time);
keyNode->setAttr("value", key.value);
int flags = key.flags;
// Just save the in/out/unify mask part. Others are for editing convenience.
flags &= (SPLINE_KEY_TANGENT_IN_MASK | SPLINE_KEY_TANGENT_OUT_MASK | SPLINE_KEY_TANGENT_UNIFY_MASK);
if (flags != 0)
{
keyNode->setAttr("flags", flags);
}
// We also have to save in-/out-tangents, because TCB infos are not used for custom tangent keys.
keyNode->setAttr("ds", m_spline->key(i).ds);
keyNode->setAttr("dd", m_spline->key(i).dd);
}
}
return true;
}
template <>
inline bool TUiAnimSplineTrack<Vec2>::SerializeSelection(XmlNodeRef& xmlNode, bool bLoading, bool bCopySelected, float fTimeOffset)
{
if (bLoading)
{
int numCur = GetNumKeys();
int num = xmlNode->getChildCount();
int type;
xmlNode->getAttr("TrackType", type);
if (type != GetCurveType())
{
return false;
}
SetNumKeys(num + numCur);
for (int i = 0; i < num; i++)
{
I2DBezierKey key; // Must be inside loop.
XmlNodeRef keyNode = xmlNode->getChild(i);
keyNode->getAttr("time", key.time);
keyNode->getAttr("value", key.value);
assert(key.time == key.value.x);
key.time += fTimeOffset;
key.value.x += fTimeOffset;
keyNode->getAttr("flags", key.flags);
SetKey(i + numCur, &key);
if (bCopySelected)
{
SelectKey(i + numCur, true);
}
// In-/Out-tangent
keyNode->getAttr("ds", m_spline->key(i + numCur).ds);
keyNode->getAttr("dd", m_spline->key(i + numCur).dd);
}
SortKeys();
}
else
{
int num = GetNumKeys();
xmlNode->setAttr("TrackType", GetCurveType());
I2DBezierKey key;
for (int i = 0; i < num; i++)
{
GetKey(i, &key);
assert(key.time == key.value.x);
if (!bCopySelected || IsKeySelected(i))
{
XmlNodeRef keyNode = xmlNode->newChild("Key");
keyNode->setAttr("time", key.time);
keyNode->setAttr("value", key.value);
int flags = key.flags;
// Just save the in/out mask part. Others are for editing convenience.
flags &= (SPLINE_KEY_TANGENT_IN_MASK | SPLINE_KEY_TANGENT_OUT_MASK);
if (flags != 0)
{
keyNode->setAttr("flags", flags);
}
// We also have to save in-/out-tangents, because TCB infos are not used for custom tangent keys.
keyNode->setAttr("ds", m_spline->key(i).ds);
keyNode->setAttr("dd", m_spline->key(i).dd);
}
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
template<>
inline void TUiAnimSplineTrack<Vec2>::GetKeyInfo(int index, const char*& description, float& duration)
{
duration = 0;
static char str[64];
description = str;
assert(index >= 0 && index < GetNumKeys());
Spline::key_type& k = m_spline->key(index);
sprintf_s(str, "%.2f", k.value.y);
}
//////////////////////////////////////////////////////////////////////////
typedef UiSpline::BezierSpline<Vec2, UiSpline::SplineKeyEx<Vec2> > BezierSplineVec2;
typedef UiSpline::TSpline<UiSpline::SplineKeyEx<Vec2>, spline::BezierBasis> TSplineBezierBasisVec2;
//////////////////////////////////////////////////////////////////////////
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(UiSpline::TrackSplineInterpolator<Vec2>, "{38F814D4-6041-4442-9704-9F68E996D55B}");
AZ_TYPE_INFO_SPECIALIZE(UiSpline::SplineKey<Vec2>, "{E2301E81-6BAF-4A17-886C-76F1A9C37118}");
AZ_TYPE_INFO_SPECIALIZE(UiSpline::SplineKeyEx<Vec2>, "{1AE37C63-D5C2-4E65-A08B-7020E7696233}");
AZ_TYPE_INFO_SPECIALIZE(BezierSplineVec2, "{EC8BA7BD-EF3B-453A-8017-CD1BF5B7C011}");
AZ_TYPE_INFO_SPECIALIZE(TSplineBezierBasisVec2, "{B661D05E-B912-4BD9-B102-FA82938243A9}");
}
namespace UiSpline
{
//////////////////////////////////////////////////////////////////////////
template <>
inline void TSplineBezierBasisVec2::Reflect(AZ::SerializeContext* serializeContext)
{
serializeContext->Class<TSplineBezierBasisVec2>()
->Version(1)
->Field("Keys", &BezierSplineVec2::m_keys);
}
//////////////////////////////////////////////////////////////////////////
template <>
inline void BezierSplineVec2::Reflect(AZ::SerializeContext* serializeContext)
{
TSplineBezierBasisVec2::Reflect(serializeContext);
serializeContext->Class<BezierSplineVec2, TSplineBezierBasisVec2>()
->Version(1)
;
}
}
//////////////////////////////////////////////////////////////////////////
// When TUiAnimSplineTrack<Vec2> is deserialized, a spline instance
// is first created in the TUiAnimSplineTrack<Vec2> constructor (via AllocSpline()),
// then the pointer is overwritten when "Spline" field is deserialized.
// To prevent a memory leak, m_spline is now an intrusive pointer, so that if/when
// the "Spline" field is deserialized, the old object will be deleted.
template<>
inline bool TUiAnimSplineTrack<Vec2>::VersionConverter(AZ::SerializeContext& context,
AZ::SerializeContext::DataElementNode& classElement)
{
bool converted = false;
if (classElement.GetVersion() == 1)
{
int splineElementIdx = classElement.FindElement(AZ_CRC("Spline", 0x35f655e9));
if (splineElementIdx != -1)
{
// Find & copy the raw pointer node
AZ::SerializeContext::DataElementNode& splinePtrNodeRef = classElement.GetSubElement(splineElementIdx);
AZ::SerializeContext::DataElementNode splinePtrNodeCopy = splinePtrNodeRef;
// Reset the node, then convert it to an intrusive pointer
splinePtrNodeRef = AZ::SerializeContext::DataElementNode();
const bool result = splinePtrNodeRef.Convert<AZStd::intrusive_ptr<UiSpline::TrackSplineInterpolator<Vec2>>>(context, "Spline");
if (result)
{
// Use the standard name used with the smart pointers serialization
// (smart pointers are serialized as containers with one element);
// Set the intrusive pointer to the raw pointer value
splinePtrNodeCopy.SetName(AZ::SerializeContext::IDataContainer::GetDefaultElementName());
splinePtrNodeRef.AddElement(splinePtrNodeCopy);
converted = true;
}
}
}
// Did not convert. Discard unknown versions if failed to convert, and hope for the best
AZ_Assert(converted, "Failed to convert TUiAnimSplineTrack<Vec2> version %d to the current version", classElement.GetVersion());
return converted;
}
template<>
inline void TUiAnimSplineTrack<Vec2>::Reflect(AZ::SerializeContext* serializeContext)
{
UiSpline::SplineKey<Vec2>::Reflect(serializeContext);
UiSpline::SplineKeyEx<Vec2>::Reflect(serializeContext);
UiSpline::TrackSplineInterpolator<Vec2>::Reflect(serializeContext);
BezierSplineVec2::Reflect(serializeContext);
serializeContext->Class<TUiAnimSplineTrack<Vec2> >()
->Version(2, &TUiAnimSplineTrack<Vec2>::VersionConverter)
->Field("Flags", &TUiAnimSplineTrack<Vec2>::m_flags)
->Field("DefaultValue", &TUiAnimSplineTrack<Vec2>::m_defaultValue)
->Field("ParamType", &TUiAnimSplineTrack<Vec2>::m_nParamType)
->Field("ParamData", &TUiAnimSplineTrack<Vec2>::m_componentParamData)
->Field("Spline", &TUiAnimSplineTrack<Vec2>::m_spline);
}