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/Maestro/Code/Source/Cinematics/AnimSplineTrack_Vec2Special...

474 lines
16 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
*
*/
// Description : 'Vec2' explicit specialization of the class template
// TAnimSplineTrack
// Notice : Should be included in AnimSplineTrack h only
#ifndef CRYINCLUDE_CRYMOVIE_ANIMSPLINETRACK_VEC2SPECIALIZATION_H
#define CRYINCLUDE_CRYMOVIE_ANIMSPLINETRACK_VEC2SPECIALIZATION_H
#pragma once
#include <AzCore/Serialization/EditContext.h>
namespace spline
{
template<>
inline void SplineKey<Vec2>::Reflect(AZ::SerializeContext* serializeContext)
{
serializeContext->Class<SplineKey<Vec2> >()
->Version(1)
->Field("time", &SplineKey<Vec2>::time)
->Field("flags", &SplineKey<Vec2>::flags)
->Field("value", &SplineKey<Vec2>::value)
->Field("ds", &SplineKey<Vec2>::ds)
->Field("dd", &SplineKey<Vec2>::dd);
}
} // namespace spline
template <>
inline TAnimSplineTrack<Vec2>::TAnimSplineTrack()
: m_refCount(0)
{
AllocSpline();
m_flags = 0;
m_defaultValue = Vec2(0, 0);
m_fMinKeyValue = 0.0f;
m_fMaxKeyValue = 0.0f;
m_bCustomColorSet = false;
m_node = nullptr;
m_trackMultiplier = 1.0f;
}
template <>
inline void TAnimSplineTrack<Vec2>::GetValue(float time, float& value, bool applyMultiplier)
{
if (GetNumKeys() == 0)
{
value = m_defaultValue.y;
}
else
{
Spline::ValueType tmp;
m_spline->Interpolate(time, tmp);
value = tmp[0];
}
if (applyMultiplier && m_trackMultiplier != 1.0f)
{
value /= m_trackMultiplier;
}
}
template <>
inline EAnimCurveType TAnimSplineTrack<Vec2>::GetCurveType() { return eAnimCurveType_BezierFloat; }
template <>
inline AnimValueType TAnimSplineTrack<Vec2>::GetValueType() { return kAnimValueDefault; }
template <>
inline void TAnimSplineTrack<Vec2>::SetValue(float time, const float& value, bool bDefault, bool applyMultiplier)
{
if (!bDefault)
{
I2DBezierKey key;
if (applyMultiplier && m_trackMultiplier != 1.0f)
{
key.value = Vec2(time, value * m_trackMultiplier);
}
else
{
key.value = Vec2(time, value);
}
SetKeyAtTime(time, &key);
}
else
{
if (applyMultiplier && m_trackMultiplier != 1.0f)
{
m_defaultValue = Vec2(time, value * m_trackMultiplier);
}
else
{
m_defaultValue = Vec2(time, value);
}
}
}
template <>
inline void TAnimSplineTrack<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 TAnimSplineTrack<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 TAnimSplineTrack<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 TAnimSplineTrack<Vec2>::CopyKey(IAnimTrack* 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;
}
/// @deprecated Serialization for Sequence data in Component Entity Sequences now occurs through AZ::SerializeContext and the Sequence Component
template <>
inline bool TAnimSplineTrack<Vec2>::Serialize(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("[CRYMOVIE:TAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing time information.");
return false;
}
if (!keyNode->getAttr("value", key.value))
{
CryLog("[CRYMOVIE:TAnimSplineTrack<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("[CRYMOVIE:TAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:missing ds spline information.");
return false;
}
if (!keyNode->getAttr("dd", m_spline->key(i).dd))
{
CryLog("[CRYMOVIE:TAnimSplineTrack<Vec2>::Serialize]Ill formed legacy track:dd spline information.");
return false;
}
// now that tangents are loaded, compute the relative angle and size for later unified Tangent manipulations
m_spline->key(i).ComputeThetaAndScale();
}
xmlNode->getAttr("Id", m_id);
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);
}
xmlNode->setAttr("Id", m_id);
}
return true;
}
template <>
inline bool TAnimSplineTrack<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 TAnimSplineTrack<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);
}
using BezierSplineVec2 = spline::BezierSpline<Vec2, spline::SplineKeyEx<Vec2>>;
using TSplineBezierBasisVec2 = spline::TSpline<spline::SplineKeyEx<Vec2>, spline::BezierBasis>;
namespace AZ
{
AZ_TYPE_INFO_SPECIALIZE(spline::TrackSplineInterpolator<Vec2>, "{173AC8F0-FD63-4583-8D38-F43FE59F2209}");
AZ_TYPE_INFO_SPECIALIZE(spline::SplineKeyEx<Vec2>, "{96BCA307-A4D5-43A0-9985-08A29BCCCB30}");
AZ_TYPE_INFO_SPECIALIZE(BezierSplineVec2, "{EE318F13-A608-4047-85B3-3D40745A19C7}");
AZ_TYPE_INFO_SPECIALIZE(TSplineBezierBasisVec2, "{B638C840-C1D7-483A-B04E-B22DA539DB8D}");
}
namespace spline
{
//////////////////////////////////////////////////////////////////////////
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 TAnimSplineTrack<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 TAnimSplineTrack<Vec2>::VersionConverter(AZ::SerializeContext& context,
AZ::SerializeContext::DataElementNode& classElement)
{
bool result = true;
if (classElement.GetVersion() < 5)
{
classElement.AddElement(context, "BaseClass1", azrtti_typeid<IAnimTrack>());
if (classElement.GetVersion() == 1)
{
bool converted = false;
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();
if (splinePtrNodeRef.Convert<AZStd::intrusive_ptr<spline::TrackSplineInterpolator<Vec2>>>(context, "Spline"))
{
// 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());
result = converted;
}
}
return result;
}
//////////////////////////////////////////////////////////////////////////
template<>
inline void TAnimSplineTrack<Vec2>::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
spline::SplineKey<Vec2>::Reflect(serializeContext);
spline::SplineKeyEx<Vec2>::Reflect(serializeContext);
spline::TrackSplineInterpolator<Vec2>::Reflect(serializeContext);
BezierSplineVec2::Reflect(serializeContext);
serializeContext->Class<TAnimSplineTrack<Vec2>, IAnimTrack>()
->Version(5, &TAnimSplineTrack<Vec2>::VersionConverter)
->Field("Flags", &TAnimSplineTrack<Vec2>::m_flags)
->Field("DefaultValue", &TAnimSplineTrack<Vec2>::m_defaultValue)
->Field("ParamType", &TAnimSplineTrack<Vec2>::m_nParamType)
->Field("Spline", &TAnimSplineTrack<Vec2>::m_spline)
->Field("Id", &TAnimSplineTrack<Vec2>::m_id);
AZ::EditContext* ec = serializeContext->GetEditContext();
// Preventing the default value from being pushed to slice to keep it from dirtying the slice when updated internally
if (ec)
{
ec->Class<TAnimSplineTrack<Vec2>>("TAnimSplineTrack Vec2", "Specialization track for Vec2 AnimSpline")->
DataElement(AZ::Edit::UIHandlers::Vector2, &TAnimSplineTrack<Vec2>::m_defaultValue, "DefaultValue", "")->
Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Hide)->
Attribute(AZ::Edit::Attributes::SliceFlags, AZ::Edit::SliceFlags::NotPushable);
}
}
}
#endif // CRYINCLUDE_CRYMOVIE_ANIMSPLINETRACK_VEC2SPECIALIZATION_H