git mv Code\Sandbox\Editor Code/Editor
Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
// Editor
|
||||
#include "TrackViewKeyPropertiesDlg.h"
|
||||
#include "Controls/ReflectedPropertyControl/ReflectedPropertyItem.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class C2DBezierKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
C2DBezierKeyUIControls()
|
||||
: m_skipOnUIChange(false)
|
||||
{}
|
||||
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariable<float> mv_value;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_value, "Value");
|
||||
}
|
||||
bool SupportTrackType([[maybe_unused]] const CAnimParamType& paramType, EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
return trackType == eAnimCurveType_BezierFloat;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 0; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {DBD76F4B-8EFC-45b6-AFB8-56F171FA150A}
|
||||
static const GUID guid =
|
||||
{
|
||||
0xdbd76f4b, 0x8efc, 0x45b6, { 0xaf, 0xb8, 0x56, 0xf1, 0x71, 0xfa, 0x15, 0xa }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
|
||||
bool m_skipOnUIChange;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool C2DBezierKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
float fMin = 0.0f;
|
||||
float fMax = 0.0f;
|
||||
|
||||
const CTrackViewTrack* pTrack = keyHandle.GetTrack();
|
||||
pTrack->GetKeyValueRange(fMin, fMax);
|
||||
|
||||
if (fMin != fMax)
|
||||
{
|
||||
float curMin, curMax, step;
|
||||
bool curMinHardLimit, curMaxHardLimit;
|
||||
|
||||
// need to call GetLimits to retrieve/maintain *HardLimit boolean values
|
||||
mv_value.GetVar()->GetLimits(curMin, curMax, step, curMinHardLimit, curMaxHardLimit);
|
||||
|
||||
step = ReflectedPropertyItem::ComputeSliderStep(fMin, fMax);
|
||||
|
||||
mv_value.GetVar()->SetLimits(fMin, fMax, step, curMinHardLimit, curMaxHardLimit);
|
||||
}
|
||||
else
|
||||
{
|
||||
mv_value.GetVar()->ClearLimits();
|
||||
}
|
||||
|
||||
EAnimCurveType trType = keyHandle.GetTrack()->GetCurveType();
|
||||
if (trType == eAnimCurveType_BezierFloat)
|
||||
{
|
||||
I2DBezierKey bezierKey;
|
||||
keyHandle.GetKey(&bezierKey);
|
||||
|
||||
m_skipOnUIChange = true;
|
||||
SyncValue(mv_value, bezierKey.value.y, true);
|
||||
m_skipOnUIChange = false;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void C2DBezierKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!sequence || !selectedKeys.AreAllKeysOfSameType() || m_skipOnUIChange)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0; keyIndex < selectedKeys.GetKeyCount(); ++keyIndex)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
EAnimCurveType trType = keyHandle.GetTrack()->GetCurveType();
|
||||
|
||||
if (trType == eAnimCurveType_BezierFloat)
|
||||
{
|
||||
I2DBezierKey bezierKey;
|
||||
keyHandle.GetKey(&bezierKey);
|
||||
|
||||
SyncValue(mv_value, bezierKey.value.y, false, pVar);
|
||||
|
||||
bool isDuringUndo = false;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::IsDuringUndoRedo);
|
||||
|
||||
if (isDuringUndo)
|
||||
{
|
||||
keyHandle.SetKey(&bezierKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Set Key Value");
|
||||
keyHandle.SetKey(&bezierKey);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(C2DBezierKeyUIControls, "TrackView.KeyUI.2DBezier", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
|
||||
// AzCore
|
||||
#include <AzCore/Asset/AssetManagerBus.h>
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimNodeType.h>
|
||||
#include <CryCommon/Maestro/Types/AnimValueType.h>
|
||||
#include <CryCommon/Maestro/Bus/SequenceComponentBus.h>
|
||||
#include <CryCommon/Maestro/Types/AssetBlendKey.h>
|
||||
|
||||
// Editor
|
||||
#include "TrackViewKeyPropertiesDlg.h"
|
||||
#include "Controls/ReflectedPropertyControl/ReflectedPropertyItem.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CAssetBlendKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
|
||||
AZ::EntityId m_entityId;
|
||||
AZ::ComponentId m_componentId;
|
||||
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariable<QString> mv_asset;
|
||||
CSmartVariable<bool> mv_loop;
|
||||
CSmartVariable<float> mv_startTime;
|
||||
CSmartVariable<float> mv_endTime;
|
||||
CSmartVariable<float> mv_timeScale;
|
||||
CSmartVariable<float> mv_blendInTime;
|
||||
CSmartVariable<float> mv_blendOutTime;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
// Init to an invalid id
|
||||
AZ::Data::AssetId assetId;
|
||||
assetId.SetInvalid();
|
||||
mv_asset->SetUserData(assetId.m_subId);
|
||||
mv_asset->SetDisplayValue(assetId.m_guid.ToString<AZStd::string>().c_str());
|
||||
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
// In the future, we may have different types of AssetBlends supported. Right now
|
||||
// "motion" for the Simple Motion Component is the only instance.
|
||||
AddVariable(mv_table, mv_asset, "Motion", IVariable::DT_MOTION);
|
||||
AddVariable(mv_table, mv_loop, "Loop");
|
||||
AddVariable(mv_table, mv_startTime, "Start Time");
|
||||
AddVariable(mv_table, mv_endTime, "End Time");
|
||||
AddVariable(mv_table, mv_timeScale, "Time Scale");
|
||||
AddVariable(mv_table, mv_blendInTime, "Blend In Time");
|
||||
AddVariable(mv_table, mv_blendOutTime, "Blend Out Time");
|
||||
mv_timeScale->SetLimits(0.001f, 100.f);
|
||||
}
|
||||
|
||||
bool SupportTrackType([[maybe_unused]] const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, AnimValueType valueType) const
|
||||
{
|
||||
return valueType == AnimValueType::AssetBlend;
|
||||
}
|
||||
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {5DC82D28-6C50-4406-8993-06770C640F98}
|
||||
static const GUID guid =
|
||||
{
|
||||
0x5DC82D28, 0x6C50, 0x4406, { 0x89, 0x93, 0x06, 0x77, 0x0C, 0x64, 0x0F, 0x98 }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
|
||||
protected:
|
||||
void ResetStartEndLimits(float AssetBlendKeyDuration);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CAssetBlendKeyUIControls::ResetStartEndLimits(float assetBlendKeyDuration)
|
||||
{
|
||||
const float time_zero = .0f;
|
||||
float step = ReflectedPropertyItem::ComputeSliderStep(time_zero, assetBlendKeyDuration);
|
||||
mv_startTime.GetVar()->SetLimits(time_zero, assetBlendKeyDuration, step, true, true);
|
||||
mv_endTime.GetVar()->SetLimits(time_zero, assetBlendKeyDuration, step, true, true);
|
||||
mv_blendInTime.GetVar()->SetLimits(time_zero, assetBlendKeyDuration, step, true, true);
|
||||
mv_blendOutTime.GetVar()->SetLimits(time_zero, assetBlendKeyDuration, step, true, true);
|
||||
}
|
||||
|
||||
bool CAssetBlendKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
if (keyHandle.GetTrack()->GetValueType() == AnimValueType::AssetBlend)
|
||||
{
|
||||
AZ::IAssetBlendKey assetBlendKey;
|
||||
keyHandle.GetKey(&assetBlendKey);
|
||||
|
||||
// Find editor object who owns this node.
|
||||
const CTrackViewTrack* pTrack = keyHandle.GetTrack();
|
||||
if (pTrack && pTrack->GetAnimNode()->GetType() == AnimNodeType::Component)
|
||||
{
|
||||
m_componentId = pTrack->GetAnimNode()->GetComponentId();
|
||||
|
||||
// try to get the AZ::EntityId from the component node's parent
|
||||
CTrackViewAnimNode* parentNode = static_cast<CTrackViewAnimNode*>(pTrack->GetAnimNode()->GetParentNode());
|
||||
if (parentNode)
|
||||
{
|
||||
m_entityId = parentNode->GetAzEntityId();
|
||||
}
|
||||
}
|
||||
|
||||
mv_asset->SetUserData(assetBlendKey.m_assetId.m_subId);
|
||||
mv_asset->SetDisplayValue(assetBlendKey.m_assetId.m_guid.ToString<AZStd::string>().c_str());
|
||||
mv_loop = assetBlendKey.m_bLoop;
|
||||
mv_endTime = assetBlendKey.m_endTime;
|
||||
mv_startTime = assetBlendKey.m_startTime;
|
||||
mv_timeScale = assetBlendKey.m_speed;
|
||||
mv_blendInTime = assetBlendKey.m_blendInTime;
|
||||
mv_blendOutTime = assetBlendKey.m_blendOutTime;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void CAssetBlendKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!pSequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0, num = (int)selectedKeys.GetKeyCount(); keyIndex < num; keyIndex++)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
CTrackViewTrack* pTrack = keyHandle.GetTrack();
|
||||
|
||||
if (keyHandle.GetTrack()->GetValueType() == AnimValueType::AssetBlend)
|
||||
{
|
||||
AZ::IAssetBlendKey assetBlendKey;
|
||||
keyHandle.GetKey(&assetBlendKey);
|
||||
|
||||
if (mv_asset.GetVar() == pVar)
|
||||
{
|
||||
AZStd::string stringGuid = mv_asset->GetDisplayValue().toLatin1().data();
|
||||
if (!stringGuid.empty())
|
||||
{
|
||||
AZ::Uuid guid(stringGuid.c_str(), stringGuid.length());
|
||||
AZ::u32 subId = mv_asset->GetUserData().value<AZ::u32>();
|
||||
assetBlendKey.m_assetId = AZ::Data::AssetId(guid, subId);
|
||||
|
||||
// Lookup Filename by assetId and get the filename part of the description
|
||||
AZStd::string assetPath;
|
||||
EBUS_EVENT_RESULT(assetPath, AZ::Data::AssetCatalogRequestBus, GetAssetPathById, assetBlendKey.m_assetId);
|
||||
|
||||
assetBlendKey.m_description = "";
|
||||
if (!assetPath.empty())
|
||||
{
|
||||
AZStd::string filename;
|
||||
if (AzFramework::StringFunc::Path::GetFileName(assetPath.c_str(), filename))
|
||||
{
|
||||
assetBlendKey.m_description = filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This call is required to make sure that the newly set animation is properly triggered.
|
||||
pTrack->GetSequence()->Reset(false);
|
||||
}
|
||||
|
||||
SyncValue(mv_loop, assetBlendKey.m_bLoop, false, pVar);
|
||||
SyncValue(mv_startTime, assetBlendKey.m_startTime, false, pVar);
|
||||
SyncValue(mv_endTime, assetBlendKey.m_endTime, false, pVar);
|
||||
SyncValue(mv_timeScale, assetBlendKey.m_speed, false, pVar);
|
||||
SyncValue(mv_blendInTime, assetBlendKey.m_blendInTime, false, pVar);
|
||||
SyncValue(mv_blendOutTime, assetBlendKey.m_blendOutTime, false, pVar);
|
||||
|
||||
if (assetBlendKey.m_assetId.IsValid())
|
||||
{
|
||||
// Ask entity id this asset blend is bound to, to
|
||||
// get the duration of this asset in an async way.
|
||||
Maestro::SequenceComponentRequests::AnimatedFloatValue currValue = 0.0f;
|
||||
Maestro::SequenceComponentRequestBus::Event(
|
||||
pSequence->GetSequenceComponentEntityId(),
|
||||
&Maestro::SequenceComponentRequestBus::Events::GetAssetDuration,
|
||||
currValue,
|
||||
m_entityId,
|
||||
m_componentId,
|
||||
assetBlendKey.m_assetId
|
||||
);
|
||||
|
||||
assetBlendKey.m_duration = currValue.GetFloatValue();
|
||||
ResetStartEndLimits(assetBlendKey.m_duration);
|
||||
}
|
||||
|
||||
keyHandle.SetKey(&assetBlendKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CAssetBlendKeyUIControls, "TrackView.KeyUI.AssetBlends", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include "AtomOutputFrameCapture.h"
|
||||
|
||||
#include <Atom/RPI.Public/Pass/Specific/RenderToTexturePass.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
#include <Atom/RPI.Reflect/System/RenderPipelineDescriptor.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Math/MatrixUtils.h>
|
||||
#include <AzCore/Name/Name.h>
|
||||
#include <AzFramework/Entity/GameEntityContextBus.h>
|
||||
#include <AzFramework/Scene/Scene.h>
|
||||
#include <AzFramework/Scene/SceneSystemInterface.h>
|
||||
|
||||
namespace TrackView
|
||||
{
|
||||
void AtomOutputFrameCapture::CreatePipeline(
|
||||
AZ::RPI::Scene& scene, const AZStd::string& pipelineName, const uint32_t width, const uint32_t height)
|
||||
{
|
||||
AZ::RPI::RenderPipelineDescriptor pipelineDesc;
|
||||
pipelineDesc.m_mainViewTagName = "MainCamera"; // must be "MainCamera"
|
||||
pipelineDesc.m_name = pipelineName;
|
||||
pipelineDesc.m_rootPassTemplate = "MainPipelineRenderToTexture";
|
||||
pipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4;
|
||||
m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc);
|
||||
|
||||
if (auto renderToTexturePass = azrtti_cast<AZ::RPI::RenderToTexturePass*>(m_renderPipeline->GetRootPass().get()))
|
||||
{
|
||||
renderToTexturePass->ResizeOutput(width, height);
|
||||
}
|
||||
|
||||
scene.AddRenderPipeline(m_renderPipeline);
|
||||
|
||||
// rendering pipeline has a tree structure
|
||||
m_passHierarchy.push_back(pipelineName);
|
||||
m_passHierarchy.push_back("CopyToSwapChain");
|
||||
|
||||
// retrieve View from the camera that's animating
|
||||
AZ::Name viewName = AZ::Name("MainCamera");
|
||||
m_view = AZ::RPI::View::CreateView(viewName, AZ::RPI::View::UsageCamera);
|
||||
m_renderPipeline->SetDefaultView(m_view);
|
||||
}
|
||||
|
||||
void AtomOutputFrameCapture::DestroyPipeline(AZ::RPI::Scene& scene)
|
||||
{
|
||||
scene.RemoveRenderPipeline(m_renderPipeline->GetId());
|
||||
m_passHierarchy.clear();
|
||||
m_renderPipeline.reset();
|
||||
m_view.reset();
|
||||
}
|
||||
|
||||
void AtomOutputFrameCapture::UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection)
|
||||
{
|
||||
m_view->SetCameraTransform(cameraTransform);
|
||||
m_view->SetViewToClipMatrix(cameraProjection);
|
||||
}
|
||||
|
||||
bool AtomOutputFrameCapture::BeginCapture(
|
||||
const AZ::RPI::AttachmentReadback::CallbackFunction& attachmentReadbackCallback, CaptureFinishedCallback captureFinishedCallback)
|
||||
{
|
||||
AZ::Render::FrameCaptureNotificationBus::Handler::BusConnect();
|
||||
|
||||
m_captureFinishedCallback = AZStd::move(captureFinishedCallback);
|
||||
|
||||
// note: "Output" (slot name) maps to MainPipeline.pass CopyToSwapChain
|
||||
bool startedCapture = false;
|
||||
AZ::Render::FrameCaptureRequestBus::BroadcastResult(
|
||||
startedCapture, &AZ::Render::FrameCaptureRequestBus::Events::CapturePassAttachmentWithCallback, m_passHierarchy,
|
||||
AZStd::string("Output"), attachmentReadbackCallback);
|
||||
|
||||
return startedCapture;
|
||||
}
|
||||
|
||||
void AtomOutputFrameCapture::OnCaptureFinished(
|
||||
[[maybe_unused]] AZ::Render::FrameCaptureResult result, [[maybe_unused]] const AZStd::string& info)
|
||||
{
|
||||
m_captureFinishedCallback();
|
||||
AZ::Render::FrameCaptureNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
AZ::Matrix3x4 TransformFromEntityId(const AZ::EntityId entityId)
|
||||
{
|
||||
AZ::Transform cameraTransform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(cameraTransform, entityId, &AZ::TransformBus::Events::GetWorldTM);
|
||||
return AZ::Matrix3x4::CreateFromTransform(cameraTransform);
|
||||
}
|
||||
|
||||
AZ::Matrix4x4 ProjectionFromCameraEntityId(const AZ::EntityId entityId, const float outputWidth, const float outputHeight)
|
||||
{
|
||||
float nearDist = 0.0f;
|
||||
Camera::CameraRequestBus::EventResult(nearDist, entityId, &Camera::CameraRequestBus::Events::GetNearClipDistance);
|
||||
float farDist = 0.0f;
|
||||
Camera::CameraRequestBus::EventResult(farDist, entityId, &Camera::CameraRequestBus::Events::GetFarClipDistance);
|
||||
float fovRad = 0.0f;
|
||||
Camera::CameraRequestBus::EventResult(fovRad, entityId, &Camera::CameraRequestBus::Events::GetFovRadians);
|
||||
|
||||
const float aspectRatio = outputWidth / outputHeight;
|
||||
|
||||
AZ::Matrix4x4 viewToClipMatrix;
|
||||
AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, fovRad, aspectRatio, nearDist, farDist, /*reverseDepth=*/true);
|
||||
return viewToClipMatrix;
|
||||
}
|
||||
|
||||
AZ::RPI::Scene* SceneFromGameEntityContext()
|
||||
{
|
||||
AzFramework::EntityContextId entityContextId;
|
||||
AzFramework::GameEntityContextRequestBus::BroadcastResult(
|
||||
entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId);
|
||||
|
||||
return AZ::RPI::Scene::GetSceneForEntityContextId(entityContextId);
|
||||
}
|
||||
} // namespace TrackView
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Atom/Feature/Utils/FrameCaptureBus.h>
|
||||
#include <AzFramework/Components/CameraBus.h>
|
||||
|
||||
namespace TrackView
|
||||
{
|
||||
//! Provides functionality to capture frames from the "MainCamera".
|
||||
//! A new pipeline is created (and associated with the scene provided), a callback can be
|
||||
//! provided to handle the attachment readback (what to do with the captured frame) and also
|
||||
//! what to do after an individual capture fully completes (called in OnCaptureFinished).
|
||||
class AtomOutputFrameCapture : private AZ::Render::FrameCaptureNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
AtomOutputFrameCapture() = default;
|
||||
|
||||
using CaptureFinishedCallback = AZStd::function<void()>;
|
||||
|
||||
//! Create a new pipeline associated with a given scene.
|
||||
//! @note "MainCamera" is the view that is captured.
|
||||
void CreatePipeline(AZ::RPI::Scene& scene, const AZStd::string& pipelineName, uint32_t width, uint32_t height);
|
||||
//! Removes the pipeline from the scene provided and then destroys it.
|
||||
//! @note scene must be the same scene used to create the pipeline.
|
||||
void DestroyPipeline(AZ::RPI::Scene& scene);
|
||||
|
||||
//! Request a capture to start.
|
||||
//! @param attachmentReadbackCallback Handles the returned attachment (image data returned by the renderer).
|
||||
//! @param captureFinishedCallback Logic to run once the capture has completed fully.
|
||||
bool BeginCapture(
|
||||
const AZ::RPI::AttachmentReadback::CallbackFunction& attachmentReadbackCallback,
|
||||
CaptureFinishedCallback captureFinishedCallback);
|
||||
|
||||
//! Update the internal view that is associated with the created pipeline.
|
||||
void UpdateView(const AZ::Matrix3x4& cameraTransform, const AZ::Matrix4x4& cameraProjection);
|
||||
|
||||
private:
|
||||
AZ::RPI::RenderPipelinePtr m_renderPipeline; //!< The internal render pipeline.
|
||||
AZ::RPI::ViewPtr m_view; //!< The view associated with the render pipeline.
|
||||
AZStd::vector<AZStd::string> m_passHierarchy; //!< Pass hierarchy (includes pipelineName and CopyToSwapChain).
|
||||
CaptureFinishedCallback m_captureFinishedCallback; //!< Stored callback called from OnCaptureFinished.
|
||||
|
||||
// FrameCaptureNotificationBus overrides ...
|
||||
void OnCaptureFinished(AZ::Render::FrameCaptureResult result, const AZStd::string& info) override;
|
||||
};
|
||||
|
||||
inline AZ::EntityId ActiveCameraEntityId()
|
||||
{
|
||||
AZ::EntityId activeCameraId;
|
||||
Camera::CameraSystemRequestBus::BroadcastResult(activeCameraId, &Camera::CameraSystemRequests::GetActiveCamera);
|
||||
return activeCameraId;
|
||||
}
|
||||
|
||||
//! Returns the transform for the given EntityId.
|
||||
AZ::Matrix3x4 TransformFromEntityId(AZ::EntityId entityId);
|
||||
|
||||
//! Returns the projection matrix for the given camera EntityId.
|
||||
//! @note Must provide a valid camera entity.
|
||||
AZ::Matrix4x4 ProjectionFromCameraEntityId(AZ::EntityId entityId, float outputWidth, float outputHeight);
|
||||
|
||||
//! Helper to return the GameEntityContext scene.
|
||||
AZ::RPI::Scene* SceneFromGameEntityContext();
|
||||
} // namespace TrackView
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
// Editor
|
||||
#include "TrackViewKeyPropertiesDlg.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CCaptureKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariable<float> mv_duration;
|
||||
CSmartVariable<float> mv_timeStep;
|
||||
CSmartVariable<QString> mv_prefix;
|
||||
CSmartVariable<QString> mv_folder;
|
||||
CSmartVariable<bool> mv_once;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
mv_duration.GetVar()->SetLimits(0, 100000.0f);
|
||||
mv_timeStep.GetVar()->SetLimits(0.001f, 1.0f);
|
||||
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_duration, "Duration");
|
||||
AddVariable(mv_table, mv_timeStep, "Time Step");
|
||||
AddVariable(mv_table, mv_prefix, "Output Prefix");
|
||||
AddVariable(mv_table, mv_folder, "Output Folder");
|
||||
AddVariable(mv_table, mv_once, "Just one frame?");
|
||||
}
|
||||
bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
return paramType == AnimParamType::Capture;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {543197BF-5E43-4abc-8F07-B84078846E4C}
|
||||
static const GUID guid =
|
||||
{
|
||||
0x543197bf, 0x5e43, 0x4abc, { 0x8f, 0x7, 0xb8, 0x40, 0x78, 0x84, 0x6e, 0x4c }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CCaptureKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Capture)
|
||||
{
|
||||
ICaptureKey captureKey;
|
||||
keyHandle.GetKey(&captureKey);
|
||||
|
||||
mv_duration = captureKey.duration;
|
||||
mv_timeStep = captureKey.timeStep;
|
||||
mv_prefix = captureKey.prefix.c_str();
|
||||
mv_folder = captureKey.folder.c_str();
|
||||
mv_once = captureKey.once;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void CCaptureKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!sequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0; keyIndex < selectedKeys.GetKeyCount(); ++keyIndex)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Capture)
|
||||
{
|
||||
ICaptureKey captureKey;
|
||||
keyHandle.GetKey(&captureKey);
|
||||
|
||||
SyncValue(mv_duration, captureKey.duration, false, pVar);
|
||||
SyncValue(mv_timeStep, captureKey.timeStep, false, pVar);
|
||||
|
||||
if (pVar == mv_folder.GetVar())
|
||||
{
|
||||
QString sFolder = mv_folder;
|
||||
captureKey.folder = sFolder.toUtf8().data();
|
||||
}
|
||||
if (pVar == mv_prefix.GetVar())
|
||||
{
|
||||
QString sPrefix = mv_prefix;
|
||||
captureKey.prefix = sPrefix.toUtf8().data();
|
||||
}
|
||||
|
||||
SyncValue(mv_once, captureKey.once, false, pVar);
|
||||
|
||||
bool isDuringUndo = false;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(
|
||||
isDuringUndo, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::IsDuringUndoRedo);
|
||||
|
||||
if (isDuringUndo)
|
||||
{
|
||||
keyHandle.SetKey(&captureKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Set Key Value");
|
||||
keyHandle.SetKey(&captureKey);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CCaptureKeyUIControls, "TrackView.KeyUI.Capture", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimNodeType.h> // for AnimNodeType
|
||||
#include <CryCommon/Maestro/Types/AnimValueType.h> // for AnimValueType
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h> // for AnimParamType
|
||||
|
||||
// Editor
|
||||
#include "Controls/ReflectedPropertyControl/ReflectedPropertyItem.h" // for ReflectedPropertyItem
|
||||
#include "TrackViewKeyPropertiesDlg.h" // for CTrackViewKeyUIControls
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CCharacterKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariable<QString> mv_animation;
|
||||
CSmartVariable<bool> mv_loop;
|
||||
CSmartVariable<bool> mv_blendGap;
|
||||
CSmartVariable<bool> mv_inplace;
|
||||
CSmartVariable<float> mv_startTime;
|
||||
CSmartVariable<float> mv_endTime;
|
||||
CSmartVariable<float> mv_timeScale;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_animation, "Animation", IVariable::DT_ANIMATION);
|
||||
AddVariable(mv_table, mv_loop, "Loop");
|
||||
AddVariable(mv_table, mv_blendGap, "Blend Gap");
|
||||
AddVariable(mv_table, mv_inplace, "In Place");
|
||||
AddVariable(mv_table, mv_startTime, "Start Time");
|
||||
AddVariable(mv_table, mv_endTime, "End Time");
|
||||
AddVariable(mv_table, mv_timeScale, "Time Scale");
|
||||
mv_timeScale->SetLimits(0.001f, 100.f);
|
||||
}
|
||||
bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, AnimValueType valueType) const
|
||||
{
|
||||
return paramType == AnimParamType::Animation || valueType == AnimValueType::CharacterAnim;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {EAA26453-6B74-4771-8FD1-14CDFF88E723}
|
||||
static const GUID guid =
|
||||
{
|
||||
0xeaa26453, 0x6b74, 0x4771, { 0x8f, 0xd1, 0x14, 0xcd, 0xff, 0x88, 0xe7, 0x23 }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
|
||||
protected:
|
||||
void ResetStartEndLimits(float characterKeyDuration);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCharacterKeyUIControls::ResetStartEndLimits(float characterKeyDuration)
|
||||
{
|
||||
const float time_zero = .0f;
|
||||
float step = ReflectedPropertyItem::ComputeSliderStep(time_zero, characterKeyDuration);
|
||||
|
||||
mv_startTime.GetVar()->SetLimits(time_zero, characterKeyDuration, step, true, true);
|
||||
mv_endTime.GetVar()->SetLimits(time_zero, characterKeyDuration, step, true, true);
|
||||
}
|
||||
|
||||
bool CCharacterKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Animation || keyHandle.GetTrack()->GetValueType() == AnimValueType::CharacterAnim)
|
||||
{
|
||||
ICharacterKey charKey;
|
||||
keyHandle.GetKey(&charKey);
|
||||
|
||||
// Find editor object who owns this node.
|
||||
const CTrackViewTrack* pTrack = keyHandle.GetTrack();
|
||||
if (pTrack->GetAnimNode()->GetType() == AnimNodeType::Component)
|
||||
{
|
||||
// no legacy entity was returned and the track's animNode is a component - try to get the AZ::EntityId from the component node's parent
|
||||
CTrackViewAnimNode* parentNode = static_cast<CTrackViewAnimNode*>(pTrack->GetAnimNode()->GetParentNode());
|
||||
if (parentNode)
|
||||
{
|
||||
AZ::EntityId azEntityId = parentNode->GetAzEntityId();
|
||||
if (azEntityId.IsValid())
|
||||
{
|
||||
static_assert(sizeof(AZ::EntityId) <= sizeof(AZ::u64), "Can't pack AZ::EntityId into a AZ::u64 in CCharacterKeyUIControls::OnKeySelectionChange.");
|
||||
mv_animation->SetUserData(static_cast<AZ::u64>(azEntityId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mv_animation = charKey.m_animation.c_str();
|
||||
mv_loop = charKey.m_bLoop;
|
||||
mv_blendGap = charKey.m_bBlendGap;
|
||||
mv_inplace = charKey.m_bInPlace;
|
||||
mv_endTime = charKey.m_endTime;
|
||||
mv_startTime = charKey.m_startTime;
|
||||
mv_timeScale = charKey.m_speed;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void CCharacterKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!pSequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0, num = (int)selectedKeys.GetKeyCount(); keyIndex < num; keyIndex++)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
CTrackViewTrack* pTrack = keyHandle.GetTrack();
|
||||
const CAnimParamType paramType = pTrack->GetParameterType();
|
||||
|
||||
if (paramType == AnimParamType::Animation || keyHandle.GetTrack()->GetValueType() == AnimValueType::CharacterAnim)
|
||||
{
|
||||
ICharacterKey charKey;
|
||||
keyHandle.GetKey(&charKey);
|
||||
|
||||
if (mv_animation.GetVar() == pVar)
|
||||
{
|
||||
charKey.m_animation = ((QString)mv_animation).toUtf8().data();
|
||||
// This call is required to make sure that the newly set animation is properly triggered.
|
||||
pTrack->GetSequence()->Reset(false);
|
||||
}
|
||||
SyncValue(mv_loop, charKey.m_bLoop, false, pVar);
|
||||
SyncValue(mv_blendGap, charKey.m_bBlendGap, false, pVar);
|
||||
SyncValue(mv_inplace, charKey.m_bInPlace, false, pVar);
|
||||
SyncValue(mv_startTime, charKey.m_startTime, false, pVar);
|
||||
SyncValue(mv_endTime, charKey.m_endTime, false, pVar);
|
||||
SyncValue(mv_timeScale, charKey.m_speed, false, pVar);
|
||||
keyHandle.SetKey(&charKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CCharacterKeyUIControls, "TrackView.KeyUI.Character", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h> // for AnimParamType
|
||||
|
||||
// Editor
|
||||
#include "TrackViewKeyPropertiesDlg.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CCommentKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariable<QString> mv_comment;
|
||||
CSmartVariable<float> mv_duration;
|
||||
CSmartVariable<float> mv_size;
|
||||
CSmartVariable<Vec3> mv_color;
|
||||
CSmartVariableEnum<int> mv_align;
|
||||
CSmartVariableEnum<QString> mv_font;
|
||||
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_comment, "Comment");
|
||||
AddVariable(mv_table, mv_duration, "Duration");
|
||||
|
||||
mv_size->SetLimits(1.f, 10.f);
|
||||
AddVariable(mv_table, mv_size, "Size");
|
||||
|
||||
AddVariable(mv_table, mv_color, "Color", IVariable::DT_COLOR);
|
||||
|
||||
mv_align->SetEnumList(NULL);
|
||||
mv_align->AddEnumItem("Left", ICommentKey::eTA_Left);
|
||||
mv_align->AddEnumItem("Center", ICommentKey::eTA_Center);
|
||||
mv_align->AddEnumItem("Right", ICommentKey::eTA_Right);
|
||||
AddVariable(mv_table, mv_align, "Align");
|
||||
|
||||
mv_font->SetEnumList(NULL);
|
||||
IFileUtil::FileArray fa;
|
||||
CFileUtil::ScanDirectory((Path::GetEditingGameDataFolder() + "/Fonts/").c_str(), "*.xml", fa, true);
|
||||
for (size_t i = 0; i < fa.size(); ++i)
|
||||
{
|
||||
string name = fa[i].filename.toUtf8().data();
|
||||
PathUtil::RemoveExtension(name);
|
||||
mv_font->AddEnumItem(name.c_str(), name.c_str());
|
||||
}
|
||||
AddVariable(mv_table, mv_font, "Font");
|
||||
}
|
||||
bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
return paramType == AnimParamType::CommentText;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {FA250B8B-FC2A-43b1-AF7A-8C3B6672B49D}
|
||||
static const GUID guid =
|
||||
{
|
||||
0xfa250b8b, 0xfc2a, 0x43b1, { 0xaf, 0x7a, 0x8c, 0x3b, 0x66, 0x72, 0xb4, 0x9d }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CCommentKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::CommentText)
|
||||
{
|
||||
ICommentKey commentKey;
|
||||
keyHandle.GetKey(&commentKey);
|
||||
|
||||
mv_comment = commentKey.m_strComment.c_str();
|
||||
mv_duration = commentKey.m_duration;
|
||||
mv_size = commentKey.m_size;
|
||||
mv_font = commentKey.m_strFont.c_str();
|
||||
mv_color = Vec3(commentKey.m_color.GetR(), commentKey.m_color.GetG(), commentKey.m_color.GetB());
|
||||
mv_align = commentKey.m_align;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Called when UI variable changes.
|
||||
void CCommentKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!sequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t keyIndex = 0, num = selectedKeys.GetKeyCount(); keyIndex < num; keyIndex++)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::CommentText)
|
||||
{
|
||||
ICommentKey commentKey;
|
||||
keyHandle.GetKey(&commentKey);
|
||||
|
||||
if (!pVar || pVar == mv_comment.GetVar())
|
||||
{
|
||||
commentKey.m_strComment = ((QString)mv_comment).toUtf8().data();
|
||||
}
|
||||
|
||||
if (!pVar || pVar == mv_font.GetVar())
|
||||
{
|
||||
QString sFont = mv_font;
|
||||
commentKey.m_strFont = sFont.toUtf8().data();
|
||||
}
|
||||
|
||||
if (!pVar || pVar == mv_align.GetVar())
|
||||
{
|
||||
commentKey.m_align = (ICommentKey::ETextAlign)((int)mv_align);
|
||||
}
|
||||
|
||||
SyncValue(mv_duration, commentKey.m_duration, false, pVar);
|
||||
Vec3 color(commentKey.m_color.GetR(), commentKey.m_color.GetG(), commentKey.m_color.GetB());
|
||||
SyncValue(mv_color, color, false, pVar);
|
||||
commentKey.m_color.Set(color.x, color.y, color.z, commentKey.m_color.GetA());
|
||||
SyncValue(mv_size, commentKey.m_size, false, pVar);
|
||||
|
||||
bool isDuringUndo = false;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::IsDuringUndoRedo);
|
||||
|
||||
if (isDuringUndo)
|
||||
{
|
||||
keyHandle.SetKey(&commentKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let the AZ Undo system manage the nodes on the sequence entity
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Change key");
|
||||
keyHandle.SetKey(&commentKey);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CCommentKeyUIControls, "TrackView.KeyUI.Comment", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "CommentNodeAnimator.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
|
||||
// Editor
|
||||
#include "Settings.h"
|
||||
|
||||
|
||||
CCommentNodeAnimator::CCommentNodeAnimator(CTrackViewAnimNode* pCommentNode)
|
||||
{
|
||||
assert(pCommentNode);
|
||||
m_pCommentNode = pCommentNode;
|
||||
}
|
||||
|
||||
CCommentNodeAnimator::~CCommentNodeAnimator()
|
||||
{
|
||||
m_pCommentNode = 0;
|
||||
}
|
||||
|
||||
void CCommentNodeAnimator::Animate(CTrackViewAnimNode* pNode, const SAnimContext& ac)
|
||||
{
|
||||
if (pNode != m_pCommentNode || pNode->IsDisabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CTrackViewTrackBundle tracks = pNode->GetAllTracks();
|
||||
|
||||
int trackCount = tracks.GetCount();
|
||||
Vec2 pos(0, 0);
|
||||
for (int i = 0; i < trackCount; ++i)
|
||||
{
|
||||
CTrackViewTrack* pTrack = tracks.GetTrack(i);
|
||||
|
||||
if (pTrack->IsMasked(ac.trackMask))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (pTrack->GetParameterType().GetType())
|
||||
{
|
||||
case AnimParamType::CommentText:
|
||||
{
|
||||
AnimateCommentTextTrack(pTrack, ac);
|
||||
}
|
||||
break;
|
||||
case AnimParamType::PositionX:
|
||||
{
|
||||
pTrack->GetValue(ac.time, pos.x);
|
||||
}
|
||||
break;
|
||||
case AnimParamType::PositionY:
|
||||
{
|
||||
pTrack->GetValue(ac.time, pos.y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Position mapping from [0,100] to [-1,1]
|
||||
pos = (pos - Vec2(50.0f, 50.0f)) / 50.0f;
|
||||
m_commentContext.m_unitPos = pos;
|
||||
}
|
||||
|
||||
void CCommentNodeAnimator::AnimateCommentTextTrack(CTrackViewTrack* pTrack, const SAnimContext& ac)
|
||||
{
|
||||
if (pTrack->GetKeyCount() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CTrackViewKeyHandle keyHandle = GetActiveKeyHandle(pTrack, ac.time);
|
||||
|
||||
if (keyHandle.IsValid())
|
||||
{
|
||||
ICommentKey commentKey;
|
||||
|
||||
keyHandle.GetKey(&commentKey);
|
||||
|
||||
if (commentKey.m_duration > 0 && ac.time < keyHandle.GetTime() + commentKey.m_duration)
|
||||
{
|
||||
m_commentContext.m_strComment = commentKey.m_strComment;
|
||||
cry_strcpy(m_commentContext.m_strFont, commentKey.m_strFont.c_str());
|
||||
m_commentContext.m_color = commentKey.m_color;
|
||||
m_commentContext.m_align = commentKey.m_align;
|
||||
m_commentContext.m_size = commentKey.m_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_commentContext.m_strComment.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_commentContext.m_strComment.clear();
|
||||
}
|
||||
}
|
||||
|
||||
CTrackViewKeyHandle CCommentNodeAnimator::GetActiveKeyHandle(CTrackViewTrack* pTrack, float fTime)
|
||||
{
|
||||
const int nkeys = pTrack->GetKeyCount();
|
||||
|
||||
if (nkeys == 0)
|
||||
{
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
const CTrackViewKeyHandle& firstKeyHandle = pTrack->GetKey(0);
|
||||
|
||||
// Time is before first key.
|
||||
if (firstKeyHandle.GetTime() > fTime)
|
||||
{
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
for (int i = 0; i < nkeys; i++)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = pTrack->GetKey(i);
|
||||
|
||||
if (fTime >= keyHandle.GetTime())
|
||||
{
|
||||
if ((i == nkeys - 1) || (fTime < pTrack->GetKey(i + 1).GetTime()))
|
||||
{
|
||||
return keyHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
void CCommentNodeAnimator::Render(CTrackViewAnimNode* pNode, [[maybe_unused]] const SAnimContext& ac)
|
||||
{
|
||||
if (!pNode->IsDisabled())
|
||||
{
|
||||
CCommentContext* cc = &m_commentContext;
|
||||
|
||||
if (!cc->m_strComment.empty())
|
||||
{
|
||||
Vec3 color(cc->m_color.GetR(), cc->m_color.GetG(), cc->m_color.GetB());
|
||||
DrawText(cc->m_strFont, cc->m_size, cc->m_unitPos, color, cc->m_strComment.c_str(), cc->m_align);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vec2 CCommentNodeAnimator::GetScreenPosFromNormalizedPos(const Vec2& unitPos)
|
||||
{
|
||||
const CCamera& cam = gEnv->pSystem->GetViewCamera();
|
||||
float width = (float)cam.GetViewSurfaceX();
|
||||
int height = cam.GetViewSurfaceZ();
|
||||
float fAspectRatio = gSettings.viewports.fDefaultAspectRatio;
|
||||
float camWidth = height * fAspectRatio;
|
||||
|
||||
float x = 0.5f * width + 0.5f * camWidth * unitPos.x;
|
||||
float y = 0.5f * height * (1.f - unitPos.y);
|
||||
|
||||
return Vec2(x, y);
|
||||
}
|
||||
|
||||
void CCommentNodeAnimator::DrawText(const char* szFontName, float fSize, const Vec2& unitPos, const ColorF col, const char* szText, int align)
|
||||
{
|
||||
IFFont* pFont = gEnv->pCryFont->GetFont(szFontName);
|
||||
if (!pFont)
|
||||
{
|
||||
pFont = gEnv->pCryFont->GetFont("default");
|
||||
}
|
||||
|
||||
if (pFont)
|
||||
{
|
||||
STextDrawContext ctx;
|
||||
ctx.SetSizeIn800x600(false);
|
||||
ctx.SetSize(Vec2(UIDRAW_TEXTSIZEFACTOR * fSize, UIDRAW_TEXTSIZEFACTOR * fSize));
|
||||
ctx.SetCharWidthScale(0.5f);
|
||||
ctx.SetProportional(false);
|
||||
ctx.SetFlags(align);
|
||||
|
||||
// alignment
|
||||
Vec2 pos = GetScreenPosFromNormalizedPos(unitPos);
|
||||
|
||||
if (align & eDrawText_Center)
|
||||
{
|
||||
pos.x -= pFont->GetTextSize(szText, true, ctx).x * 0.5f;
|
||||
}
|
||||
else if (align & eDrawText_Right)
|
||||
{
|
||||
pos.x -= pFont->GetTextSize(szText, true, ctx).x;
|
||||
}
|
||||
|
||||
// Color
|
||||
ctx.SetColor(col);
|
||||
|
||||
pFont->DrawString(pos.x, pos.y, szText, true, ctx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : Comment node animator class
|
||||
|
||||
/*
|
||||
CCommentContext stores information about comment track.
|
||||
The Comment Track is activated only in the editor.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_COMMENTNODEANIMATOR_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_COMMENTNODEANIMATOR_H
|
||||
#pragma once
|
||||
|
||||
#include "TrackViewAnimNode.h"
|
||||
|
||||
class CTrackViewTrack;
|
||||
|
||||
struct CCommentContext
|
||||
{
|
||||
CCommentContext()
|
||||
: m_nLastActiveKeyIndex(-1)
|
||||
, m_size(1.0f)
|
||||
, m_align(0)
|
||||
, m_color(0.f, 0.f, 0.f, 1.f)
|
||||
{
|
||||
sprintf_s(m_strFont, sizeof(m_strFont), "default");
|
||||
m_unitPos = Vec2(0.f, 0.f);
|
||||
}
|
||||
|
||||
int m_nLastActiveKeyIndex;
|
||||
|
||||
AZStd::string m_strComment;
|
||||
char m_strFont[64];
|
||||
Vec2 m_unitPos;
|
||||
AZ::Color m_color;
|
||||
float m_size;
|
||||
int m_align;
|
||||
};
|
||||
|
||||
class CCommentNodeAnimator
|
||||
: public IAnimNodeAnimator
|
||||
{
|
||||
public:
|
||||
CCommentNodeAnimator(CTrackViewAnimNode* pCommentNode);
|
||||
virtual void Animate(CTrackViewAnimNode* pNode, const SAnimContext& ac);
|
||||
virtual void Render(CTrackViewAnimNode* pNode, const SAnimContext& ac);
|
||||
|
||||
private:
|
||||
virtual ~CCommentNodeAnimator();
|
||||
|
||||
void AnimateCommentTextTrack(CTrackViewTrack* pTrack, const SAnimContext& ac);
|
||||
CTrackViewKeyHandle GetActiveKeyHandle(CTrackViewTrack* pTrack, float fTime);
|
||||
Vec2 GetScreenPosFromNormalizedPos(const Vec2& unitPos);
|
||||
void DrawText(const char* szFontName, float fSize, const Vec2& unitPos, const ColorF col, const char* szText, int align);
|
||||
|
||||
CTrackViewAnimNode* m_pCommentNode;
|
||||
CCommentContext m_commentContext;
|
||||
};
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_COMMENTNODEANIMATOR_H
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h> // for AnimParamType
|
||||
|
||||
// Editor
|
||||
#include "TrackViewKeyPropertiesDlg.h" // for CTrackViewKeyUIControls
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CConsoleKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariable<QString> mv_command;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_command, "Command");
|
||||
}
|
||||
bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
return paramType == AnimParamType::Console;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {3E9D2C57-BFB1-42f9-82AC-A393C1062634}
|
||||
static const GUID guid =
|
||||
{
|
||||
0x3e9d2c57, 0xbfb1, 0x42f9, { 0x82, 0xac, 0xa3, 0x93, 0xc1, 0x6, 0x26, 0x34 }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CConsoleKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Console)
|
||||
{
|
||||
IConsoleKey consoleKey;
|
||||
keyHandle.GetKey(&consoleKey);
|
||||
|
||||
mv_command = ((QString)consoleKey.command.c_str()).toUtf8().data();
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void CConsoleKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!sequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0; keyIndex < selectedKeys.GetKeyCount(); ++keyIndex)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Console)
|
||||
{
|
||||
IConsoleKey consoleKey;
|
||||
keyHandle.GetKey(&consoleKey);
|
||||
|
||||
if (pVar == mv_command.GetVar())
|
||||
{
|
||||
consoleKey.command = ((QString)mv_command).toUtf8().data();
|
||||
}
|
||||
|
||||
bool isDuringUndo = false;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::IsDuringUndoRedo);
|
||||
|
||||
if (isDuringUndo)
|
||||
{
|
||||
keyHandle.SetKey(&consoleKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Set Key Value");
|
||||
keyHandle.SetKey(&consoleKey);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CConsoleKeyUIControls, "TrackView.KeyUI.Console", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "DirectorNodeAnimator.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h> // for AnimParamType
|
||||
|
||||
// Editor
|
||||
#include "TrackView/TrackViewSequenceManager.h" // for CTrackViewSequence
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CDirectorNodeAnimator::CDirectorNodeAnimator(CTrackViewAnimNode* pDirectorNode)
|
||||
: m_pDirectorNode(pDirectorNode)
|
||||
{
|
||||
assert(m_pDirectorNode != nullptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CDirectorNodeAnimator::Animate(CTrackViewAnimNode* pNode, const SAnimContext& ac)
|
||||
{
|
||||
if (!pNode->IsActiveDirector())
|
||||
{
|
||||
// Don't animate if it's not the sequence track of the active director
|
||||
return;
|
||||
}
|
||||
|
||||
CTrackViewTrack* pSequenceTrack = pNode->GetTrackForParameter(AnimParamType::Sequence);
|
||||
if (pSequenceTrack && !pSequenceTrack->IsDisabled())
|
||||
{
|
||||
std::vector<CTrackViewSequence*> inactiveSequences;
|
||||
std::vector<CTrackViewSequence*> activeSequences;
|
||||
|
||||
// Construct sets of sequences that need to be bound/unbound at this point
|
||||
const float time = ac.time;
|
||||
const unsigned int numKeys = pSequenceTrack->GetKeyCount();
|
||||
for (unsigned int i = 0; i < numKeys; ++i)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = pSequenceTrack->GetKey(i);
|
||||
|
||||
ISequenceKey sequenceKey;
|
||||
keyHandle.GetKey(&sequenceKey);
|
||||
|
||||
CTrackViewSequence* pSequence = GetSequenceFromSequenceKey(sequenceKey);
|
||||
|
||||
if (pSequence)
|
||||
{
|
||||
if (sequenceKey.time <= time)
|
||||
{
|
||||
stl::push_back_unique(activeSequences, pSequence);
|
||||
stl::find_and_erase(inactiveSequences, pSequence);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!stl::find(activeSequences, pSequence))
|
||||
{
|
||||
stl::push_back_unique(inactiveSequences, pSequence);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unbind must occur before binding, because entities can be referenced in multiple sequences
|
||||
for (auto iter = inactiveSequences.begin(); iter != inactiveSequences.end(); ++iter)
|
||||
{
|
||||
CTrackViewSequence* pSequence = *iter;
|
||||
if (pSequence->IsBoundToEditorObjects())
|
||||
{
|
||||
// No notifications because unbinding would call ForceAnimation again
|
||||
CTrackViewSequenceNoNotificationContext context(pSequence);
|
||||
pSequence->UnBindFromEditorObjects();
|
||||
}
|
||||
}
|
||||
|
||||
// Now bind sequences
|
||||
for (auto iter = activeSequences.begin(); iter != activeSequences.end(); ++iter)
|
||||
{
|
||||
CTrackViewSequence* pSequence = *iter;
|
||||
if (!pSequence->IsBoundToEditorObjects())
|
||||
{
|
||||
// No notifications because binding would call ForceAnimation again
|
||||
CTrackViewSequenceNoNotificationContext context(pSequence);
|
||||
pSequence->BindToEditorObjects();
|
||||
|
||||
// Make sure the sequence is active, harmless to call if the sequences is already
|
||||
// active. The sequence may not be active in the Editor if this key was just created.
|
||||
pSequence->Activate();
|
||||
}
|
||||
}
|
||||
|
||||
// Animate sub sequences
|
||||
ForEachActiveSequence(ac, pSequenceTrack, true,
|
||||
[&](CTrackViewSequence* pSequence, const SAnimContext& newAnimContext)
|
||||
{
|
||||
pSequence->Animate(newAnimContext);
|
||||
},
|
||||
[&](CTrackViewSequence* pSequence, [[maybe_unused]] const SAnimContext& newAnimContext)
|
||||
{
|
||||
pSequence->Reset(false);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CDirectorNodeAnimator::Render(CTrackViewAnimNode* pNode, const SAnimContext& ac)
|
||||
{
|
||||
if (!pNode->IsActiveDirector())
|
||||
{
|
||||
// Don't animate if it's not the sequence track of the active director
|
||||
return;
|
||||
}
|
||||
|
||||
CTrackViewTrack* pSequenceTrack = pNode->GetTrackForParameter(AnimParamType::Sequence);
|
||||
if (pSequenceTrack && !pSequenceTrack->IsDisabled())
|
||||
{
|
||||
// Render sub sequences
|
||||
ForEachActiveSequence(ac, pSequenceTrack, false,
|
||||
[&](CTrackViewSequence* pSequence, [[maybe_unused]] const SAnimContext& newAnimContext)
|
||||
{
|
||||
pSequence->Render(newAnimContext);
|
||||
},
|
||||
[&]([[maybe_unused]] CTrackViewSequence* pSequence, [[maybe_unused]] const SAnimContext& newAnimContext) {}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CDirectorNodeAnimator::ForEachActiveSequence(const SAnimContext& ac, CTrackViewTrack* pSequenceTrack,
|
||||
const bool bHandleOtherKeys, std::function<void(CTrackViewSequence*, const SAnimContext&)> animateFunction,
|
||||
std::function<void(CTrackViewSequence*, const SAnimContext&)> resetFunction)
|
||||
{
|
||||
const float time = ac.time;
|
||||
const unsigned int numKeys = pSequenceTrack->GetKeyCount();
|
||||
|
||||
if (bHandleOtherKeys)
|
||||
{
|
||||
// Reset all non-active sequences first
|
||||
for (unsigned int i = 0; i < numKeys; ++i)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = pSequenceTrack->GetKey(i);
|
||||
|
||||
ISequenceKey sequenceKey;
|
||||
keyHandle.GetKey(&sequenceKey);
|
||||
|
||||
CTrackViewSequence* pSequence = GetSequenceFromSequenceKey(sequenceKey);
|
||||
|
||||
if (pSequence)
|
||||
{
|
||||
SAnimContext newAnimContext = ac;
|
||||
const float duration = sequenceKey.fDuration;
|
||||
const float sequenceTime = ac.time - sequenceKey.time + sequenceKey.fStartTime;
|
||||
const float sequenceDuration = duration + sequenceKey.fStartTime;
|
||||
|
||||
newAnimContext.time = std::min(sequenceTime, sequenceDuration);
|
||||
const bool bInsideKeyRange = (sequenceTime >= 0.0f) && (sequenceTime <= sequenceDuration);
|
||||
|
||||
if (!bInsideKeyRange)
|
||||
{
|
||||
if (ac.forcePlay && sequenceTime >= 0.0f && newAnimContext.time != pSequence->GetTime())
|
||||
{
|
||||
// If forcing animation force previous keys to their last playback position
|
||||
animateFunction(pSequence, newAnimContext);
|
||||
}
|
||||
|
||||
resetFunction(pSequence, newAnimContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < numKeys; ++i)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = pSequenceTrack->GetKey(i);
|
||||
|
||||
ISequenceKey sequenceKey;
|
||||
keyHandle.GetKey(&sequenceKey);
|
||||
|
||||
CTrackViewSequence* pSequence = GetSequenceFromSequenceKey(sequenceKey);
|
||||
|
||||
if (pSequence)
|
||||
{
|
||||
SAnimContext newAnimContext = ac;
|
||||
const float duration = sequenceKey.fDuration;
|
||||
const float sequenceTime = ac.time - sequenceKey.time + sequenceKey.fStartTime;
|
||||
const float sequenceDuration = duration + sequenceKey.fStartTime;
|
||||
|
||||
newAnimContext.time = std::min(sequenceTime, sequenceDuration);
|
||||
const bool bInsideKeyRange = (sequenceTime >= 0.0f) && (sequenceTime <= sequenceDuration);
|
||||
|
||||
if ((bInsideKeyRange && (newAnimContext.time != pSequence->GetTime() || ac.forcePlay)))
|
||||
{
|
||||
animateFunction(pSequence, newAnimContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CDirectorNodeAnimator::UnBind([[maybe_unused]] CTrackViewAnimNode* pNode)
|
||||
{
|
||||
const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
|
||||
|
||||
const unsigned int numSequences = pSequenceManager->GetCount();
|
||||
for (unsigned int sequenceIndex = 0; sequenceIndex < numSequences; ++sequenceIndex)
|
||||
{
|
||||
CTrackViewSequence* pSequence = pSequenceManager->GetSequenceByIndex(sequenceIndex);
|
||||
|
||||
if (pSequence->IsActiveSequence())
|
||||
{
|
||||
// Don't care about the active sequence
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pSequence->IsBoundToEditorObjects())
|
||||
{
|
||||
pSequence->UnBindFromEditorObjects();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ CTrackViewSequence* CDirectorNodeAnimator::GetSequenceFromSequenceKey(const ISequenceKey& sequenceKey)
|
||||
{
|
||||
CTrackViewSequence* retSequence = nullptr;
|
||||
const CTrackViewSequenceManager* sequenceManager = GetIEditor()->GetSequenceManager();
|
||||
|
||||
if (sequenceManager)
|
||||
{
|
||||
if (sequenceKey.sequenceEntityId.IsValid())
|
||||
{
|
||||
retSequence = sequenceManager->GetSequenceByEntityId(sequenceKey.sequenceEntityId);
|
||||
AZ_Assert(retSequence, "Null sequence returned when a Sequence Component was expected.");
|
||||
}
|
||||
}
|
||||
|
||||
return retSequence;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_DIRECTORNODEANIMATOR_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_DIRECTORNODEANIMATOR_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "TrackViewAnimNode.h"
|
||||
|
||||
// This is used to bind/unbind sub sequences in director nodes
|
||||
// when the sequence time changes. A sequence only gets bound if it was already
|
||||
// referred in time before.
|
||||
class CDirectorNodeAnimator
|
||||
: public IAnimNodeAnimator
|
||||
{
|
||||
public:
|
||||
CDirectorNodeAnimator(CTrackViewAnimNode* pDirectorNode);
|
||||
|
||||
virtual void Animate(CTrackViewAnimNode* pNode, const SAnimContext& ac) override;
|
||||
virtual void Render(CTrackViewAnimNode* pNode, const SAnimContext& ac) override;
|
||||
virtual void UnBind(CTrackViewAnimNode* pNode) override;
|
||||
|
||||
// Utility function to find a CTrackViewSequence* from an ISequenceKey
|
||||
static CTrackViewSequence* GetSequenceFromSequenceKey(const ISequenceKey& sequenceKey);
|
||||
|
||||
private:
|
||||
void ForEachActiveSequence(const SAnimContext& ac, CTrackViewTrack* pSequenceTrack,
|
||||
const bool bHandleOtherKeys, std::function<void(CTrackViewSequence*, const SAnimContext&)> animateFunction,
|
||||
std::function<void(CTrackViewSequence*, const SAnimContext&)> resetFunction);
|
||||
|
||||
CTrackViewAnimNode* m_pDirectorNode;
|
||||
};
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_DIRECTORNODEANIMATOR_H
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/any.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
/**
|
||||
* This bus can be used to send commands to the track view.
|
||||
*/
|
||||
class EditorLayerTrackViewRequests
|
||||
: public AZ::ComponentBus
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Gets the number of sequences.
|
||||
*/
|
||||
virtual int GetNumSequences() = 0;
|
||||
|
||||
/**
|
||||
* Creates a new sequence of the given type(0 = Object Entity Sequence(Legacy), 1 = Component Entity Sequence(PREVIEW)) with the given name.
|
||||
*/
|
||||
virtual void NewSequence(const char* name, int sequenceType) = 0;
|
||||
|
||||
/**
|
||||
* Plays the current sequence in TrackView.
|
||||
*/
|
||||
virtual void PlaySequence() = 0;
|
||||
|
||||
/**
|
||||
* Stops any sequence currently playing in TrackView.
|
||||
*/
|
||||
virtual void StopSequence() = 0;
|
||||
|
||||
/**
|
||||
* Sets the time of the sequence currently playing in TrackView.
|
||||
*/
|
||||
virtual void SetSequenceTime(float time) = 0;
|
||||
|
||||
/**
|
||||
* Adds an entity node(s) from viewport selection to the current sequence.
|
||||
*/
|
||||
virtual void AddSelectedEntities() = 0;
|
||||
|
||||
/**
|
||||
* Adds a layer node from the current layer to the current sequence.
|
||||
*/
|
||||
virtual void AddLayerNode() = 0;
|
||||
|
||||
/**
|
||||
* Adds a track of the given parameter ID to the node.
|
||||
*/
|
||||
virtual void AddTrack(const char* paramName, const char* nodeName, const char* parentDirectorName) = 0;
|
||||
|
||||
/**
|
||||
* Deletes a track of the given parameter ID (in the given index in case of a multi-track) from the node.
|
||||
*/
|
||||
virtual void DeleteTrack(const char* paramName, uint32 index, const char* nodeName, const char* parentDirectorName) = 0;
|
||||
|
||||
/**
|
||||
* Gets number of keys of the specified track.
|
||||
*/
|
||||
virtual int GetNumTrackKeys(const char* paramName, int trackIndex, const char* nodeName, const char* parentDirectorName) = 0;
|
||||
|
||||
/**
|
||||
* Activates/deactivates TrackView recording mode.
|
||||
*/
|
||||
virtual void SetRecording(bool bRecording) = 0;
|
||||
|
||||
/**
|
||||
* Deletes the specified sequence.
|
||||
*/
|
||||
virtual void DeleteSequence(const char* name) = 0;
|
||||
|
||||
/**
|
||||
* Sets the specified sequence as a current one in TrackView.
|
||||
*/
|
||||
virtual void SetCurrentSequence(const char* name) = 0;
|
||||
|
||||
/**
|
||||
* Gets the name of a sequence by its index.
|
||||
*/
|
||||
virtual AZStd::string GetSequenceName(unsigned int index) = 0;
|
||||
|
||||
/**
|
||||
* Gets the time range of a sequence as a pair.
|
||||
*/
|
||||
virtual TRange<float> GetSequenceTimeRange(const char* name) = 0;
|
||||
|
||||
/**
|
||||
* Adds a new node with the given type & name to the current sequence.
|
||||
*/
|
||||
virtual void AddNode(const char* nodeTypeString, const char* nodeName) = 0;
|
||||
|
||||
/**
|
||||
* Deletes the specified node from the current sequence.
|
||||
*/
|
||||
virtual void DeleteNode(AZStd::string_view nodeName, AZStd::string_view parentDirectorName) = 0;
|
||||
|
||||
/**
|
||||
* Gets the number of nodes.
|
||||
*/
|
||||
virtual int GetNumNodes(AZStd::string_view parentDirectorName) = 0;
|
||||
|
||||
/**
|
||||
* Gets the name of a sequence by its index.
|
||||
*/
|
||||
virtual AZStd::string GetNodeName(int index, AZStd::string_view parentDirectorName) = 0;
|
||||
|
||||
/**
|
||||
* Gets the value of the specified key.
|
||||
*/
|
||||
virtual AZStd::any GetKeyValue(const char* paramName, int trackIndex, int keyIndex, const char* nodeName, const char* parentDirectorName) = 0;
|
||||
|
||||
/**
|
||||
* Gets the interpolated value of a track at the specified time.
|
||||
*/
|
||||
virtual AZStd::any GetInterpolatedValue(const char* paramName, int trackIndex, float time, const char* nodeName, const char* parentDirectorName) = 0;
|
||||
|
||||
/**
|
||||
* Sets the time range of a sequence.
|
||||
*/
|
||||
virtual void SetSequenceTimeRange(const char* name, float start, float end) = 0;
|
||||
};
|
||||
using EditorLayerTrackViewRequestBus = AZ::EBus<EditorLayerTrackViewRequests>;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewKeyPropertiesDlg.h" // for CTrackViewKeyUIControls
|
||||
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h> // AnimParamType
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CEventKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariableArray mv_deprecated;
|
||||
|
||||
CSmartVariableEnum<QString> mv_animation;
|
||||
CSmartVariableEnum<QString> mv_event;
|
||||
CSmartVariable<QString> mv_value;
|
||||
CSmartVariable<bool> mv_notrigger_in_scrubbing;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_event, "Event");
|
||||
AddVariable(mv_table, mv_value, "Value");
|
||||
AddVariable(mv_table, mv_notrigger_in_scrubbing, "No trigger in scrubbing");
|
||||
AddVariable(mv_deprecated, "Deprecated");
|
||||
AddVariable(mv_deprecated, mv_animation, "Animation");
|
||||
}
|
||||
bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
return paramType == AnimParamType::Event;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {ED5A2023-EDE1-4a47-BBE6-7D7BA0E4001D}
|
||||
static const GUID guid =
|
||||
{
|
||||
0xed5a2023, 0xede1, 0x4a47, { 0xbb, 0xe6, 0x7d, 0x7b, 0xa0, 0xe4, 0x0, 0x1d }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CEventKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Event)
|
||||
{
|
||||
mv_event.SetEnumList(NULL);
|
||||
mv_animation.SetEnumList(NULL);
|
||||
|
||||
// Add <None> for empty, unset event
|
||||
mv_event->AddEnumItem(QObject::tr("<None>"), "");
|
||||
mv_animation->AddEnumItem(QObject::tr("<None>"), "");
|
||||
|
||||
IEventKey eventKey;
|
||||
keyHandle.GetKey(&eventKey);
|
||||
|
||||
mv_event = eventKey.event.c_str();
|
||||
mv_value = eventKey.eventValue.c_str();
|
||||
mv_animation = eventKey.animation.c_str();
|
||||
mv_notrigger_in_scrubbing = eventKey.bNoTriggerInScrubbing;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void CEventKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!sequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0; keyIndex < selectedKeys.GetKeyCount(); ++keyIndex)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Event)
|
||||
{
|
||||
IEventKey eventKey;
|
||||
keyHandle.GetKey(&eventKey);
|
||||
|
||||
QByteArray event, value, animation;
|
||||
event = static_cast<QString>(mv_event).toUtf8();
|
||||
value = static_cast<QString>(mv_value).toUtf8();
|
||||
animation = static_cast<QString>(mv_animation).toUtf8();
|
||||
|
||||
if (pVar == mv_event.GetVar())
|
||||
{
|
||||
eventKey.event = event.data();
|
||||
}
|
||||
if (pVar == mv_value.GetVar())
|
||||
{
|
||||
eventKey.eventValue = value.data();
|
||||
}
|
||||
if (pVar == mv_animation.GetVar())
|
||||
{
|
||||
eventKey.animation = animation.data();
|
||||
}
|
||||
SyncValue(mv_notrigger_in_scrubbing, eventKey.bNoTriggerInScrubbing, false, pVar);
|
||||
|
||||
bool isDuringUndo = false;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::IsDuringUndoRedo);
|
||||
|
||||
if (isDuringUndo)
|
||||
{
|
||||
keyHandle.SetKey(&eventKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Set Key Value");
|
||||
keyHandle.SetKey(&eventKey);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CEventKeyUIControls, "TrackView.KeyUI.Event", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
|
||||
// Editor
|
||||
#include "TrackViewKeyPropertiesDlg.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CGotoKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariable<float> mv_command;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_command, "Goto Time");
|
||||
}
|
||||
bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
if (paramType == AnimParamType::Goto)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {3E9D2C57-BFB1-42f9-82AC-A393C1062634}
|
||||
static const GUID guid =
|
||||
{
|
||||
0x9b79c8b6, 0xe332, 0x4b9b, { 0xb2, 0x63, 0xef, 0x7e, 0x82, 0x7, 0xa4, 0x47 }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CGotoKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Goto)
|
||||
{
|
||||
IDiscreteFloatKey discreteFloatKey;
|
||||
keyHandle.GetKey(&discreteFloatKey);
|
||||
|
||||
mv_command = discreteFloatKey.m_fValue;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Called when UI variable changes.
|
||||
void CGotoKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!sequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0; keyIndex < selectedKeys.GetKeyCount(); ++keyIndex)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Goto)
|
||||
{
|
||||
IDiscreteFloatKey discreteFloatKey;
|
||||
|
||||
keyHandle.GetKey(&discreteFloatKey);
|
||||
SyncValue(mv_command, discreteFloatKey.m_fValue, false, pVar);
|
||||
|
||||
bool isDuringUndo = false;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::IsDuringUndoRedo);
|
||||
|
||||
if (isDuringUndo)
|
||||
{
|
||||
keyHandle.SetKey(&discreteFloatKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Set Key Value");
|
||||
keyHandle.SetKey(&discreteFloatKey);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CGotoKeyUIControls, "TrackView.KeyUI.Goto", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
|
||||
// Editor
|
||||
#include "TrackViewKeyPropertiesDlg.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//!
|
||||
class CScreenFaderKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariable<float> mv_fadeTime;
|
||||
CSmartVariable<Vec3> mv_fadeColor;
|
||||
CSmartVariable<QString> mv_strTexture;
|
||||
CSmartVariable<bool> mv_bUseCurColor;
|
||||
CSmartVariableEnum<int> mv_fadeType;
|
||||
CSmartVariableEnum<int> mv_fadechangeType;
|
||||
|
||||
public:
|
||||
//-----------------------------------------------------------------------------
|
||||
//!
|
||||
virtual bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
return paramType == AnimParamType::ScreenFader;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//!
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
|
||||
mv_fadeType->SetEnumList(NULL);
|
||||
mv_fadeType->AddEnumItem("FadeIn", IScreenFaderKey::eFT_FadeIn);
|
||||
mv_fadeType->AddEnumItem("FadeOut", IScreenFaderKey::eFT_FadeOut);
|
||||
AddVariable(mv_table, mv_fadeType, "Type");
|
||||
|
||||
mv_fadechangeType->SetEnumList(NULL);
|
||||
mv_fadechangeType->AddEnumItem("Linear", IScreenFaderKey::eFCT_Linear);
|
||||
mv_fadechangeType->AddEnumItem("Square", IScreenFaderKey::eFCT_Square);
|
||||
mv_fadechangeType->AddEnumItem("Cubic Square", IScreenFaderKey::eFCT_CubicSquare);
|
||||
mv_fadechangeType->AddEnumItem("Square Root", IScreenFaderKey::eFCT_SquareRoot);
|
||||
mv_fadechangeType->AddEnumItem("Sin", IScreenFaderKey::eFCT_Sin);
|
||||
AddVariable(mv_table, mv_fadechangeType, "ChangeType");
|
||||
|
||||
AddVariable(mv_table, mv_fadeColor, "Color", IVariable::DT_COLOR);
|
||||
|
||||
mv_fadeTime->SetLimits(0.f, 100.f);
|
||||
AddVariable(mv_table, mv_fadeTime, "Duration");
|
||||
AddVariable(mv_table, mv_strTexture, "Texture", IVariable::DT_TEXTURE);
|
||||
AddVariable(mv_table, mv_bUseCurColor, "Use Current Color");
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//!
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& keys);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//!
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& keys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {FBBC2407-C36B-45b2-9A54-0CF9CD3908FD}
|
||||
static const GUID guid =
|
||||
{
|
||||
0xfbbc2407, 0xc36b, 0x45b2, { 0x9a, 0x54, 0xc, 0xf9, 0xcd, 0x39, 0x8, 0xfd }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CScreenFaderKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& keys)
|
||||
{
|
||||
if (!keys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (keys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = keys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::ScreenFader)
|
||||
{
|
||||
IScreenFaderKey screenFaderKey;
|
||||
keyHandle.GetKey(&screenFaderKey);
|
||||
|
||||
mv_fadeTime = screenFaderKey.m_fadeTime;
|
||||
mv_fadeColor = Vec3(screenFaderKey.m_fadeColor.GetR(), screenFaderKey.m_fadeColor.GetG(), screenFaderKey.m_fadeColor.GetB());
|
||||
mv_strTexture = screenFaderKey.m_strTexture.c_str();
|
||||
mv_bUseCurColor = screenFaderKey.m_bUseCurColor;
|
||||
mv_fadeType = (int)screenFaderKey.m_fadeType;
|
||||
mv_fadechangeType = (int)screenFaderKey.m_fadeChangeType;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScreenFaderKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t keyIndex = 0, num = selectedKeys.GetKeyCount(); keyIndex < num; ++keyIndex)
|
||||
{
|
||||
CTrackViewKeyHandle selectedKey = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
CAnimParamType paramType = selectedKey.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::ScreenFader)
|
||||
{
|
||||
IScreenFaderKey screenFaderKey;
|
||||
selectedKey.GetKey(&screenFaderKey);
|
||||
|
||||
SyncValue(mv_fadeTime, screenFaderKey.m_fadeTime, false, pVar);
|
||||
|
||||
SyncValue(mv_bUseCurColor, screenFaderKey.m_bUseCurColor, false, pVar);
|
||||
|
||||
if (pVar == mv_fadeTime.GetVar())
|
||||
{
|
||||
screenFaderKey.m_fadeTime = MAX((float)mv_fadeTime, 0.f);
|
||||
}
|
||||
else if (pVar == mv_strTexture.GetVar())
|
||||
{
|
||||
QString sTexture = mv_strTexture;
|
||||
screenFaderKey.m_strTexture = sTexture.toUtf8().data();
|
||||
}
|
||||
else if (pVar == mv_fadeType.GetVar())
|
||||
{
|
||||
screenFaderKey.m_fadeType = IScreenFaderKey::EFadeType((int)mv_fadeType);
|
||||
}
|
||||
else if (pVar == mv_fadechangeType.GetVar())
|
||||
{
|
||||
screenFaderKey.m_fadeChangeType = IScreenFaderKey::EFadeChangeType((int)mv_fadechangeType);
|
||||
}
|
||||
else if (pVar == mv_fadeColor.GetVar())
|
||||
{
|
||||
Vec3 color = mv_fadeColor;
|
||||
screenFaderKey.m_fadeColor = AZ::Color(color.x, color.y, color.z, screenFaderKey.m_fadeType == IScreenFaderKey::eFT_FadeIn ? 1.f : 0.f);
|
||||
}
|
||||
|
||||
selectedKey.SetKey(&screenFaderKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CScreenFaderKeyUIControls, "TrackView.KeyUI.ScreenFader", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewKeyPropertiesDlg.h" // for CTrackViewKeyUIControls
|
||||
|
||||
#include <AzCore/Component/EntityBus.h> // for AZ::EntitySystemBus
|
||||
#include <AzFramework/Components/CameraBus.h> // for Camera::CameraNotificationBus
|
||||
#include <CryCommon/Maestro/Types/AnimValueType.h> // for AnimValueType
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CSelectKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
, protected Camera::CameraNotificationBus::Handler
|
||||
, protected AZ::EntitySystemBus::Handler
|
||||
{
|
||||
public:
|
||||
CSelectKeyUIControls() {}
|
||||
|
||||
~CSelectKeyUIControls() override;
|
||||
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariableEnum<QString> mv_camera;
|
||||
CSmartVariable<float> mv_BlendTime;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_camera, "Camera");
|
||||
AddVariable(mv_table, mv_BlendTime, "Blend time");
|
||||
|
||||
Camera::CameraNotificationBus::Handler::BusConnect();
|
||||
AZ::EntitySystemBus::Handler::BusConnect();
|
||||
}
|
||||
bool SupportTrackType([[maybe_unused]] const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, AnimValueType valueType) const
|
||||
{
|
||||
return valueType == AnimValueType::Select;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {9018D0D1-24CC-45e5-9D3D-16D3F9E591B2}
|
||||
static const GUID guid =
|
||||
{
|
||||
0x9018d0d1, 0x24cc, 0x45e5, { 0x9d, 0x3d, 0x16, 0xd3, 0xf9, 0xe5, 0x91, 0xb2 }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
|
||||
protected:
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// CameraNotificationBus interface implementation
|
||||
void OnCameraAdded(const AZ::EntityId& cameraId) override;
|
||||
void OnCameraRemoved(const AZ::EntityId& cameraId) override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::EntitySystemBus::Handler
|
||||
void OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name) override;
|
||||
|
||||
private:
|
||||
|
||||
void ResetCameraEntries();
|
||||
};
|
||||
|
||||
CSelectKeyUIControls::~CSelectKeyUIControls()
|
||||
{
|
||||
AZ::EntitySystemBus::Handler::BusDisconnect();
|
||||
Camera::CameraNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSelectKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
AnimValueType valueType = keyHandle.GetTrack()->GetValueType();
|
||||
if (valueType == AnimValueType::Select)
|
||||
{
|
||||
ResetCameraEntries();
|
||||
|
||||
// Get All cameras.
|
||||
mv_camera.SetEnumList(NULL);
|
||||
|
||||
mv_camera->AddEnumItem(QObject::tr("<None>"), QString::number(static_cast<AZ::u64>(AZ::EntityId::InvalidEntityId)));
|
||||
|
||||
// Find all Component Entity Cameras
|
||||
AZ::EBusAggregateResults<AZ::EntityId> cameraComponentEntities;
|
||||
Camera::CameraBus::BroadcastResult(cameraComponentEntities, &Camera::CameraRequests::GetCameras);
|
||||
|
||||
// add names of all found entities with Camera Components
|
||||
for (int i = 0; i < cameraComponentEntities.values.size(); i++)
|
||||
{
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, cameraComponentEntities.values[i]);
|
||||
if (entity)
|
||||
{
|
||||
// For Camera Components the enum value is the stringified AZ::EntityId of the entity with the Camera Component
|
||||
QString entityIdString = QString::number(static_cast<AZ::u64>(entity->GetId()));
|
||||
mv_camera->AddEnumItem(entity->GetName().c_str(), entityIdString);
|
||||
}
|
||||
}
|
||||
|
||||
ISelectKey selectKey;
|
||||
keyHandle.GetKey(&selectKey);
|
||||
|
||||
mv_camera = QString::number(static_cast<AZ::u64>(selectKey.cameraAzEntityId));
|
||||
|
||||
mv_BlendTime.GetVar()->SetLimits(0.0f, selectKey.fDuration > .0f ? selectKey.fDuration : 1.0f, 0.1f, true, false);
|
||||
mv_BlendTime = selectKey.fBlendTime;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void CSelectKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!sequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0; keyIndex < selectedKeys.GetKeyCount(); ++keyIndex)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
AnimValueType valueType = keyHandle.GetTrack()->GetValueType();
|
||||
if (valueType == AnimValueType::Select)
|
||||
{
|
||||
ISelectKey selectKey;
|
||||
keyHandle.GetKey(&selectKey);
|
||||
|
||||
if (pVar == mv_camera.GetVar())
|
||||
{
|
||||
QString entityIdString = mv_camera;
|
||||
selectKey.cameraAzEntityId = AZ::EntityId(entityIdString.toULongLong());
|
||||
selectKey.szSelection = mv_camera.GetVar()->GetDisplayValue().toUtf8().data();
|
||||
}
|
||||
|
||||
if (pVar == mv_BlendTime.GetVar())
|
||||
{
|
||||
if (mv_BlendTime < 0.0f)
|
||||
{
|
||||
mv_BlendTime = 0.0f;
|
||||
}
|
||||
|
||||
selectKey.fBlendTime = mv_BlendTime;
|
||||
}
|
||||
|
||||
if (!selectKey.szSelection.empty())
|
||||
{
|
||||
IAnimSequence* pSequence = GetIEditor()->GetSystem()->GetIMovieSystem()->FindLegacySequenceByName(selectKey.szSelection.c_str());
|
||||
if (pSequence)
|
||||
{
|
||||
selectKey.fDuration = pSequence->GetTimeRange().Length();
|
||||
}
|
||||
}
|
||||
|
||||
bool isDuringUndo = false;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::IsDuringUndoRedo);
|
||||
|
||||
if (isDuringUndo)
|
||||
{
|
||||
keyHandle.SetKey(&selectKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Set Key Value");
|
||||
keyHandle.SetKey(&selectKey);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSelectKeyUIControls::OnCameraAdded(const AZ::EntityId & cameraId)
|
||||
{
|
||||
// Add a single camera component
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, cameraId);
|
||||
if (entity)
|
||||
{
|
||||
// For Camera Components the enum value is the stringified AZ::EntityId of the entity with the Camera Component
|
||||
QString entityIdString = QString::number(static_cast<AZ::u64>(entity->GetId()));
|
||||
mv_camera->AddEnumItem(entity->GetName().c_str(), entityIdString);
|
||||
}
|
||||
}
|
||||
|
||||
void CSelectKeyUIControls::OnCameraRemoved(const AZ::EntityId & cameraId)
|
||||
{
|
||||
mv_camera->EnableUpdateCallbacks(false);
|
||||
|
||||
// We can't iterate or remove an item from the enum list, and Camera::CameraRequests::GetCameras
|
||||
// still includes the deleted camera at this point. Reset the list anyway and filter out the
|
||||
// deleted camera.
|
||||
mv_camera->SetEnumList(NULL);
|
||||
mv_camera->AddEnumItem(QObject::tr("<None>"), QString::number(static_cast<AZ::u64>(AZ::EntityId::InvalidEntityId)));
|
||||
|
||||
AZ::EBusAggregateResults<AZ::EntityId> cameraComponentEntities;
|
||||
Camera::CameraBus::BroadcastResult(cameraComponentEntities, &Camera::CameraRequests::GetCameras);
|
||||
for (int i = 0; i < cameraComponentEntities.values.size(); i++)
|
||||
{
|
||||
if (cameraId == cameraComponentEntities.values[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
OnCameraAdded(cameraComponentEntities.values[i]);
|
||||
}
|
||||
|
||||
mv_camera->EnableUpdateCallbacks(true);
|
||||
}
|
||||
|
||||
void CSelectKeyUIControls::OnEntityNameChanged(const AZ::EntityId & entityId, [[maybe_unused]] const AZStd::string & name)
|
||||
{
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, entityId);
|
||||
if (entity == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::Entity::ComponentArrayType cameraComponents = entity->FindComponents(EditorCameraComponentTypeId);
|
||||
if (cameraComponents.size() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mv_camera->EnableUpdateCallbacks(false);
|
||||
ResetCameraEntries();
|
||||
mv_camera->EnableUpdateCallbacks(true);
|
||||
}
|
||||
|
||||
void CSelectKeyUIControls::ResetCameraEntries()
|
||||
{
|
||||
mv_camera.SetEnumList(NULL);
|
||||
mv_camera->AddEnumItem(QObject::tr("<None>"), QString::number(static_cast<AZ::u64>(AZ::EntityId::InvalidEntityId)));
|
||||
|
||||
// Find all Component Entity Cameras
|
||||
AZ::EBusAggregateResults<AZ::EntityId> cameraComponentEntities;
|
||||
Camera::CameraBus::BroadcastResult(cameraComponentEntities, &Camera::CameraRequests::GetCameras);
|
||||
|
||||
// add names of all found entities with Camera Components
|
||||
for (int i = 0; i < cameraComponentEntities.values.size(); i++)
|
||||
{
|
||||
OnCameraAdded(cameraComponentEntities.values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CSelectKeyUIControls, "TrackView.KeyUI.Select", "TrackViewKeyUI");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : A dialog for batch-rendering sequences
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AtomOutputFrameCapture.h"
|
||||
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QTimer>
|
||||
#include <QFutureWatcher>
|
||||
#include <QValidator>
|
||||
|
||||
class QStringListModel;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class SequenceBatchRenderDialog;
|
||||
}
|
||||
|
||||
class CSequenceBatchRenderDialog
|
||||
: public QDialog
|
||||
, public IMovieListener
|
||||
{
|
||||
public:
|
||||
CSequenceBatchRenderDialog(float fps, QWidget* pParent = nullptr);
|
||||
virtual ~CSequenceBatchRenderDialog();
|
||||
|
||||
void reject() override; // overriding so Qt doesn't cancel
|
||||
|
||||
protected:
|
||||
void OnInitDialog();
|
||||
|
||||
void OnAddRenderItem();
|
||||
void OnRemoveRenderItem();
|
||||
void OnClearRenderItems();
|
||||
void OnUpdateRenderItem();
|
||||
void OnLoadPreset();
|
||||
void OnSavePreset();
|
||||
void OnGo();
|
||||
void OnDone();
|
||||
void OnSequenceSelected();
|
||||
void OnRenderItemSelChange();
|
||||
void OnFPSEditChange();
|
||||
void OnFPSChange(int itemIndex);
|
||||
void OnImageFormatChange();
|
||||
void OnResolutionSelected();
|
||||
void OnStartFrameChange();
|
||||
void OnEndFrameChange();
|
||||
void OnLoadBatch();
|
||||
void OnSaveBatch();
|
||||
void OnKickIdle();
|
||||
void OnCancelRender();
|
||||
|
||||
void SaveOutputOptions(const QString& pathname) const;
|
||||
bool LoadOutputOptions(const QString& pathname);
|
||||
|
||||
QString m_ffmpegPluginStatusMsg;
|
||||
bool m_bFFMPEGCommandAvailable;
|
||||
|
||||
float m_fpsForTimeToFrameConversion; // FPS setting in TrackView
|
||||
struct SRenderItem
|
||||
{
|
||||
IAnimSequence* pSequence;
|
||||
IAnimNode* pDirectorNode;
|
||||
Range frameRange;
|
||||
int resW, resH;
|
||||
int fps;
|
||||
QString folder;
|
||||
QString prefix;
|
||||
QStringList cvars;
|
||||
bool disableDebugInfo;
|
||||
bool bCreateVideo;
|
||||
SRenderItem()
|
||||
: pSequence(NULL)
|
||||
, pDirectorNode(NULL)
|
||||
, disableDebugInfo(false)
|
||||
, bCreateVideo(false) {}
|
||||
bool operator==(const SRenderItem& item)
|
||||
{
|
||||
if (pSequence == item.pSequence
|
||||
&& pDirectorNode == item.pDirectorNode
|
||||
&& frameRange == item.frameRange
|
||||
&& resW == item.resW && resH == item.resH
|
||||
&& fps == item.fps
|
||||
&& folder == item.folder
|
||||
&& prefix == item.prefix
|
||||
&& cvars == item.cvars
|
||||
&& disableDebugInfo == item.disableDebugInfo
|
||||
&& bCreateVideo == item.bCreateVideo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
std::vector<SRenderItem> m_renderItems;
|
||||
|
||||
// Capture States
|
||||
enum class CaptureState
|
||||
{
|
||||
Idle,
|
||||
WarmingUpAfterResChange,
|
||||
EnteringGameMode,
|
||||
BeginPlayingSequence,
|
||||
Capturing,
|
||||
End,
|
||||
FFMPEGProcessing,
|
||||
Finalize
|
||||
};
|
||||
|
||||
struct SRenderContext
|
||||
{
|
||||
int currentItemIndex;
|
||||
float expectedTotalTime;
|
||||
float spentTime;
|
||||
int flagBU;
|
||||
Range rangeBU;
|
||||
int cvarCustomResWidthBU, cvarCustomResHeightBU;
|
||||
int cvarDisplayInfoBU;
|
||||
int framesSpentInCurrentPhase;
|
||||
IAnimNode* pActiveDirectorBU;
|
||||
ICaptureKey captureOptions;
|
||||
bool processingFFMPEG;
|
||||
// Signals when an mpeg is finished being processed.
|
||||
QFutureWatcher<void> processingFFMPEGWatcher;
|
||||
// True if the user canceled a render.
|
||||
bool canceled;
|
||||
// The sequence that triggered the CaptureState::Ending.
|
||||
IAnimSequence* endingSequence;
|
||||
// Current capture state.
|
||||
CaptureState captureState;
|
||||
// Is an individual frame currently being captured.
|
||||
bool capturingFrame;
|
||||
// Current frame being captured
|
||||
int frameNumber;
|
||||
|
||||
bool IsInRendering() const
|
||||
{ return currentItemIndex >= 0; }
|
||||
|
||||
SRenderContext()
|
||||
: currentItemIndex(-1)
|
||||
, expectedTotalTime(0)
|
||||
, spentTime(0)
|
||||
, flagBU(0)
|
||||
, pActiveDirectorBU(NULL)
|
||||
, cvarCustomResWidthBU(0)
|
||||
, cvarCustomResHeightBU(0)
|
||||
, cvarDisplayInfoBU(0)
|
||||
, framesSpentInCurrentPhase(0)
|
||||
, processingFFMPEG(false)
|
||||
, canceled(false)
|
||||
, endingSequence(nullptr)
|
||||
, captureState(CaptureState::Idle)
|
||||
, capturingFrame(false)
|
||||
, frameNumber(0) {}
|
||||
};
|
||||
SRenderContext m_renderContext;
|
||||
|
||||
// Custom validator to make sure the prefix is a valid part of a filename.
|
||||
class CPrefixValidator : public QValidator
|
||||
{
|
||||
public:
|
||||
CPrefixValidator(QObject* parent) : QValidator(parent) {}
|
||||
|
||||
QValidator::State validate(QString& input, [[maybe_unused]] int& pos) const override
|
||||
{
|
||||
bool valid = input.isEmpty() || AzFramework::StringFunc::Path::IsValid(input.toUtf8().data());
|
||||
return valid ? QValidator::State::Acceptable : QValidator::State::Invalid;
|
||||
}
|
||||
};
|
||||
|
||||
// Custom values from resolution/FPS combo boxes
|
||||
int m_customResW, m_customResH;
|
||||
int m_customFPS;
|
||||
|
||||
void InitializeContext();
|
||||
virtual void OnMovieEvent(IMovieListener::EMovieEvent event, IAnimSequence* pSequence);
|
||||
|
||||
void CaptureItemStart();
|
||||
|
||||
// Capture State Updates
|
||||
void OnUpdateWarmingUpAfterResChange();
|
||||
void OnUpdateEnteringGameMode();
|
||||
void OnUpdateBeginPlayingSequence();
|
||||
void OnUpdateCapturing();
|
||||
void OnUpdateEnd(IAnimSequence* pSequence);
|
||||
void OnUpdateFFMPEGProcessing();
|
||||
void OnUpdateFinalize();
|
||||
|
||||
bool SetUpNewRenderItem(SRenderItem& item);
|
||||
void AddItem(const SRenderItem& item);
|
||||
QString GetCaptureItemString(const SRenderItem& item) const;
|
||||
|
||||
protected slots:
|
||||
void OnKickIdleTimout();
|
||||
|
||||
bool GetResolutionFromCustomResText(const char* customResText, int& retCustomWidth, int& retCustomHeight) const;
|
||||
|
||||
private:
|
||||
void CheckForEnableUpdateButton();
|
||||
void stashActiveViewportResolution();
|
||||
void UpdateSpinnerProgressMessage(const char* description);
|
||||
void EnterCaptureState(CaptureState captureState);
|
||||
void SetEnableEditorIdleProcessing(bool enabled);
|
||||
|
||||
QScopedPointer<Ui::SequenceBatchRenderDialog> m_ui;
|
||||
QStringListModel* m_renderListModel;
|
||||
QTimer m_renderTimer;
|
||||
bool m_editorIdleProcessingEnabled;
|
||||
int32 CV_TrackViewRenderOutputCapturing;
|
||||
QScopedPointer<CPrefixValidator> m_prefixValidator;
|
||||
|
||||
TrackView::AtomOutputFrameCapture m_atomOutputFrameCapture;
|
||||
};
|
||||
@@ -0,0 +1,406 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SequenceBatchRenderDialog</class>
|
||||
<widget class="QDialog" name="SequenceBatchRenderDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>572</width>
|
||||
<height>614</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Render Output</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="BATCH_RENDER_INPUT_GROUP_BOX">
|
||||
<property name="title">
|
||||
<string>Input</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="5" colspan="2">
|
||||
<widget class="QLabel" name="BATCH_RENDER_FRAME_IN_FPS">
|
||||
<property name="text">
|
||||
<string>In 30 FPS</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Sequence:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>End frame:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="7">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Director:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="8">
|
||||
<widget class="QComboBox" name="m_shotCombo"/>
|
||||
</item>
|
||||
<item row="1" column="7" colspan="2">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="m_startFrame"/>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="5">
|
||||
<widget class="QComboBox" name="m_sequenceCombo"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Start frame:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QSpinBox" name="m_endFrame"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="BATCH_RENDER_OUTPUT_GROUP_BOX">
|
||||
<property name="title">
|
||||
<string>Output</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Resolution:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="m_resolutionCombo"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>FPS:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="m_fpsCombo">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::NoInsert</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Capture Options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="0" colspan="3">
|
||||
<widget class="QCheckBox" name="m_createVideoCheckBox">
|
||||
<property name="text">
|
||||
<string>Create a video (mp4)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>File prefix:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="BATCH_RENDER_FILE_PREFIX">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Format:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3">
|
||||
<widget class="QCheckBox" name="m_disableDebugInfoCheckBox">
|
||||
<property name="text">
|
||||
<string>Disable Debug Info</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="m_imageFormatCombo">
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>Custom Configs</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Input cvars for further customization:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="m_cvarsEdit">
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:4.125pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8.25pt;"><br /></p></body></html></string>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Destination:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="m_destinationEdit">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="BATCH_RENDER_LOAD_PRESET">
|
||||
<property name="text">
|
||||
<string>Load Preset...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="BATCH_RENDER_SAVE_PRESET">
|
||||
<property name="text">
|
||||
<string>Save Preset...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="BATCH_RENDER_LIST_GROUP_BOX">
|
||||
<property name="title">
|
||||
<string>Batch</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QListView" name="m_renderList"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="BATCH_RENDER_ADD_SEQ">
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="BATCH_RENDER_REMOVE_SEQ">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="BATCH_RENDER_CLEAR_SEQ">
|
||||
<property name="text">
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="m_updateBtn">
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="BATCH_RENDER_LOAD_BATCH">
|
||||
<property name="text">
|
||||
<string>Load Batch...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="BATCH_RENDER_SAVE_BATCH">
|
||||
<property name="text">
|
||||
<string>Save Batch...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="m_progressBar">
|
||||
<property name="textVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="m_progressStatusMsg">
|
||||
<property name="text">
|
||||
<string>Static</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4" stretch="1,0,0">
|
||||
<item>
|
||||
<widget class="QLabel" name="BATCH_RENDER_PRESS_ESC_TO_CANCEL">
|
||||
<property name="text">
|
||||
<string>Press ESC to cancel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignHCenter|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="m_pGoBtn">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="CANCEL">
|
||||
<property name="text">
|
||||
<string>Done</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
|
||||
// Editor
|
||||
#include "TrackViewDialog.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CSequenceKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariableEnum<QString> mv_sequence;
|
||||
CSmartVariable<bool> mv_overrideTimes;
|
||||
CSmartVariable<float> mv_startTime;
|
||||
CSmartVariable<float> mv_endTime;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_sequence, "Sequence");
|
||||
AddVariable(mv_table, mv_overrideTimes, "Override Start/End Times");
|
||||
AddVariable(mv_table, mv_startTime, "Start Time");
|
||||
AddVariable(mv_table, mv_endTime, "End Time");
|
||||
}
|
||||
bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
return paramType == AnimParamType::Sequence;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {68030C46-1402-45d1-91B3-8EC6F29C0FED}
|
||||
static const GUID guid =
|
||||
{
|
||||
0x68030c46, 0x1402, 0x45d1, { 0x91, 0xb3, 0x8e, 0xc6, 0xf2, 0x9c, 0xf, 0xed }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_skipOnUIChange = false;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSequenceKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Sequence)
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// fill sequence comboBox with available sequences
|
||||
mv_sequence.SetEnumList(NULL);
|
||||
|
||||
// Insert '<None>' empty enum
|
||||
mv_sequence->AddEnumItem(QObject::tr("<None>"), CTrackViewDialog::GetEntityIdAsString(AZ::EntityId(AZ::EntityId::InvalidEntityId)));
|
||||
|
||||
const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
|
||||
for (int i = 0; i < pSequenceManager->GetCount(); ++i)
|
||||
{
|
||||
CTrackViewSequence* pCurrentSequence = pSequenceManager->GetSequenceByIndex(i);
|
||||
bool bNotMe = pCurrentSequence != pSequence;
|
||||
bool bNotParent = !bNotMe || pCurrentSequence->IsAncestorOf(pSequence) == false;
|
||||
if (bNotMe && bNotParent)
|
||||
{
|
||||
string seqName = pCurrentSequence->GetName();
|
||||
|
||||
QString ownerIdString = CTrackViewDialog::GetEntityIdAsString(pCurrentSequence->GetSequenceComponentEntityId());
|
||||
mv_sequence->AddEnumItem(seqName.c_str(), ownerIdString);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// fill Key Properties with selected key values
|
||||
ISequenceKey sequenceKey;
|
||||
keyHandle.GetKey(&sequenceKey);
|
||||
|
||||
QString entityIdString = CTrackViewDialog::GetEntityIdAsString((sequenceKey.sequenceEntityId));
|
||||
mv_sequence = entityIdString;
|
||||
|
||||
mv_overrideTimes = sequenceKey.bOverrideTimes;
|
||||
if (!sequenceKey.bOverrideTimes)
|
||||
{
|
||||
IAnimSequence* pSequence2 = GetIEditor()->GetSystem()->GetIMovieSystem()->FindSequence(sequenceKey.sequenceEntityId);
|
||||
|
||||
if (pSequence2)
|
||||
{
|
||||
sequenceKey.fStartTime = pSequence2->GetTimeRange().start;
|
||||
sequenceKey.fEndTime = pSequence2->GetTimeRange().end;
|
||||
}
|
||||
else
|
||||
{
|
||||
sequenceKey.fStartTime = 0.0f;
|
||||
sequenceKey.fEndTime = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't trigger an OnUIChange event, since this code is the one
|
||||
// updating the start/end ui elements, not the user setting new values.
|
||||
m_skipOnUIChange = true;
|
||||
mv_startTime = sequenceKey.fStartTime;
|
||||
mv_endTime = sequenceKey.fEndTime;
|
||||
m_skipOnUIChange = false;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void CSequenceKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!sequence || !selectedKeys.AreAllKeysOfSameType() || m_skipOnUIChange)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0; keyIndex < selectedKeys.GetKeyCount(); ++keyIndex)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Sequence)
|
||||
{
|
||||
ISequenceKey sequenceKey;
|
||||
keyHandle.GetKey(&sequenceKey);
|
||||
|
||||
AZ::EntityId seqOwnerId;
|
||||
if (pVar == mv_sequence.GetVar())
|
||||
{
|
||||
QString entityIdString = mv_sequence;
|
||||
seqOwnerId = AZ::EntityId(static_cast<AZ::u64>(entityIdString.toULongLong()));
|
||||
|
||||
sequenceKey.szSelection.clear(); // clear deprecated legacy data
|
||||
sequenceKey.sequenceEntityId = seqOwnerId;
|
||||
}
|
||||
|
||||
SyncValue(mv_overrideTimes, sequenceKey.bOverrideTimes, false, pVar);
|
||||
|
||||
IAnimSequence* pSequence = GetIEditor()->GetSystem()->GetIMovieSystem()->FindSequence(seqOwnerId);
|
||||
|
||||
if (!sequenceKey.bOverrideTimes)
|
||||
{
|
||||
if (pSequence)
|
||||
{
|
||||
sequenceKey.fStartTime = pSequence->GetTimeRange().start;
|
||||
sequenceKey.fEndTime = pSequence->GetTimeRange().end;
|
||||
}
|
||||
else
|
||||
{
|
||||
sequenceKey.fStartTime = 0.0f;
|
||||
sequenceKey.fEndTime = 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SyncValue(mv_startTime, sequenceKey.fStartTime, false, pVar);
|
||||
SyncValue(mv_endTime, sequenceKey.fEndTime, false, pVar);
|
||||
}
|
||||
|
||||
sequenceKey.fDuration = sequenceKey.fEndTime - sequenceKey.fStartTime > 0 ? sequenceKey.fEndTime - sequenceKey.fStartTime : 0.0f;
|
||||
|
||||
IMovieSystem* pMovieSystem = GetIEditor()->GetSystem()->GetIMovieSystem();
|
||||
|
||||
if (pMovieSystem != NULL)
|
||||
{
|
||||
pMovieSystem->SetStartEndTime(pSequence, sequenceKey.fStartTime, sequenceKey.fEndTime);
|
||||
}
|
||||
|
||||
bool isDuringUndo = false;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::IsDuringUndoRedo);
|
||||
|
||||
if (isDuringUndo)
|
||||
{
|
||||
keyHandle.SetKey(&sequenceKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Set Key Value");
|
||||
keyHandle.SetKey(&sequenceKey);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CSequenceKeyUIControls, "TrackView.KeyUI.Sequence", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h> // for AnimParamType
|
||||
|
||||
// Editor
|
||||
#include "TrackViewKeyPropertiesDlg.h" // for CTrackViewKeyUIControls
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CSoundKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariableArray mv_options;
|
||||
|
||||
CSmartVariable<QString> mv_startTrigger;
|
||||
CSmartVariable<QString> mv_stopTrigger;
|
||||
CSmartVariable<float> mv_duration;
|
||||
CSmartVariable<Vec3> mv_customColor;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_startTrigger, "StartTrigger", IVariable::DT_AUDIO_TRIGGER);
|
||||
AddVariable(mv_table, mv_stopTrigger, "StopTrigger", IVariable::DT_AUDIO_TRIGGER);
|
||||
AddVariable(mv_table, mv_duration, "Duration");
|
||||
AddVariable(mv_options, "Options");
|
||||
AddVariable(mv_options, mv_customColor, "Custom Color", IVariable::DT_COLOR);
|
||||
}
|
||||
bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
return paramType == AnimParamType::Sound;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {AB2226E5-D593-49d2-B7CB-989412CAAEDE}
|
||||
static const GUID guid =
|
||||
{
|
||||
0xab2226e5, 0xd593, 0x49d2, { 0xb7, 0xcb, 0x98, 0x94, 0x12, 0xca, 0xae, 0xde }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CSoundKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Sound)
|
||||
{
|
||||
ISoundKey soundKey;
|
||||
keyHandle.GetKey(&soundKey);
|
||||
|
||||
mv_startTrigger = soundKey.sStartTrigger.c_str();
|
||||
mv_stopTrigger = soundKey.sStopTrigger.c_str();
|
||||
mv_duration = soundKey.fDuration;
|
||||
mv_customColor = soundKey.customColor;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void CSoundKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!pSequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0; keyIndex < selectedKeys.GetKeyCount(); ++keyIndex)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::Sound)
|
||||
{
|
||||
ISoundKey soundKey;
|
||||
keyHandle.GetKey(&soundKey);
|
||||
bool bChangedSoundFile = false;
|
||||
|
||||
if (pVar == mv_startTrigger.GetVar())
|
||||
{
|
||||
QString sFilename = mv_startTrigger;
|
||||
bChangedSoundFile = sFilename != soundKey.sStartTrigger.c_str();
|
||||
soundKey.sStartTrigger = sFilename.toUtf8().data();
|
||||
}
|
||||
else if (pVar == mv_stopTrigger.GetVar())
|
||||
{
|
||||
QString sFilename = mv_stopTrigger;
|
||||
bChangedSoundFile = sFilename != soundKey.sStopTrigger.c_str();
|
||||
soundKey.sStopTrigger = sFilename.toUtf8().data();
|
||||
}
|
||||
|
||||
SyncValue(mv_duration, soundKey.fDuration, false, pVar);
|
||||
SyncValue(mv_customColor, soundKey.customColor, false, pVar);
|
||||
|
||||
keyHandle.SetKey(&soundKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CSoundKeyUIControls, "TrackView.KeyUI.Sound", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TVCustomizeTrackColorsDialog</class>
|
||||
<widget class="QDialog" name="TVCustomizeTrackColorsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>555</width>
|
||||
<height>100</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Customize Track Colors</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="1,0,0,0,0,0">
|
||||
<item row="0" column="0" colspan="6">
|
||||
<widget class="QWidget" name="frame" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="buttonResetAll">
|
||||
<property name="text">
|
||||
<string>Reset All</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="buttonExport">
|
||||
<property name="text">
|
||||
<string>Export</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="5">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="buttonImport">
|
||||
<property name="text">
|
||||
<string>Import</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>5</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>TVCustomizeTrackColorsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>TVCustomizeTrackColorsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : A dialog for customizing track colors
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TVCustomizeTrackColorsDlg.h"
|
||||
|
||||
// Qt
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
|
||||
// Editor
|
||||
#include "TrackViewDialog.h"
|
||||
#include "QtUI/ColorButton.h"
|
||||
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
#include <TrackView/ui_TVCustomizeTrackColorsDialog.h>
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
|
||||
#define TRACKCOLOR_ENTRY_PREFIX ("TrackColor")
|
||||
#define TRACKCOLOR_FOR_OTHERS_ENTRY ("TrackColorForOthers")
|
||||
#define TRACKCOLOR_FOR_DISABLED_ENTRY ("TrackColorForDisabled")
|
||||
#define TRACKCOLOR_FOR_MUTED_ENTRY ("TrackColorForMuted")
|
||||
|
||||
struct STrackEntry
|
||||
{
|
||||
CAnimParamType paramType;
|
||||
QString name;
|
||||
QColor defaultColor;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
const STrackEntry g_trackEntries[] = {
|
||||
// Color for tracks
|
||||
{ AnimParamType::FOV, "FOV", QColor(220, 220, 220) },
|
||||
{ AnimParamType::Position, "Pos", QColor(90, 150, 90) },
|
||||
{ AnimParamType::Rotation, "Rot", QColor(90, 150, 90) },
|
||||
{ AnimParamType::Scale, "Scale", QColor(90, 150, 90) },
|
||||
{ AnimParamType::Event, "Event", QColor(220, 220, 220) },
|
||||
{ AnimParamType::Visibility, "Visibility", QColor(220, 220, 220) },
|
||||
{ AnimParamType::Camera, "Camera", QColor(220, 220, 220) },
|
||||
{ AnimParamType::Sound, "Sound", QColor(220, 220, 220) },
|
||||
{ AnimParamType::Animation, "Animation", QColor(220, 220, 220) },
|
||||
{ AnimParamType::Sequence, "Sequence", QColor(220, 220, 220) },
|
||||
{ AnimParamType::Console, "Console", QColor(220, 220, 220) },
|
||||
{ AnimParamType::LookAt, "LookAt", QColor(220, 220, 220) },
|
||||
{ AnimParamType::TrackEvent, "TrackEvent", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ShakeMultiplier, "ShakeMult", QColor(90, 150, 90) },
|
||||
{ AnimParamType::TransformNoise, "Noise", QColor(90, 150, 90) },
|
||||
{ AnimParamType::TimeWarp, "Timewarp", QColor(220, 220, 220) },
|
||||
{ AnimParamType::FixedTimeStep, "FixedTimeStep", QColor(220, 220, 220) },
|
||||
{ AnimParamType::DepthOfField, "DepthOfField", QColor(90, 150, 90) },
|
||||
{ AnimParamType::CommentText, "CommentText", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ScreenFader, "ScreenFader", QColor(220, 220, 220) },
|
||||
{ AnimParamType::LightDiffuse, "LightDiffuseColor", QColor(90, 150, 90) },
|
||||
{ AnimParamType::LightRadius, "LightRadius", QColor(220, 220, 220) },
|
||||
{ AnimParamType::LightDiffuseMult, "LightDiffuseMult", QColor(220, 220, 220) },
|
||||
{ AnimParamType::LightHDRDynamic, "LightHDRDynamic", QColor(220, 220, 220) },
|
||||
{ AnimParamType::LightSpecularMult, "LightSpecularMult", QColor(220, 220, 220) },
|
||||
{ AnimParamType::LightSpecPercentage, "LightSpecularPercent", QColor(220, 220, 220) },
|
||||
{ AnimParamType::FocusDistance, "FocusDistance", QColor(220, 220, 220) },
|
||||
{ AnimParamType::FocusRange, "FocusRange", QColor(220, 220, 220) },
|
||||
{ AnimParamType::BlurAmount, "BlurAmount", QColor(220, 220, 220) },
|
||||
{ AnimParamType::PositionX, "PosX", QColor(220, 220, 220) },
|
||||
{ AnimParamType::PositionY, "PosY", QColor(220, 220, 220) },
|
||||
{ AnimParamType::PositionZ, "PosZ", QColor(220, 220, 220) },
|
||||
{ AnimParamType::RotationX, "RotX", QColor(220, 220, 220) },
|
||||
{ AnimParamType::RotationY, "RotY", QColor(220, 220, 220) },
|
||||
{ AnimParamType::RotationZ, "RotZ", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ScaleX, "ScaleX", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ScaleY, "ScaleY", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ScaleZ, "ScaleZ", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ShakeAmpAMult, "ShakeMultAmpA", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ShakeAmpBMult, "ShakeMultAmpB", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ShakeFreqAMult, "ShakeMultFreqA", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ShakeFreqBMult, "ShakeMultFreqB", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ColorR, "ColorR", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ColorG, "ColorG", QColor(220, 220, 220) },
|
||||
{ AnimParamType::ColorB, "ColorB", QColor(220, 220, 220) },
|
||||
{ AnimParamType::MaterialOpacity, "MaterialOpacity", QColor(220, 220, 220) },
|
||||
{ AnimParamType::MaterialSmoothness, "MaterialGlossiness", QColor(220, 220, 220) },
|
||||
{ AnimParamType::MaterialEmissive, "MaterialEmission", QColor(220, 220, 220) },
|
||||
{ AnimParamType::MaterialEmissiveIntensity, "MaterialEmissionIntensity", QColor(220, 220, 220) },
|
||||
{ AnimParamType::NearZ, "NearZ", QColor(220, 220, 220) },
|
||||
|
||||
{ AnimParamType::User, "", QColor(0, 0, 0) }, // An empty string means a separator row.
|
||||
|
||||
// Misc colors for special states of a track
|
||||
{ AnimParamType::User, "Others", QColor(220, 220, 220) },
|
||||
{ AnimParamType::User, "Disabled/Inactive", QColor(255, 224, 224) },
|
||||
{ AnimParamType::User, "Muted", QColor(255, 224, 224) },
|
||||
};
|
||||
|
||||
const int kButtonsIdBase = 0x7fff;
|
||||
const int kMaxRows = 20;
|
||||
const int kColumnWidth = 300;
|
||||
const int kRowHeight = 24;
|
||||
|
||||
const int kOthersEntryIndex = arraysize(g_trackEntries) - 3;
|
||||
const int kDisabledEntryIndex = arraysize(g_trackEntries) - 2;
|
||||
const int kMutedEntryIndex = arraysize(g_trackEntries) - 1;
|
||||
}
|
||||
|
||||
std::map<CAnimParamType, QColor> CTVCustomizeTrackColorsDlg::s_trackColors;
|
||||
QColor CTVCustomizeTrackColorsDlg::s_colorForDisabled;
|
||||
QColor CTVCustomizeTrackColorsDlg::s_colorForMuted;
|
||||
QColor CTVCustomizeTrackColorsDlg::s_colorForOthers;
|
||||
|
||||
CTVCustomizeTrackColorsDlg::CTVCustomizeTrackColorsDlg(QWidget* pParent)
|
||||
: QDialog(pParent)
|
||||
, m_aLabels(arraysize(g_trackEntries))
|
||||
, m_colorButtons(arraysize(g_trackEntries))
|
||||
, m_ui(new Ui::TVCustomizeTrackColorsDialog)
|
||||
{
|
||||
OnInitDialog();
|
||||
}
|
||||
|
||||
CTVCustomizeTrackColorsDlg::~CTVCustomizeTrackColorsDlg()
|
||||
{
|
||||
}
|
||||
|
||||
void CTVCustomizeTrackColorsDlg::OnInitDialog()
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &CTVCustomizeTrackColorsDlg::accept);
|
||||
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &CTVCustomizeTrackColorsDlg::reject);
|
||||
connect(m_ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &CTVCustomizeTrackColorsDlg::OnApply);
|
||||
connect(m_ui->buttonResetAll, &QPushButton::clicked, this, &CTVCustomizeTrackColorsDlg::OnResetAll);
|
||||
connect(m_ui->buttonExport, &QPushButton::clicked, this, &CTVCustomizeTrackColorsDlg::OnExport);
|
||||
connect(m_ui->buttonImport, &QPushButton::clicked, this, &CTVCustomizeTrackColorsDlg::OnImport);
|
||||
|
||||
|
||||
QRect labelRect(QPoint(30, 30), QPoint(150, 50));
|
||||
QRect buttonRect(QPoint(180, 30), QPoint(280, 50));
|
||||
// Create a label and a color button for each track.
|
||||
int col = 0, i = 0;
|
||||
std::for_each(g_trackEntries, g_trackEntries + arraysize(g_trackEntries), [&](const STrackEntry& entry)
|
||||
{
|
||||
const QString labelText = entry.name;
|
||||
|
||||
if(!labelText.isEmpty())
|
||||
{
|
||||
m_aLabels[i] = new QLabel(m_ui->frame);
|
||||
m_aLabels[i]->setGeometry(labelRect);
|
||||
m_aLabels[i]->setText(labelText);
|
||||
|
||||
m_colorButtons[i] = new ColorButton(m_ui->frame);
|
||||
m_colorButtons[i]->setGeometry(buttonRect);
|
||||
|
||||
if(entry.paramType.GetType() == AnimParamType::User)
|
||||
{
|
||||
assert(kOthersEntryIndex <= i);
|
||||
if (i == kOthersEntryIndex)
|
||||
{
|
||||
m_colorButtons[i]->SetColor(s_colorForOthers);
|
||||
}
|
||||
else if(i == kDisabledEntryIndex)
|
||||
{
|
||||
m_colorButtons[i]->SetColor(s_colorForDisabled);
|
||||
}
|
||||
else if(i == kMutedEntryIndex)
|
||||
{
|
||||
m_colorButtons[i]->SetColor(s_colorForMuted);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_colorButtons[i]->SetColor(s_trackColors[entry.paramType]);
|
||||
}
|
||||
}
|
||||
|
||||
if(i % kMaxRows == kMaxRows - 1)
|
||||
{
|
||||
++col;
|
||||
labelRect.moveTopLeft(QPoint(30+kColumnWidth*col, 30));
|
||||
buttonRect.moveTopLeft(QPoint(180+kColumnWidth*col, 30));
|
||||
}
|
||||
else
|
||||
{
|
||||
labelRect.translate(0, kRowHeight);
|
||||
buttonRect.translate(0, kRowHeight);
|
||||
}
|
||||
++i;
|
||||
});
|
||||
|
||||
// Resize this dialog to fit the contents.
|
||||
const QSize size(60 + kColumnWidth * (col + 1), 100 + kMaxRows * kRowHeight);
|
||||
m_ui->frame->setFixedSize(size);
|
||||
setFixedSize(sizeHint());
|
||||
}
|
||||
|
||||
void CTVCustomizeTrackColorsDlg::accept()
|
||||
{
|
||||
OnApply();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void CTVCustomizeTrackColorsDlg::OnApply()
|
||||
{
|
||||
int i = 0;
|
||||
std::for_each(g_trackEntries, g_trackEntries + arraysize(g_trackEntries), [&](const STrackEntry& entry)
|
||||
{
|
||||
if(entry.paramType.GetType() != AnimParamType::User)
|
||||
{
|
||||
s_trackColors[entry.paramType] = m_colorButtons[i]->Color();
|
||||
}
|
||||
++i;
|
||||
});
|
||||
|
||||
s_colorForOthers = m_colorButtons[kOthersEntryIndex]->Color();
|
||||
s_colorForDisabled = m_colorButtons[kDisabledEntryIndex]->Color();
|
||||
s_colorForMuted = m_colorButtons[kMutedEntryIndex]->Color();
|
||||
|
||||
CTrackViewDialog::GetCurrentInstance()->InvalidateDopeSheet();
|
||||
}
|
||||
|
||||
void CTVCustomizeTrackColorsDlg::OnResetAll()
|
||||
{
|
||||
int i = 0;
|
||||
std::for_each(g_trackEntries, g_trackEntries + arraysize(g_trackEntries), [&](const STrackEntry& entry)
|
||||
{
|
||||
const QString labelText = entry.name;
|
||||
if(!labelText.isEmpty())
|
||||
{
|
||||
m_colorButtons[i]->SetColor(entry.defaultColor);
|
||||
}
|
||||
++i;
|
||||
});
|
||||
}
|
||||
|
||||
void CTVCustomizeTrackColorsDlg::SaveColors(const char* sectionName)
|
||||
{
|
||||
QSettings settings;
|
||||
for (auto g : QString(sectionName).split('\\'))
|
||||
{
|
||||
settings.beginGroup(g);
|
||||
}
|
||||
std::for_each(begin(s_trackColors), end(s_trackColors),
|
||||
[&](const std::pair<CAnimParamType, QColor>& pair)
|
||||
{
|
||||
const QString trackColorEntry = QString::fromLatin1("%1%2").arg(TRACKCOLOR_ENTRY_PREFIX).arg(static_cast<int>(pair.first.GetType()));
|
||||
settings.setValue(trackColorEntry, pair.second.rgb());
|
||||
});
|
||||
|
||||
settings.setValue(TRACKCOLOR_FOR_OTHERS_ENTRY, s_colorForOthers.rgb());
|
||||
settings.setValue(TRACKCOLOR_FOR_DISABLED_ENTRY, s_colorForDisabled.rgb());
|
||||
settings.setValue(TRACKCOLOR_FOR_MUTED_ENTRY, s_colorForMuted.rgb());
|
||||
}
|
||||
|
||||
void CTVCustomizeTrackColorsDlg::LoadColors(const char* sectionName)
|
||||
{
|
||||
QSettings settings;
|
||||
for (auto g : QString(sectionName).split('\\'))
|
||||
{
|
||||
settings.beginGroup(g);
|
||||
}
|
||||
std::for_each(g_trackEntries, g_trackEntries + arraysize(g_trackEntries), [&](const STrackEntry& entry)
|
||||
{
|
||||
if (entry.paramType.GetType() != AnimParamType::User)
|
||||
{
|
||||
s_trackColors[entry.paramType] = QColor::fromRgb(settings.value(QStringLiteral("%2%3").arg(TRACKCOLOR_ENTRY_PREFIX).arg(static_cast<int>(entry.paramType.GetType())), entry.defaultColor.rgb()).toInt());
|
||||
}
|
||||
});
|
||||
|
||||
s_colorForOthers = QColor::fromRgb(settings.value(TRACKCOLOR_FOR_OTHERS_ENTRY, g_trackEntries[kOthersEntryIndex].defaultColor.rgb()).toInt());
|
||||
s_colorForDisabled = QColor::fromRgb(settings.value(TRACKCOLOR_FOR_DISABLED_ENTRY, g_trackEntries[kDisabledEntryIndex].defaultColor.rgb()).toInt());
|
||||
s_colorForMuted = QColor::fromRgb(settings.value(TRACKCOLOR_FOR_MUTED_ENTRY, g_trackEntries[kMutedEntryIndex].defaultColor.rgb()).toInt());
|
||||
}
|
||||
|
||||
void CTVCustomizeTrackColorsDlg::OnExport()
|
||||
{
|
||||
QString savePath;
|
||||
if (CFileUtil::SelectSaveFile("Custom Track Colors Files (*.ctc)", "ctc",
|
||||
Path::GetUserSandboxFolder(), savePath))
|
||||
{
|
||||
Export(savePath);
|
||||
}
|
||||
}
|
||||
|
||||
void CTVCustomizeTrackColorsDlg::OnImport()
|
||||
{
|
||||
QString loadPath;
|
||||
if (CFileUtil::SelectFile("Custom Track Colors Files (*.ctc)",
|
||||
Path::GetUserSandboxFolder(), loadPath))
|
||||
{
|
||||
if (Import(loadPath))
|
||||
{
|
||||
// since the user is explicitly pressing 'Import', we assume he or she wants to apply this import
|
||||
// to see the result immediately, based on a customer feedback sample of one
|
||||
OnApply();
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Cannot import"), tr("The file format is invalid!"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTVCustomizeTrackColorsDlg::Export(const QString& fullPath) const
|
||||
{
|
||||
XmlNodeRef customTrackColorsNode = XmlHelpers::CreateXmlNode("customtrackcolors");
|
||||
|
||||
int i = 0;
|
||||
std::for_each(g_trackEntries, g_trackEntries + arraysize(g_trackEntries), [&](const STrackEntry& entry)
|
||||
{
|
||||
if(entry.paramType.GetType() != AnimParamType::User)
|
||||
{
|
||||
XmlNodeRef entryNode = customTrackColorsNode->newChild("entry");
|
||||
|
||||
// Serialization is const safe
|
||||
CAnimParamType ¶mType = const_cast<CAnimParamType&>( entry.paramType );
|
||||
paramType.Serialize( entryNode, false );
|
||||
entryNode->setAttr("color", m_colorButtons[i]->Color().rgb());
|
||||
}
|
||||
++i;
|
||||
});
|
||||
|
||||
XmlNodeRef othersNode = customTrackColorsNode->newChild("others");
|
||||
othersNode->setAttr("color", m_colorButtons[kOthersEntryIndex]->Color().rgb());
|
||||
XmlNodeRef disabledNode = customTrackColorsNode->newChild("disabled");
|
||||
disabledNode->setAttr("color", m_colorButtons[kDisabledEntryIndex]->Color().rgb());
|
||||
XmlNodeRef mutedNode = customTrackColorsNode->newChild("muted");
|
||||
mutedNode->setAttr("color", m_colorButtons[kMutedEntryIndex]->Color().rgb());
|
||||
|
||||
XmlHelpers::SaveXmlNode(GetIEditor()->GetFileUtil(), customTrackColorsNode, fullPath.toStdString().c_str());
|
||||
}
|
||||
|
||||
bool CTVCustomizeTrackColorsDlg::Import(const QString& fullPath)
|
||||
{
|
||||
XmlNodeRef customTrackColorsNode = XmlHelpers::LoadXmlFromFile(fullPath.toStdString().c_str());
|
||||
if (customTrackColorsNode == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QColor color;
|
||||
for (int i = 0; i < customTrackColorsNode->getChildCount(); ++i)
|
||||
{
|
||||
XmlNodeRef childNode = customTrackColorsNode->getChild(i);
|
||||
if (QString(childNode->getTag()) != "entry")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CAnimParamType paramType;
|
||||
paramType.Serialize(childNode, true);
|
||||
|
||||
// Get the entry index for this param type.
|
||||
const STrackEntry* pEntry = std::find_if(g_trackEntries, g_trackEntries + arraysize(g_trackEntries),
|
||||
[=](const STrackEntry& entry)
|
||||
{
|
||||
return entry.paramType == paramType;
|
||||
});
|
||||
int entryIndex = pEntry - g_trackEntries;
|
||||
if (entryIndex >= arraysize(g_trackEntries)) // If not found, skip this.
|
||||
{
|
||||
continue;
|
||||
}
|
||||
GetQColorFromXmlNode(color, childNode);
|
||||
m_colorButtons[entryIndex]->SetColor(color);
|
||||
}
|
||||
|
||||
XmlNodeRef othersNode = customTrackColorsNode->findChild("others");
|
||||
if (othersNode)
|
||||
{
|
||||
GetQColorFromXmlNode(color, othersNode);
|
||||
m_colorButtons[kOthersEntryIndex]->SetColor(color);
|
||||
}
|
||||
|
||||
XmlNodeRef disabledNode = customTrackColorsNode->findChild("disabled");
|
||||
if (disabledNode)
|
||||
{
|
||||
GetQColorFromXmlNode(color, disabledNode);
|
||||
m_colorButtons[kDisabledEntryIndex]->SetColor(color);
|
||||
}
|
||||
|
||||
XmlNodeRef mutedNode = customTrackColorsNode->findChild("muted");
|
||||
if (mutedNode)
|
||||
{
|
||||
GetQColorFromXmlNode(color, mutedNode);
|
||||
m_colorButtons[kMutedEntryIndex]->SetColor(color);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <TrackView/moc_TVCustomizeTrackColorsDlg.cpp>
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : A dialog for customizing track colors
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TVCUSTOMIZETRACKCOLORSDLG_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TVCUSTOMIZETRACKCOLORSDLG_H
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QDialog>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class TVCustomizeTrackColorsDialog;
|
||||
}
|
||||
|
||||
class QLabel;
|
||||
class ColorButton;
|
||||
|
||||
class CTVCustomizeTrackColorsDlg
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class CTrackViewDialog;
|
||||
public:
|
||||
CTVCustomizeTrackColorsDlg(QWidget* pParent = nullptr);
|
||||
virtual ~CTVCustomizeTrackColorsDlg();
|
||||
|
||||
static QColor GetTrackColor(CAnimParamType paramType)
|
||||
{
|
||||
auto itr = s_trackColors.find(paramType);
|
||||
if (itr != end(s_trackColors))
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return s_colorForOthers;
|
||||
}
|
||||
}
|
||||
static QColor GetColorForDisabledTracks()
|
||||
{ return s_colorForDisabled; }
|
||||
static QColor GetColorForMutedTracks()
|
||||
{ return s_colorForMuted; }
|
||||
|
||||
private:
|
||||
|
||||
inline void GetQColorFromXmlNode(QColor& colorOut, const XmlNodeRef& xmlNode) const
|
||||
{
|
||||
QRgb rgb = -1;
|
||||
xmlNode->getAttr("color", rgb);
|
||||
colorOut.setRgb(rgb);
|
||||
};
|
||||
|
||||
virtual void OnInitDialog();
|
||||
void OnApply();
|
||||
void OnResetAll();
|
||||
void OnExport();
|
||||
void OnImport();
|
||||
void accept() override;
|
||||
|
||||
void Export(const QString& fullPath) const;
|
||||
bool Import(const QString& fullPath);
|
||||
|
||||
static void SaveColors(const char* sectionName);
|
||||
static void LoadColors(const char* sectionName);
|
||||
|
||||
QVector<QLabel*> m_aLabels;
|
||||
QVector<ColorButton*> m_colorButtons;
|
||||
|
||||
QScopedPointer<Ui::TVCustomizeTrackColorsDialog> m_ui;
|
||||
|
||||
static std::map<CAnimParamType, QColor> s_trackColors;
|
||||
static QColor s_colorForDisabled;
|
||||
static QColor s_colorForMuted;
|
||||
static QColor s_colorForOthers;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TVCUSTOMIZETRACKCOLORSDLG_H
|
||||
@@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TVEventsDialog.h"
|
||||
|
||||
// Qt
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimNodeType.h>
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
|
||||
// Editor
|
||||
#include "AnimationContext.h"
|
||||
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
#include <TrackView/ui_TVEventsDialog.h>
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
|
||||
// CTVEventsDialog dialog
|
||||
|
||||
namespace
|
||||
{
|
||||
const int kCountSubItemIndex = 1;
|
||||
const int kTimeSubItemIndex = 2;
|
||||
}
|
||||
|
||||
class TVEventsModel
|
||||
: public QAbstractTableModel
|
||||
{
|
||||
public:
|
||||
TVEventsModel(QObject* parent = nullptr)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override
|
||||
{
|
||||
if (parent.isValid())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
assert(sequence);
|
||||
return sequence->GetTrackEventsCount();
|
||||
}
|
||||
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override
|
||||
{
|
||||
return parent.isValid() ? 0 : 3;
|
||||
}
|
||||
|
||||
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override
|
||||
{
|
||||
if (parent.isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
assert(sequence);
|
||||
|
||||
AzToolsFramework::ScopedUndoBatch undo("Remove Track Event");
|
||||
|
||||
for (int r = row; r < row + count; ++r)
|
||||
{
|
||||
const QString eventName = index(r, 0).data().toString();
|
||||
beginRemoveRows(QModelIndex(), r, r);
|
||||
result &= sequence->RemoveTrackEvent(eventName.toUtf8().data());
|
||||
endRemoveRows();
|
||||
|
||||
undo.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool addRow(const QString& name)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
assert(sequence);
|
||||
const int index = rowCount();
|
||||
beginInsertRows(QModelIndex(), index, index);
|
||||
bool result = false;
|
||||
|
||||
AzToolsFramework::ScopedUndoBatch undo("Add Track Event");
|
||||
result = sequence->AddTrackEvent(name.toUtf8().data());
|
||||
undo.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
|
||||
endInsertRows();
|
||||
if (!result)
|
||||
{
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
endRemoveRows();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool moveRow(const QModelIndex& index, bool up)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
assert(sequence);
|
||||
if (!index.isValid() || (up && index.row() == 0) || (!up && index.row() == rowCount() - 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
AzToolsFramework::ScopedUndoBatch undo("Move Track Event");
|
||||
if (up)
|
||||
{
|
||||
beginMoveRows(QModelIndex(), index.row(), index.row(), QModelIndex(), index.row() - 1);
|
||||
result = sequence->MoveUpTrackEvent(index.sibling(index.row(), 0).data().toString().toUtf8().data());
|
||||
}
|
||||
else
|
||||
{
|
||||
beginMoveRows(QModelIndex(), index.row() + 1, index.row() + 1, QModelIndex(), index.row());
|
||||
result = sequence->MoveDownTrackEvent(index.sibling(index.row(), 0).data().toString().toUtf8().data());
|
||||
}
|
||||
undo.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
|
||||
endMoveRows();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
assert(sequence);
|
||||
if (role != Qt::DisplayRole)
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
float timeFirstUsed;
|
||||
int usageCount = GetNumberOfUsageAndFirstTimeUsed(sequence->GetTrackEvent(index.row()), timeFirstUsed);
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case 0:
|
||||
return QString::fromLatin1(sequence->GetTrackEvent(index.row()));
|
||||
case 1:
|
||||
return usageCount;
|
||||
case 2:
|
||||
return usageCount > 0 ? QString::number(timeFirstUsed, 'f', 3) : QString();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
assert(sequence);
|
||||
if (role != Qt::DisplayRole && role != Qt::EditRole)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (index.column() != 0 || value.toString().isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
const QString oldName = index.data().toString();
|
||||
const QString newName = value.toString();
|
||||
|
||||
AzToolsFramework::ScopedUndoBatch undo("Set Track Event Data");
|
||||
result = sequence->RenameTrackEvent(oldName.toUtf8().data(), newName.toUtf8().data());
|
||||
undo.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
|
||||
emit dataChanged(index, index);
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
|
||||
{
|
||||
if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (section)
|
||||
{
|
||||
case 0:
|
||||
return tr("Event");
|
||||
case 1:
|
||||
return tr("# of use");
|
||||
case 2:
|
||||
return tr("Time of first usage");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
int GetNumberOfUsageAndFirstTimeUsed(const char* eventName, float& timeFirstUsed) const;
|
||||
};
|
||||
|
||||
CTVEventsDialog::CTVEventsDialog(QWidget* pParent /*=NULL*/)
|
||||
: QDialog(pParent)
|
||||
, m_ui(new Ui::TVEventsDialog)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
OnInitDialog();
|
||||
|
||||
connect(m_ui->buttonAddEvent, &QPushButton::clicked, this, &CTVEventsDialog::OnBnClickedButtonAddEvent);
|
||||
connect(m_ui->buttonRemoveEvent, &QPushButton::clicked, this, &CTVEventsDialog::OnBnClickedButtonRemoveEvent);
|
||||
connect(m_ui->buttonRenameEvent, &QPushButton::clicked, this, &CTVEventsDialog::OnBnClickedButtonRenameEvent);
|
||||
connect(m_ui->buttonUpEvent, &QPushButton::clicked, this, &CTVEventsDialog::OnBnClickedButtonUpEvent);
|
||||
connect(m_ui->buttonDownEvent, &QPushButton::clicked, this, &CTVEventsDialog::OnBnClickedButtonDownEvent);
|
||||
connect(m_ui->m_List->selectionModel(), &QItemSelectionModel::selectionChanged, this, &CTVEventsDialog::OnListItemChanged);
|
||||
}
|
||||
|
||||
CTVEventsDialog::~CTVEventsDialog()
|
||||
{
|
||||
}
|
||||
|
||||
// CTVEventsDialog message handlers
|
||||
|
||||
void CTVEventsDialog::OnBnClickedButtonAddEvent()
|
||||
{
|
||||
const QString add = QInputDialog::getText(this, tr("Track Event Name"), QString());
|
||||
if (!add.isEmpty() && static_cast<TVEventsModel*>(m_ui->m_List->model())->addRow(add))
|
||||
{
|
||||
m_lastAddedEvent = add;
|
||||
m_ui->m_List->setCurrentIndex(m_ui->m_List->model()->index(m_ui->m_List->model()->rowCount() - 1, 0));
|
||||
}
|
||||
m_ui->m_List->setFocus();
|
||||
}
|
||||
|
||||
void CTVEventsDialog::OnBnClickedButtonRemoveEvent()
|
||||
{
|
||||
QList<QPersistentModelIndex> indexes;
|
||||
for (auto index : m_ui->m_List->selectionModel()->selectedRows())
|
||||
{
|
||||
indexes.push_back(index);
|
||||
}
|
||||
|
||||
for (auto index : indexes)
|
||||
{
|
||||
if (QMessageBox::warning(this, tr("Remove Event"), tr("This removal might cause some link breakages in Flow Graph.\nStill continue?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
|
||||
{
|
||||
m_ui->m_List->model()->removeRow(index.row());
|
||||
}
|
||||
}
|
||||
m_ui->m_List->setFocus();
|
||||
}
|
||||
|
||||
void CTVEventsDialog::OnBnClickedButtonRenameEvent()
|
||||
{
|
||||
const QModelIndex index = m_ui->m_List->currentIndex();
|
||||
|
||||
if (index.isValid())
|
||||
{
|
||||
const QString newName = QInputDialog::getText(this, tr("Track Event Name"), QString());
|
||||
if (!newName.isEmpty())
|
||||
{
|
||||
m_ui->m_List->model()->setData(index.sibling(index.row(), 0), newName);
|
||||
}
|
||||
}
|
||||
m_ui->m_List->setFocus();
|
||||
}
|
||||
|
||||
void CTVEventsDialog::OnBnClickedButtonUpEvent()
|
||||
{
|
||||
static_cast<TVEventsModel*>(m_ui->m_List->model())->moveRow(m_ui->m_List->currentIndex(), true);
|
||||
UpdateButtons();
|
||||
m_ui->m_List->setFocus();
|
||||
}
|
||||
|
||||
void CTVEventsDialog::OnBnClickedButtonDownEvent()
|
||||
{
|
||||
static_cast<TVEventsModel*>(m_ui->m_List->model())->moveRow(m_ui->m_List->currentIndex(), false);
|
||||
UpdateButtons();
|
||||
m_ui->m_List->setFocus();
|
||||
}
|
||||
|
||||
void CTVEventsDialog::OnInitDialog()
|
||||
{
|
||||
m_ui->m_List->setModel(new TVEventsModel(this));
|
||||
m_ui->m_List->header()->resizeSections(QHeaderView::ResizeToContents);
|
||||
|
||||
assert(GetIEditor()->GetAnimation()->GetSequence());
|
||||
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
void CTVEventsDialog::OnListItemChanged()
|
||||
{
|
||||
UpdateButtons();
|
||||
}
|
||||
|
||||
void CTVEventsDialog::UpdateButtons()
|
||||
{
|
||||
bool bRemove = false, bRename = false, bUp = false, bDown = false;
|
||||
|
||||
int nSelected = m_ui->m_List->selectionModel()->selectedRows().count();
|
||||
if (nSelected > 1)
|
||||
{
|
||||
bRemove = true;
|
||||
bRename = false;
|
||||
}
|
||||
else if (nSelected > 0)
|
||||
{
|
||||
bRemove = bRename = true;
|
||||
|
||||
const QModelIndex index = m_ui->m_List->selectionModel()->selectedRows().first();
|
||||
if (index.row() > 0)
|
||||
{
|
||||
bUp = true;
|
||||
}
|
||||
if (index.row() < m_ui->m_List->model()->rowCount() - 1)
|
||||
{
|
||||
bDown = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_ui->buttonRemoveEvent->setEnabled(bRemove);
|
||||
m_ui->buttonRenameEvent->setEnabled(bRename);
|
||||
m_ui->buttonUpEvent->setEnabled(bUp);
|
||||
m_ui->buttonDownEvent->setEnabled(bDown);
|
||||
}
|
||||
|
||||
const QString& CTVEventsDialog::GetLastAddedEvent()
|
||||
{
|
||||
return m_lastAddedEvent;
|
||||
}
|
||||
|
||||
int TVEventsModel::GetNumberOfUsageAndFirstTimeUsed(const char* eventName, float& timeFirstUsed) const
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
int usageCount = 0;
|
||||
float firstTime = std::numeric_limits<float>::max();
|
||||
|
||||
CTrackViewAnimNodeBundle nodeBundle = sequence->GetAnimNodesByType(AnimNodeType::Event);
|
||||
const unsigned int numNodes = nodeBundle.GetCount();
|
||||
|
||||
for (unsigned int currentNode = 0; currentNode < numNodes; ++currentNode)
|
||||
{
|
||||
CTrackViewAnimNode* pCurrentNode = nodeBundle.GetNode(currentNode);
|
||||
|
||||
CTrackViewTrackBundle tracks = pCurrentNode->GetTracksByParam(AnimParamType::TrackEvent);
|
||||
const unsigned int numTracks = tracks.GetCount();
|
||||
|
||||
for (unsigned int currentTrack = 0; currentTrack < numTracks; ++currentTrack)
|
||||
{
|
||||
CTrackViewTrack* pTrack = tracks.GetTrack(currentTrack);
|
||||
|
||||
for (int currentKey = 0; currentKey < pTrack->GetKeyCount(); ++currentKey)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = pTrack->GetKey(currentKey);
|
||||
|
||||
IEventKey key;
|
||||
keyHandle.GetKey(&key);
|
||||
|
||||
if (strcmp(key.event.c_str(), eventName) == 0) // If it has a key with the specified event set
|
||||
{
|
||||
++usageCount;
|
||||
if (key.time < firstTime)
|
||||
{
|
||||
firstTime = key.time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (usageCount > 0)
|
||||
{
|
||||
timeFirstUsed = firstTime;
|
||||
}
|
||||
return usageCount;
|
||||
}
|
||||
|
||||
#include <TrackView/moc_TVEventsDialog.cpp>
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TVEVENTSDIALOG_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TVEVENTSDIALOG_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <IMovieSystem.h>
|
||||
|
||||
#include <QDialog>
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class TVEventsDialog;
|
||||
}
|
||||
|
||||
// CTVEventsDialog dialog
|
||||
|
||||
class CTVEventsDialog
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CTVEventsDialog(QWidget* pParent = nullptr); // standard constructor
|
||||
virtual ~CTVEventsDialog();
|
||||
|
||||
void OnBnClickedButtonAddEvent();
|
||||
void OnBnClickedButtonRemoveEvent();
|
||||
void OnBnClickedButtonRenameEvent();
|
||||
void OnBnClickedButtonUpEvent();
|
||||
void OnBnClickedButtonDownEvent();
|
||||
void OnListItemChanged();
|
||||
|
||||
const QString& GetLastAddedEvent();
|
||||
|
||||
protected:
|
||||
void OnInitDialog();
|
||||
|
||||
void UpdateButtons();
|
||||
|
||||
private:
|
||||
QScopedPointer<Ui::TVEventsDialog> m_ui;
|
||||
QString m_lastAddedEvent;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TVEVENTSDIALOG_H
|
||||
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TVEventsDialog</class>
|
||||
<widget class="QDialog" name="TVEventsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>427</width>
|
||||
<height>308</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>350</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>TrackView Events</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="5">
|
||||
<widget class="QTreeView" name="m_List">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="buttonAddEvent">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="buttonRemoveEvent">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="buttonRenameEvent">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rename</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="buttonUpEvent">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Up</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QPushButton" name="buttonDownEvent">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Down</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : implementation file
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TVSequenceProps.h"
|
||||
|
||||
// Qt
|
||||
#include <QMessageBox>
|
||||
|
||||
// Editor
|
||||
#include "TrackViewSequence.h"
|
||||
#include "TrackViewSequenceManager.h"
|
||||
#include "AnimationContext.h"
|
||||
|
||||
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
#include <TrackView/ui_TVSequenceProps.h>
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
|
||||
CTVSequenceProps::CTVSequenceProps(CTrackViewSequence* pSequence, float fps, QWidget* pParent)
|
||||
: QDialog(pParent)
|
||||
, m_FPS(fps)
|
||||
, m_outOfRange(0)
|
||||
, m_timeUnit(Seconds)
|
||||
, ui(new Ui::CTVSequenceProps)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
assert(pSequence);
|
||||
m_pSequence = pSequence;
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &CTVSequenceProps::OnOK);
|
||||
connect(ui->CUT_SCENE, &QCheckBox::toggled, this, &CTVSequenceProps::ToggleCutsceneOptions);
|
||||
connect(ui->TO_SECONDS, &QRadioButton::toggled, this, &CTVSequenceProps::OnBnClickedToSeconds);
|
||||
connect(ui->TO_FRAMES, &QRadioButton::toggled, this, &CTVSequenceProps::OnBnClickedToFrames);
|
||||
|
||||
OnInitDialog();
|
||||
}
|
||||
|
||||
CTVSequenceProps::~CTVSequenceProps()
|
||||
{
|
||||
}
|
||||
|
||||
// CTVSequenceProps message handlers
|
||||
BOOL CTVSequenceProps::OnInitDialog()
|
||||
{
|
||||
ui->NAME->setText(m_pSequence->GetName());
|
||||
int seqFlags = m_pSequence->GetFlags();
|
||||
|
||||
ui->ALWAYS_PLAY->setChecked((seqFlags & IAnimSequence::eSeqFlags_PlayOnReset));
|
||||
ui->CUT_SCENE->setChecked((seqFlags & IAnimSequence::eSeqFlags_CutScene));
|
||||
ui->DISABLEPLAYER->setChecked((seqFlags & IAnimSequence::eSeqFlags_NoPlayer));
|
||||
ui->DISABLESOUNDS->setChecked((seqFlags & IAnimSequence::eSeqFlags_NoGameSounds));
|
||||
ui->NOSEEK->setChecked((seqFlags & IAnimSequence::eSeqFlags_NoSeek));
|
||||
ui->NOABORT->setChecked((seqFlags & IAnimSequence::eSeqFlags_NoAbort));
|
||||
ui->EARLYMOVIEUPDATE->setChecked((seqFlags & IAnimSequence::eSeqFlags_EarlyMovieUpdate));
|
||||
|
||||
ToggleCutsceneOptions(ui->CUT_SCENE->isChecked());
|
||||
|
||||
ui->MOVE_SCALE_KEYS->setChecked(BST_UNCHECKED);
|
||||
|
||||
ui->START_TIME->setRange(0.0, (1e+5));
|
||||
ui->END_TIME->setRange(0.0, (1e+5));
|
||||
|
||||
Range timeRange = m_pSequence->GetTimeRange();
|
||||
float invFPS = 1.0f / m_FPS;
|
||||
|
||||
m_timeUnit = Seconds;
|
||||
ui->START_TIME->setValue(timeRange.start);
|
||||
ui->START_TIME->setSingleStep(invFPS);
|
||||
ui->END_TIME->setValue(timeRange.end);
|
||||
ui->END_TIME->setSingleStep(invFPS);
|
||||
|
||||
|
||||
m_outOfRange = 0;
|
||||
if (m_pSequence->GetFlags() & IAnimSequence::eSeqFlags_OutOfRangeConstant)
|
||||
{
|
||||
m_outOfRange = 1;
|
||||
ui->ORT_CONSTANT->setChecked(true);
|
||||
}
|
||||
else if (m_pSequence->GetFlags() & IAnimSequence::eSeqFlags_OutOfRangeLoop)
|
||||
{
|
||||
m_outOfRange = 2;
|
||||
ui->ORT_LOOP->setChecked(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->ORT_ONCE->setChecked(true);
|
||||
}
|
||||
|
||||
return TRUE; // return TRUE unless you set the focus to a control
|
||||
// EXCEPTION: OCX Property Pages should return FALSE
|
||||
}
|
||||
|
||||
void CTVSequenceProps::MoveScaleKeys()
|
||||
{
|
||||
// Move/Rescale the sequence to a new time range.
|
||||
Range timeRangeOld = m_pSequence->GetTimeRange();
|
||||
Range timeRangeNew;
|
||||
timeRangeNew.start = ui->START_TIME->value();
|
||||
timeRangeNew.end = ui->END_TIME->value();
|
||||
|
||||
if (!(timeRangeNew == timeRangeOld))
|
||||
{
|
||||
m_pSequence->AdjustKeysToTimeRange(timeRangeNew);
|
||||
}
|
||||
}
|
||||
|
||||
void CTVSequenceProps::UpdateSequenceProps(const QString& name)
|
||||
{
|
||||
if (ui->MOVE_SCALE_KEYS->isChecked())
|
||||
{
|
||||
MoveScaleKeys();
|
||||
}
|
||||
|
||||
Range timeRange;
|
||||
timeRange.start = ui->START_TIME->value();
|
||||
timeRange.end = ui->END_TIME->value();
|
||||
|
||||
if (m_timeUnit == Frames)
|
||||
{
|
||||
float invFPS = 1.0f / m_FPS;
|
||||
timeRange.start = ui->START_TIME->value() * invFPS;
|
||||
timeRange.end = ui->END_TIME->value() * invFPS;
|
||||
}
|
||||
|
||||
m_pSequence->SetTimeRange(timeRange);
|
||||
|
||||
CAnimationContext* ac = GetIEditor()->GetAnimation();
|
||||
if (ac)
|
||||
{
|
||||
ac->UpdateTimeRange();
|
||||
}
|
||||
|
||||
QString seqName = m_pSequence->GetName();
|
||||
if (name != seqName)
|
||||
{
|
||||
// Rename sequence.
|
||||
const CTrackViewSequenceManager* sequenceManager = GetIEditor()->GetSequenceManager();
|
||||
|
||||
sequenceManager->RenameNode(m_pSequence, name.toUtf8().data());
|
||||
}
|
||||
|
||||
int seqFlags = m_pSequence->GetFlags();
|
||||
seqFlags &= ~(IAnimSequence::eSeqFlags_OutOfRangeConstant | IAnimSequence::eSeqFlags_OutOfRangeLoop);
|
||||
|
||||
if (ui->ALWAYS_PLAY->isChecked())
|
||||
{
|
||||
seqFlags |= IAnimSequence::eSeqFlags_PlayOnReset;
|
||||
}
|
||||
else
|
||||
{
|
||||
seqFlags &= ~IAnimSequence::eSeqFlags_PlayOnReset;
|
||||
}
|
||||
|
||||
if (ui->CUT_SCENE->isChecked())
|
||||
{
|
||||
seqFlags |= IAnimSequence::eSeqFlags_CutScene;
|
||||
}
|
||||
else
|
||||
{
|
||||
seqFlags &= ~IAnimSequence::eSeqFlags_CutScene;
|
||||
}
|
||||
|
||||
if (ui->DISABLEPLAYER->isChecked())
|
||||
{
|
||||
seqFlags |= IAnimSequence::eSeqFlags_NoPlayer;
|
||||
}
|
||||
else
|
||||
{
|
||||
seqFlags &= (~IAnimSequence::eSeqFlags_NoPlayer);
|
||||
}
|
||||
|
||||
if (ui->ORT_CONSTANT->isChecked())
|
||||
{
|
||||
seqFlags |= IAnimSequence::eSeqFlags_OutOfRangeConstant;
|
||||
}
|
||||
else if (ui->ORT_LOOP->isChecked())
|
||||
{
|
||||
seqFlags |= IAnimSequence::eSeqFlags_OutOfRangeLoop;
|
||||
}
|
||||
|
||||
if (ui->DISABLESOUNDS->isChecked())
|
||||
{
|
||||
seqFlags |= IAnimSequence::eSeqFlags_NoGameSounds;
|
||||
}
|
||||
else
|
||||
{
|
||||
seqFlags &= (~IAnimSequence::eSeqFlags_NoGameSounds);
|
||||
}
|
||||
|
||||
if (ui->NOSEEK->isChecked())
|
||||
{
|
||||
seqFlags |= IAnimSequence::eSeqFlags_NoSeek;
|
||||
}
|
||||
else
|
||||
{
|
||||
seqFlags &= (~IAnimSequence::eSeqFlags_NoSeek);
|
||||
}
|
||||
|
||||
if (ui->NOABORT->isChecked())
|
||||
{
|
||||
seqFlags |= IAnimSequence::eSeqFlags_NoAbort;
|
||||
}
|
||||
else
|
||||
{
|
||||
seqFlags &= (~IAnimSequence::eSeqFlags_NoAbort);
|
||||
}
|
||||
|
||||
if (ui->EARLYMOVIEUPDATE->isChecked())
|
||||
{
|
||||
seqFlags |= IAnimSequence::eSeqFlags_EarlyMovieUpdate;
|
||||
}
|
||||
else
|
||||
{
|
||||
seqFlags &= (~IAnimSequence::eSeqFlags_EarlyMovieUpdate);
|
||||
}
|
||||
|
||||
if (static_cast<IAnimSequence::EAnimSequenceFlags>(seqFlags) != m_pSequence->GetFlags())
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Change TrackView Sequence Flags");
|
||||
m_pSequence->SetFlags(static_cast<IAnimSequence::EAnimSequenceFlags>(seqFlags));
|
||||
undoBatch.MarkEntityDirty(m_pSequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
}
|
||||
|
||||
void CTVSequenceProps::OnOK()
|
||||
{
|
||||
QString name = ui->NAME->text();
|
||||
if (name.isEmpty())
|
||||
{
|
||||
QMessageBox::warning(this, "Sequence Properties", "A sequence name cannot be empty!");
|
||||
return;
|
||||
}
|
||||
else if (name.contains('/'))
|
||||
{
|
||||
QMessageBox::warning(this, "Sequence Properties", "A sequence name cannot contain a '/' character!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pSequence != nullptr)
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Change TrackView Sequence Settings");
|
||||
UpdateSequenceProps(name);
|
||||
undoBatch.MarkEntityDirty(m_pSequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
|
||||
accept();
|
||||
}
|
||||
|
||||
void CTVSequenceProps::ToggleCutsceneOptions(bool bActivated)
|
||||
{
|
||||
if (bActivated == FALSE)
|
||||
{
|
||||
ui->NOABORT->setChecked(false);
|
||||
ui->DISABLEPLAYER->setChecked(false);
|
||||
ui->DISABLESOUNDS->setChecked(false);
|
||||
}
|
||||
|
||||
ui->NOABORT->setEnabled(bActivated);
|
||||
ui->DISABLEPLAYER->setEnabled(bActivated);
|
||||
ui->DISABLESOUNDS->setEnabled(bActivated);
|
||||
}
|
||||
|
||||
void CTVSequenceProps::OnBnClickedToFrames(bool v)
|
||||
{
|
||||
if (!v)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ui->START_TIME->setSingleStep(1.0f);
|
||||
ui->END_TIME->setSingleStep(1.0f);
|
||||
|
||||
ui->START_TIME->setValue(std::round(ui->START_TIME->value() * static_cast<double>(m_FPS)));
|
||||
ui->END_TIME->setValue(std::round(ui->END_TIME->value() * static_cast<double>(m_FPS)));
|
||||
|
||||
m_timeUnit = Frames;
|
||||
}
|
||||
|
||||
|
||||
void CTVSequenceProps::OnBnClickedToSeconds(bool v)
|
||||
{
|
||||
if (!v)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
float fInvFPS = 1.0f / m_FPS;
|
||||
|
||||
ui->START_TIME->setSingleStep(fInvFPS);
|
||||
ui->END_TIME->setSingleStep(fInvFPS);
|
||||
|
||||
ui->START_TIME->setValue(ui->START_TIME->value() * fInvFPS);
|
||||
ui->END_TIME->setValue(ui->END_TIME->value() * fInvFPS);
|
||||
|
||||
m_timeUnit = Seconds;
|
||||
}
|
||||
|
||||
#include <TrackView/moc_TVSequenceProps.cpp>
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TVSEQUENCEPROPS_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TVSEQUENCEPROPS_H
|
||||
#pragma once
|
||||
|
||||
|
||||
class CTrackViewSequence;
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QDialog>
|
||||
#include <QScopedPointer>
|
||||
#endif
|
||||
|
||||
namespace Ui {
|
||||
class CTVSequenceProps;
|
||||
}
|
||||
|
||||
class CTVSequenceProps
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CTVSequenceProps(CTrackViewSequence* pSequence, float fps, QWidget* pParent = NULL); // standard constructor
|
||||
~CTVSequenceProps();
|
||||
|
||||
private:
|
||||
enum SequenceTimeUnit
|
||||
{
|
||||
Seconds = 0,
|
||||
Frames
|
||||
};
|
||||
CTrackViewSequence* m_pSequence;
|
||||
|
||||
virtual BOOL OnInitDialog();
|
||||
virtual void OnOK();
|
||||
|
||||
void MoveScaleKeys();
|
||||
float m_FPS;
|
||||
int m_outOfRange;
|
||||
SequenceTimeUnit m_timeUnit;
|
||||
|
||||
QScopedPointer<Ui::CTVSequenceProps> ui;
|
||||
|
||||
public slots:
|
||||
void OnBnClickedToFrames(bool);
|
||||
void OnBnClickedToSeconds(bool);
|
||||
|
||||
private slots:
|
||||
void ToggleCutsceneOptions(bool);
|
||||
void UpdateSequenceProps(const QString& name);
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TVSEQUENCEPROPS_H
|
||||
@@ -0,0 +1,270 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CTVSequenceProps</class>
|
||||
<widget class="QDialog" name="CTVSequenceProps">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>310</width>
|
||||
<height>485</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit Sequence</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox2">
|
||||
<property name="title">
|
||||
<string>Properties</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="3" column="0" colspan="3">
|
||||
<widget class="QCheckBox" name="EARLYMOVIEUPDATE">
|
||||
<property name="text">
|
||||
<string>Update Movie System First</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="NOSEEK">
|
||||
<property name="text">
|
||||
<string>NoSeek</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QLineEdit" name="NAME">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label2">
|
||||
<property name="text">
|
||||
<string>Sequence Name</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="ALWAYS_PLAY">
|
||||
<property name="text">
|
||||
<string>Autostart</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="CUT_SCENE">
|
||||
<property name="text">
|
||||
<string>Cut-Scene</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox3">
|
||||
<property name="title">
|
||||
<string>Cut-Scene Toggles</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="NOABORT">
|
||||
<property name="text">
|
||||
<string>Non-Skippable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="DISABLEPLAYER">
|
||||
<property name="text">
|
||||
<string>Disable Player</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="DISABLESOUNDS">
|
||||
<property name="text">
|
||||
<string>Disable Sounds</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox4">
|
||||
<property name="title">
|
||||
<string>Timing</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label1">
|
||||
<property name="text">
|
||||
<string>Start Time:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="START_TIME">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>EndTime:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="END_TIME">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Display Start/End Time As:</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="TO_FRAMES">
|
||||
<property name="text">
|
||||
<string>Frames</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="TO_SECONDS">
|
||||
<property name="text">
|
||||
<string>Seconds</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="MOVE_SCALE_KEYS">
|
||||
<property name="text">
|
||||
<string>Move/Scale Keys</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Out Of Range</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="ORT_ONCE">
|
||||
<property name="text">
|
||||
<string>Once</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="ORT_CONSTANT">
|
||||
<property name="text">
|
||||
<string>Constant</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="ORT_LOOP">
|
||||
<property name="text">
|
||||
<string>Loop</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>CTVSequenceProps</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>196</x>
|
||||
<y>465</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>239</x>
|
||||
<y>407</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h> // for AnimParamType
|
||||
|
||||
// Editor
|
||||
#include "TrackViewKeyPropertiesDlg.h" // for CTrackViewKeyUIControls// Editor
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CTimeRangeKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariable<float> mv_startTime;
|
||||
CSmartVariable<float> mv_endTime;
|
||||
CSmartVariable<float> mv_timeScale;
|
||||
CSmartVariable<bool> mv_bLoop;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_startTime, "Start Time");
|
||||
AddVariable(mv_table, mv_endTime, "End Time");
|
||||
AddVariable(mv_table, mv_timeScale, "Time Scale");
|
||||
AddVariable(mv_table, mv_bLoop, "Loop");
|
||||
mv_timeScale->SetLimits(0.001f, 100.f);
|
||||
}
|
||||
bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
return paramType == AnimParamType::TimeRanges;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {E977A6F4-CEC1-4c67-8735-28721B3F6FEF}
|
||||
static const GUID guid = {
|
||||
0xe977a6f4, 0xcec1, 0x4c67, { 0x87, 0x35, 0x28, 0x72, 0x1b, 0x3f, 0x6f, 0xef }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTimeRangeKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::TimeRanges)
|
||||
{
|
||||
ICharacterKey timeRangeKey;
|
||||
keyHandle.GetKey(&timeRangeKey);
|
||||
|
||||
mv_endTime = timeRangeKey.m_endTime;
|
||||
mv_startTime = timeRangeKey.m_startTime;
|
||||
mv_timeScale = timeRangeKey.m_speed;
|
||||
mv_bLoop = timeRangeKey.m_bLoop;
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void CTimeRangeKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!pSequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0, num = (int)selectedKeys.GetKeyCount(); keyIndex < num; keyIndex++)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::TimeRanges)
|
||||
{
|
||||
ITimeRangeKey timeRangeKey;
|
||||
keyHandle.GetKey(&timeRangeKey);
|
||||
|
||||
SyncValue(mv_startTime, timeRangeKey.m_startTime, false, pVar);
|
||||
SyncValue(mv_endTime, timeRangeKey.m_endTime, false, pVar);
|
||||
SyncValue(mv_timeScale, timeRangeKey.m_speed, false, pVar);
|
||||
SyncValue(mv_bLoop, timeRangeKey.m_bLoop, false, pVar);
|
||||
|
||||
// Clamp values
|
||||
if (!timeRangeKey.m_bLoop)
|
||||
{
|
||||
timeRangeKey.m_endTime = std::min(timeRangeKey.m_duration, timeRangeKey.m_endTime);
|
||||
}
|
||||
timeRangeKey.m_startTime = std::min(timeRangeKey.m_duration, timeRangeKey.m_startTime);
|
||||
timeRangeKey.m_startTime = std::min(timeRangeKey.m_endTime, timeRangeKey.m_startTime);
|
||||
|
||||
keyHandle.SetKey(&timeRangeKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CTimeRangeKeyUIControls, "TrackView.KeyUI.TimeRange", "TrackViewKeyUI");
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
|
||||
// Editor
|
||||
#include "TrackViewKeyPropertiesDlg.h"
|
||||
#include "TVEventsDialog.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CTrackEventKeyUIControls
|
||||
: public CTrackViewKeyUIControls
|
||||
{
|
||||
public:
|
||||
CSmartVariableArray mv_table;
|
||||
CSmartVariableEnum<QString> mv_event;
|
||||
CSmartVariable<QString> mv_value;
|
||||
|
||||
virtual void OnCreateVars()
|
||||
{
|
||||
AddVariable(mv_table, "Key Properties");
|
||||
AddVariable(mv_table, mv_event, "Track Event");
|
||||
mv_event->SetFlags(mv_event->GetFlags() | IVariable::UI_UNSORTED);
|
||||
AddVariable(mv_table, mv_value, "Value");
|
||||
}
|
||||
bool SupportTrackType(const CAnimParamType& paramType, [[maybe_unused]] EAnimCurveType trackType, [[maybe_unused]] AnimValueType valueType) const
|
||||
{
|
||||
return paramType == AnimParamType::TrackEvent;
|
||||
}
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys);
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys);
|
||||
|
||||
virtual unsigned int GetPriority() const { return 1; }
|
||||
|
||||
static const GUID& GetClassID()
|
||||
{
|
||||
// {F7D002EB-1FEA-46fa-B857-FC2B1B990B7F}
|
||||
static const GUID guid =
|
||||
{
|
||||
0xf7d002eb, 0x1fea, 0x46fa, { 0xb8, 0x57, 0xfc, 0x2b, 0x1b, 0x99, 0xb, 0x7f }
|
||||
};
|
||||
return guid;
|
||||
}
|
||||
|
||||
private:
|
||||
void OnEventEdit();
|
||||
void BuildEventDropDown(QString& curEvent, const QString& addedEvent = "");
|
||||
|
||||
QString m_lastEvent;
|
||||
|
||||
static const char* GetAddEventString()
|
||||
{
|
||||
static const char* addEventString = "Add a new event...";
|
||||
|
||||
return addEventString;
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackEventKeyUIControls::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
if (!selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
const CTrackViewKeyHandle& keyHandle = selectedKeys.GetKey(0);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::TrackEvent)
|
||||
{
|
||||
IEventKey eventKey;
|
||||
keyHandle.GetKey(&eventKey);
|
||||
|
||||
// Provide builder with current event value to ensure
|
||||
// dropdown is displayed properly and value is updated if not found
|
||||
QString event = eventKey.event.c_str();
|
||||
BuildEventDropDown(event);
|
||||
|
||||
mv_event = event;
|
||||
mv_value = eventKey.eventValue.c_str();
|
||||
|
||||
bAssigned = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_lastEvent = mv_event;
|
||||
|
||||
return bAssigned;
|
||||
}
|
||||
|
||||
// Called when UI variable changes.
|
||||
void CTrackEventKeyUIControls::OnUIChange(IVariable* pVar, CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!pSequence || !selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mv_event == GetAddEventString())
|
||||
{
|
||||
mv_event = m_lastEvent;
|
||||
OnEventEdit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mv_event == "___spacer___")
|
||||
{
|
||||
mv_event = m_lastEvent;
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int keyIndex = 0; keyIndex < selectedKeys.GetKeyCount(); ++keyIndex)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = selectedKeys.GetKey(keyIndex);
|
||||
|
||||
CAnimParamType paramType = keyHandle.GetTrack()->GetParameterType();
|
||||
if (paramType == AnimParamType::TrackEvent)
|
||||
{
|
||||
IEventKey eventKey;
|
||||
keyHandle.GetKey(&eventKey);
|
||||
|
||||
QByteArray event, value;
|
||||
event = static_cast<QString>(mv_event).toUtf8();
|
||||
value = static_cast<QString>(mv_value).toUtf8();
|
||||
|
||||
if (pVar == mv_event.GetVar())
|
||||
{
|
||||
eventKey.event = event.data();
|
||||
}
|
||||
if (pVar == mv_value.GetVar())
|
||||
{
|
||||
eventKey.eventValue = value.data();
|
||||
}
|
||||
eventKey.animation = "";
|
||||
eventKey.duration = 0;
|
||||
|
||||
keyHandle.SetKey(&eventKey);
|
||||
}
|
||||
}
|
||||
|
||||
m_lastEvent = mv_event;
|
||||
}
|
||||
|
||||
void CTrackEventKeyUIControls::OnEventEdit()
|
||||
{
|
||||
// Create dialog
|
||||
CTVEventsDialog dlg;
|
||||
dlg.exec();
|
||||
|
||||
QString event = mv_event;
|
||||
BuildEventDropDown(event, dlg.GetLastAddedEvent());
|
||||
|
||||
// The step below is necessary to make the event drop-down up-to-date.
|
||||
mv_event.GetVar()->EnableNotifyWithoutValueChange(true);
|
||||
mv_event = event;
|
||||
mv_event.GetVar()->EnableNotifyWithoutValueChange(false);
|
||||
}
|
||||
|
||||
void CTrackEventKeyUIControls::BuildEventDropDown(QString& curEvent, const QString& addedEvent)
|
||||
{
|
||||
if (CAnimationContext* context = GetIEditor()->GetAnimation())
|
||||
{
|
||||
CTrackViewSequence* sequence = context->GetSequence();
|
||||
|
||||
if (sequence)
|
||||
{
|
||||
bool curEventExists = false;
|
||||
bool addedEventExists = false;
|
||||
mv_event.SetEnumList(NULL);
|
||||
const int eventCount = sequence->GetTrackEventsCount();
|
||||
|
||||
// Need to check if event exists before adding all events
|
||||
// This handles the case where the current event got deleted in the dialog but no new events were added
|
||||
for (int i = 0; i < eventCount; ++i)
|
||||
{
|
||||
const char* trackEvent = sequence->GetTrackEvent(i);
|
||||
|
||||
if (curEvent == trackEvent)
|
||||
{
|
||||
curEventExists = true;
|
||||
}
|
||||
if (addedEvent == trackEvent)
|
||||
{
|
||||
addedEventExists = true;
|
||||
}
|
||||
if (curEventExists && addedEventExists)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!curEventExists)
|
||||
{
|
||||
if (addedEventExists)
|
||||
{
|
||||
// Set added event if key not set
|
||||
curEvent = addedEvent;
|
||||
}
|
||||
else
|
||||
{
|
||||
mv_event->AddEnumItem(QObject::tr("<None>"), "");
|
||||
curEvent = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Add Events
|
||||
for (int i = 0; i < eventCount; ++i)
|
||||
{
|
||||
const char* trackEvent = sequence->GetTrackEvent(i);
|
||||
|
||||
mv_event->AddEnumItem(trackEvent, trackEvent);
|
||||
}
|
||||
|
||||
// Used as a spacer to make Add a new event... standout
|
||||
mv_event->AddEnumItem(QObject::tr(""), "___spacer___");
|
||||
|
||||
// Add a new event... to open event editor when selected
|
||||
mv_event->AddEnumItem(QObject::tr(GetAddEventString()), GetAddEventString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QT_CLASS_DESC(CTrackEventKeyUIControls, "TrackView.KeyUI.TrackEvent", "TrackViewKeyUI");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/std/containers/map.h>
|
||||
#include <AzCore/Component/EntityId.h>
|
||||
#include <AzCore/Component/EntityBus.h>
|
||||
#include <AzFramework/Entity/EntityContextBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
|
||||
#include "TrackViewNode.h"
|
||||
#include "TrackViewTrack.h"
|
||||
#include "Objects/TrackGizmo.h"
|
||||
|
||||
class CTrackViewAnimNode;
|
||||
class QWidget;
|
||||
|
||||
// Represents a bundle of anim nodes
|
||||
class CTrackViewAnimNodeBundle
|
||||
{
|
||||
public:
|
||||
unsigned int GetCount() const { return m_animNodes.size(); }
|
||||
CTrackViewAnimNode* GetNode(const unsigned int index) { return m_animNodes[index]; }
|
||||
const CTrackViewAnimNode* GetNode(const unsigned int index) const { return m_animNodes[index]; }
|
||||
|
||||
void Clear();
|
||||
const bool DoesContain(const CTrackViewNode* pTargetNode);
|
||||
|
||||
void AppendAnimNode(CTrackViewAnimNode* pNode);
|
||||
void AppendAnimNodeBundle(const CTrackViewAnimNodeBundle& bundle);
|
||||
|
||||
void ExpandAll(bool bAlsoExpandParentNodes = true);
|
||||
void CollapseAll();
|
||||
|
||||
private:
|
||||
std::vector<CTrackViewAnimNode*> m_animNodes;
|
||||
};
|
||||
|
||||
// Callback called by animation node when its animated.
|
||||
class IAnimNodeAnimator
|
||||
{
|
||||
public:
|
||||
virtual ~IAnimNodeAnimator() {}
|
||||
|
||||
virtual void Animate(CTrackViewAnimNode* pNode, const SAnimContext& ac) = 0;
|
||||
virtual void Render([[maybe_unused]] CTrackViewAnimNode* pNode, [[maybe_unused]] const SAnimContext& ac) {}
|
||||
|
||||
// Called when binding/unbinding the owning node
|
||||
virtual void Bind([[maybe_unused]] CTrackViewAnimNode* pNode) {}
|
||||
virtual void UnBind([[maybe_unused]] CTrackViewAnimNode* pNode) {}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This class represents a IAnimNode in TrackView and contains
|
||||
// the editor side code for changing it
|
||||
//
|
||||
// It does *not* have ownership of the IAnimNode, therefore deleting it
|
||||
// will not destroy the CryMovie track
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
class CTrackViewAnimNode
|
||||
: public CTrackViewNode
|
||||
, public IAnimNodeOwner
|
||||
, public ITransformDelegate
|
||||
, public AzToolsFramework::EditorEntityContextNotificationBus::Handler
|
||||
, public AZ::EntityBus::Handler
|
||||
, private AZ::TransformNotificationBus::Handler
|
||||
, private AzToolsFramework::EntitySelectionEvents::Bus::Handler
|
||||
{
|
||||
public:
|
||||
CTrackViewAnimNode(IAnimSequence* pSequence, IAnimNode* pAnimNode, CTrackViewNode* pParentNode);
|
||||
~CTrackViewAnimNode();
|
||||
|
||||
// Rendering
|
||||
virtual void Render(const SAnimContext& ac);
|
||||
|
||||
// Playback
|
||||
virtual void Animate(const SAnimContext& animContext);
|
||||
|
||||
// Binding/Unbinding
|
||||
virtual void BindToEditorObjects();
|
||||
virtual void UnBindFromEditorObjects();
|
||||
virtual bool IsBoundToEditorObjects() const;
|
||||
|
||||
// Console sync
|
||||
virtual void SyncToConsole(SAnimContext& animContext);
|
||||
|
||||
// CTrackViewAnimNode
|
||||
virtual ETrackViewNodeType GetNodeType() const override { return eTVNT_AnimNode; }
|
||||
|
||||
// Create & remove sub anim nodes
|
||||
virtual CTrackViewAnimNode* CreateSubNode(
|
||||
const QString& name, const AnimNodeType animNodeType, AZ::EntityId entityId = AZ::EntityId(),
|
||||
AZ::Uuid componentTypeId = AZ::Uuid::CreateNull(), AZ::ComponentId componenId=AZ::InvalidComponentId);
|
||||
virtual void RemoveSubNode(CTrackViewAnimNode* pSubNode);
|
||||
|
||||
// Create & remove sub tracks
|
||||
virtual CTrackViewTrack* CreateTrack(const CAnimParamType& paramType);
|
||||
virtual void RemoveTrack(CTrackViewTrack* pTrack);
|
||||
|
||||
// Add selected entities from scene to group node
|
||||
virtual CTrackViewAnimNodeBundle AddSelectedEntities(const AZStd::vector<AnimParamType>& tracks);
|
||||
|
||||
// Add current layer to group node
|
||||
virtual void AddCurrentLayer();
|
||||
|
||||
// Director related
|
||||
virtual void SetAsActiveDirector();
|
||||
virtual bool IsActiveDirector() const;
|
||||
|
||||
// Checks if anim node is part of active sequence and of an active director
|
||||
virtual bool IsActive();
|
||||
|
||||
// Set as view camera
|
||||
virtual void SetAsViewCamera();
|
||||
|
||||
// Name setter/getter
|
||||
virtual const char* GetName() const override { return m_animNode->GetName(); }
|
||||
virtual bool SetName(const char* pName) override;
|
||||
virtual bool CanBeRenamed() const override;
|
||||
|
||||
// Node owner setter/getter
|
||||
virtual void SetNodeEntityId(AZ::EntityId entityId);
|
||||
virtual AZ::EntityId GetNodeEntityId(const bool bSearch = true);
|
||||
|
||||
AZ::EntityId GetAzEntityId() const { return m_animNode ? m_animNode->GetAzEntityId() : AZ::EntityId(); }
|
||||
bool IsBoundToAzEntity() const { return m_animNode ? m_animNode->GetAzEntityId().IsValid(): false; }
|
||||
|
||||
// Snap time value to prev/next key in sequence
|
||||
virtual bool SnapTimeToPrevKey(float& time) const override;
|
||||
virtual bool SnapTimeToNextKey(float& time) const override;
|
||||
|
||||
// Expanded state interface
|
||||
void SetExpanded(bool expanded) override;
|
||||
bool GetExpanded() const override;
|
||||
|
||||
// Node getters
|
||||
CTrackViewAnimNodeBundle GetAllAnimNodes();
|
||||
CTrackViewAnimNodeBundle GetSelectedAnimNodes();
|
||||
CTrackViewAnimNodeBundle GetAllOwnedNodes(AZ::EntityId entityId);
|
||||
CTrackViewAnimNodeBundle GetAnimNodesByType(AnimNodeType animNodeType);
|
||||
CTrackViewAnimNodeBundle GetAnimNodesByName(const char* pName);
|
||||
|
||||
// Track getters
|
||||
virtual CTrackViewTrackBundle GetAllTracks();
|
||||
virtual CTrackViewTrackBundle GetSelectedTracks();
|
||||
virtual CTrackViewTrackBundle GetTracksByParam(const CAnimParamType& paramType) const;
|
||||
|
||||
// Key getters
|
||||
virtual CTrackViewKeyBundle GetAllKeys() override;
|
||||
virtual CTrackViewKeyBundle GetSelectedKeys() override;
|
||||
virtual CTrackViewKeyBundle GetKeysInTimeRange(const float t0, const float t1) override;
|
||||
|
||||
// Type getters
|
||||
AnimNodeType GetType() const;
|
||||
|
||||
// Flags
|
||||
EAnimNodeFlags GetFlags() const;
|
||||
bool AreFlagsSetOnNodeOrAnyParent(EAnimNodeFlags flagsToCheck) const;
|
||||
|
||||
// Disabled state
|
||||
virtual void SetDisabled(bool bDisabled) override;
|
||||
virtual bool IsDisabled() const override;
|
||||
bool CanBeEnabled() const override;
|
||||
|
||||
// Return track assigned to the specified parameter.
|
||||
CTrackViewTrack* GetTrackForParameter(const CAnimParamType& paramType, uint32 index = 0) const;
|
||||
|
||||
// Rotation/Position & Scale
|
||||
void SetPos(const Vec3& position);
|
||||
Vec3 GetPos() const { return m_animNode->GetPos(); }
|
||||
void SetScale(const Vec3& scale);
|
||||
Vec3 GetScale() const { return m_animNode->GetScale(); }
|
||||
void SetRotation(const Quat& rotation);
|
||||
Quat GetRotation() const { return m_animNode->GetRotate(); }
|
||||
Quat GetRotation(float time) const { return m_animNode != nullptr ? m_animNode->GetRotate(time) : Quat(0,0,0,0); }
|
||||
|
||||
// Param
|
||||
unsigned int GetParamCount() const;
|
||||
CAnimParamType GetParamType(unsigned int index) const;
|
||||
const char* GetParamName(const CAnimParamType& paramType) const;
|
||||
bool IsParamValid(const CAnimParamType& param) const;
|
||||
IAnimNode::ESupportedParamFlags GetParamFlags(const CAnimParamType& paramType) const;
|
||||
AnimValueType GetParamValueType(const CAnimParamType& paramType) const;
|
||||
void UpdateDynamicParams();
|
||||
|
||||
// Parameter getters/setters
|
||||
template <class Type>
|
||||
bool SetParamValue(const float time, const CAnimParamType& param, const Type& value)
|
||||
{
|
||||
AZ_Assert(m_animNode, "Expected valid m_animNode");
|
||||
return m_animNode->SetParamValue(time, param, value);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
bool GetParamValue(const float time, const CAnimParamType& param, Type& value)
|
||||
{
|
||||
AZ_Assert(m_animNode, "Expected valid m_animNode");
|
||||
return m_animNode->GetParamValue(time, param, value);
|
||||
}
|
||||
|
||||
// Check if it's a group node
|
||||
virtual bool IsGroupNode() const override;
|
||||
|
||||
// Generate a new node name
|
||||
virtual QString GetAvailableNodeNameStartingWith(const QString& name) const;
|
||||
|
||||
// Copy/Paste nodes
|
||||
virtual void CopyNodesToClipboard(const bool bOnlySelected, QWidget* context);
|
||||
virtual bool PasteNodesFromClipboard(QWidget* context);
|
||||
|
||||
// Set new parent
|
||||
virtual void SetNewParent(CTrackViewAnimNode* pNewParent);
|
||||
|
||||
// Check if this node may be moved to new parent
|
||||
virtual bool IsValidReparentingTo(CTrackViewAnimNode* pNewParent);
|
||||
|
||||
int GetDefaultKeyTangentFlags() const { return m_animNode ? m_animNode->GetDefaultKeyTangentFlags() : SPLINE_KEY_TANGENT_UNIFIED; }
|
||||
|
||||
void SetComponent(AZ::ComponentId componentId, const AZ::Uuid& componentTypeId);
|
||||
|
||||
// returns the AZ::ComponentId of the component associated with this node if it is of type AnimNodeType::Component, InvalidComponentId otherwise
|
||||
AZ::ComponentId GetComponentId() const;
|
||||
|
||||
// IAnimNodeOwner
|
||||
void MarkAsModified() override;
|
||||
// ~IAnimNodeOwner
|
||||
|
||||
// Compares all of the node's track values at the given time with the associated property value and
|
||||
// sets a key at that time if they are different to match the latter
|
||||
// Returns the number of keys set
|
||||
int SetKeysForChangedTrackValues(float time) { return m_animNode->SetKeysForChangedTrackValues(time); }
|
||||
|
||||
// returns true if this node is associated with an AnimNodeType::AzEntity node and contains a component with the given id
|
||||
bool ContainsComponentWithId(AZ::ComponentId componentId) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AzToolsFramework::EditorEntityContextNotificationBus implementation
|
||||
void OnStartPlayInEditor() override;
|
||||
void OnStopPlayInEditor() override;
|
||||
//~AzToolsFramework::EditorEntityContextNotificationBus implementation
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::EntityBus
|
||||
void OnEntityActivated(const AZ::EntityId& entityId) override;
|
||||
void OnEntityDestruction(const AZ::EntityId& entityId) override;
|
||||
//~AZ::EntityBus
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//! AZ::TransformNotificationBus::Handler
|
||||
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
|
||||
void OnParentChanged(AZ::EntityId oldParent, AZ::EntityId newParent) override;
|
||||
void OnParentTransformWillChange(AZ::Transform oldTransform, AZ::Transform newTransform) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OnEntityRemoved();
|
||||
|
||||
// Creates a sub-node for the given component. Returns a pointer to the created component sub-node
|
||||
CTrackViewAnimNode* AddComponent(const AZ::Component* component, bool disabled);
|
||||
|
||||
// Depth-first search for TrackViewAnimNode associated with the given animNode. Returns the first match found or nullptr if not found
|
||||
CTrackViewAnimNode* FindNodeByAnimNode(const IAnimNode* animNode);
|
||||
|
||||
protected:
|
||||
IAnimNode* GetAnimNode() { return m_animNode.get(); }
|
||||
|
||||
private:
|
||||
// Copy selected keys to XML representation for clipboard
|
||||
virtual void CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks) override;
|
||||
|
||||
void CopyNodesToClipboardRec(CTrackViewAnimNode* pCurrentAnimNode, XmlNodeRef& xmlNode, const bool bOnlySelected);
|
||||
|
||||
void PasteTracksFrom(XmlNodeRef& xmlNodeWithTracks);
|
||||
|
||||
bool HasObsoleteTrackRec(CTrackViewNode* pCurrentNode) const;
|
||||
CTrackViewTrackBundle GetTracks(const bool bOnlySelected, const CAnimParamType& paramType) const;
|
||||
|
||||
void PasteNodeFromClipboard(AZStd::map<int, IAnimNode*>& copiedIdToNodeMap, XmlNodeRef xmlNode);
|
||||
|
||||
void SetPosRotScaleTracksDefaultValues(bool positionAllowed = true, bool rotationAllowed = true, bool scaleAllowed = true);
|
||||
|
||||
void UpdateTrackGizmo();
|
||||
|
||||
bool CheckTrackAnimated(const CAnimParamType& paramType) const;
|
||||
|
||||
// IAnimNodeOwner
|
||||
void OnNodeVisibilityChanged(IAnimNode* pNode, const bool bHidden) override;
|
||||
void OnNodeReset(IAnimNode* pNode) override;
|
||||
// ~IAnimNodeOwner
|
||||
|
||||
// ITransformDelegate
|
||||
void MatrixInvalidated() override;
|
||||
|
||||
Vec3 GetTransformDelegatePos(const Vec3& realPos) const override;
|
||||
Quat GetTransformDelegateRotation(const Quat& realRotation) const override;
|
||||
Vec3 GetTransformDelegateScale(const Vec3& realScale) const override;
|
||||
|
||||
void SetTransformDelegatePos(const Vec3& position) override;
|
||||
void SetTransformDelegateRotation(const Quat& rotation) override;
|
||||
void SetTransformDelegateScale(const Vec3& scale) override;
|
||||
|
||||
// If those return true the base object uses its own transform instead
|
||||
bool IsPositionDelegated() const override;
|
||||
bool IsRotationDelegated() const override;
|
||||
bool IsScaleDelegated() const override;
|
||||
// ~ITransformDelegate
|
||||
|
||||
// Helper for Is<Position/Rotation/Scale>Delegated to call internally
|
||||
bool IsTransformAnimParamTypeDelegated(AnimParamType animParamType) const;
|
||||
|
||||
// EntitySelectionEvents
|
||||
void OnSelected() override;
|
||||
void OnDeselected() override;
|
||||
|
||||
void OnSelectionChanged(bool selected);
|
||||
|
||||
void UpdateKeyDataAfterParentChanged(const AZ::Transform& oldParentWorldTM, const AZ::Transform& newParentWorldTM);
|
||||
|
||||
// Used to track Editor object listener registration
|
||||
void RegisterEditorObjectListeners(AZ::EntityId entityId);
|
||||
void UnRegisterEditorObjectListeners();
|
||||
|
||||
// Helper functions
|
||||
static void RemoveChildNode(CTrackViewAnimNode* child);
|
||||
static AZ::Transform GetEntityWorldTM(AZ::EntityId entityId);
|
||||
static void SetParentsInChildren(CTrackViewAnimNode* currentNode);
|
||||
|
||||
IAnimSequence* m_animSequence;
|
||||
AZStd::intrusive_ptr<IAnimNode> m_animNode;
|
||||
AZ::EntityId m_nodeEntityId;
|
||||
AZStd::unique_ptr<IAnimNodeAnimator> m_pNodeAnimator;
|
||||
_smart_ptr<CGizmo> m_trackGizmo;
|
||||
|
||||
// used to stash the Editor sequence and node entity Ids when we switch to game mode from the editor
|
||||
AZ::EntityId m_stashedAnimNodeEditorAzEntityId;
|
||||
AZ::EntityId m_stashedAnimSequenceEditorAzEntityId;
|
||||
|
||||
// Used to track Editor object listener registration
|
||||
AZ::EntityId m_entityIdListenerRegistered;
|
||||
|
||||
// used to return a const reference to a null Uuid
|
||||
static const AZ::Uuid s_nullUuid;
|
||||
};
|
||||
@@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewCurveEditor.h"
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
#include "TrackView/ui_TrackViewCurveEditor.h"
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
|
||||
|
||||
#define IDC_TRACKVIEWGRAPH_CURVE 1
|
||||
#define IDC_TIMELINE 2
|
||||
|
||||
#define IDC_HORIZON_SLIDER 3
|
||||
#define IDC_VERTICAL_SLIDER 4
|
||||
|
||||
//! It's for mapping from a slider control range to a real zoom range, and vice versa.
|
||||
#define SLIDER_MULTIPLIER 100.f
|
||||
#define SLIDERRANGE_TO_ZOOM(SLIDERVALUE) (float)SLIDERVALUE / SLIDER_MULTIPLIER
|
||||
#define ZOOMRANGE_TO_SLIDER(ZOOMVALUE) (int)(ZOOMVALUE * SLIDER_MULTIPLIER)
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
TrackViewCurveEditorDialog::TrackViewCurveEditorDialog(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_widget = new CTrackViewCurveEditor(this);
|
||||
QVBoxLayout* l = new QVBoxLayout;
|
||||
l->setMargin(0);
|
||||
l->addWidget(m_widget);
|
||||
setLayout(l);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewCurveEditor::CTrackViewCurveEditor(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_ui(new Ui::TrackViewCurveEditor)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
m_bLevelClosing = false;
|
||||
m_bIgnoreSelfEvents = false;
|
||||
GetIEditor()->RegisterNotifyListener(this);
|
||||
GetIEditor()->GetAnimation()->AddListener(this);
|
||||
|
||||
m_timelineCtrl.SetTimeRange(Range(0, 1));
|
||||
m_timelineCtrl.SetTicksTextScale(1.0f);
|
||||
|
||||
m_ui->m_wndSpline->SetTimelineCtrl(&m_timelineCtrl);
|
||||
|
||||
connect(&m_timelineCtrl, &TimelineWidget::change, this, &CTrackViewCurveEditor::OnTimelineChange);
|
||||
connect(m_ui->m_wndSpline, &SplineWidget::change, this, &CTrackViewCurveEditor::OnSplineChange);
|
||||
connect(m_ui->m_wndSpline, &SplineWidget::timeChange, this, &CTrackViewCurveEditor::OnSplineTimeMarkerChange);
|
||||
|
||||
connect(m_ui->buttonTangentAuto, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_TANGENT_AUTO); });
|
||||
connect(m_ui->buttonTangentInZero, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_TANGENT_IN_ZERO); });
|
||||
connect(m_ui->buttonTangentInStep, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_TANGENT_IN_STEP); });
|
||||
connect(m_ui->buttonTangentInLinear, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_TANGENT_IN_LINEAR); });
|
||||
connect(m_ui->buttonTangentOutZero, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_TANGENT_OUT_ZERO); });
|
||||
connect(m_ui->buttonTangentOutStep, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_TANGENT_OUT_STEP); });
|
||||
connect(m_ui->buttonTangentOutLinear, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_TANGENT_OUT_LINEAR); });
|
||||
connect(m_ui->buttonSplineFitX, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_SPLINE_FIT_X); });
|
||||
connect(m_ui->buttonSplineFitY, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_SPLINE_FIT_Y); });
|
||||
connect(m_ui->buttonSplineSnapGridX, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_SPLINE_SNAP_GRID_X); });
|
||||
connect(m_ui->buttonSplineSnapGridY, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_SPLINE_SNAP_GRID_Y); });
|
||||
connect(m_ui->buttonTangentUnify, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_TANGENT_UNIFY); });
|
||||
connect(m_ui->buttonFreezeKeys, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_FREEZE_KEYS); });
|
||||
connect(m_ui->buttonFreezeTangents, &QToolButton::clicked, this, [&]() {OnSplineCmd(ID_FREEZE_TANGENTS); });
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewCurveEditor::~CTrackViewCurveEditor()
|
||||
{
|
||||
GetIEditor()->GetAnimation()->RemoveListener(this);
|
||||
GetIEditor()->UnregisterNotifyListener(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CTrackViewGraph message handlers
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnSequenceChanged([[maybe_unused]] CTrackViewSequence* pSequence)
|
||||
{
|
||||
UpdateSplines();
|
||||
update();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnEditorNotifyEvent(EEditorNotifyEvent event)
|
||||
{
|
||||
if (m_bIgnoreSelfEvents)
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch (event)
|
||||
{
|
||||
case eNotify_OnCloseScene:
|
||||
m_ui->m_wndSpline->RemoveAllSplines();
|
||||
m_bLevelClosing = true;
|
||||
break;
|
||||
case eNotify_OnBeginNewScene:
|
||||
case eNotify_OnBeginSceneOpen:
|
||||
m_bLevelClosing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::UpdateSplines()
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (!pSequence || m_bLevelClosing)
|
||||
{
|
||||
// No sequence selected, remove any splines.
|
||||
if (nullptr != m_ui)
|
||||
{
|
||||
if (nullptr != m_ui->m_wndSpline)
|
||||
{
|
||||
m_ui->m_wndSpline->RemoveAllSplines();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
CTrackViewTrackBundle selectedTracks;
|
||||
selectedTracks = pSequence->GetSelectedTracks();
|
||||
|
||||
std::set<CTrackViewTrack*> oldTracks;
|
||||
for (auto iter = m_ui->m_wndSpline->GetTracks().begin(); iter != m_ui->m_wndSpline->GetTracks().end(); ++iter)
|
||||
{
|
||||
CTrackViewTrack* pTrack = *iter;
|
||||
oldTracks.insert(pTrack);
|
||||
}
|
||||
|
||||
std::set<CTrackViewTrack*> newTracks;
|
||||
if (selectedTracks.AreAllOfSameType())
|
||||
{
|
||||
for (int i = 0; i < selectedTracks.GetCount(); i++)
|
||||
{
|
||||
CTrackViewTrack* pTrack = selectedTracks.GetTrack(i);
|
||||
|
||||
if (pTrack->IsCompoundTrack())
|
||||
{
|
||||
unsigned int numChildTracks = pTrack->GetChildCount();
|
||||
for (unsigned int ii = 0; ii < numChildTracks; ++ii)
|
||||
{
|
||||
CTrackViewTrack* pChildTrack = static_cast<CTrackViewTrack*>(pTrack->GetChild(ii));
|
||||
newTracks.insert(pChildTrack);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newTracks.insert(pTrack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldTracks == newTracks)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_ui->m_wndSpline->RemoveAllSplines();
|
||||
for (auto iter = newTracks.begin(); iter != newTracks.end(); ++iter)
|
||||
{
|
||||
AddSpline(*iter);
|
||||
}
|
||||
|
||||
UpdateTimeRange(pSequence);
|
||||
|
||||
// If it is a rotation track, adjust the default value range properly to accommodate some degree values.
|
||||
if (selectedTracks.HasRotationTrack())
|
||||
{
|
||||
m_ui->m_wndSpline->SetDefaultValueRange(Range(-180.0f, 180.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui->m_wndSpline->SetDefaultValueRange(Range(-1.1f, 1.1f));
|
||||
}
|
||||
|
||||
ResetSplineCtrlZoomLevel();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::AddSpline(CTrackViewTrack* pTrack)
|
||||
{
|
||||
if (!pTrack->GetSpline())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int subTrackIndex = pTrack->GetSubTrackIndex();
|
||||
|
||||
if (subTrackIndex >= 0)
|
||||
{
|
||||
QColor trackColor = QColor(255, 0, 0);
|
||||
switch (subTrackIndex)
|
||||
{
|
||||
case 0:
|
||||
trackColor = QColor(255, 0, 0);
|
||||
break;
|
||||
case 1:
|
||||
trackColor = QColor(0, 255, 0);
|
||||
break;
|
||||
case 2:
|
||||
trackColor = QColor(0, 0, 255);
|
||||
break;
|
||||
case 3:
|
||||
trackColor = QColor(255, 255, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
m_ui->m_wndSpline->AddSpline(pTrack->GetSpline(), pTrack, trackColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
QColor afColorArray[4];
|
||||
afColorArray[0] = QColor(255, 0, 0);
|
||||
afColorArray[1] = QColor(0, 255, 0);
|
||||
afColorArray[2] = QColor(0, 0, 255);
|
||||
afColorArray[3] = QColor(255, 0, 255); //Pink... so you know it's wrong if you see it.
|
||||
|
||||
m_ui->m_wndSpline->AddSpline(pTrack->GetSpline(), pTrack, afColorArray);
|
||||
}
|
||||
}
|
||||
|
||||
void CTrackViewCurveEditor::showEvent(QShowEvent* event)
|
||||
{
|
||||
QWidget::showEvent(event);
|
||||
OnSplineCmdUpdateUI();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnSplineChange()
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
if (pSequence)
|
||||
{
|
||||
pSequence->OnKeysChanged();
|
||||
}
|
||||
|
||||
// In the end, focus this again in order to properly catch 'KeyDown' messages.
|
||||
m_ui->m_wndSpline->setFocus();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnSplineCmd(UINT cmd)
|
||||
{
|
||||
m_ui->m_wndSpline->OnUserCommand(cmd);
|
||||
OnSplineCmdUpdateUI();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnSplineCmdUpdateUI()
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (m_bLevelClosing || !pSequence)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_ui->buttonSplineSnapGridX->setChecked(m_ui->m_wndSpline->IsSnapTime());
|
||||
m_ui->buttonSplineSnapGridY->setChecked(m_ui->m_wndSpline->IsSnapValue());
|
||||
m_ui->buttonTangentUnify->setChecked(m_ui->m_wndSpline->IsUnifiedKeyCurrentlySelected());
|
||||
m_ui->buttonFreezeKeys->setChecked(m_ui->m_wndSpline->IsKeysFrozen());
|
||||
m_ui->buttonFreezeTangents->setChecked(m_ui->m_wndSpline->IsTangentsFrozen());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnTimeChanged(float newTime)
|
||||
{
|
||||
m_ui->m_wndSpline->SetTimeMarker(newTime);
|
||||
m_ui->m_wndSpline->update();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::SetEditLock(bool bLock)
|
||||
{
|
||||
m_ui->m_wndSpline->SetEditLock(bLock);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnTimelineChange()
|
||||
{
|
||||
float fTime = m_timelineCtrl.GetTimeMarker();
|
||||
GetIEditor()->GetAnimation()->SetTime(fTime);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnSplineTimeMarkerChange()
|
||||
{
|
||||
float fTime = m_ui->m_wndSpline->GetTimeMarker();
|
||||
GetIEditor()->GetAnimation()->SetTime(fTime);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::SetFPS(float fps)
|
||||
{
|
||||
m_timelineCtrl.SetFPS(fps);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
float CTrackViewCurveEditor::GetFPS() const
|
||||
{
|
||||
return m_timelineCtrl.GetFPS();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::SetTickDisplayMode(ETVTickMode mode)
|
||||
{
|
||||
if (mode == eTVTickMode_InFrames)
|
||||
{
|
||||
m_timelineCtrl.SetMarkerStyle(TimelineWidget::MARKER_STYLE_FRAMES);
|
||||
m_ui->m_wndSpline->SetTooltipValueScale(GetFPS(), 1.0f);
|
||||
}
|
||||
else if (mode == eTVTickMode_InSeconds)
|
||||
{
|
||||
m_timelineCtrl.SetMarkerStyle(TimelineWidget::MARKER_STYLE_SECONDS);
|
||||
m_ui->m_wndSpline->SetTooltipValueScale(1.0f, 1.0f);
|
||||
}
|
||||
|
||||
m_timelineCtrl.update();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::ResetSplineCtrlZoomLevel()
|
||||
{
|
||||
m_ui->m_wndSpline->FitSplineToViewHeight();
|
||||
m_ui->m_wndSpline->FitSplineToViewWidth();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnKeysChanged([[maybe_unused]] CTrackViewSequence* pSequence)
|
||||
{
|
||||
m_ui->m_wndSpline->update();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnKeyAdded(CTrackViewKeyHandle& addedKeyHandle)
|
||||
{
|
||||
EAnimCurveType trType = addedKeyHandle.GetTrack()->GetCurveType();
|
||||
if (trType == eAnimCurveType_BezierFloat)
|
||||
{
|
||||
// we query the added key's track to find the default tangent flags to use for newly created keys
|
||||
const int tangentFlagsForNewKeys = addedKeyHandle.GetTrack()->GetAnimNode()->GetDefaultKeyTangentFlags();
|
||||
I2DBezierKey bezierKey;
|
||||
addedKeyHandle.GetKey(&bezierKey);
|
||||
|
||||
// clear any existing in and out tangent flags
|
||||
bezierKey.flags &= ~SPLINE_KEY_TANGENT_ALL_MASK;
|
||||
|
||||
// set tangent flags to the default tangent flags used for the track's animNode and save them
|
||||
bezierKey.flags |= tangentFlagsForNewKeys;
|
||||
addedKeyHandle.SetKey(&bezierKey);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnKeySelectionChanged([[maybe_unused]] CTrackViewSequence* pSequence)
|
||||
{
|
||||
if (isVisible())
|
||||
{
|
||||
m_ui->m_wndSpline->update();
|
||||
m_ui->buttonTangentUnify->setChecked(m_ui->m_wndSpline->IsUnifiedKeyCurrentlySelected());
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnNodeChanged([[maybe_unused]] CTrackViewNode* pNode, ENodeChangeType type)
|
||||
{
|
||||
if (isVisible() && type == ITrackViewSequenceListener::eNodeChangeType_Removed)
|
||||
{
|
||||
UpdateSplines();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewCurveEditor::OnNodeSelectionChanged([[maybe_unused]] CTrackViewSequence* pSequence)
|
||||
{
|
||||
if (isVisible())
|
||||
{
|
||||
UpdateSplines();
|
||||
}
|
||||
}
|
||||
|
||||
void CTrackViewCurveEditor::OnSequenceSettingsChanged(CTrackViewSequence* pSequence)
|
||||
{
|
||||
if (isVisible())
|
||||
{
|
||||
UpdateTimeRange(pSequence);
|
||||
m_timelineCtrl.update();
|
||||
m_ui->m_wndSpline->update();
|
||||
}
|
||||
}
|
||||
|
||||
void CTrackViewCurveEditor::UpdateTimeRange(CTrackViewSequence* pSequence)
|
||||
{
|
||||
Range timeRange = pSequence->GetTimeRange();
|
||||
m_ui->m_wndSpline->SetTimeRange(timeRange);
|
||||
m_timelineCtrl.SetTimeRange(timeRange);
|
||||
m_ui->m_wndSpline->SetValueRange(Range(-2000.0f, 2000.0f));
|
||||
}
|
||||
|
||||
void CTrackViewCurveEditor::SetPlayCallback(const std::function<void()>& callback)
|
||||
{
|
||||
m_ui->m_wndSpline->SetPlayCallback(callback);
|
||||
m_timelineCtrl.SetPlayCallback(callback);
|
||||
}
|
||||
|
||||
CTrackViewSplineCtrl& CTrackViewCurveEditor::GetSplineCtrl()
|
||||
{
|
||||
return *m_ui->m_wndSpline;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWCURVEEDITOR_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWCURVEEDITOR_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "TrackViewDopeSheetBase.h"
|
||||
#include "TrackViewSplineCtrl.h"
|
||||
#include "Controls/TimelineCtrl.h"
|
||||
#include "TrackViewTimeline.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class TrackViewCurveEditor;
|
||||
}
|
||||
|
||||
/** CTrackViewGraph dialog.
|
||||
Placed at the same position as tracks dialog, and display spline graphs of track.
|
||||
*/
|
||||
class CTrackViewCurveEditor
|
||||
: public QWidget
|
||||
, public IAnimationContextListener
|
||||
, public IEditorNotifyListener
|
||||
, public ITrackViewSequenceListener
|
||||
{
|
||||
friend class TrackViewCurveEditorDialog;
|
||||
public:
|
||||
CTrackViewCurveEditor(QWidget* parent);
|
||||
virtual ~CTrackViewCurveEditor();
|
||||
|
||||
void SetEditLock(bool bLock);
|
||||
|
||||
void SetFPS(float fps);
|
||||
float GetFPS() const;
|
||||
void SetTickDisplayMode(ETVTickMode mode);
|
||||
|
||||
CTrackViewSplineCtrl& GetSplineCtrl();
|
||||
void ResetSplineCtrlZoomLevel();
|
||||
|
||||
void SetPlayCallback(const std::function<void()>& callback);
|
||||
|
||||
// IAnimationContextListener
|
||||
virtual void OnSequenceChanged(CTrackViewSequence* pNewSequence);
|
||||
virtual void OnTimeChanged(float newTime);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
private:
|
||||
|
||||
void OnSplineChange();
|
||||
void OnSplineCmd(UINT cmd);
|
||||
void OnSplineCmdUpdateUI();
|
||||
void OnTimelineChange();
|
||||
void OnSplineTimeMarkerChange();
|
||||
|
||||
// IEditorNotifyListener
|
||||
virtual void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
|
||||
|
||||
//ITrackViewSequenceListener
|
||||
void OnKeysChanged(CTrackViewSequence* pSequence) override;
|
||||
void OnKeyAdded(CTrackViewKeyHandle& addedKeyHandle) override;
|
||||
void OnKeySelectionChanged(CTrackViewSequence* pSequence) override;
|
||||
void OnNodeChanged(CTrackViewNode* pNode, ENodeChangeType type) override;
|
||||
void OnNodeSelectionChanged(CTrackViewSequence* pSequence) override;
|
||||
void OnSequenceSettingsChanged(CTrackViewSequence* pSequence) override;
|
||||
//~ITrackViewSequenceListener
|
||||
|
||||
void UpdateSplines();
|
||||
void UpdateTimeRange(CTrackViewSequence* pSequence);
|
||||
|
||||
void AddSpline(CTrackViewTrack* pTrack);
|
||||
|
||||
TrackView::CTrackViewTimelineWidget m_timelineCtrl;
|
||||
|
||||
bool m_bIgnoreSelfEvents;
|
||||
|
||||
bool m_bLevelClosing;
|
||||
|
||||
QScopedPointer<Ui::TrackViewCurveEditor> m_ui;
|
||||
};
|
||||
|
||||
class TrackViewCurveEditorDialog
|
||||
: public QWidget
|
||||
, public ITrackViewSequenceListener
|
||||
, public IAnimationContextListener
|
||||
{
|
||||
public:
|
||||
TrackViewCurveEditorDialog(QWidget* parent);
|
||||
virtual ~TrackViewCurveEditorDialog() {}
|
||||
|
||||
void SetPlayCallback(const std::function<void()>& callback) { m_widget->SetPlayCallback(callback); }
|
||||
|
||||
void SetEditLock(bool bLock) { m_widget->SetEditLock(bLock); }
|
||||
|
||||
CTrackViewSplineCtrl& GetSplineCtrl(){ return m_widget->GetSplineCtrl(); }
|
||||
|
||||
void SetFPS(float fps) { m_widget->SetFPS(fps); }
|
||||
float GetFPS() const { return m_widget->GetFPS(); }
|
||||
void SetTickDisplayMode(ETVTickMode mode) { m_widget->SetTickDisplayMode(mode); }
|
||||
|
||||
virtual void OnSequenceChanged(CTrackViewSequence* pNewSequence) { m_widget->OnSequenceChanged(pNewSequence); }
|
||||
virtual void OnTimeChanged(float newTime) { m_widget->OnTimeChanged(newTime); }
|
||||
|
||||
// ITrackViewSequenceListener delegation to m_widget
|
||||
void OnKeysChanged(CTrackViewSequence* pSequence) override { m_widget->OnKeysChanged(pSequence); }
|
||||
void OnKeyAdded(CTrackViewKeyHandle& addedKeyHandle) override { m_widget->OnKeyAdded(addedKeyHandle); }
|
||||
void OnKeySelectionChanged(CTrackViewSequence* pSequence) override { m_widget->OnKeySelectionChanged(pSequence); }
|
||||
void OnNodeChanged(CTrackViewNode* pNode, ENodeChangeType type) override { m_widget->OnNodeChanged(pNode, type); }
|
||||
void OnNodeSelectionChanged(CTrackViewSequence* pSequence) override { m_widget->OnNodeSelectionChanged(pSequence); }
|
||||
void OnSequenceSettingsChanged(CTrackViewSequence* pSequence) override { m_widget->OnSequenceSettingsChanged(pSequence); }
|
||||
//~ITrackViewSequenceListener
|
||||
|
||||
private:
|
||||
CTrackViewCurveEditor* m_widget;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWCURVEEDITOR_H
|
||||
@@ -0,0 +1,431 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TrackViewCurveEditor</class>
|
||||
<widget class="QWidget" name="TrackViewCurveEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>588</width>
|
||||
<height>285</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="CTrackViewSplineCtrl" name="m_wndSpline" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonTangentAuto">
|
||||
<property name="toolTip">
|
||||
<string>Set In/Out Tangents to Auto</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_00.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_00.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonTangentInZero">
|
||||
<property name="toolTip">
|
||||
<string>Set In Tangent to Zero</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_01.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_01.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonTangentInStep">
|
||||
<property name="toolTip">
|
||||
<string>Set In Tangent to Step</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_02.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_02.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonTangentInLinear">
|
||||
<property name="toolTip">
|
||||
<string>Set In Tangent to Linear</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_03.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_03.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonTangentOutZero">
|
||||
<property name="toolTip">
|
||||
<string>Set Out Tangent to Zero</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_04.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_04.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonTangentOutStep">
|
||||
<property name="toolTip">
|
||||
<string>Set Out Tangent to Step</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_05.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_05.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonTangentOutLinear">
|
||||
<property name="toolTip">
|
||||
<string>Set Out Tangent to Linear</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_06.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_06.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonSplineFitX">
|
||||
<property name="toolTip">
|
||||
<string>Fit splines to the visible width</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_07.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_07.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonSplineFitY">
|
||||
<property name="toolTip">
|
||||
<string>Fit splines to the visible height</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_08.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_08.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_4">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonSplineSnapGridX">
|
||||
<property name="toolTip">
|
||||
<string>Snap to time grid</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_09.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_09.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonSplineSnapGridY">
|
||||
<property name="toolTip">
|
||||
<string>Snap to value grid</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_10.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_10.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_5">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonTangentUnify">
|
||||
<property name="toolTip">
|
||||
<string>Unify/Break Tangent Handles</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_11.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_11.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_6">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonFreezeKeys">
|
||||
<property name="toolTip">
|
||||
<string>Freeze/Unfreeze all keys</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_12.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_12.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonFreezeTangents">
|
||||
<property name="toolTip">
|
||||
<string>Freeze/Unfreeze all tangent handles</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="TrackViewDialog.qrc">
|
||||
<normaloff>:/TrackViewCurveEditor/spline_edit_bar_13.png</normaloff>:/TrackViewCurveEditor/spline_edit_bar_13.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CTrackViewSplineCtrl</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>TrackView/TrackViewSplineCtrl.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="TrackViewDialog.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : CTrackViewDialog Implementation file.
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWDIALOG_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWDIALOG_H
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "IMovieSystem.h"
|
||||
|
||||
#include "TrackViewNodes.h"
|
||||
#include "TrackViewDopeSheetBase.h"
|
||||
#include "TrackViewCurveEditor.h"
|
||||
#include "TrackViewKeyPropertiesDlg.h"
|
||||
#include "TrackViewSequence.h"
|
||||
#include "TrackViewSequenceManager.h"
|
||||
#include "AnimationContext.h"
|
||||
|
||||
#include <AzCore/Component/EntityBus.h>
|
||||
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
||||
|
||||
#include <QMainWindow>
|
||||
#endif
|
||||
|
||||
class QSplitter;
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
|
||||
class CMovieCallback;
|
||||
class CTrackViewFindDlg;
|
||||
|
||||
class CTrackViewDialog
|
||||
: public QMainWindow
|
||||
, public IAnimationContextListener
|
||||
, public IEditorNotifyListener
|
||||
, public ITrackViewSequenceListener
|
||||
, public ITrackViewSequenceManagerListener
|
||||
, public AZ::EntitySystemBus::Handler
|
||||
, private AzToolsFramework::ToolsApplicationNotificationBus::Handler
|
||||
, IUndoManagerListener
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
friend CMovieCallback;
|
||||
|
||||
CTrackViewDialog(QWidget* pParent = NULL);
|
||||
~CTrackViewDialog();
|
||||
|
||||
static void RegisterViewClass();
|
||||
static const GUID& GetClassID();
|
||||
|
||||
static CTrackViewDialog* GetCurrentInstance() { return s_pTrackViewDialog; }
|
||||
|
||||
void InvalidateDopeSheet();
|
||||
void Update();
|
||||
|
||||
void ReloadSequences();
|
||||
void InvalidateSequence();
|
||||
|
||||
void UpdateSequenceLockStatus();
|
||||
|
||||
// IAnimationContextListener
|
||||
virtual void OnSequenceChanged(CTrackViewSequence* pNewSequence) override;
|
||||
|
||||
// ITrackViewSequenceListener
|
||||
virtual void OnSequenceSettingsChanged(CTrackViewSequence* pSequence) override;
|
||||
|
||||
void UpdateDopeSheetTime(CTrackViewSequence* pSequence);
|
||||
|
||||
const CTrackViewDopeSheetBase& GetTrackViewDopeSheet() const { return *m_wndDopeSheet; }
|
||||
const AZStd::vector<AnimParamType>& GetDefaultTracksForEntityNode() const { return m_defaultTracksForEntityNode; }
|
||||
|
||||
bool IsDoingUndoOperation() const { return m_bDoingUndoOperation; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::EntitySystemBus
|
||||
void OnEntityDestruction(const AZ::EntityId& entityId) override;
|
||||
//~AZ::EntitySystemBus
|
||||
|
||||
public: // static functions
|
||||
|
||||
static QString GetEntityIdAsString(const AZ::EntityId& entityId) { return QString::number(static_cast<AZ::u64>(entityId)); }
|
||||
|
||||
protected slots:
|
||||
void OnGoToPrevKey();
|
||||
void OnGoToNextKey();
|
||||
void OnAddKey();
|
||||
void OnDelKey();
|
||||
void OnMoveKey();
|
||||
void OnSlideKey();
|
||||
void OnScaleKey();
|
||||
void OnSyncSelectedTracksToBase();
|
||||
void OnSyncSelectedTracksFromBase();
|
||||
void OnAddSequence();
|
||||
void OnExportFBXSequence();
|
||||
void OnExportNodeKeysGlobalTime();
|
||||
void OnDelSequence();
|
||||
void OnEditSequence();
|
||||
void OnSequenceComboBox();
|
||||
void OnAddSelectedNode();
|
||||
void OnAddDirectorNode();
|
||||
void OnFindNode();
|
||||
|
||||
void OnRecord();
|
||||
void OnAutoRecord();
|
||||
void OnAutoRecordStep();
|
||||
void OnGoToStart();
|
||||
void OnGoToEnd();
|
||||
void OnPlay();
|
||||
void OnPlaySetScale();
|
||||
void OnStop();
|
||||
void OnStopHardReset();
|
||||
void OnPause();
|
||||
void OnLoop();
|
||||
|
||||
void OnSnapNone();
|
||||
void OnSnapMagnet();
|
||||
void OnSnapFrame();
|
||||
void OnSnapTick();
|
||||
void OnSnapFPS();
|
||||
|
||||
void OnCustomizeTrackColors();
|
||||
|
||||
void OnBatchRender();
|
||||
|
||||
void OnModeDopeSheet();
|
||||
void OnModeCurveEditor();
|
||||
void OnOpenCurveEditor();
|
||||
|
||||
void OnViewTickInSeconds();
|
||||
void OnViewTickInFrames();
|
||||
|
||||
void OnTracksToolBar();
|
||||
void OnToggleDisable();
|
||||
void OnToggleMute();
|
||||
void OnMuteAll();
|
||||
void OnUnmuteAll();
|
||||
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
|
||||
#endif
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
private slots:
|
||||
void ReadLayouts();
|
||||
void FillAddSelectedEntityMenu();
|
||||
|
||||
private:
|
||||
|
||||
enum class ViewMode
|
||||
{
|
||||
TrackView = 1,
|
||||
CurveEditor = 2,
|
||||
Both = 3
|
||||
};
|
||||
|
||||
void setViewMode(ViewMode);
|
||||
void UpdateActions();
|
||||
void ReloadSequencesComboBox();
|
||||
|
||||
void UpdateTracksToolBar();
|
||||
void ClearTracksToolBar();
|
||||
void AddButtonToTracksToolBar(const CAnimParamType& paramId, const QIcon& hIcon, const QString& title);
|
||||
void SetNodeForTracksToolBar(CTrackViewAnimNode* pNode) { m_pNodeForTracksToolBar = pNode; }
|
||||
|
||||
void SetEditLock(bool bLock);
|
||||
void OnGameOrSimModeLock(bool lock);
|
||||
|
||||
void InitMenu();
|
||||
void InitToolbar();
|
||||
void InitSequences();
|
||||
void OnAddEntityNodeMenu();
|
||||
|
||||
void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
|
||||
BOOL OnInitDialog();
|
||||
|
||||
void SaveLayouts();
|
||||
void SaveMiscSettings() const;
|
||||
void ReadMiscSettings();
|
||||
void SaveTrackColors() const;
|
||||
void ReadTrackColors();
|
||||
|
||||
void SetCursorPosText(float fTime);
|
||||
|
||||
#if defined(AZ_PLATFORM_WINDOWS)
|
||||
bool processRawInput(MSG* pMsg);
|
||||
#endif
|
||||
|
||||
virtual void OnNodeSelectionChanged(CTrackViewSequence* pSequence) override;
|
||||
virtual void OnNodeRenamed(CTrackViewNode* pNode, const char* pOldName) override;
|
||||
|
||||
void OnSequenceAdded(CTrackViewSequence* pSequence) override;
|
||||
void OnSequenceRemoved(CTrackViewSequence* pSequence) override;
|
||||
|
||||
void AddSequenceListeners(CTrackViewSequence* sequence);
|
||||
void RemoveSequenceListeners(CTrackViewSequence* sequence);
|
||||
|
||||
void AddDialogListeners();
|
||||
void RemoveDialogListeners();
|
||||
|
||||
virtual void BeginUndoTransaction();
|
||||
virtual void EndUndoTransaction();
|
||||
void SaveCurrentSequenceToFBX();
|
||||
void SaveSequenceTimingToXML();
|
||||
|
||||
// ToolsApplicationNotificationBus ...
|
||||
void AfterEntitySelectionChanged(
|
||||
const AzToolsFramework::EntityIdList& newlySelectedEntities,
|
||||
const AzToolsFramework::EntityIdList& newlyDeselectedEntities) override;
|
||||
|
||||
// Instance
|
||||
static CTrackViewDialog* s_pTrackViewDialog;
|
||||
|
||||
// GUI
|
||||
QSplitter* m_wndSplitter;
|
||||
CTrackViewNodesCtrl* m_wndNodesCtrl;
|
||||
CTrackViewDopeSheetBase* m_wndDopeSheet;
|
||||
QDockWidget* m_wndCurveEditorDock;
|
||||
TrackViewCurveEditorDialog* m_wndCurveEditor;
|
||||
CTrackViewKeyPropertiesDlg* m_wndKeyProperties;
|
||||
CTrackViewFindDlg* m_findDlg;
|
||||
QToolBar* m_mainToolBar;
|
||||
QToolBar* m_keysToolBar;
|
||||
QToolBar* m_playToolBar;
|
||||
QToolBar* m_viewToolBar;
|
||||
QToolBar* m_tracksToolBar;
|
||||
QComboBox* m_sequencesComboBox;
|
||||
|
||||
QLabel* m_cursorPos;
|
||||
QLabel* m_activeCamStatic;
|
||||
|
||||
// CryMovie
|
||||
CMovieCallback* m_pMovieCallback;
|
||||
|
||||
// Current sequence
|
||||
AZ::EntityId m_currentSequenceEntityId;
|
||||
|
||||
// State
|
||||
bool m_bRecord;
|
||||
bool m_bAutoRecord;
|
||||
bool m_bPlay;
|
||||
bool m_bPause;
|
||||
bool m_bNeedReloadSequence;
|
||||
bool m_bIgnoreUpdates;
|
||||
bool m_bDoingUndoOperation;
|
||||
bool m_lazyInitDone;
|
||||
bool m_bEditLock;
|
||||
bool m_enteringGameOrSimModeLock = false;
|
||||
bool m_needReAddListeners = false;
|
||||
|
||||
float m_fLastTime;
|
||||
float m_fAutoRecordStep;
|
||||
|
||||
CTrackViewAnimNode* m_pNodeForTracksToolBar;
|
||||
|
||||
int m_currentToolBarParamTypeId;
|
||||
std::vector<CAnimParamType> m_toolBarParamTypes;
|
||||
|
||||
// Default tracks menu
|
||||
AZStd::vector<AnimParamType> m_defaultTracksForEntityNode;
|
||||
|
||||
QHash<int, QAction*> m_actions;
|
||||
ViewMode m_lastMode = ViewMode::TrackView;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWDIALOG_H
|
||||
@@ -0,0 +1,110 @@
|
||||
<RCC>
|
||||
<qresource prefix="/nodes">
|
||||
<file>tvnodes-00.png</file>
|
||||
<file>tvnodes-01.png</file>
|
||||
<file>tvnodes-02.png</file>
|
||||
<file>tvnodes-03.png</file>
|
||||
<file>tvnodes-04.png</file>
|
||||
<file>tvnodes-05.png</file>
|
||||
<file>tvnodes-06.png</file>
|
||||
<file>tvnodes-07.png</file>
|
||||
<file>tvnodes-08.png</file>
|
||||
<file>tvnodes-09.png</file>
|
||||
<file>tvnodes-10.png</file>
|
||||
<file>tvnodes-11.png</file>
|
||||
<file>tvnodes-12.png</file>
|
||||
<file>tvnodes-13.png</file>
|
||||
<file>tvnodes-14.png</file>
|
||||
<file>tvnodes-15.png</file>
|
||||
<file>tvnodes-16.png</file>
|
||||
<file>tvnodes-17.png</file>
|
||||
<file>tvnodes-18.png</file>
|
||||
<file>tvnodes-19.png</file>
|
||||
<file>tvnodes-20.png</file>
|
||||
<file>tvnodes-21.png</file>
|
||||
<file>tvnodes-22.png</file>
|
||||
<file>tvnodes-23.png</file>
|
||||
<file>tvnodes-24.png</file>
|
||||
<file>tvnodes-25.png</file>
|
||||
<file>tvnodes-26.png</file>
|
||||
<file>tvnodes-27.png</file>
|
||||
<file>tvnodes-28.png</file>
|
||||
<file>tvnodes-29.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/Trackview/main">
|
||||
<file>tvmain-00.png</file>
|
||||
<file>tvmain-01.png</file>
|
||||
<file>tvmain-02.png</file>
|
||||
<file>tvmain-03.png</file>
|
||||
<file>tvmain-04.png</file>
|
||||
<file>tvmain-05.png</file>
|
||||
<file>tvmain-06.png</file>
|
||||
<file>tvmain-07.png</file>
|
||||
<file>tvmain-08.png</file>
|
||||
<file>tvmain-09.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/Trackview/view">
|
||||
<file>tvview-00.png</file>
|
||||
<file>tvview-01.png</file>
|
||||
<file>tvview-02.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/Trackview/play">
|
||||
<file>tvplay-00.png</file>
|
||||
<file>tvplay-01.png</file>
|
||||
<file>tvplay-02.png</file>
|
||||
<file>tvplay-03.png</file>
|
||||
<file>tvplay-04.png</file>
|
||||
<file>tvplay-05.png</file>
|
||||
<file>tvplay-06.png</file>
|
||||
<file>tvplay-07.png</file>
|
||||
<file>tvplay-08.png</file>
|
||||
<file>tvplay-09.png</file>
|
||||
<file>tvplay-10.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/Trackview/keys">
|
||||
<file>tvkeys-00.png</file>
|
||||
<file>tvkeys-01.png</file>
|
||||
<file>tvkeys-02.png</file>
|
||||
<file>tvkeys-03.png</file>
|
||||
<file>tvkeys-04.png</file>
|
||||
<file>tvkeys-05.png</file>
|
||||
<file>tvkeys-06.png</file>
|
||||
<file>tvkeys-07.png</file>
|
||||
<file>tvkeys-08.png</file>
|
||||
<file>tvkeys-09.png</file>
|
||||
<file>tvkeys-10.png</file>
|
||||
<file>tvkeys-11.png</file>
|
||||
<file>tvkeys-12.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/Trackview/marker">
|
||||
<file>bmp00016_00.png</file>
|
||||
<file>bmp00016_01.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/Trackview">
|
||||
<file>trackview_keys_00.png</file>
|
||||
<file>trackview_keys_01.png</file>
|
||||
<file>trackview_keys_02.png</file>
|
||||
<file>trackview_keys_03.png</file>
|
||||
<file>clapperboard_cancel.png</file>
|
||||
<file>clapperboard_ready.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/TrackViewCurveEditor">
|
||||
<file>spline_edit_bar_00.png</file>
|
||||
<file>spline_edit_bar_01.png</file>
|
||||
<file>spline_edit_bar_02.png</file>
|
||||
<file>spline_edit_bar_03.png</file>
|
||||
<file>spline_edit_bar_04.png</file>
|
||||
<file>spline_edit_bar_05.png</file>
|
||||
<file>spline_edit_bar_06.png</file>
|
||||
<file>spline_edit_bar_07.png</file>
|
||||
<file>spline_edit_bar_08.png</file>
|
||||
<file>spline_edit_bar_09.png</file>
|
||||
<file>spline_edit_bar_10.png</file>
|
||||
<file>spline_edit_bar_11.png</file>
|
||||
<file>spline_edit_bar_12.png</file>
|
||||
<file>spline_edit_bar_13.png</file>
|
||||
<file>spline_edit_bar_14.png</file>
|
||||
<file>spline_edit_bar_15.png</file>
|
||||
<file>spline_edit_bar_16.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWDOPESHEETBASE_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWDOPESHEETBASE_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <IMovieSystem.h>
|
||||
#include "TrackViewNode.h"
|
||||
#include "TrackViewSequence.h"
|
||||
#include "AnimationContext.h"
|
||||
#include <QWidget>
|
||||
|
||||
class CTVTrackPropsDialog;
|
||||
class CTrackViewNodesCtrl;
|
||||
class CTrackViewKeyPropertiesDlg;
|
||||
class CTrackViewNode;
|
||||
class CTrackViewTrack;
|
||||
class CTrackViewAnimNode;
|
||||
|
||||
class QRubberBand;
|
||||
class QScrollBar;
|
||||
class ReflectedPropertyControl;
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
class Color;
|
||||
}
|
||||
|
||||
enum ETVActionMode
|
||||
{
|
||||
eTVActionMode_MoveKey = 1,
|
||||
eTVActionMode_AddKeys,
|
||||
eTVActionMode_SlideKey,
|
||||
eTVActionMode_ScaleKey,
|
||||
};
|
||||
|
||||
enum ESnappingMode
|
||||
{
|
||||
eSnappingMode_SnapNone = 0,
|
||||
eSnappingMode_SnapTick,
|
||||
eSnappingMode_SnapMagnet,
|
||||
eSnappingMode_SnapFrame,
|
||||
};
|
||||
|
||||
enum ETVTickMode
|
||||
{
|
||||
eTVTickMode_InSeconds = 0,
|
||||
eTVTickMode_InFrames,
|
||||
};
|
||||
|
||||
/** TrackView DopeSheet interface
|
||||
*/
|
||||
class CTrackViewDopeSheetBase
|
||||
: public QWidget
|
||||
, public IAnimationContextListener
|
||||
, public ITrackViewSequenceListener
|
||||
{
|
||||
public:
|
||||
CTrackViewDopeSheetBase(QWidget* parent = 0);
|
||||
virtual ~CTrackViewDopeSheetBase();
|
||||
|
||||
void SetNodesCtrl(CTrackViewNodesCtrl* pNodesCtrl) { m_pNodesCtrl = pNodesCtrl; }
|
||||
|
||||
void SetTimeScale(float timeScale, float fAnchorTime);
|
||||
float GetTimeScale() { return m_timeScale; }
|
||||
|
||||
void SetScrollOffset(int hpos);
|
||||
|
||||
int GetScrollPos() const;
|
||||
|
||||
void SetTimeRange(float start, float end);
|
||||
void SetStartMarker(float fTime);
|
||||
void SetEndMarker(float fTime);
|
||||
|
||||
void SetMouseActionMode(ETVActionMode mode);
|
||||
|
||||
void SetKeyPropertiesDlg(CTrackViewKeyPropertiesDlg* dlg) { m_keyPropertiesDlg = dlg; }
|
||||
|
||||
void SetSnappingMode(ESnappingMode mode) { m_snappingMode = mode; }
|
||||
ESnappingMode GetSnappingMode() const { return m_snappingMode; }
|
||||
void SetSnapFPS(UINT fps);
|
||||
|
||||
ETVTickMode GetTickDisplayMode() const { return m_tickDisplayMode; }
|
||||
void SetTickDisplayMode(ETVTickMode mode);
|
||||
|
||||
void SetEditLock(bool bLock) { m_bEditLock = bLock; }
|
||||
|
||||
// IAnimationContextListener
|
||||
virtual void OnTimeChanged(float newTime) override;
|
||||
|
||||
float TickSnap(float time) const;
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event) override;
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||
|
||||
private:
|
||||
void OnHScroll();
|
||||
void OnLButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point);
|
||||
void OnLButtonDblClk(Qt::KeyboardModifiers modifiers, const QPoint& point);
|
||||
void OnRButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point);
|
||||
void OnLButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point);
|
||||
void OnMButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point);
|
||||
void OnMButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point);
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
bool event(QEvent* event) override;
|
||||
void OnRButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point);
|
||||
void OnCaptureChanged();
|
||||
|
||||
private slots:
|
||||
void OnCurrentColorChange(const AZ::Color& color);
|
||||
|
||||
private:
|
||||
void UpdateColorKey(const QColor& color, bool addToUndo);
|
||||
void UpdateColorKeyHelper(const ColorF& color);
|
||||
void AddKeys(const QPoint& point, const bool bTryAddKeysInGroup);
|
||||
|
||||
void ShowKeyPropertyCtrlOnSpot(int x, int y, bool bMultipleKeysSelected, bool bKeyChangeInSameTrack);
|
||||
void HideKeyPropertyCtrlOnSpot();
|
||||
|
||||
// Utility functions to change the selected track(s) in the given track(s)
|
||||
void ChangeSequenceTrackSelection(CTrackViewSequence* sequence, CTrackViewTrack* trackToSelect) const;
|
||||
void ChangeSequenceTrackSelection(CTrackViewSequence* sequence, CTrackViewTrackBundle trackBundle, bool multiTrackSelection) const;
|
||||
|
||||
XmlNodeRef GetKeysInClickboard();
|
||||
void StartPasteKeys();
|
||||
|
||||
CTrackViewKeyHandle FirstKeyFromPoint(const QPoint& point);
|
||||
CTrackViewKeyHandle DurationKeyFromPoint(const QPoint& point);
|
||||
CTrackViewKeyHandle CheckCursorOnStartEndTimeAdjustBar(const QPoint& point, bool& bStart);
|
||||
|
||||
void SelectKeys(const QRect& rc, const bool bMultiSelection);
|
||||
|
||||
int NumKeysFromPoint(const QPoint& point);
|
||||
|
||||
//! Select all keys within time frame defined by this client rectangle.
|
||||
void SelectAllKeysWithinTimeFrame(const QRect& rc, const bool bMultiSelection);
|
||||
|
||||
//! Return time snapped to time step,
|
||||
double GetTickTime() const;
|
||||
float MagnetSnap(float time, const CTrackViewAnimNode* pNode) const;
|
||||
float FrameSnap(float time) const;
|
||||
|
||||
//! Return move time offset snapped with current snap settings
|
||||
float ComputeSnappedMoveOffset();
|
||||
|
||||
//! Returns visible time range.
|
||||
Range GetVisibleRange() const;
|
||||
Range GetTimeRange(const QRect& rc) const;
|
||||
|
||||
void SetHorizontalExtent(int min, int max);
|
||||
|
||||
void SetCurrTime(float time);
|
||||
|
||||
//! Return client position for given time.
|
||||
int TimeToClient(float time) const;
|
||||
|
||||
float TimeFromPoint(const QPoint& point) const;
|
||||
float TimeFromPointUnsnapped(const QPoint& point) const;
|
||||
|
||||
void SetLeftOffset(int ofs) { m_leftOffset = ofs; };
|
||||
|
||||
void SetMouseCursor(const QCursor& cursor);
|
||||
|
||||
void ShowKeyTooltip(CTrackViewKeyHandle& keyHandle, const QPoint& point);
|
||||
|
||||
bool IsOkToAddKeyHere(const CTrackViewTrack* pTrack, float time) const;
|
||||
|
||||
void MouseMoveSelect(const QPoint& point);
|
||||
void MouseMoveMove(const QPoint& point, Qt::KeyboardModifiers modifiers);
|
||||
|
||||
void MouseMoveDragTime(const QPoint& point, Qt::KeyboardModifiers modifiers);
|
||||
void MouseMoveOver(const QPoint& point);
|
||||
void MouseMoveDragEndMarker(const QPoint& point, Qt::KeyboardModifiers modifiers);
|
||||
|
||||
void CancelDrag();
|
||||
|
||||
float SnapTime(Qt::KeyboardModifiers modifiers, const QPoint& p);
|
||||
|
||||
void MouseMoveDragStartMarker(const QPoint& point, Qt::KeyboardModifiers modifiers);
|
||||
void MouseMoveStartEndTimeAdjust(const QPoint& point, bool bStart);
|
||||
|
||||
CTrackViewNode* GetNodeFromPointRec(CTrackViewNode* pCurrentNode, const QPoint& point);
|
||||
CTrackViewNode* GetNodeFromPoint(const QPoint& point);
|
||||
CTrackViewAnimNode* GetAnimNodeFromPoint(const QPoint& point);
|
||||
CTrackViewTrack* GetTrackFromPoint(const QPoint& point);
|
||||
|
||||
void LButtonDownOnTimeAdjustBar(const QPoint& point, CTrackViewKeyHandle& keyHandle, bool bStart);
|
||||
void LButtonDownOnKey(const QPoint& point, CTrackViewKeyHandle& keyHandle, Qt::KeyboardModifiers modifiers);
|
||||
|
||||
bool CreateColorKey(CTrackViewTrack* pTrack, float keyTime);
|
||||
void EditSelectedColorKey(CTrackViewTrack* pTrack);
|
||||
|
||||
void AcceptUndo();
|
||||
|
||||
// Returns the snapping mode modified active keys
|
||||
ESnappingMode GetKeyModifiedSnappingMode();
|
||||
|
||||
QRect GetNodeRect(const CTrackViewNode* pNode) const;
|
||||
|
||||
void StoreMementoForTracksWithSelectedKeys();
|
||||
|
||||
// Drawing methods.
|
||||
void DrawControl(QPainter* pDC, const QRect& rcUpdate);
|
||||
void DrawNodesRecursive(CTrackViewNode* pNode, QPainter* pDC, const QRect& rcUpdate);
|
||||
void DrawTimeline(QPainter* pDC, const QRect& rcUpdate);
|
||||
void DrawSummary(QPainter* pDC, const QRect& rcUpdate);
|
||||
void DrawSelectedKeyIndicators(QPainter* pDC);
|
||||
void DrawTicks(QPainter* pDC, const QRect& rc, Range& timeRange);
|
||||
void DrawNodeTrack(CTrackViewAnimNode* pAnimNode, QPainter* pDC, const QRect& trackRect);
|
||||
void DrawTrack(CTrackViewTrack* pTrack, QPainter* pDC, const QRect& trackRect);
|
||||
void DrawKeys(CTrackViewTrack* pTrack, QPainter* pDC, QRect& rc, Range& timeRange);
|
||||
void DrawSequenceTrack(const Range& timeRange, QPainter* pDC, CTrackViewTrack* pTrack, const QRect& rc);
|
||||
void DrawBoolTrack(const Range& timeRange, QPainter* pDC, CTrackViewTrack* pTrack, const QRect& rc);
|
||||
void DrawSelectTrack(const Range& timeRange, QPainter* pDC, CTrackViewTrack* pTrack, const QRect& rc);
|
||||
void DrawKeyDuration(CTrackViewTrack* pTrack, QPainter* pDC, const QRect& rc, int keyIndex);
|
||||
void DrawGoToTrackArrow(CTrackViewTrack* pTrack, QPainter* pDC, const QRect& rc);
|
||||
void DrawColorGradient(QPainter* pDC, const QRect& rc, const CTrackViewTrack* pTrack);
|
||||
void DrawClipboardKeys(QPainter* pDC, const QRect& rc);
|
||||
void DrawTrackClipboardKeys(QPainter* pDC, CTrackViewTrack* pTrack, XmlNodeRef trackNode, const float timeOffset);
|
||||
|
||||
CTrackViewNodesCtrl* m_pNodesCtrl;
|
||||
void ComputeFrameSteps(const Range& VisRange);
|
||||
void DrawTimeLineInFrames(QPainter* dc, const QRect& rc, const QColor& lineCol, const QColor& textCol, double step);
|
||||
void DrawTimeLineInSeconds(QPainter* dc, const QRect& rc, const QColor& lineCol, const QColor& textCol, double step);
|
||||
|
||||
static bool CompareKeyHandleByTime(const CTrackViewKeyHandle &a, const CTrackViewKeyHandle &b);
|
||||
|
||||
QBrush m_bkgrBrush;
|
||||
QBrush m_bkgrBrushEmpty;
|
||||
QBrush m_selectedBrush;
|
||||
QBrush m_timeBkgBrush;
|
||||
QBrush m_timeHighlightBrush;
|
||||
QBrush m_visibilityBrush;
|
||||
QBrush m_selectTrackBrush;
|
||||
|
||||
QCursor m_currCursor;
|
||||
QCursor m_crsLeftRight;
|
||||
QCursor m_crsAddKey;
|
||||
QCursor m_crsCross;
|
||||
QCursor m_crsAdjustLR;
|
||||
|
||||
QRect m_rcClient;
|
||||
QPoint m_scrollOffset;
|
||||
QRect m_rcSelect;
|
||||
QRect m_rcTimeline;
|
||||
QRect m_rcSummary;
|
||||
|
||||
QPoint m_lastTooltipPos;
|
||||
QPoint m_mouseDownPos;
|
||||
QPoint m_mouseOverPos;
|
||||
|
||||
QPixmap m_offscreenBitmap;
|
||||
|
||||
QRubberBand* m_rubberBand;
|
||||
QScrollBar* m_scrollBar;
|
||||
|
||||
// Time
|
||||
float m_timeScale;
|
||||
float m_currentTime;
|
||||
float m_storedTime;
|
||||
Range m_timeRange;
|
||||
Range m_timeMarked;
|
||||
|
||||
// This is how often to place ticks.
|
||||
// value of 10 means place ticks every 10 second.
|
||||
double m_ticksStep;
|
||||
|
||||
CTrackViewKeyPropertiesDlg* m_keyPropertiesDlg;
|
||||
ReflectedPropertyControl* m_wndPropsOnSpot;
|
||||
const CTrackViewTrack* m_pLastTrackSelectedOnSpot;
|
||||
|
||||
QFont m_descriptionFont;
|
||||
|
||||
// Mouse interaction state
|
||||
int m_mouseMode;
|
||||
int m_mouseActionMode;
|
||||
bool m_bZoomDrag;
|
||||
bool m_bMoveDrag;
|
||||
bool m_bCursorWasInKey;
|
||||
bool m_bJustSelected;
|
||||
bool m_bMouseMovedAfterRButtonDown;
|
||||
bool m_bKeysMoved;
|
||||
bool m_stashedRecordModeWhileTimeDragging;
|
||||
|
||||
// Offset for keys while moving/pasting
|
||||
float m_keyTimeOffset;
|
||||
|
||||
// If control is locked for editing
|
||||
bool m_bEditLock;
|
||||
|
||||
// Fast redraw: Only redraw time slider. Everything else is buffered.
|
||||
bool m_bFastRedraw;
|
||||
|
||||
// Scrolling
|
||||
int m_leftOffset;
|
||||
int m_scrollMin;
|
||||
int m_scrollMax;
|
||||
|
||||
// Snapping
|
||||
ESnappingMode m_snappingMode;
|
||||
float m_snapFrameTime;
|
||||
|
||||
// Ticks in frames or seconds
|
||||
ETVTickMode m_tickDisplayMode;
|
||||
double m_fFrameTickStep;
|
||||
double m_fFrameLabelStep;
|
||||
|
||||
// Key for time adjust
|
||||
CTrackViewKeyHandle m_keyForTimeAdjust;
|
||||
|
||||
// Cached clipboard XML for eTVMouseMode_Paste
|
||||
XmlNodeRef m_clipboardKeys;
|
||||
|
||||
// Store current track whose color is being updated
|
||||
CTrackViewTrack* m_colorUpdateTrack;
|
||||
|
||||
// Store the key time of that track
|
||||
float m_colorUpdateKeyTime;
|
||||
|
||||
// Mementos of unchanged tracks for Move/Scale/Slide etc.
|
||||
struct TrackMemento
|
||||
{
|
||||
CTrackViewTrackMemento m_memento;
|
||||
|
||||
// Also need to store key selection states,
|
||||
// because RestoreMemento will destroy them
|
||||
std::vector<bool> m_keySelectionStates;
|
||||
};
|
||||
|
||||
std::unordered_map<CTrackViewTrack*, TrackMemento> m_trackMementos;
|
||||
|
||||
#ifdef DEBUG
|
||||
unsigned int m_redrawCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWDOPESHEETBASE_H
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewDoubleSpinBox.h"
|
||||
|
||||
CTrackViewDoubleSpinBox::CTrackViewDoubleSpinBox(QWidget* parent)
|
||||
: AzQtComponents::DoubleSpinBox(parent)
|
||||
{
|
||||
}
|
||||
|
||||
CTrackViewDoubleSpinBox::~CTrackViewDoubleSpinBox()
|
||||
{
|
||||
}
|
||||
|
||||
void CTrackViewDoubleSpinBox::stepBy(int steps)
|
||||
{
|
||||
AzQtComponents::DoubleSpinBox::stepBy(steps);
|
||||
Q_EMIT stepByFinished();
|
||||
}
|
||||
|
||||
#include <TrackView/moc_TrackViewDoubleSpinBox.cpp>
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzQtComponents/Components/Widgets/SpinBox.h>
|
||||
#endif
|
||||
|
||||
class CTrackViewDoubleSpinBox
|
||||
: public AzQtComponents::DoubleSpinBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CTrackViewDoubleSpinBox(QWidget* parent = nullptr);
|
||||
~CTrackViewDoubleSpinBox() override;
|
||||
|
||||
protected:
|
||||
virtual void stepBy(int steps) override;
|
||||
|
||||
signals:
|
||||
void stepByFinished();
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewEventNode.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewEventNode::CTrackViewEventNode(IAnimSequence* pSequence, IAnimNode* pAnimNode, CTrackViewNode* pParentNode)
|
||||
: CTrackViewAnimNode(pSequence, pAnimNode, pParentNode)
|
||||
{
|
||||
if (GetAnimNode() && GetAnimNode()->GetSequence())
|
||||
{
|
||||
GetAnimNode()->GetSequence()->AddTrackEventListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewEventNode::~CTrackViewEventNode()
|
||||
{
|
||||
if (GetAnimNode() && GetAnimNode()->GetSequence())
|
||||
{
|
||||
GetAnimNode()->GetSequence()->RemoveTrackEventListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewEventNode::OnTrackEvent([[maybe_unused]] IAnimSequence* pSequence, int reason, const char* event, void* pUserData)
|
||||
{
|
||||
ITrackEventListener::ETrackEventReason eReason = static_cast<ITrackEventListener::ETrackEventReason>(reason);
|
||||
switch (eReason)
|
||||
{
|
||||
case ITrackEventListener::eTrackEventReason_Renamed:
|
||||
RenameTrackEvent(event, static_cast<const char*>(pUserData));
|
||||
break;
|
||||
case ITrackEventListener::eTrackEventReason_Removed:
|
||||
RemoveTrackEvent(event);
|
||||
default:
|
||||
// do nothing for events we're not interested in
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewEventNode::RenameTrackEvent(const char* fromName, const char* toName)
|
||||
{
|
||||
CTrackViewTrackBundle eventTracks = GetTracksByParam(AnimParamType::TrackEvent);
|
||||
const uint numEventTracks = eventTracks.GetCount();
|
||||
|
||||
for (uint i = 0; i < numEventTracks; ++i)
|
||||
{
|
||||
CTrackViewTrack* eventTrack = eventTracks.GetTrack(i);
|
||||
if (eventTrack)
|
||||
{
|
||||
// Go through all keys searching for match to the fromName and re-set these keys to use the toName
|
||||
CTrackViewKeyBundle allKeys = eventTrack->GetAllKeys();
|
||||
const uint numKeys = allKeys.GetKeyCount();
|
||||
for (uint k = 0; k < numKeys; ++k)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = allKeys.GetKey(k);
|
||||
IEventKey eventKey;
|
||||
|
||||
keyHandle.GetKey(&eventKey);
|
||||
if (strcmp(eventKey.event.c_str(), fromName) == 0)
|
||||
{
|
||||
// we have a match - re-set the eventKey with the toName
|
||||
eventKey.event = toName;
|
||||
keyHandle.SetKey(&eventKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewEventNode::RemoveTrackEvent(const char* removedEventName)
|
||||
{
|
||||
// rename the removedEventName keys to the empty string, which represents an unset event key
|
||||
RenameTrackEvent(removedEventName, "");
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWEVENTNODE_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWEVENTNODE_H
|
||||
#pragma once
|
||||
|
||||
#include "IMovieSystem.h"
|
||||
#include "TrackViewAnimNode.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// This class represents an IAnimNode deditcated to firing Track Events
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CTrackViewEventNode
|
||||
: public CTrackViewAnimNode
|
||||
, public ITrackEventListener
|
||||
{
|
||||
public:
|
||||
CTrackViewEventNode(IAnimSequence* pSequence, IAnimNode* pAnimNode, CTrackViewNode* pParentNode);
|
||||
virtual ~CTrackViewEventNode();
|
||||
|
||||
// overrides from ITrackEventListener
|
||||
void OnTrackEvent(IAnimSequence* pSequence, int reason, const char* event, void* pUserData) override;
|
||||
|
||||
protected:
|
||||
// updates existing keys using fromName events, changes them to use the toName events instead
|
||||
void RenameTrackEvent(const char* fromName, const char* toName);
|
||||
|
||||
// updates existing keys using removedEventName events to use the empty string (representing no event)
|
||||
void RemoveTrackEvent(const char* removedEventName);
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWEVENTNODE_H
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewFindDlg.h"
|
||||
|
||||
// Editor
|
||||
#include "TrackViewSequenceManager.h"
|
||||
#include "AnimationContext.h"
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
#include <TrackView/ui_TrackViewFindDlg.h>
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
#include "Maestro/Types/AnimNodeType.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CTrackViewFindDlg dialog
|
||||
|
||||
|
||||
CTrackViewFindDlg::CTrackViewFindDlg(const char* title, QWidget* pParent /*=NULL*/)
|
||||
: QDialog(pParent)
|
||||
, ui(new Ui::TrackViewFindDlg)
|
||||
{
|
||||
setWindowTitle(title);
|
||||
|
||||
m_tvDlg = 0;
|
||||
m_numSeqs = 0;
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->LIST->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
connect(ui->OK, &QPushButton::clicked, this, &CTrackViewFindDlg::OnOK);
|
||||
connect(ui->CANCEL, &QPushButton::clicked, this, &CTrackViewFindDlg::OnCancel);
|
||||
connect(ui->FILTER, &QLineEdit::textEdited, this, &CTrackViewFindDlg::OnFilterChange);
|
||||
connect(ui->LIST, &QListWidget::itemDoubleClicked, this, &CTrackViewFindDlg::OnItemDoubleClicked);
|
||||
|
||||
FillData();
|
||||
}
|
||||
|
||||
CTrackViewFindDlg::~CTrackViewFindDlg()
|
||||
{
|
||||
}
|
||||
|
||||
void CTrackViewFindDlg::FillData()
|
||||
{
|
||||
m_numSeqs = 0;
|
||||
m_objs.resize(0);
|
||||
for (int k = 0; k < GetIEditor()->GetMovieSystem()->GetNumSequences(); ++k)
|
||||
{
|
||||
IAnimSequence* seq = GetIEditor()->GetMovieSystem()->GetSequence(k);
|
||||
for (int i = 0; i < seq->GetNodeCount(); i++)
|
||||
{
|
||||
IAnimNode* pNode = seq->GetNode(i);
|
||||
ObjName obj;
|
||||
obj.m_objName = pNode->GetName();
|
||||
obj.m_directorName = pNode->HasDirectorAsParent() ? pNode->HasDirectorAsParent()->GetName() : "";
|
||||
string fullname = seq->GetName();
|
||||
obj.m_seqName = fullname.c_str();
|
||||
m_objs.push_back(obj);
|
||||
}
|
||||
m_numSeqs++;
|
||||
}
|
||||
FillList();
|
||||
}
|
||||
|
||||
|
||||
void CTrackViewFindDlg::Init(CTrackViewDialog* tvDlg)
|
||||
{
|
||||
m_tvDlg = tvDlg;
|
||||
}
|
||||
|
||||
void CTrackViewFindDlg::FillList()
|
||||
{
|
||||
QString filter = ui->FILTER->text();
|
||||
ui->LIST->clear();
|
||||
|
||||
for (int i = 0; i < m_objs.size(); i++)
|
||||
{
|
||||
ObjName pObj = m_objs[i];
|
||||
if (filter.isEmpty() || pObj.m_objName.contains(filter, Qt::CaseInsensitive))
|
||||
{
|
||||
QString text = pObj.m_objName;
|
||||
if (!pObj.m_directorName.isEmpty())
|
||||
{
|
||||
text += " (";
|
||||
text += pObj.m_directorName;
|
||||
text += ")";
|
||||
}
|
||||
if (m_numSeqs > 1)
|
||||
{
|
||||
text += " / ";
|
||||
text += pObj.m_seqName;
|
||||
}
|
||||
ui->LIST->addItem(text);
|
||||
}
|
||||
}
|
||||
ui->LIST->setCurrentRow(0);
|
||||
}
|
||||
|
||||
void CTrackViewFindDlg::OnOK()
|
||||
{
|
||||
ProcessSel();
|
||||
accept();
|
||||
}
|
||||
|
||||
void CTrackViewFindDlg::OnCancel()
|
||||
{
|
||||
reject();
|
||||
}
|
||||
|
||||
void CTrackViewFindDlg::OnFilterChange([[maybe_unused]] const QString& text)
|
||||
{
|
||||
FillList();
|
||||
}
|
||||
|
||||
void CTrackViewFindDlg::ProcessSel()
|
||||
{
|
||||
QList<QListWidgetItem*> selection = ui->LIST->selectedItems();
|
||||
|
||||
if (selection.size() != 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int index = ui->LIST->row(selection.first());
|
||||
|
||||
if (index >= 0 && m_tvDlg)
|
||||
{
|
||||
ObjName object = m_objs[index];
|
||||
|
||||
const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
|
||||
CTrackViewSequence* pSequence = pSequenceManager->GetSequenceByName(object.m_seqName);
|
||||
|
||||
if (pSequence)
|
||||
{
|
||||
CAnimationContext* pAnimationContext = GetIEditor()->GetAnimation();
|
||||
pAnimationContext->SetSequence(pSequence, false, false);
|
||||
|
||||
CTrackViewAnimNode* pParentDirector = pSequence;
|
||||
CTrackViewAnimNodeBundle foundDirectorNodes = pSequence->GetAnimNodesByName(object.m_directorName.toUtf8().data());
|
||||
if (foundDirectorNodes.GetCount() > 0 && foundDirectorNodes.GetNode(0)->GetType() == AnimNodeType::Director)
|
||||
{
|
||||
pParentDirector = foundDirectorNodes.GetNode(0);
|
||||
}
|
||||
|
||||
CTrackViewAnimNodeBundle foundNodes = pParentDirector->GetAnimNodesByName(object.m_objName.toUtf8().data());
|
||||
|
||||
const uint numNodes = foundNodes.GetCount();
|
||||
for (uint i = 0; i < numNodes; ++i)
|
||||
{
|
||||
foundNodes.GetNode(i)->SetSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTrackViewFindDlg::OnItemDoubleClicked()
|
||||
{
|
||||
ProcessSel();
|
||||
}
|
||||
|
||||
#include <TrackView/moc_TrackViewFindDlg.cpp>
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWFINDDLG_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWFINDDLG_H
|
||||
#pragma once
|
||||
|
||||
// TrackViewFindDlg.h : header file
|
||||
//
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QDialog>
|
||||
#include <QScopedPointer>
|
||||
#endif
|
||||
|
||||
class CTrackViewDialog;
|
||||
|
||||
namespace Ui {
|
||||
class TrackViewFindDlg;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// CTrackViewFindDlg dialog
|
||||
class CTrackViewFindDlg
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
// Construction
|
||||
public:
|
||||
CTrackViewFindDlg(const char* title = NULL, QWidget* pParent = NULL); // standard constructor
|
||||
~CTrackViewFindDlg();
|
||||
|
||||
//Functions
|
||||
void FillData();
|
||||
void FillList();
|
||||
void Init(CTrackViewDialog* tvDlg);
|
||||
void ProcessSel();
|
||||
|
||||
protected slots:
|
||||
void OnOK();
|
||||
void OnCancel();
|
||||
void OnFilterChange(const QString& text);
|
||||
void OnItemDoubleClicked();
|
||||
|
||||
protected:
|
||||
struct ObjName
|
||||
{
|
||||
QString m_objName;
|
||||
QString m_directorName;
|
||||
QString m_seqName;
|
||||
};
|
||||
|
||||
std::vector<ObjName> m_objs;
|
||||
CTrackViewDialog* m_tvDlg;
|
||||
|
||||
int m_numSeqs;
|
||||
|
||||
QScopedPointer<Ui::TrackViewFindDlg> ui;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWFINDDLG_H
|
||||
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TrackViewFindDlg</class>
|
||||
<widget class="QDialog" name="TrackViewFindDlg">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>312</width>
|
||||
<height>410</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="STATIC">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>11</y>
|
||||
<width>57</width>
|
||||
<height>13</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enter filter:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignTop|Qt::AlignLeft</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="FILTER">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>28</y>
|
||||
<width>291</width>
|
||||
<height>19</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="LIST">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>57</y>
|
||||
<width>291</width>
|
||||
<height>305</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>200</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="CANCEL">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>139</x>
|
||||
<y>376</y>
|
||||
<width>75</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="OK">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>226</x>
|
||||
<y>376</y>
|
||||
<width>75</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Find</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</ui>
|
||||
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewKeyPropertiesDlg.h"
|
||||
|
||||
// Qt
|
||||
#include <QMessageBox>
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimValueType.h>
|
||||
|
||||
// Editor
|
||||
#include "Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h"
|
||||
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
#include <TrackView/ui_TrackViewTrackPropsDlg.h>
|
||||
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyUIControls::OnInternalVariableChange(IVariable* var)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
AZ_Assert(sequence, "Expected valid sequence.");
|
||||
if (sequence)
|
||||
{
|
||||
CTrackViewKeyBundle keys = sequence->GetSelectedKeys();
|
||||
OnUIChange(var, keys);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyPropertiesDlg::CTrackViewKeyPropertiesDlg(QWidget* hParentWnd)
|
||||
: QWidget(hParentWnd)
|
||||
, m_pLastTrackSelected(nullptr)
|
||||
, m_sequence(nullptr)
|
||||
{
|
||||
QVBoxLayout* l = new QVBoxLayout();
|
||||
l->setMargin(0);
|
||||
m_wndTrackProps = new CTrackViewTrackPropsDlg(this);
|
||||
l->addWidget(m_wndTrackProps);
|
||||
m_wndProps = new ReflectedPropertyControl(this);
|
||||
m_wndProps->Setup(true, 120);
|
||||
m_wndProps->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
l->addWidget(m_wndProps);
|
||||
|
||||
m_wndProps->SetStoreUndoByItems(false);
|
||||
|
||||
setLayout(l);
|
||||
|
||||
m_pVarBlock = new CVarBlock;
|
||||
|
||||
// Add key UI classes
|
||||
std::vector<IClassDesc*> classes;
|
||||
GetIEditor()->GetClassFactory()->GetClassesByCategory("TrackViewKeyUI", classes); // BySystemID(ESYSTEM_CLASS_TRACKVIEW_KEYUI, classes);
|
||||
for (IClassDesc* iclass : classes)
|
||||
{
|
||||
if (QObject* pObj = iclass->CreateQObject())
|
||||
{
|
||||
auto keyControl = qobject_cast<CTrackViewKeyUIControls*>(pObj);
|
||||
Q_ASSERT(keyControl);
|
||||
m_keyControls.push_back(keyControl);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort key controls by descending priority
|
||||
std::stable_sort(m_keyControls.begin(), m_keyControls.end(),
|
||||
[](const _smart_ptr<CTrackViewKeyUIControls>& a, const _smart_ptr<CTrackViewKeyUIControls>& b)
|
||||
{
|
||||
return a->GetPriority() > b->GetPriority();
|
||||
}
|
||||
);
|
||||
|
||||
CreateAllVars();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyPropertiesDlg::OnVarChange(IVariable* pVar)
|
||||
{
|
||||
// If it was a motion that just changed, we need to rebuild the controls
|
||||
// so the min/max on the sliders update correctly.
|
||||
if (m_sequence && pVar->GetDataType() == IVariable::DT_MOTION)
|
||||
{
|
||||
OnKeySelectionChanged(m_sequence);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyPropertiesDlg::CreateAllVars()
|
||||
{
|
||||
for (int i = 0; i < (int)m_keyControls.size(); i++)
|
||||
{
|
||||
m_keyControls[i]->SetKeyPropertiesDlg(this);
|
||||
m_keyControls[i]->OnCreateVars();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyPropertiesDlg::PopulateVariables()
|
||||
{
|
||||
// Must first clear any selection in properties window.
|
||||
m_wndProps->RemoveAllItems();
|
||||
m_wndProps->AddVarBlock(m_pVarBlock);
|
||||
|
||||
m_wndProps->SetUpdateCallback(AZStd::bind(&CTrackViewKeyPropertiesDlg::OnVarChange, this, AZStd::placeholders::_1));
|
||||
//m_wndProps->m_props.ExpandAll();
|
||||
|
||||
|
||||
ReloadValues();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyPropertiesDlg::PopulateVariables(ReflectedPropertyControl* propCtrl)
|
||||
{
|
||||
propCtrl->RemoveAllItems();
|
||||
propCtrl->AddVarBlock(m_pVarBlock);
|
||||
|
||||
propCtrl->ReloadValues();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyPropertiesDlg::OnKeysChanged(CTrackViewSequence* pSequence)
|
||||
{
|
||||
CTrackViewKeyBundle selectedKeys = pSequence->GetSelectedKeys();
|
||||
|
||||
if (selectedKeys.GetKeyCount() > 0 && selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
CTrackViewTrack* pTrack = selectedKeys.GetKey(0).GetTrack();
|
||||
|
||||
CAnimParamType paramType = pTrack->GetParameterType();
|
||||
EAnimCurveType trackType = pTrack->GetCurveType();
|
||||
AnimValueType valueType = pTrack->GetValueType();
|
||||
|
||||
for (int i = 0; i < (int)m_keyControls.size(); i++)
|
||||
{
|
||||
if (m_keyControls[i]->SupportTrackType(paramType, trackType, valueType))
|
||||
{
|
||||
m_keyControls[i]->OnKeySelectionChange(selectedKeys);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyPropertiesDlg::OnKeySelectionChanged(CTrackViewSequence* sequence)
|
||||
{
|
||||
m_sequence = sequence;
|
||||
|
||||
if (nullptr == sequence)
|
||||
{
|
||||
m_wndProps->ClearSelection();
|
||||
m_pVarBlock->DeleteAllVariables();
|
||||
m_wndProps->setEnabled(false);
|
||||
m_wndTrackProps->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
CTrackViewKeyBundle selectedKeys = sequence->GetSelectedKeys();
|
||||
|
||||
m_wndTrackProps->OnKeySelectionChange(selectedKeys);
|
||||
|
||||
bool bSelectChangedInSameTrack
|
||||
= m_pLastTrackSelected
|
||||
&& selectedKeys.GetKeyCount() == 1
|
||||
&& selectedKeys.GetKey(0).GetTrack() == m_pLastTrackSelected;
|
||||
|
||||
// Every Key in an Asset Blend track can have different min/max values on the float sliders
|
||||
// because it's based on the duration of the motion that is set. So don't try to
|
||||
// reuse the controls when the selection changes, otherwise the tooltips may be wrong.
|
||||
bool reuseControls = bSelectChangedInSameTrack && m_pLastTrackSelected && (m_pLastTrackSelected->GetValueType() != AnimValueType::AssetBlend);
|
||||
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
m_pLastTrackSelected = selectedKeys.GetKey(0).GetTrack();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pLastTrackSelected = nullptr;
|
||||
}
|
||||
|
||||
if (reuseControls)
|
||||
{
|
||||
m_wndProps->ClearSelection();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pVarBlock->DeleteAllVariables();
|
||||
}
|
||||
|
||||
m_wndProps->setEnabled(false);
|
||||
m_wndTrackProps->setEnabled(false);
|
||||
bool bAssigned = false;
|
||||
if (selectedKeys.GetKeyCount() > 0 && selectedKeys.AreAllKeysOfSameType())
|
||||
{
|
||||
CTrackViewTrack* pTrack = selectedKeys.GetKey(0).GetTrack();
|
||||
|
||||
CAnimParamType paramType = pTrack->GetParameterType();
|
||||
EAnimCurveType trackType = pTrack->GetCurveType();
|
||||
AnimValueType valueType = pTrack->GetValueType();
|
||||
|
||||
for (int i = 0; i < (int)m_keyControls.size(); i++)
|
||||
{
|
||||
if (m_keyControls[i]->SupportTrackType(paramType, trackType, valueType))
|
||||
{
|
||||
if (!reuseControls)
|
||||
{
|
||||
AddVars(m_keyControls[i]);
|
||||
}
|
||||
|
||||
if (m_keyControls[i]->OnKeySelectionChange(selectedKeys))
|
||||
{
|
||||
bAssigned = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_wndProps->setEnabled(true);
|
||||
m_wndTrackProps->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_wndProps->setEnabled(false);
|
||||
m_wndTrackProps->setEnabled(false);
|
||||
}
|
||||
|
||||
if (reuseControls)
|
||||
{
|
||||
ReloadValues();
|
||||
}
|
||||
else
|
||||
{
|
||||
PopulateVariables();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyPropertiesDlg::AddVars(CTrackViewKeyUIControls* pUI)
|
||||
{
|
||||
CVarBlock* pVB = pUI->GetVarBlock();
|
||||
for (int i = 0, num = pVB->GetNumVariables(); i < num; i++)
|
||||
{
|
||||
IVariable* pVar = pVB->GetVariable(i);
|
||||
m_pVarBlock->AddVariable(pVar);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyPropertiesDlg::ReloadValues()
|
||||
{
|
||||
m_wndProps->ReloadValues();
|
||||
}
|
||||
|
||||
void CTrackViewKeyPropertiesDlg::OnSequenceChanged(CTrackViewSequence* sequence)
|
||||
{
|
||||
OnKeySelectionChanged(sequence);
|
||||
m_wndTrackProps->OnSequenceChanged();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewTrackPropsDlg::CTrackViewTrackPropsDlg(QWidget* parent /* = 0 */)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::CTrackViewTrackPropsDlg)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// Use editingFinished and a custom signal stepByFinished (and not valueChanged)
|
||||
// so the time will be updated when the user finishes editing the time field (hits enter)
|
||||
// or if the arrow keys (or mouse click on the arrow buttons) in the spinner box are
|
||||
// pressed. Don't just use valueChanged because we don't want intermediate values
|
||||
// like 1 as the user is typing 10 to register as updates to the key values. Keys
|
||||
// are identified by time, so the keys jumping around like that can stomp existing keys
|
||||
// that happen to live at the intermediate values.
|
||||
connect(ui->TIME, SIGNAL(editingFinished()), this, SLOT(OnUpdateTime()));
|
||||
connect(ui->TIME, SIGNAL(stepByFinished()), this, SLOT(OnUpdateTime()));
|
||||
}
|
||||
|
||||
CTrackViewTrackPropsDlg::~CTrackViewTrackPropsDlg()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrackPropsDlg::OnSequenceChanged()
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
|
||||
if (pSequence)
|
||||
{
|
||||
Range range = pSequence->GetTimeRange();
|
||||
ui->TIME->setRange(range.start, range.end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewTrackPropsDlg::OnKeySelectionChange(CTrackViewKeyBundle& selectedKeys)
|
||||
{
|
||||
m_keyHandle = CTrackViewKeyHandle();
|
||||
|
||||
if (selectedKeys.GetKeyCount() == 1)
|
||||
{
|
||||
m_keyHandle = selectedKeys.GetKey(0);
|
||||
}
|
||||
|
||||
if (m_keyHandle.IsValid())
|
||||
{
|
||||
// Block the callback, the values is already set in m_keyHandle.GetTime(), no need to
|
||||
// reset it and create an undo even like the user was setting it via the UI.
|
||||
ui->TIME->blockSignals(true);
|
||||
ui->TIME->setValue(m_keyHandle.GetTime());
|
||||
ui->TIME->blockSignals(false);
|
||||
ui->PREVNEXT->setText(QString::number(m_keyHandle.GetIndex() + 1));
|
||||
|
||||
ui->PREVNEXT->setEnabled(true);
|
||||
ui->TIME->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->PREVNEXT->setEnabled(FALSE);
|
||||
ui->TIME->setEnabled(FALSE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CTrackViewTrackPropsDlg::OnUpdateTime()
|
||||
{
|
||||
if (!m_keyHandle.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const float time = (float)ui->TIME->value();
|
||||
|
||||
// Check if the sequence is legacy
|
||||
CTrackViewTrack* track = m_keyHandle.GetTrack();
|
||||
if (nullptr != track)
|
||||
{
|
||||
CTrackViewSequence* sequence = track->GetSequence();
|
||||
if (nullptr != sequence && !AZ::IsClose(m_keyHandle.GetTime(), time, AZ::Constants::FloatEpsilon))
|
||||
{
|
||||
bool isDuringUndo = false;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::IsDuringUndoRedo);
|
||||
|
||||
if (isDuringUndo)
|
||||
{
|
||||
m_keyHandle.SetTime(time);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let the AZ Undo system manage the nodes on the sequence entity
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Change key time");
|
||||
|
||||
CTrackViewKeyHandle existingKey = track->GetKeyByTime(time);
|
||||
|
||||
// If there is an existing key at this time, remove it so the
|
||||
// new key at this time is the only one here. Make sure it's actually a different
|
||||
// key, because time can "change" but then be quantized (or snapped) to the same time by track->GetKeyByTime(time).
|
||||
if (existingKey.IsValid() && (existingKey.GetIndex() != m_keyHandle.GetIndex()))
|
||||
{
|
||||
// Save the old time before we set the new time so we
|
||||
// can reselect the m_keyHandle after the Delete.
|
||||
float currentTime = m_keyHandle.GetTime();
|
||||
|
||||
// There is a bug in QT where editingFinished will get fired a second time if we show a QMessageBox
|
||||
// so work around it by blocking signal before we do it.
|
||||
ui->TIME->blockSignals(true);
|
||||
|
||||
QString msgBody = "There is an existing key at the specified time. If you continue, the existing key will be removed.";
|
||||
if (QMessageBox::warning(this, "Overwrite Existing Key?", msgBody, QMessageBox::Cancel | QMessageBox::Yes) == QMessageBox::Cancel)
|
||||
{
|
||||
// Restore the old value and return.
|
||||
ui->TIME->setValue(currentTime);
|
||||
ui->TIME->blockSignals(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->TIME->blockSignals(false);
|
||||
}
|
||||
|
||||
// Delete the key that is able to get replaced. This will
|
||||
// cause a sort and may cause m_keyHandle to become invalid.
|
||||
existingKey.Delete();
|
||||
|
||||
// Reselect the key handle by time.
|
||||
m_keyHandle = track->GetKeyByTime(currentTime);
|
||||
}
|
||||
|
||||
m_keyHandle.SetTime(time);
|
||||
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <TrackView/moc_TrackViewKeyPropertiesDlg.cpp>
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWKEYPROPERTIESDLG_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWKEYPROPERTIESDLG_H
|
||||
#pragma once
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "TrackViewSequence.h"
|
||||
#include "TrackViewNode.h"
|
||||
#include "Plugin.h"
|
||||
#include "TrackViewDopeSheetBase.h"
|
||||
#include "QtViewPane.h"
|
||||
|
||||
#include <QScopedPointer>
|
||||
#include <QDockWidget>
|
||||
#endif
|
||||
|
||||
namespace Ui {
|
||||
class CTrackViewTrackPropsDlg;
|
||||
class CTrackViewKeyPropertiesDlg;
|
||||
}
|
||||
|
||||
class ReflectedPropertyControl;
|
||||
class CTrackViewKeyPropertiesDlg;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CTrackViewKeyUIControls
|
||||
: public QObject
|
||||
, public _i_reference_target_t
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CTrackViewKeyUIControls()
|
||||
{
|
||||
m_pVarBlock = new CVarBlock;
|
||||
m_onSetCallback = AZStd::bind(&CTrackViewKeyUIControls::OnInternalVariableChange, this, AZStd::placeholders::_1);
|
||||
};
|
||||
|
||||
void SetKeyPropertiesDlg(CTrackViewKeyPropertiesDlg* pDlg) { m_pKeyPropertiesDlg = pDlg; }
|
||||
|
||||
// Return internal variable block.
|
||||
CVarBlock* GetVarBlock() const { return m_pVarBlock; }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Callbacks that must be implemented in derived class
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Returns true if specified animation track type is supported by this UI.
|
||||
virtual bool SupportTrackType(const CAnimParamType& paramType, EAnimCurveType trackType, AnimValueType valueType) const = 0;
|
||||
|
||||
// Called when UI variable changes.
|
||||
virtual void OnCreateVars() = 0;
|
||||
|
||||
// Called when user changes selected keys.
|
||||
// Return true if control update UI values
|
||||
virtual bool OnKeySelectionChange(CTrackViewKeyBundle& keys) = 0;
|
||||
|
||||
// Called when UI variable changes.
|
||||
virtual void OnUIChange(IVariable* pVar, CTrackViewKeyBundle& keys) = 0;
|
||||
|
||||
// Get priority of key UI control, so that specializations can have precedence
|
||||
virtual unsigned int GetPriority() const = 0;
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Helper functions.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
template <class T>
|
||||
void SyncValue(CSmartVariable<T>& var, T& value, bool bCopyToUI, IVariable* pSrcVar = NULL)
|
||||
{
|
||||
if (bCopyToUI)
|
||||
{
|
||||
var = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pSrcVar || pSrcVar == var.GetVar())
|
||||
{
|
||||
value = var;
|
||||
}
|
||||
}
|
||||
}
|
||||
void AddVariable(CVariableBase& varArray, CVariableBase& var, const char* varName, unsigned char dataType = IVariable::DT_SIMPLE)
|
||||
{
|
||||
if (varName)
|
||||
{
|
||||
var.SetName(varName);
|
||||
}
|
||||
var.SetDataType(dataType);
|
||||
var.AddOnSetCallback(&m_onSetCallback);
|
||||
varArray.AddVariable(&var);
|
||||
m_registeredVariables.push_back(&var);
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void AddVariable(CVariableBase& var, const char* varName, unsigned char dataType = IVariable::DT_SIMPLE)
|
||||
{
|
||||
if (varName)
|
||||
{
|
||||
var.SetName(varName);
|
||||
}
|
||||
var.SetDataType(dataType);
|
||||
var.AddOnSetCallback(&m_onSetCallback);
|
||||
m_pVarBlock->AddVariable(&var);
|
||||
m_registeredVariables.push_back(&var);
|
||||
}
|
||||
void OnInternalVariableChange(IVariable* pVar);
|
||||
|
||||
protected:
|
||||
_smart_ptr<CVarBlock> m_pVarBlock;
|
||||
std::vector<_smart_ptr<IVariable> > m_registeredVariables;
|
||||
CTrackViewKeyPropertiesDlg* m_pKeyPropertiesDlg;
|
||||
IVariable::OnSetCallback m_onSetCallback;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CTrackViewTrackPropsDlg
|
||||
: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CTrackViewTrackPropsDlg(QWidget* parent = 0);
|
||||
~CTrackViewTrackPropsDlg();
|
||||
|
||||
void OnSequenceChanged();
|
||||
bool OnKeySelectionChange(CTrackViewKeyBundle& keys);
|
||||
void ReloadKey();
|
||||
|
||||
protected slots:
|
||||
void OnUpdateTime();
|
||||
|
||||
protected:
|
||||
CTrackViewKeyHandle m_keyHandle;
|
||||
QScopedPointer<Ui::CTrackViewTrackPropsDlg> ui;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class TrackViewKeys;
|
||||
class CTrackViewKeyPropertiesDlg
|
||||
: public QWidget
|
||||
, public ITrackViewSequenceListener
|
||||
{
|
||||
public:
|
||||
CTrackViewKeyPropertiesDlg(QWidget* hParentWnd);
|
||||
|
||||
void SetKeysCtrl(CTrackViewDopeSheetBase* pKeysCtrl)
|
||||
{
|
||||
m_keysCtrl = pKeysCtrl;
|
||||
if (m_keysCtrl)
|
||||
{
|
||||
m_keysCtrl->SetKeyPropertiesDlg(this);
|
||||
}
|
||||
}
|
||||
|
||||
void OnSequenceChanged(CTrackViewSequence* sequence);
|
||||
|
||||
void PopulateVariables();
|
||||
void PopulateVariables(ReflectedPropertyControl* propCtrl);
|
||||
|
||||
// ITrackViewSequenceListener
|
||||
virtual void OnKeysChanged(CTrackViewSequence* pSequence) override;
|
||||
virtual void OnKeySelectionChanged(CTrackViewSequence* pSequence) override;
|
||||
|
||||
protected:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void OnVarChange(IVariable* pVar);
|
||||
void CreateAllVars();
|
||||
void AddVars(CTrackViewKeyUIControls* pUI);
|
||||
void ReloadValues();
|
||||
|
||||
protected:
|
||||
std::vector< _smart_ptr<CTrackViewKeyUIControls> > m_keyControls;
|
||||
|
||||
_smart_ptr<CVarBlock> m_pVarBlock;
|
||||
|
||||
ReflectedPropertyControl* m_wndProps;
|
||||
CTrackViewTrackPropsDlg* m_wndTrackProps;
|
||||
|
||||
CTrackViewDopeSheetBase* m_keysCtrl;
|
||||
|
||||
CTrackViewTrack* m_pLastTrackSelected;
|
||||
CTrackViewSequence* m_sequence;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWKEYPROPERTIESDLG_H
|
||||
@@ -0,0 +1,713 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewNode.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimNodeType.h>
|
||||
|
||||
// Editor
|
||||
#include "TrackView/TrackViewTrack.h"
|
||||
#include "TrackView/TrackViewSequence.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyConstHandle::GetKey(IKey* pKey) const
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
m_pTrack->GetKey(m_keyIndex, pKey);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
float CTrackViewKeyConstHandle::GetTime() const
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
return m_pTrack->GetKeyTime(m_keyIndex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyHandle::SetKey(IKey* pKey)
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
m_pTrack->SetKey(m_keyIndex, pKey);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyHandle::GetKey(IKey* pKey) const
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
m_pTrack->GetKey(m_keyIndex, pKey);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyHandle::Select(bool bSelect)
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
m_pTrack->SelectKey(m_keyIndex, bSelect);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewKeyHandle::IsSelected() const
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
return m_pTrack->IsKeySelected(m_keyIndex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyHandle::SetTime(float time, bool notifyListeners)
|
||||
{
|
||||
AZ_Assert(m_bIsValid, "Expected a valid key handle.");
|
||||
|
||||
// Flag the current key, because the key handle may become invalid
|
||||
// after the time is set and it is potentially sorted into a different
|
||||
// index.
|
||||
m_pTrack->SetSortMarkerKey(m_keyIndex, true);
|
||||
|
||||
// set the new time, this may cause a sort that reorders the keys, making
|
||||
// m_keyIndex incorrect.
|
||||
m_pTrack->SetKeyTime(m_keyIndex, time, notifyListeners);
|
||||
|
||||
// If the key at this index changed because of the key sort by time.
|
||||
// We need to search through the keys now and find the marker.
|
||||
if (!m_pTrack->IsSortMarkerKey(m_keyIndex))
|
||||
{
|
||||
CTrackViewKeyBundle allKeys = m_pTrack->GetAllKeys();
|
||||
for (int x = 0; x < allKeys.GetKeyCount(); x++)
|
||||
{
|
||||
unsigned int curIndex = allKeys.GetKey(x).GetIndex();
|
||||
if (m_pTrack->IsSortMarkerKey(curIndex))
|
||||
{
|
||||
m_keyIndex = curIndex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clear the sort marker
|
||||
m_pTrack->SetSortMarkerKey(m_keyIndex, false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
float CTrackViewKeyHandle::GetTime() const
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
return m_pTrack->GetKeyTime(m_keyIndex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
float CTrackViewKeyHandle::GetDuration() const
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
const char* desc = nullptr;
|
||||
float duration = 0;
|
||||
m_pTrack->m_pAnimTrack->GetKeyInfo(m_keyIndex, desc, duration);
|
||||
|
||||
return duration;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
const char* CTrackViewKeyHandle::GetDescription() const
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
const char* desc = "";
|
||||
float duration = 0;
|
||||
m_pTrack->m_pAnimTrack->GetKeyInfo(m_keyIndex, desc, duration);
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyHandle::Offset(float offset, bool notifyListeners)
|
||||
{
|
||||
AZ_Assert(m_bIsValid, "Expected key handle to be in a valid state.");
|
||||
|
||||
float newTime = m_pTrack->GetKeyTime(m_keyIndex) + offset;
|
||||
m_pTrack->SetKeyTime(m_keyIndex, newTime, notifyListeners);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyHandle::Delete()
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
m_pTrack->RemoveKey(m_keyIndex);
|
||||
m_bIsValid = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewKeyHandle::Clone()
|
||||
{
|
||||
assert(m_bIsValid);
|
||||
|
||||
unsigned int newKeyIndex = m_pTrack->CloneKey(m_keyIndex);
|
||||
return CTrackViewKeyHandle(m_pTrack, newKeyIndex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewKeyHandle::GetNextKey()
|
||||
{
|
||||
return m_pTrack->GetNextKey(GetTime());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewKeyHandle::GetPrevKey()
|
||||
{
|
||||
return m_pTrack->GetPrevKey(GetTime());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewKeyHandle::GetAboveKey() const
|
||||
{
|
||||
// Search for track above that has keys
|
||||
for (CTrackViewNode* pCurrentNode = m_pTrack->GetAboveNode(); pCurrentNode; pCurrentNode = pCurrentNode->GetAboveNode())
|
||||
{
|
||||
if (pCurrentNode->GetNodeType() == eTVNT_Track)
|
||||
{
|
||||
CTrackViewTrack* pCurrentTrack = static_cast<CTrackViewTrack*>(pCurrentNode);
|
||||
const unsigned int keyCount = pCurrentTrack->GetKeyCount();
|
||||
if (keyCount > 0)
|
||||
{
|
||||
// Return key with nearest time to this key
|
||||
return pCurrentTrack->GetNearestKeyByTime(GetTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewKeyHandle::GetBelowKey() const
|
||||
{
|
||||
// Search for track below that has keys
|
||||
for (CTrackViewNode* pCurrentNode = m_pTrack->GetBelowNode(); pCurrentNode; pCurrentNode = pCurrentNode->GetBelowNode())
|
||||
{
|
||||
if (pCurrentNode->GetNodeType() == eTVNT_Track)
|
||||
{
|
||||
CTrackViewTrack* pCurrentTrack = static_cast<CTrackViewTrack*>(pCurrentNode);
|
||||
const unsigned int keyCount = pCurrentTrack->GetKeyCount();
|
||||
if (keyCount > 0)
|
||||
{
|
||||
// Return key with nearest time to this key
|
||||
return pCurrentTrack->GetNearestKeyByTime(GetTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewKeyHandle::operator==(const CTrackViewKeyHandle& keyHandle) const
|
||||
{
|
||||
return m_pTrack == keyHandle.m_pTrack && m_keyIndex == keyHandle.m_keyIndex;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewKeyHandle::operator!=(const CTrackViewKeyHandle& keyHandle) const
|
||||
{
|
||||
return !(*this == keyHandle);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyBundle::AppendKey(const CTrackViewKeyHandle& keyHandle)
|
||||
{
|
||||
// Check if newly added key has different type than existing ones
|
||||
if (m_bAllOfSameType && m_keys.size() > 0)
|
||||
{
|
||||
const CTrackViewKeyHandle& lastKey = m_keys.back();
|
||||
|
||||
const CTrackViewTrack* pMyTrack = keyHandle.GetTrack();
|
||||
const CTrackViewTrack* pOtherTrack = lastKey.GetTrack();
|
||||
|
||||
// Check if keys are from sub tracks, always compare types of parent track
|
||||
if (pMyTrack->IsSubTrack())
|
||||
{
|
||||
pMyTrack = static_cast<const CTrackViewTrack*>(pMyTrack->GetParentNode());
|
||||
}
|
||||
|
||||
if (pOtherTrack->IsSubTrack())
|
||||
{
|
||||
pOtherTrack = static_cast<const CTrackViewTrack*>(pOtherTrack->GetParentNode());
|
||||
}
|
||||
|
||||
// Do comparison
|
||||
if (pMyTrack->GetParameterType() != pOtherTrack->GetParameterType()
|
||||
|| pMyTrack->GetCurveType() != pOtherTrack->GetCurveType()
|
||||
|| pMyTrack->GetValueType() != pOtherTrack->GetValueType())
|
||||
{
|
||||
m_bAllOfSameType = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_keys.push_back(keyHandle);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyBundle::AppendKeyBundle(const CTrackViewKeyBundle& bundle)
|
||||
{
|
||||
for (auto iter = bundle.m_keys.begin(); iter != bundle.m_keys.end(); ++iter)
|
||||
{
|
||||
AppendKey(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewKeyBundle::SelectKeys(const bool bSelected)
|
||||
{
|
||||
const unsigned int numKeys = GetKeyCount();
|
||||
|
||||
for (unsigned int i = 0; i < numKeys; ++i)
|
||||
{
|
||||
GetKey(i).Select(bSelected);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewKeyBundle::GetSingleSelectedKey()
|
||||
{
|
||||
const unsigned int keyCount = GetKeyCount();
|
||||
|
||||
if (keyCount == 1)
|
||||
{
|
||||
return m_keys[0];
|
||||
}
|
||||
else if (keyCount > 1 && keyCount <= 4)
|
||||
{
|
||||
// All keys must have same time & same parent track
|
||||
CTrackViewNode* pFirstParent = m_keys[0].GetTrack()->GetParentNode();
|
||||
const float firstTime = m_keys[0].GetTime();
|
||||
|
||||
// Parent must be a track
|
||||
if (pFirstParent->GetNodeType() != eTVNT_Track)
|
||||
{
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
// Check other keys for equality
|
||||
for (unsigned int i = 0; i < keyCount; ++i)
|
||||
{
|
||||
if (m_keys[i].GetTrack()->GetParentNode() != pFirstParent || m_keys[i].GetTime() != firstTime)
|
||||
{
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<CTrackViewTrack*>(pFirstParent)->GetKeyByTime(firstTime);
|
||||
}
|
||||
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewNode::CTrackViewNode(CTrackViewNode* pParent)
|
||||
: m_pParentNode(pParent)
|
||||
, m_bSelected(false)
|
||||
, m_bHidden(false)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewNode::HasObsoleteTrack() const
|
||||
{
|
||||
return HasObsoleteTrackRec(this);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewNode::HasObsoleteTrackRec(const CTrackViewNode* pCurrentNode) const
|
||||
{
|
||||
if (pCurrentNode->GetNodeType() == eTVNT_Track)
|
||||
{
|
||||
const CTrackViewTrack* pTrack = static_cast<const CTrackViewTrack*>(pCurrentNode);
|
||||
|
||||
EAnimCurveType trackType = pTrack->GetCurveType();
|
||||
if (trackType == eAnimCurveType_TCBFloat || trackType == eAnimCurveType_TCBQuat || trackType == eAnimCurveType_TCBVector)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < pCurrentNode->GetChildCount(); ++i)
|
||||
{
|
||||
CTrackViewNode* pNode = pCurrentNode->GetChild(i);
|
||||
|
||||
if (HasObsoleteTrackRec(pNode))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewNode::ClearSelection()
|
||||
{
|
||||
CTrackViewSequenceNotificationContext context(GetSequence());
|
||||
|
||||
SetSelected(false);
|
||||
|
||||
const unsigned int numChilds = GetChildCount();
|
||||
for (unsigned int childIndex = 0; childIndex < numChilds; ++childIndex)
|
||||
{
|
||||
GetChild(childIndex)->ClearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewNode* CTrackViewNode::GetAboveNode() const
|
||||
{
|
||||
CTrackViewNode* pParent = GetParentNode();
|
||||
if (!pParent)
|
||||
{
|
||||
// The root does not have an above node
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CTrackViewNode* pPrevSibling = GetPrevSibling();
|
||||
if (!pPrevSibling)
|
||||
{
|
||||
// First sibling -> parent is above node
|
||||
return pParent;
|
||||
}
|
||||
|
||||
// Find last node in sibling tree
|
||||
CTrackViewNode* pCurrentNode = pPrevSibling;
|
||||
while (pCurrentNode && pCurrentNode->GetChildCount() > 0 && pCurrentNode->GetExpanded())
|
||||
{
|
||||
pCurrentNode = pCurrentNode->GetChild(pCurrentNode->GetChildCount() - 1);
|
||||
}
|
||||
|
||||
return pCurrentNode;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewNode* CTrackViewNode::GetBelowNode() const
|
||||
{
|
||||
const unsigned int childCount = GetChildCount();
|
||||
if (childCount > 0 && GetExpanded())
|
||||
{
|
||||
return GetChild(0);
|
||||
}
|
||||
|
||||
CTrackViewNode* pParent = GetParentNode();
|
||||
if (!pParent)
|
||||
{
|
||||
// Root without children
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If there is a next sibling return it
|
||||
CTrackViewNode* pNextSibling = GetNextSibling();
|
||||
if (pNextSibling)
|
||||
{
|
||||
return pNextSibling;
|
||||
}
|
||||
|
||||
// Otherwise we need to go up the tree and check
|
||||
// the parent nodes for next siblings
|
||||
CTrackViewNode* pCurrentNode = pParent;
|
||||
while (pCurrentNode)
|
||||
{
|
||||
CTrackViewNode* pNextParentSibling = pCurrentNode->GetNextSibling();
|
||||
if (pNextParentSibling)
|
||||
{
|
||||
return pNextParentSibling;
|
||||
}
|
||||
|
||||
pCurrentNode = pCurrentNode->GetParentNode();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewNode* CTrackViewNode::GetPrevSibling() const
|
||||
{
|
||||
CTrackViewNode* pParent = GetParentNode();
|
||||
if (!pParent)
|
||||
{
|
||||
// The root does not have siblings
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Search for prev sibling
|
||||
unsigned int siblingCount = pParent->GetChildCount();
|
||||
assert(siblingCount > 0);
|
||||
|
||||
for (unsigned int i = 1; i < siblingCount; ++i)
|
||||
{
|
||||
CTrackViewNode* pSibling = pParent->GetChild(i);
|
||||
if (pSibling == this)
|
||||
{
|
||||
return pParent->GetChild(i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewNode* CTrackViewNode::GetNextSibling() const
|
||||
{
|
||||
CTrackViewNode* pParent = GetParentNode();
|
||||
if (!pParent)
|
||||
{
|
||||
// The root does not have siblings
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Search for next sibling
|
||||
unsigned int siblingCount = pParent->GetChildCount();
|
||||
assert(siblingCount > 0);
|
||||
|
||||
for (unsigned int i = 0; i < siblingCount - 1; ++i)
|
||||
{
|
||||
CTrackViewNode* pSibling = pParent->GetChild(i);
|
||||
if (pSibling == this)
|
||||
{
|
||||
return pParent->GetChild(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewNode::SetSelected(bool bSelected)
|
||||
{
|
||||
if (bSelected != m_bSelected)
|
||||
{
|
||||
m_bSelected = bSelected;
|
||||
|
||||
if (m_bSelected)
|
||||
{
|
||||
GetSequence()->OnNodeChanged(this, ITrackViewSequenceListener::eNodeChangeType_Selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetSequence()->OnNodeChanged(this, ITrackViewSequenceListener::eNodeChangeType_Deselected);
|
||||
}
|
||||
|
||||
GetSequence()->OnNodeSelectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewSequence* CTrackViewNode::GetSequence()
|
||||
{
|
||||
for (CTrackViewNode* pCurrentNode = this; pCurrentNode; pCurrentNode = pCurrentNode->GetParentNode())
|
||||
{
|
||||
if (pCurrentNode->GetNodeType() == eTVNT_Sequence)
|
||||
{
|
||||
return static_cast<CTrackViewSequence*>(pCurrentNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Every node belongs to a sequence
|
||||
assert(false);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
const CTrackViewSequence* CTrackViewNode::GetSequenceConst() const
|
||||
{
|
||||
for (const CTrackViewNode* pCurrentNode = this; pCurrentNode; pCurrentNode = pCurrentNode->GetParentNode())
|
||||
{
|
||||
if (pCurrentNode->GetNodeType() == eTVNT_Sequence)
|
||||
{
|
||||
return static_cast<const CTrackViewSequence*>(pCurrentNode);
|
||||
}
|
||||
}
|
||||
|
||||
AZ_Assert(false, "Every node belongs to a sequence");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewNode::AddNode(CTrackViewNode* pNode)
|
||||
{
|
||||
assert (pNode->GetNodeType() != eTVNT_Sequence);
|
||||
|
||||
m_childNodes.push_back(std::unique_ptr<CTrackViewNode>(pNode));
|
||||
SortNodes();
|
||||
|
||||
pNode->m_pParentNode = this;
|
||||
GetSequence()->OnNodeChanged(pNode, ITrackViewSequenceListener::eNodeChangeType_Added);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewNode::SortNodes()
|
||||
{
|
||||
// Sort with operator<
|
||||
std::stable_sort(m_childNodes.begin(), m_childNodes.end(),
|
||||
[&](const std::unique_ptr<CTrackViewNode>& a, const std::unique_ptr<CTrackViewNode>& b) -> bool
|
||||
{
|
||||
const CTrackViewNode* pA = a.get();
|
||||
const CTrackViewNode* pB = b.get();
|
||||
return *pA < *pB;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
static int GetNodeOrder(AnimNodeType nodeType)
|
||||
{
|
||||
AZ_Assert(nodeType < AnimNodeType::Num, "Expected nodeType to be less than AnimNodeType::Num");
|
||||
|
||||
// note: this array gets over-allocated and is sparsely populated because the eAnimNodeType enums are not sequential in IMovieSystem.h
|
||||
// I wonder if the original authors intended this? Not a big deal, just some trivial memory wastage.
|
||||
static int nodeOrder[static_cast<int>(AnimNodeType::Num)];
|
||||
nodeOrder[static_cast<int>(AnimNodeType::Invalid)] = 0;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::Director)] = 1;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::Alembic)] = 4;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::CVar)] = 6;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::ScriptVar)] = 7;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::Material)] = 8;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::Event)] = 9;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::Layer)] = 10;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::Comment)] = 11;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::RadialBlur)] = 12;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::ColorCorrection)] = 13;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::DepthOfField)] = 14;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::ScreenFader)] = 15;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::Light)] = 16;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::ShadowSetup)] = 17;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::Environment)] = 18;
|
||||
nodeOrder[static_cast<int>(AnimNodeType::Group)] = 19;
|
||||
|
||||
return nodeOrder[static_cast<int>(nodeType)];
|
||||
}
|
||||
}
|
||||
|
||||
bool CTrackViewNode::operator<(const CTrackViewNode& otherNode) const
|
||||
{
|
||||
// Order nodes before tracks
|
||||
if (GetNodeType() < otherNode.GetNodeType())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (GetNodeType() > otherNode.GetNodeType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Same node type
|
||||
switch (GetNodeType())
|
||||
{
|
||||
case eTVNT_AnimNode:
|
||||
{
|
||||
const CTrackViewAnimNode& thisAnimNode = static_cast<const CTrackViewAnimNode&>(*this);
|
||||
const CTrackViewAnimNode& otherAnimNode = static_cast<const CTrackViewAnimNode&>(otherNode);
|
||||
|
||||
const int thisTypeOrder = GetNodeOrder(thisAnimNode.GetType());
|
||||
const int otherTypeOrder = GetNodeOrder(otherAnimNode.GetType());
|
||||
|
||||
if (thisTypeOrder == otherTypeOrder)
|
||||
{
|
||||
// Same node type, sort by name
|
||||
return azstricmp(thisAnimNode.GetName(), otherAnimNode.GetName()) < 0;
|
||||
}
|
||||
|
||||
return thisTypeOrder < otherTypeOrder;
|
||||
}
|
||||
case eTVNT_Track:
|
||||
const CTrackViewTrack& thisTrack = static_cast<const CTrackViewTrack&>(*this);
|
||||
const CTrackViewTrack& otherTrack = static_cast<const CTrackViewTrack&>(otherNode);
|
||||
|
||||
if (thisTrack.GetParameterType() == otherTrack.GetParameterType())
|
||||
{
|
||||
// Same parameter type, sort by name
|
||||
return azstricmp(thisTrack.GetName(), otherTrack.GetName()) < 0;
|
||||
}
|
||||
|
||||
return thisTrack.GetParameterType() < otherTrack.GetParameterType();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewNode::SetHidden(bool bHidden)
|
||||
{
|
||||
bool bWasHidden = m_bHidden;
|
||||
m_bHidden = bHidden;
|
||||
|
||||
if (bHidden && !bWasHidden)
|
||||
{
|
||||
GetSequence()->OnNodeChanged(this, ITrackViewSequenceListener::eNodeChangeType_Hidden);
|
||||
}
|
||||
else if (!bHidden && bWasHidden)
|
||||
{
|
||||
GetSequence()->OnNodeChanged(this, ITrackViewSequenceListener::eNodeChangeType_Unhidden);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewNode::IsHidden() const
|
||||
{
|
||||
return m_bHidden;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewNode* CTrackViewNode::GetFirstSelectedNode()
|
||||
{
|
||||
if (IsSelected())
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
const unsigned int numChilds = GetChildCount();
|
||||
for (unsigned int childIndex = 0; childIndex < numChilds; ++childIndex)
|
||||
{
|
||||
CTrackViewNode* pSelectedNode = GetChild(childIndex)->GetFirstSelectedNode();
|
||||
if (pSelectedNode)
|
||||
{
|
||||
return pSelectedNode;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewAnimNode* CTrackViewNode::GetDirector()
|
||||
{
|
||||
for (CTrackViewNode* pCurrentNode = GetParentNode(); pCurrentNode; pCurrentNode = pCurrentNode->GetParentNode())
|
||||
{
|
||||
if (pCurrentNode->GetNodeType() == eTVNT_AnimNode)
|
||||
{
|
||||
CTrackViewAnimNode* pParentAnimNode = static_cast<CTrackViewAnimNode*>(pCurrentNode);
|
||||
|
||||
if (pParentAnimNode->GetType() == AnimNodeType::Director)
|
||||
{
|
||||
return pParentAnimNode;
|
||||
}
|
||||
}
|
||||
else if (pCurrentNode->GetNodeType() == eTVNT_Sequence)
|
||||
{
|
||||
return static_cast<CTrackViewAnimNode*>(pCurrentNode);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWNODE_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWNODE_H
|
||||
#pragma once
|
||||
|
||||
|
||||
class CTrackViewTrack;
|
||||
class CTrackViewSequence;
|
||||
struct IKey;
|
||||
class CTrackViewAnimNode;
|
||||
|
||||
|
||||
class CTrackViewKeyConstHandle
|
||||
{
|
||||
public:
|
||||
CTrackViewKeyConstHandle()
|
||||
: m_bIsValid(false)
|
||||
, m_keyIndex(0)
|
||||
, m_pTrack(nullptr) {}
|
||||
|
||||
CTrackViewKeyConstHandle(const CTrackViewTrack* pTrack, unsigned int keyIndex)
|
||||
: m_bIsValid(true)
|
||||
, m_keyIndex(keyIndex)
|
||||
, m_pTrack(pTrack) {}
|
||||
|
||||
void GetKey(IKey* pKey) const;
|
||||
float GetTime() const;
|
||||
const CTrackViewTrack* GetTrack() const { return m_pTrack; }
|
||||
|
||||
private:
|
||||
bool m_bIsValid;
|
||||
unsigned int m_keyIndex;
|
||||
const CTrackViewTrack* m_pTrack;
|
||||
};
|
||||
|
||||
// Represents one CryMovie key
|
||||
class CTrackViewKeyHandle
|
||||
{
|
||||
public:
|
||||
CTrackViewKeyHandle()
|
||||
: m_bIsValid(false)
|
||||
, m_keyIndex(0)
|
||||
, m_pTrack(nullptr) {}
|
||||
|
||||
CTrackViewKeyHandle(CTrackViewTrack* pTrack, unsigned int keyIndex)
|
||||
: m_bIsValid(true)
|
||||
, m_keyIndex(keyIndex)
|
||||
, m_pTrack(pTrack) {}
|
||||
|
||||
void SetKey(IKey* pKey);
|
||||
void GetKey(IKey* pKey) const;
|
||||
|
||||
CTrackViewTrack* GetTrack() { return m_pTrack; }
|
||||
const CTrackViewTrack* GetTrack() const { return m_pTrack; }
|
||||
|
||||
bool IsValid() const { return m_bIsValid; }
|
||||
unsigned int GetIndex() const { return m_keyIndex; }
|
||||
|
||||
void Select(bool bSelect);
|
||||
bool IsSelected() const;
|
||||
|
||||
void SetTime(float time, bool notifyListeners = true);
|
||||
float GetTime() const;
|
||||
|
||||
float GetDuration() const;
|
||||
|
||||
const char* GetDescription() const;
|
||||
|
||||
void Offset(float offset, bool notifyListeners);
|
||||
|
||||
bool operator==(const CTrackViewKeyHandle& keyHandle) const;
|
||||
bool operator!=(const CTrackViewKeyHandle& keyHandle) const;
|
||||
|
||||
// Deletes key. Note that handle will be invalid afterwards
|
||||
void Delete();
|
||||
|
||||
CTrackViewKeyHandle Clone();
|
||||
|
||||
// Get next/prev/above/below key in expanded node tree
|
||||
// Note: Key is assumed to be already visible
|
||||
CTrackViewKeyHandle GetNextKey();
|
||||
CTrackViewKeyHandle GetPrevKey();
|
||||
CTrackViewKeyHandle GetAboveKey() const;
|
||||
CTrackViewKeyHandle GetBelowKey() const;
|
||||
|
||||
private:
|
||||
bool m_bIsValid;
|
||||
unsigned int m_keyIndex;
|
||||
CTrackViewTrack* m_pTrack;
|
||||
};
|
||||
|
||||
// Abstract base class that defines common
|
||||
// operations for key bundles and tracks
|
||||
class ITrackViewKeyBundle
|
||||
{
|
||||
public:
|
||||
virtual bool AreAllKeysOfSameType() const = 0;
|
||||
|
||||
virtual unsigned int GetKeyCount() const = 0;
|
||||
virtual CTrackViewKeyHandle GetKey(unsigned int index) = 0;
|
||||
|
||||
virtual void SelectKeys(const bool bSelected) = 0;
|
||||
};
|
||||
|
||||
// Represents a bundle of keys
|
||||
class CTrackViewKeyBundle
|
||||
: public ITrackViewKeyBundle
|
||||
{
|
||||
friend class CTrackViewTrack;
|
||||
friend class CTrackViewAnimNode;
|
||||
|
||||
public:
|
||||
CTrackViewKeyBundle()
|
||||
: m_bAllOfSameType(true) {}
|
||||
|
||||
virtual bool AreAllKeysOfSameType() const override { return m_bAllOfSameType; }
|
||||
|
||||
virtual unsigned int GetKeyCount() const override { return m_keys.size(); }
|
||||
virtual CTrackViewKeyHandle GetKey(unsigned int index) override { return m_keys[index]; }
|
||||
|
||||
virtual void SelectKeys(const bool bSelected) override;
|
||||
|
||||
CTrackViewKeyHandle GetSingleSelectedKey();
|
||||
|
||||
private:
|
||||
void AppendKey(const CTrackViewKeyHandle& keyHandle);
|
||||
void AppendKeyBundle(const CTrackViewKeyBundle& bundle);
|
||||
|
||||
bool m_bAllOfSameType;
|
||||
std::vector<CTrackViewKeyHandle> m_keys;
|
||||
};
|
||||
|
||||
// Types of nodes that derive from CTrackViewNode
|
||||
enum ETrackViewNodeType
|
||||
{
|
||||
eTVNT_Sequence,
|
||||
eTVNT_AnimNode,
|
||||
eTVNT_Track
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This is the base class for all sequences, nodes and tracks in TrackView,
|
||||
// which provides a interface for common operations
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
class CTrackViewNode
|
||||
{
|
||||
public:
|
||||
CTrackViewNode(CTrackViewNode* pParent);
|
||||
virtual ~CTrackViewNode() {}
|
||||
|
||||
// Name
|
||||
virtual const char* GetName() const = 0;
|
||||
virtual bool SetName([[maybe_unused]] const char* pName) { return false; };
|
||||
virtual bool CanBeRenamed() const { return false; }
|
||||
|
||||
// CryMovie node type
|
||||
virtual ETrackViewNodeType GetNodeType() const = 0;
|
||||
|
||||
// Get the sequence of this node
|
||||
CTrackViewSequence* GetSequence();
|
||||
const CTrackViewSequence* GetSequenceConst() const;
|
||||
|
||||
// Get parent
|
||||
CTrackViewNode* GetParentNode() const { return m_pParentNode; }
|
||||
|
||||
// Children
|
||||
unsigned int GetChildCount() const { return m_childNodes.size(); }
|
||||
CTrackViewNode* GetChild(unsigned int index) const { return m_childNodes[index].get(); }
|
||||
|
||||
// Snap time value to prev/next key in sequence
|
||||
virtual bool SnapTimeToPrevKey(float& time) const = 0;
|
||||
virtual bool SnapTimeToNextKey(float& time) const = 0;
|
||||
|
||||
// Selection state
|
||||
virtual void SetSelected(bool bSelected);
|
||||
virtual bool IsSelected() const { return m_bSelected; }
|
||||
|
||||
// Clear selection of this node and all sub nodes
|
||||
void ClearSelection();
|
||||
|
||||
// Expanded state interface
|
||||
virtual void SetExpanded(bool expanded) = 0;
|
||||
virtual bool GetExpanded() const = 0;
|
||||
|
||||
// Disabled state
|
||||
virtual bool CanBeEnabled() const { return true; }
|
||||
virtual void SetDisabled([[maybe_unused]] bool bDisabled) {}
|
||||
virtual bool IsDisabled() const { return false; }
|
||||
|
||||
// Hidden state
|
||||
void SetHidden(bool bHidden);
|
||||
bool IsHidden() const;
|
||||
|
||||
// Key getters
|
||||
virtual CTrackViewKeyBundle GetSelectedKeys() = 0;
|
||||
virtual CTrackViewKeyBundle GetAllKeys() = 0;
|
||||
virtual CTrackViewKeyBundle GetKeysInTimeRange(const float t0, const float t1) = 0;
|
||||
|
||||
// Check if node itself is obsolete, or any child is an obsolete track
|
||||
bool HasObsoleteTrack() const;
|
||||
|
||||
// Get above/below nodes in pCurrentNode node tree
|
||||
CTrackViewNode* GetAboveNode() const;
|
||||
CTrackViewNode* GetBelowNode() const;
|
||||
|
||||
// Get previous or next sibling of this node
|
||||
CTrackViewNode* GetPrevSibling() const;
|
||||
CTrackViewNode* GetNextSibling() const;
|
||||
|
||||
// Check if it's a group node
|
||||
virtual bool IsGroupNode() const { return false; }
|
||||
|
||||
// Copy selected keys to XML representation for clipboard
|
||||
virtual void CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks) = 0;
|
||||
|
||||
// Sorting
|
||||
bool operator<(const CTrackViewNode& pOtherNode) const;
|
||||
|
||||
// Get first selected node in tree
|
||||
CTrackViewNode* GetFirstSelectedNode();
|
||||
|
||||
// Get director of this node
|
||||
CTrackViewAnimNode* GetDirector();
|
||||
|
||||
protected:
|
||||
void AddNode(CTrackViewNode* pNode);
|
||||
void SortNodes();
|
||||
|
||||
bool HasObsoleteTrackRec(const CTrackViewNode* pCurrentNode) const;
|
||||
|
||||
CTrackViewNode* m_pParentNode;
|
||||
std::vector<std::unique_ptr<CTrackViewNode> > m_childNodes;
|
||||
|
||||
bool m_bSelected;
|
||||
bool m_bHidden;
|
||||
};
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWNODE_H
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewNodeFactories.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimNodeType.h>
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
|
||||
// Editor
|
||||
#include "TrackViewEventNode.h"
|
||||
|
||||
|
||||
CTrackViewAnimNode* CTrackViewAnimNodeFactory::BuildAnimNode(IAnimSequence* pSequence, IAnimNode* pAnimNode, CTrackViewNode* pParentNode)
|
||||
{
|
||||
CTrackViewAnimNode* retNode = nullptr;
|
||||
|
||||
if (pAnimNode->GetType() == AnimNodeType::Event)
|
||||
{
|
||||
retNode = new CTrackViewEventNode(pSequence, pAnimNode, pParentNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
retNode = new CTrackViewAnimNode(pSequence, pAnimNode, pParentNode);
|
||||
}
|
||||
|
||||
return retNode;
|
||||
}
|
||||
|
||||
CTrackViewTrack* CTrackViewTrackFactory::BuildTrack(IAnimTrack* pTrack, CTrackViewAnimNode* pTrackAnimNode,
|
||||
CTrackViewNode* pParentNode, bool bIsSubTrack, unsigned int subTrackIndex)
|
||||
{
|
||||
return new CTrackViewTrack(pTrack, pTrackAnimNode, pParentNode, bIsSubTrack, subTrackIndex);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWNODEFACTORIES_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWNODEFACTORIES_H
|
||||
#pragma once
|
||||
|
||||
|
||||
class CTrackViewTrack;
|
||||
class CTrackViewAnimNode;
|
||||
class CTrackViewNode;
|
||||
|
||||
class CTrackViewAnimNodeFactory
|
||||
{
|
||||
public:
|
||||
CTrackViewAnimNode* BuildAnimNode(IAnimSequence* pSequence, IAnimNode* pAnimNode, CTrackViewNode* pParentNode);
|
||||
};
|
||||
|
||||
class CTrackViewTrackFactory
|
||||
{
|
||||
public:
|
||||
CTrackViewTrack* BuildTrack(IAnimTrack* pTrack, CTrackViewAnimNode* pTrackAnimNode,
|
||||
CTrackViewNode* pParentNode, bool bIsSubTrack = false, unsigned int subTrackIndex = 0);
|
||||
};
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWNODEFACTORIES_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
// Description : TrackView's tree control.
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWNODES_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWNODES_H
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Component/Entity.h>
|
||||
|
||||
#include "TrackViewNode.h"
|
||||
#include "TrackViewSequence.h"
|
||||
#include "Undo/Undo.h"
|
||||
#include "Export/ExportManager.h"
|
||||
|
||||
#include <IMovieSystem.h>
|
||||
#include <QMap>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
#include <QWidget>
|
||||
#endif
|
||||
|
||||
// forward declarations.
|
||||
class CTrackViewNode;
|
||||
class CTrackViewAnimNode;
|
||||
class CTrackViewTrack;
|
||||
class CTrackViewSequence;
|
||||
class CTrackViewDopeSheetBase;
|
||||
class CTrackViewDialog;
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class CTrackViewNodesCtrl;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
class CTrackViewNodesCtrl
|
||||
: public QWidget
|
||||
, public ITrackViewSequenceListener
|
||||
, public IUndoManagerListener
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class CRecord
|
||||
: public QTreeWidgetItem
|
||||
{
|
||||
friend class CTrackViewNodesCtrl;
|
||||
|
||||
public:
|
||||
enum Roles
|
||||
{
|
||||
EnableRole = Qt::UserRole + 1
|
||||
};
|
||||
|
||||
CRecord(CTrackViewNode* pNode = nullptr);
|
||||
CTrackViewNode* GetNode() const { return m_pNode; }
|
||||
bool IsGroup() const { return m_pNode->GetChildCount() != 0; }
|
||||
const QString GetName() const { return m_pNode->GetName(); }
|
||||
|
||||
// Workaround: CXTPReportRecord::IsVisible is
|
||||
// unreliable after the last visible element
|
||||
bool IsVisible() const { return m_bVisible; }
|
||||
|
||||
QRect GetRect() const { return treeWidget()->visualItemRect(this); }
|
||||
|
||||
private:
|
||||
bool m_bVisible;
|
||||
CTrackViewNode* m_pNode;
|
||||
};
|
||||
|
||||
CTrackViewNodesCtrl(QWidget* hParentWnd, CTrackViewDialog* parent = 0);
|
||||
~CTrackViewNodesCtrl();
|
||||
|
||||
void SetTrackViewDialog(CTrackViewDialog* dlg) { m_pTrackViewDialog = dlg; }
|
||||
void OnSequenceChanged();
|
||||
|
||||
void SetDopeSheet(CTrackViewDopeSheetBase* keysCtrl);
|
||||
|
||||
void SetEditLock(bool bLock) { m_bEditLock = bLock; }
|
||||
|
||||
float SaveVerticalScrollPos() const;
|
||||
void RestoreVerticalScrollPos(float fScrollPos);
|
||||
|
||||
CRecord* GetNodeRecord(const CTrackViewNode* pNode) const;
|
||||
|
||||
virtual void Reload();
|
||||
virtual void OnFillItems();
|
||||
|
||||
// ITrackViewSequenceListener
|
||||
virtual void OnNodeChanged(CTrackViewNode* pNode, ITrackViewSequenceListener::ENodeChangeType type) override;
|
||||
virtual void OnNodeRenamed(CTrackViewNode* pNode, const char* pOldName) override;
|
||||
virtual void OnNodeSelectionChanged(CTrackViewSequence* pSequence) override;
|
||||
virtual void OnKeysChanged(CTrackViewSequence* pSequence) override;
|
||||
virtual void OnKeySelectionChanged(CTrackViewSequence* pSequence) override;
|
||||
|
||||
// IUndoManagerListener
|
||||
virtual void BeginUndoTransaction() override;
|
||||
virtual void EndUndoTransaction() override;
|
||||
|
||||
// Helper for dialog
|
||||
QIcon GetIconForTrack(const CTrackViewTrack* pTrack);
|
||||
void ShowNextResult();
|
||||
|
||||
void Update();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
bool event(QEvent* event) override;
|
||||
bool eventFilter(QObject* o, QEvent* e) override;
|
||||
|
||||
private slots:
|
||||
void OnNMRclick(QPoint pos);
|
||||
void OnItemExpanded(QTreeWidgetItem*);
|
||||
void OnSelectionChanged();
|
||||
void OnItemDblClick(QTreeWidgetItem* item, int);
|
||||
void OnFilterChange(const QString& text);
|
||||
|
||||
private:
|
||||
void CreateFolder(CTrackViewAnimNode* pGroupNode);
|
||||
void EditEvents();
|
||||
|
||||
void ImportFromFBX();
|
||||
CTrackViewTrack* GetTrackViewTrack(const Export::EntityAnimData* pAnimData, CTrackViewTrackBundle trackBundle, const QString& nodeName);
|
||||
|
||||
void AddMenuSeperatorConditional(QMenu& menu, bool& bAppended);
|
||||
void AddGroupNodeAddItems(struct SContextMenu& contextMenu, CTrackViewAnimNode* pAnimNode);
|
||||
int ShowPopupMenuSingleSelection(struct SContextMenu& contextMenu, CTrackViewSequence* pSequence, CTrackViewNode* pNode);
|
||||
int ShowPopupMenuMultiSelection(struct SContextMenu& contextMenu);
|
||||
int ShowPopupMenu(QPoint point, const CRecord* pItemInfo);
|
||||
|
||||
bool FillAddTrackMenu(struct STrackMenuTreeNode& menuAddTrack, const CTrackViewAnimNode* pAnimNode);
|
||||
|
||||
void CreateAddTrackMenuRec(QMenu& parent, const QString& name, CTrackViewAnimNode* animNode, struct STrackMenuTreeNode& node, unsigned int& currentId);
|
||||
|
||||
void SetPopupMenuLock(QMenu* menu);
|
||||
void CreateSetAnimationLayerPopupMenu(QMenu& menuSetLayer, CTrackViewTrack* pTrack) const;
|
||||
|
||||
int GetIconIndexForTrack(const CTrackViewTrack* pTrack) const;
|
||||
int GetIconIndexForNode(AnimNodeType type) const;
|
||||
|
||||
void AddNodeRecord(CRecord* pParentRecord, CTrackViewNode* pNode);
|
||||
CRecord* AddTrackRecord(CRecord* pParentRecord, CTrackViewTrack* pTrack);
|
||||
CRecord* AddAnimNodeRecord(CRecord* pParentRecord, CTrackViewAnimNode* pNode);
|
||||
|
||||
void FillNodesRec(CRecord* pRecord, CTrackViewNode* pCurrentNode);
|
||||
|
||||
void EraseNodeRecordRec(CTrackViewNode* pNode);
|
||||
|
||||
void UpdateNodeRecord(CRecord* pRecord);
|
||||
void UpdateTrackRecord(CRecord* pRecord, CTrackViewTrack* pTrack);
|
||||
void UpdateAnimNodeRecord(CRecord* pRecord, CTrackViewAnimNode* pAnimNode);
|
||||
|
||||
void FillAutoCompletionListForFilter();
|
||||
|
||||
// Utility function for handling material nodes
|
||||
// It'll return -1 if the found material isn't a multi-material.
|
||||
static int GetMatNameAndSubMtlIndexFromName(QString& matName, const char* nodeName);
|
||||
|
||||
void CustomizeTrackColor(CTrackViewTrack* pTrack);
|
||||
void ClearCustomTrackColor(CTrackViewTrack* pTrack);
|
||||
|
||||
// For drawing dope sheet
|
||||
void UpdateRecordVisibility();
|
||||
|
||||
void UpdateDopeSheet();
|
||||
|
||||
int GetInsertPosition(CRecord* pParentRecord, CTrackViewNode* pNode);
|
||||
|
||||
void SelectRow(CTrackViewNode* pNode, const bool bEnsureVisible, const bool bDeselectOtherRows);
|
||||
void DeselectRow(CTrackViewNode* pNode);
|
||||
|
||||
CTrackViewDopeSheetBase* m_pDopeSheet;
|
||||
CTrackViewDialog* m_pTrackViewDialog;
|
||||
|
||||
typedef std::vector<CRecord*> ItemInfos;
|
||||
ItemInfos m_itemInfos;
|
||||
|
||||
bool m_bSelectionChanging;
|
||||
bool m_bEditLock;
|
||||
|
||||
QCursor m_arrowCursor;
|
||||
QCursor m_noIcon;
|
||||
|
||||
UINT m_currentMatchIndex;
|
||||
UINT m_matchCount;
|
||||
|
||||
bool m_bIgnoreNotifications;
|
||||
bool m_bNeedReload;
|
||||
float m_storedScrollPosition;
|
||||
|
||||
// Drag and drop
|
||||
CTrackViewAnimNodeBundle m_draggedNodes;
|
||||
CTrackViewAnimNode* m_pDragTarget;
|
||||
|
||||
std::unordered_map<unsigned int, CAnimParamType> m_menuParamTypeMap;
|
||||
std::unordered_map<const CTrackViewNode*, CRecord*> m_nodeToRecordMap;
|
||||
|
||||
QMap<int, QIcon> m_imageList;
|
||||
QScopedPointer<Ui::CTrackViewNodesCtrl> ui;
|
||||
|
||||
//! Cached map of component icons.
|
||||
//! Key: Component's RTTI type
|
||||
//! Value: Icon for this component
|
||||
AZStd::unordered_map<AZ::Uuid, QIcon> m_componentTypeToIconMap;
|
||||
};
|
||||
|
||||
|
||||
typedef CTrackViewNode* CTrackViewNodePtr;
|
||||
Q_DECLARE_METATYPE(CTrackViewNodePtr);
|
||||
QDataStream& operator<<(QDataStream& out, const CTrackViewNodePtr& obj);
|
||||
QDataStream& operator>>(QDataStream& in, CTrackViewNodePtr& obj);
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWNODES_H
|
||||
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CTrackViewNodesCtrl</class>
|
||||
<widget class="QWidget" name="CTrackViewNodesCtrl">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLineEdit" name="searchField">
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::ClickFocus</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="searchCount">
|
||||
<property name="text">
|
||||
<string>0/0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="CTrackViewNodesTreeWidget" name="treeWidget">
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragDrop</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="noitems">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>There are no items to show</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CTrackViewNodesTreeWidget</class>
|
||||
<extends>QTreeWidget</extends>
|
||||
<header location="global">TrackView/TrackViewNodes.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,706 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewPythonFuncs.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimNodeType.h>
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
#include <CryCommon/Maestro/Types/AnimValueType.h>
|
||||
|
||||
// Editor
|
||||
#include "AnimationContext.h"
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
CTrackViewSequence* GetSequenceByEntityIdOrName(const CTrackViewSequenceManager* pSequenceManager, const char* entityIdOrName)
|
||||
{
|
||||
// the "name" string will be an AZ::EntityId in string form if this was called from
|
||||
// TrackView code. But for backward compatibility we also support a sequence name.
|
||||
bool isNameAValidU64 = false;
|
||||
QString entityIdString = entityIdOrName;
|
||||
AZ::u64 nameAsU64 = entityIdString.toULongLong(&isNameAValidU64);
|
||||
|
||||
CTrackViewSequence* pSequence = nullptr;
|
||||
if (isNameAValidU64)
|
||||
{
|
||||
// "name" string was a valid u64 represented as a string. Use as an entity Id to search for sequence.
|
||||
pSequence = pSequenceManager->GetSequenceByEntityId(AZ::EntityId(nameAsU64));
|
||||
}
|
||||
|
||||
if (!pSequence)
|
||||
{
|
||||
// name passed in could not find a sequence by using it as an EntityId. Use it as a
|
||||
// sequence name for backward compatibility
|
||||
pSequence = pSequenceManager->GetSequenceByName(entityIdOrName);
|
||||
}
|
||||
|
||||
return pSequence;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Misc
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void PyTrackViewSetRecording(bool bRecording)
|
||||
{
|
||||
CAnimationContext* pAnimationContext = GetIEditor()->GetAnimation();
|
||||
if (pAnimationContext)
|
||||
{
|
||||
pAnimationContext->SetRecording(bRecording);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Sequences
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void PyTrackViewNewSequence(const char* name, int sequenceType)
|
||||
{
|
||||
CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
|
||||
|
||||
CTrackViewSequence* pSequence = pSequenceManager->GetSequenceByName(name);
|
||||
if (pSequence)
|
||||
{
|
||||
throw std::runtime_error("A sequence with this name already exists");
|
||||
}
|
||||
|
||||
CUndo undo("Create TrackView sequence");
|
||||
pSequenceManager->CreateSequence(name, static_cast<SequenceType>(sequenceType));
|
||||
}
|
||||
|
||||
void PyTrackViewDeleteSequence(const char* name)
|
||||
{
|
||||
CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
|
||||
CTrackViewSequence* pSequence = GetSequenceByEntityIdOrName(pSequenceManager, name);
|
||||
if (pSequence)
|
||||
{
|
||||
pSequenceManager->DeleteSequence(pSequence);
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Could not find sequence");
|
||||
}
|
||||
|
||||
void PyTrackViewSetCurrentSequence(const char* name)
|
||||
{
|
||||
const CTrackViewSequenceManager* sequenceManager = GetIEditor()->GetSequenceManager();
|
||||
CTrackViewSequence* sequence = GetSequenceByEntityIdOrName(sequenceManager, name);
|
||||
CAnimationContext* animationContext = GetIEditor()->GetAnimation();
|
||||
bool force = false;
|
||||
bool noNotify = false;
|
||||
bool user = true;
|
||||
animationContext->SetSequence(sequence, force, noNotify, user);
|
||||
}
|
||||
|
||||
int PyTrackViewGetNumSequences()
|
||||
{
|
||||
const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
|
||||
AZ_TracePrintf("", "PyTrackViewGetNumSequences called")
|
||||
return pSequenceManager->GetCount();
|
||||
}
|
||||
|
||||
AZStd::string PyTrackViewGetSequenceName(unsigned int index)
|
||||
{
|
||||
if (index < PyTrackViewGetNumSequences())
|
||||
{
|
||||
const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
|
||||
return pSequenceManager->GetSequenceByIndex(index)->GetName();
|
||||
}
|
||||
|
||||
throw std::runtime_error("Could not find sequence");
|
||||
}
|
||||
|
||||
Range PyTrackViewGetSequenceTimeRange(const char* name)
|
||||
{
|
||||
const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
|
||||
CTrackViewSequence* pSequence = GetSequenceByEntityIdOrName(pSequenceManager, name);
|
||||
if (!pSequence)
|
||||
{
|
||||
throw std::runtime_error("A sequence with this name doesn't exists");
|
||||
}
|
||||
|
||||
return pSequence->GetTimeRange();
|
||||
}
|
||||
|
||||
void PyTrackViewSetSequenceTimeRange(const char* name, float start, float end)
|
||||
{
|
||||
const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
|
||||
CTrackViewSequence* pSequence = GetSequenceByEntityIdOrName(pSequenceManager, name);
|
||||
if (!pSequence)
|
||||
{
|
||||
throw std::runtime_error("A sequence with this name doesn't exists");
|
||||
}
|
||||
|
||||
CUndo undo("Set sequence time range");
|
||||
pSequence->SetTimeRange(Range(start, end));
|
||||
pSequence->MarkAsModified();
|
||||
}
|
||||
|
||||
void PyTrackViewPlaySequence()
|
||||
{
|
||||
CAnimationContext* pAnimationContext = GetIEditor()->GetAnimation();
|
||||
if (pAnimationContext->IsPlaying())
|
||||
{
|
||||
throw std::runtime_error("A sequence is already playing");
|
||||
}
|
||||
|
||||
pAnimationContext->SetPlaying(true);
|
||||
}
|
||||
|
||||
void PyTrackViewStopSequence()
|
||||
{
|
||||
CAnimationContext* pAnimationContext = GetIEditor()->GetAnimation();
|
||||
if (!pAnimationContext->IsPlaying())
|
||||
{
|
||||
throw std::runtime_error("No sequence is playing");
|
||||
}
|
||||
|
||||
pAnimationContext->SetPlaying(false);
|
||||
}
|
||||
|
||||
void PyTrackViewSetSequenceTime(float time)
|
||||
{
|
||||
CAnimationContext* pAnimationContext = GetIEditor()->GetAnimation();
|
||||
pAnimationContext->SetTime(time);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Nodes
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void PyTrackViewAddNode(const char* nodeTypeString, const char* nodeName)
|
||||
{
|
||||
CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
|
||||
if (!pSequence)
|
||||
{
|
||||
throw std::runtime_error("No sequence is active");
|
||||
}
|
||||
|
||||
const AnimNodeType nodeType = GetIEditor()->GetMovieSystem()->GetNodeTypeFromString(nodeTypeString);
|
||||
if (nodeType == AnimNodeType::Invalid)
|
||||
{
|
||||
throw std::runtime_error("Invalid node type");
|
||||
}
|
||||
|
||||
CUndo undo("Create anim node");
|
||||
pSequence->CreateSubNode(nodeName, nodeType);
|
||||
}
|
||||
|
||||
void PyTrackViewAddSelectedEntities()
|
||||
{
|
||||
CAnimationContext* animationContext = GetIEditor()->GetAnimation();
|
||||
CTrackViewSequence* sequence = animationContext->GetSequence();
|
||||
if (!sequence)
|
||||
{
|
||||
throw std::runtime_error("No sequence is active");
|
||||
}
|
||||
|
||||
AZStd::vector<AnimParamType> tracks = {
|
||||
AnimParamType::Position,
|
||||
AnimParamType::Rotation
|
||||
};
|
||||
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Add entities to Track View");
|
||||
sequence->AddSelectedEntities(tracks);
|
||||
sequence->BindToEditorObjects();
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
|
||||
void PyTrackViewAddLayerNode()
|
||||
{
|
||||
CAnimationContext* pAnimationContext = GetIEditor()->GetAnimation();
|
||||
CTrackViewSequence* pSequence = pAnimationContext->GetSequence();
|
||||
if (!pSequence)
|
||||
{
|
||||
throw std::runtime_error("No sequence is active");
|
||||
}
|
||||
|
||||
CUndo undo("Add current layer to TrackView");
|
||||
pSequence->AddCurrentLayer();
|
||||
}
|
||||
|
||||
CTrackViewAnimNode* GetNodeFromName(const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
CAnimationContext* pAnimationContext = GetIEditor()->GetAnimation();
|
||||
CTrackViewSequence* pSequence = pAnimationContext->GetSequence();
|
||||
if (!pSequence)
|
||||
{
|
||||
throw std::runtime_error("No sequence is active");
|
||||
}
|
||||
|
||||
CTrackViewAnimNode* pParentDirector = pSequence;
|
||||
if (strlen(parentDirectorName) > 0)
|
||||
{
|
||||
CTrackViewAnimNodeBundle foundNodes = pSequence->GetAnimNodesByName(parentDirectorName);
|
||||
if (foundNodes.GetCount() == 0 || foundNodes.GetNode(0)->GetType() != AnimNodeType::Director)
|
||||
{
|
||||
throw std::runtime_error("Director node not found");
|
||||
}
|
||||
|
||||
pParentDirector = foundNodes.GetNode(0);
|
||||
}
|
||||
|
||||
CTrackViewAnimNodeBundle foundNodes = pParentDirector->GetAnimNodesByName(nodeName);
|
||||
return (foundNodes.GetCount() > 0) ? foundNodes.GetNode(0) : nullptr;
|
||||
}
|
||||
|
||||
void PyTrackViewDeleteNode(AZStd::string_view nodeName, AZStd::string_view parentDirectorName)
|
||||
{
|
||||
CTrackViewAnimNode* pNode = GetNodeFromName(nodeName.data(), parentDirectorName.data());
|
||||
if (pNode == nullptr)
|
||||
{
|
||||
throw std::runtime_error("Couldn't find node");
|
||||
}
|
||||
|
||||
CTrackViewAnimNode* pParentNode = static_cast<CTrackViewAnimNode*>(pNode->GetParentNode());
|
||||
|
||||
CUndo undo("Delete TrackView Node");
|
||||
pParentNode->RemoveSubNode(pNode);
|
||||
}
|
||||
|
||||
void PyTrackViewAddTrack(const char* paramName, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
CTrackViewAnimNode* pNode = GetNodeFromName(nodeName, parentDirectorName);
|
||||
if (!pNode)
|
||||
{
|
||||
throw std::runtime_error("Couldn't find node");
|
||||
}
|
||||
|
||||
// Add tracks to menu, that can be added to animation node.
|
||||
const int paramCount = pNode->GetParamCount();
|
||||
for (int i = 0; i < paramCount; ++i)
|
||||
{
|
||||
CAnimParamType paramType = pNode->GetParamType(i);
|
||||
|
||||
if (paramType == AnimParamType::Invalid)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
IAnimNode::ESupportedParamFlags paramFlags = pNode->GetParamFlags(paramType);
|
||||
|
||||
CTrackViewTrack* pTrack = pNode->GetTrackForParameter(paramType);
|
||||
if (!pTrack || (paramFlags & IAnimNode::eSupportedParamFlags_MultipleTracks))
|
||||
{
|
||||
const char* name = pNode->GetParamName(paramType);
|
||||
if (_stricmp(name, paramName) == 0)
|
||||
{
|
||||
CUndo undo("Create track");
|
||||
if (!pNode->CreateTrack(paramType))
|
||||
{
|
||||
undo.Cancel();
|
||||
throw std::runtime_error("Could not create track");
|
||||
}
|
||||
|
||||
pNode->SetSelected(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("Could not create track");
|
||||
}
|
||||
|
||||
void PyTrackViewDeleteTrack(const char* paramName, uint32 index, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
CTrackViewAnimNode* pNode = GetNodeFromName(nodeName, parentDirectorName);
|
||||
if (!pNode)
|
||||
{
|
||||
throw std::runtime_error("Couldn't find node");
|
||||
}
|
||||
|
||||
const CAnimParamType paramType = GetIEditor()->GetMovieSystem()->GetParamTypeFromString(paramName);
|
||||
CTrackViewTrack* pTrack = pNode->GetTrackForParameter(paramType, index);
|
||||
if (!pTrack)
|
||||
{
|
||||
throw std::runtime_error("Could not find track");
|
||||
}
|
||||
|
||||
CUndo undo("Delete TrackView track");
|
||||
pNode->RemoveTrack(pTrack);
|
||||
}
|
||||
|
||||
int PyTrackViewGetNumNodes(AZStd::string_view parentDirectorName)
|
||||
{
|
||||
CAnimationContext* pAnimationContext = GetIEditor()->GetAnimation();
|
||||
CTrackViewSequence* pSequence = pAnimationContext->GetSequence();
|
||||
if (!pSequence)
|
||||
{
|
||||
throw std::runtime_error("No sequence is active");
|
||||
}
|
||||
|
||||
CTrackViewAnimNode* pParentDirector = pSequence;
|
||||
if (!parentDirectorName.empty())
|
||||
{
|
||||
CTrackViewAnimNodeBundle foundNodes = pSequence->GetAnimNodesByName(parentDirectorName.data());
|
||||
if (foundNodes.GetCount() == 0 || foundNodes.GetNode(0)->GetType() != AnimNodeType::Director)
|
||||
{
|
||||
throw std::runtime_error("Director node not found");
|
||||
}
|
||||
|
||||
pParentDirector = foundNodes.GetNode(0);
|
||||
}
|
||||
|
||||
CTrackViewAnimNodeBundle foundNodes = pParentDirector->GetAllAnimNodes();
|
||||
return foundNodes.GetCount();
|
||||
}
|
||||
|
||||
AZStd::string PyTrackViewGetNodeName(int index, AZStd::string_view parentDirectorName)
|
||||
{
|
||||
CAnimationContext* pAnimationContext = GetIEditor()->GetAnimation();
|
||||
CTrackViewSequence* pSequence = pAnimationContext->GetSequence();
|
||||
if (!pSequence)
|
||||
{
|
||||
throw std::runtime_error("No sequence is active");
|
||||
}
|
||||
|
||||
CTrackViewAnimNode* pParentDirector = pSequence;
|
||||
if (!parentDirectorName.empty())
|
||||
{
|
||||
CTrackViewAnimNodeBundle foundNodes = pSequence->GetAnimNodesByName(parentDirectorName.data());
|
||||
if (foundNodes.GetCount() == 0 || foundNodes.GetNode(0)->GetType() != AnimNodeType::Director)
|
||||
{
|
||||
throw std::runtime_error("Director node not found");
|
||||
}
|
||||
|
||||
pParentDirector = foundNodes.GetNode(0);
|
||||
}
|
||||
|
||||
CTrackViewAnimNodeBundle foundNodes = pParentDirector->GetAllAnimNodes();
|
||||
if (index < 0 || index >= foundNodes.GetCount())
|
||||
{
|
||||
throw std::runtime_error("Invalid node index");
|
||||
}
|
||||
|
||||
return foundNodes.GetNode(index)->GetName();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Tracks
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewTrack* GetTrack(const char* paramName, uint32 index, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
CTrackViewAnimNode* pNode = GetNodeFromName(nodeName, parentDirectorName);
|
||||
if (!pNode)
|
||||
{
|
||||
throw std::runtime_error("Couldn't find node");
|
||||
}
|
||||
|
||||
const CAnimParamType paramType = GetIEditor()->GetMovieSystem()->GetParamTypeFromString(paramName);
|
||||
CTrackViewTrack* pTrack = pNode->GetTrackForParameter(paramType, index);
|
||||
if (!pTrack)
|
||||
{
|
||||
throw std::runtime_error("Track doesn't exist");
|
||||
}
|
||||
|
||||
return pTrack;
|
||||
}
|
||||
|
||||
std::set<float> GetKeyTimeSet(CTrackViewTrack* pTrack)
|
||||
{
|
||||
std::set<float> keyTimeSet;
|
||||
for (uint i = 0; i < pTrack->GetKeyCount(); ++i)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = pTrack->GetKey(i);
|
||||
keyTimeSet.insert(keyHandle.GetTime());
|
||||
}
|
||||
|
||||
return keyTimeSet;
|
||||
}
|
||||
|
||||
int PyTrackViewGetNumTrackKeys(const char* paramName, int trackIndex, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
CTrackViewTrack* pTrack = GetTrack(paramName, trackIndex, nodeName, parentDirectorName);
|
||||
return (int)GetKeyTimeSet(pTrack).size();
|
||||
}
|
||||
|
||||
AZStd::any PyTrackViewGetInterpolatedValue(const char* paramName, int trackIndex, float time, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
CTrackViewTrack* pTrack = GetTrack(paramName, trackIndex, nodeName, parentDirectorName);
|
||||
|
||||
switch (pTrack->GetValueType())
|
||||
{
|
||||
case AnimValueType::Float:
|
||||
case AnimValueType::DiscreteFloat:
|
||||
{
|
||||
float value;
|
||||
pTrack->GetValue(time, value);
|
||||
return AZStd::make_any<float>(value);
|
||||
}
|
||||
break;
|
||||
case AnimValueType::Bool:
|
||||
{
|
||||
bool value;
|
||||
pTrack->GetValue(time, value);
|
||||
return AZStd::make_any<bool>(value);
|
||||
}
|
||||
break;
|
||||
case AnimValueType::Quat:
|
||||
{
|
||||
Quat value;
|
||||
pTrack->GetValue(time, value);
|
||||
Ang3 rotation(value);
|
||||
return AZStd::make_any<AZ::Vector3>(rotation.x, rotation.y, rotation.z);
|
||||
}
|
||||
case AnimValueType::Vector:
|
||||
{
|
||||
Vec3 value;
|
||||
pTrack->GetValue(time, value);
|
||||
return AZStd::make_any<AZ::Vector3>(value.x, value.y, value.z);
|
||||
}
|
||||
break;
|
||||
case AnimValueType::Vector4:
|
||||
{
|
||||
Vec4 value;
|
||||
pTrack->GetValue(time, value);
|
||||
return AZStd::make_any<AZ::Vector4>(value.x, value.y, value.z, value.w);
|
||||
}
|
||||
break;
|
||||
case AnimValueType::RGB:
|
||||
{
|
||||
Vec3 value;
|
||||
pTrack->GetValue(time, value);
|
||||
return AZStd::make_any<AZ::Color>(value.x, value.y, value.z, 0.0f);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unsupported key type");
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::any PyTrackViewGetKeyValue(const char* paramName, int trackIndex, int keyIndex, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
CTrackViewTrack* pTrack = GetTrack(paramName, trackIndex, nodeName, parentDirectorName);
|
||||
|
||||
std::set<float> keyTimeSet = GetKeyTimeSet(pTrack);
|
||||
if (keyIndex < 0 || keyIndex >= keyTimeSet.size())
|
||||
{
|
||||
throw std::runtime_error("Invalid key index");
|
||||
}
|
||||
|
||||
auto keyTimeIter = keyTimeSet.begin();
|
||||
std::advance(keyTimeIter, keyIndex);
|
||||
const float keyTime = *keyTimeIter;
|
||||
|
||||
return PyTrackViewGetInterpolatedValue(paramName, trackIndex, keyTime, nodeName, parentDirectorName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
void TrackViewComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->EBus<EditorLayerTrackViewRequestBus>("EditorLayerTrackViewRequestBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "track_view")
|
||||
->Event("AddNode", &EditorLayerTrackViewRequestBus::Events::AddNode)
|
||||
->Event("AddTrack", &EditorLayerTrackViewRequestBus::Events::AddTrack)
|
||||
->Event("AddLayerNode", &EditorLayerTrackViewRequestBus::Events::AddLayerNode)
|
||||
->Event("AddSelectedEntities", &EditorLayerTrackViewRequestBus::Events::AddSelectedEntities)
|
||||
->Event("DeleteNode", &EditorLayerTrackViewRequestBus::Events::DeleteNode)
|
||||
->Event("DeleteTrack", &EditorLayerTrackViewRequestBus::Events::DeleteTrack)
|
||||
->Event("DeleteSequence", &EditorLayerTrackViewRequestBus::Events::DeleteSequence)
|
||||
->Event("GetInterpolatedValue", &EditorLayerTrackViewRequestBus::Events::GetInterpolatedValue)
|
||||
->Event("GetKeyValue", &EditorLayerTrackViewRequestBus::Events::GetKeyValue)
|
||||
->Event("GetNodeName", &EditorLayerTrackViewRequestBus::Events::GetNodeName)
|
||||
->Event("GetNumNodes", &EditorLayerTrackViewRequestBus::Events::GetNumNodes)
|
||||
->Event("GetNumSequences", &EditorLayerTrackViewRequestBus::Events::GetNumSequences)
|
||||
->Event("GetNumTrackKeys", &EditorLayerTrackViewRequestBus::Events::GetNumTrackKeys)
|
||||
->Event("GetSequenceName", &EditorLayerTrackViewRequestBus::Events::GetSequenceName)
|
||||
->Event("GetSequenceTimeRange", &EditorLayerTrackViewRequestBus::Events::GetSequenceTimeRange)
|
||||
->Event("NewSequence", &EditorLayerTrackViewRequestBus::Events::NewSequence)
|
||||
->Event("PlaySequence", &EditorLayerTrackViewRequestBus::Events::PlaySequence)
|
||||
->Event("SetCurrentSequence", &EditorLayerTrackViewRequestBus::Events::SetCurrentSequence)
|
||||
->Event("SetRecording", &EditorLayerTrackViewRequestBus::Events::SetRecording)
|
||||
->Event("SetSequenceTimeRange", &EditorLayerTrackViewRequestBus::Events::SetSequenceTimeRange)
|
||||
->Event("SetTime", &EditorLayerTrackViewRequestBus::Events::SetSequenceTime)
|
||||
->Event("StopSequence", &EditorLayerTrackViewRequestBus::Events::StopSequence)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void TrackViewComponent::Activate()
|
||||
{
|
||||
EditorLayerTrackViewRequestBus::Handler::BusConnect(GetEntityId());
|
||||
}
|
||||
|
||||
void TrackViewComponent::Deactivate()
|
||||
{
|
||||
EditorLayerTrackViewRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
int TrackViewComponent::GetNumSequences()
|
||||
{
|
||||
return PyTrackViewGetNumSequences();
|
||||
}
|
||||
|
||||
void TrackViewComponent::NewSequence(const char* name, int sequenceType)
|
||||
{
|
||||
return PyTrackViewNewSequence(name, sequenceType);
|
||||
}
|
||||
|
||||
void TrackViewComponent::PlaySequence()
|
||||
{
|
||||
return PyTrackViewPlaySequence();
|
||||
}
|
||||
|
||||
void TrackViewComponent::StopSequence()
|
||||
{
|
||||
return PyTrackViewStopSequence();
|
||||
}
|
||||
|
||||
void TrackViewComponent::SetSequenceTime(float time)
|
||||
{
|
||||
return PyTrackViewSetSequenceTime(time);
|
||||
}
|
||||
|
||||
void TrackViewComponent::AddSelectedEntities()
|
||||
{
|
||||
return PyTrackViewAddSelectedEntities();
|
||||
}
|
||||
|
||||
void TrackViewComponent::AddLayerNode()
|
||||
{
|
||||
return PyTrackViewAddLayerNode();
|
||||
}
|
||||
|
||||
void TrackViewComponent::AddTrack(const char* paramName, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
return PyTrackViewAddTrack(paramName, nodeName, parentDirectorName);
|
||||
}
|
||||
|
||||
void TrackViewComponent::DeleteTrack(const char* paramName, uint32 index, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
return PyTrackViewDeleteTrack(paramName, index, nodeName, parentDirectorName);
|
||||
}
|
||||
|
||||
int TrackViewComponent::GetNumTrackKeys(const char* paramName, int trackIndex, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
return PyTrackViewGetNumTrackKeys(paramName, trackIndex, nodeName, parentDirectorName);
|
||||
}
|
||||
|
||||
void TrackViewComponent::SetRecording(bool bRecording)
|
||||
{
|
||||
return PyTrackViewSetRecording(bRecording);
|
||||
}
|
||||
|
||||
void TrackViewComponent::DeleteSequence(const char* name)
|
||||
{
|
||||
return PyTrackViewDeleteSequence(name);
|
||||
}
|
||||
|
||||
void TrackViewComponent::SetCurrentSequence(const char* name)
|
||||
{
|
||||
return PyTrackViewSetCurrentSequence(name);
|
||||
}
|
||||
|
||||
AZStd::string TrackViewComponent::GetSequenceName(unsigned int index)
|
||||
{
|
||||
return PyTrackViewGetSequenceName(index);
|
||||
}
|
||||
|
||||
Range TrackViewComponent::GetSequenceTimeRange(const char* name)
|
||||
{
|
||||
return PyTrackViewGetSequenceTimeRange(name);
|
||||
}
|
||||
|
||||
void TrackViewComponent::AddNode(const char* nodeTypeString, const char* nodeName)
|
||||
{
|
||||
return PyTrackViewAddNode(nodeTypeString, nodeName);
|
||||
}
|
||||
|
||||
void TrackViewComponent::DeleteNode(AZStd::string_view nodeName, AZStd::string_view parentDirectorName)
|
||||
{
|
||||
return PyTrackViewDeleteNode(nodeName, parentDirectorName);
|
||||
}
|
||||
|
||||
int TrackViewComponent::GetNumNodes(AZStd::string_view parentDirectorName)
|
||||
{
|
||||
return PyTrackViewGetNumNodes(parentDirectorName);
|
||||
}
|
||||
|
||||
AZStd::string TrackViewComponent::GetNodeName(int index, AZStd::string_view parentDirectorName)
|
||||
{
|
||||
return PyTrackViewGetNodeName(index, parentDirectorName);
|
||||
}
|
||||
|
||||
AZStd::any TrackViewComponent::GetKeyValue(const char* paramName, int trackIndex, int keyIndex, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
return PyTrackViewGetKeyValue(paramName, trackIndex, keyIndex, nodeName, parentDirectorName);
|
||||
}
|
||||
|
||||
AZStd::any TrackViewComponent::GetInterpolatedValue(const char* paramName, int trackIndex, float time, const char* nodeName, const char* parentDirectorName)
|
||||
{
|
||||
return PyTrackViewGetInterpolatedValue(paramName, trackIndex, time, nodeName, parentDirectorName);
|
||||
}
|
||||
|
||||
void TrackViewComponent::SetSequenceTimeRange(const char* name, float start, float end)
|
||||
{
|
||||
return PyTrackViewSetSequenceTimeRange(name, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
void TrackViewFuncsHandler::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->Class<Range>("CryRange")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "legacy.trackview")
|
||||
->Property("start", BehaviorValueProperty(&Range::start))
|
||||
->Property("end", BehaviorValueProperty(&Range::end))
|
||||
;
|
||||
|
||||
// this will put these methods into the 'azlmbr.legacy.trackview' module
|
||||
auto addLegacyTrackview = [](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder)
|
||||
{
|
||||
methodBuilder->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Legacy/TrackView")
|
||||
->Attribute(AZ::Script::Attributes::Module, "legacy.trackview");
|
||||
};
|
||||
addLegacyTrackview(behaviorContext->Method("set_recording", PyTrackViewSetRecording, nullptr, "Activates/deactivates TrackView recording mode."));
|
||||
|
||||
addLegacyTrackview(behaviorContext->Method("new_sequence", PyTrackViewNewSequence, nullptr, "Creates a new sequence of the given type (0=Object Entity Sequence (Legacy), 1=Component Entity Sequence (PREVIEW)) with the given name."));
|
||||
addLegacyTrackview(behaviorContext->Method("delete_sequence", PyTrackViewDeleteSequence, nullptr, "Deletes the specified sequence."));
|
||||
addLegacyTrackview(behaviorContext->Method("set_current_sequence", PyTrackViewSetCurrentSequence, nullptr, "Sets the specified sequence as a current one in TrackView."));
|
||||
addLegacyTrackview(behaviorContext->Method("get_num_sequences", PyTrackViewGetNumSequences, nullptr, "Gets the number of sequences."));
|
||||
addLegacyTrackview(behaviorContext->Method("get_sequence_name", PyTrackViewGetSequenceName, nullptr, "Gets the name of a sequence by its index."));
|
||||
|
||||
addLegacyTrackview(behaviorContext->Method("get_sequence_time_range", PyTrackViewGetSequenceTimeRange, nullptr, "Gets the time range of a sequence as a pair."));
|
||||
|
||||
addLegacyTrackview(behaviorContext->Method("set_sequence_time_range", PyTrackViewSetSequenceTimeRange, nullptr, "Sets the time range of a sequence."));
|
||||
addLegacyTrackview(behaviorContext->Method("play_sequence", PyTrackViewPlaySequence, nullptr, "Plays the current sequence in TrackView."));
|
||||
addLegacyTrackview(behaviorContext->Method("stop_sequence", PyTrackViewStopSequence, nullptr, "Stops any sequence currently playing in TrackView."));
|
||||
addLegacyTrackview(behaviorContext->Method("set_time", PyTrackViewSetSequenceTime, nullptr, "Sets the time of the sequence currently playing in TrackView."));
|
||||
|
||||
addLegacyTrackview(behaviorContext->Method("add_node", PyTrackViewAddNode, nullptr, "Adds a new node with the given type & name to the current sequence."));
|
||||
addLegacyTrackview(behaviorContext->Method("add_selected_entities", PyTrackViewAddSelectedEntities, nullptr, "Adds an entity node(s) from viewport selection to the current sequence."));
|
||||
addLegacyTrackview(behaviorContext->Method("add_layer_node", PyTrackViewAddLayerNode, nullptr, "Adds a layer node from the current layer to the current sequence."));
|
||||
addLegacyTrackview(behaviorContext->Method("delete_node", PyTrackViewDeleteNode, nullptr, "Deletes the specified node from the current sequence."));
|
||||
addLegacyTrackview(behaviorContext->Method("add_track", PyTrackViewAddTrack, nullptr, "Adds a track of the given parameter ID to the node."));
|
||||
addLegacyTrackview(behaviorContext->Method("delete_track", PyTrackViewDeleteTrack, nullptr, "Deletes a track of the given parameter ID (in the given index in case of a multi-track) from the node."));
|
||||
addLegacyTrackview(behaviorContext->Method("get_num_nodes", PyTrackViewGetNumNodes, nullptr, "Gets the number of nodes."));
|
||||
addLegacyTrackview(behaviorContext->Method("get_node_name", PyTrackViewGetNodeName, nullptr, "Gets the name of a sequence by its index."));
|
||||
|
||||
addLegacyTrackview(behaviorContext->Method("get_num_track_keys", PyTrackViewGetNumTrackKeys, nullptr, "Gets number of keys of the specified track."));
|
||||
|
||||
addLegacyTrackview(behaviorContext->Method("get_key_value", PyTrackViewGetKeyValue, nullptr, "Gets the value of the specified key."));
|
||||
addLegacyTrackview(behaviorContext->Method("get_interpolated_value", PyTrackViewGetInterpolatedValue, nullptr, "Gets the interpolated value of a track at the specified time."));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <Include/SandboxAPI.h>
|
||||
#include "EditorTrackViewEventsBus.h"
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
//! A legacy component to reflect scriptable commands for the Editor
|
||||
class TrackViewFuncsHandler
|
||||
: public AZ::Component
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(TrackViewFuncsHandler, "{5315678D-2951-4CF6-A9DC-CE21CD23C9C9}")
|
||||
|
||||
SANDBOX_API static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
// AZ::Component ...
|
||||
void Activate() override {}
|
||||
void Deactivate() override {}
|
||||
};
|
||||
|
||||
//! Component to access the TrackView
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
class SANDBOX_API TrackViewComponent final
|
||||
: public AZ::Component
|
||||
, public EditorLayerTrackViewRequestBus::Handler
|
||||
{
|
||||
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
|
||||
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
|
||||
public:
|
||||
AZ_COMPONENT(TrackViewComponent, "{3CF943CC-6F10-4B19-88FC-CFB697558FFD}")
|
||||
|
||||
TrackViewComponent() = default;
|
||||
~TrackViewComponent() override = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
// Component...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
int GetNumSequences() override;
|
||||
|
||||
void NewSequence(const char* name, int sequenceType) override;
|
||||
|
||||
void PlaySequence() override;
|
||||
|
||||
void StopSequence() override;
|
||||
|
||||
void SetSequenceTime(float time) override;
|
||||
|
||||
void AddSelectedEntities() override;
|
||||
|
||||
void AddLayerNode() override;
|
||||
|
||||
void AddTrack(const char* paramName, const char* nodeName, const char* parentDirectorName) override;
|
||||
|
||||
void DeleteTrack(const char* paramName, uint32 index, const char* nodeName, const char* parentDirectorName) override;
|
||||
|
||||
int GetNumTrackKeys(const char* paramName, int trackIndex, const char* nodeName, const char* parentDirectorName) override;
|
||||
|
||||
void SetRecording(bool bRecording) override;
|
||||
|
||||
void DeleteSequence(const char* name) override;
|
||||
|
||||
void SetCurrentSequence(const char* name) override;
|
||||
|
||||
AZStd::string GetSequenceName(unsigned int index) override;
|
||||
|
||||
TRange<float> GetSequenceTimeRange(const char* name) override;
|
||||
|
||||
void AddNode(const char* nodeTypeString, const char* nodeName) override;
|
||||
|
||||
void DeleteNode(AZStd::string_view nodeName, AZStd::string_view parentDirectorName) override;
|
||||
|
||||
int GetNumNodes(AZStd::string_view parentDirectorName) override;
|
||||
|
||||
AZStd::string GetNodeName(int index, AZStd::string_view parentDirectorName) override;
|
||||
|
||||
AZStd::any GetKeyValue(const char* paramName, int trackIndex, int keyIndex, const char* nodeName, const char* parentDirectorName) override;
|
||||
|
||||
AZStd::any GetInterpolatedValue(const char* paramName, int trackIndex, float time, const char* nodeName, const char* parentDirectorName) override;
|
||||
|
||||
void SetSequenceTimeRange(const char* name, float start, float end) override;
|
||||
|
||||
};
|
||||
|
||||
} // namespace AzToolsFramework
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWSEQUENCE_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWSEQUENCE_H
|
||||
#pragma once
|
||||
|
||||
#include "IMovieSystem.h"
|
||||
|
||||
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
|
||||
|
||||
#include "TrackViewAnimNode.h"
|
||||
#include "Undo/Undo.h"
|
||||
|
||||
struct ITrackViewSequenceListener
|
||||
{
|
||||
// Called when sequence settings (time range, flags) have changed
|
||||
virtual void OnSequenceSettingsChanged([[maybe_unused]] CTrackViewSequence* pSequence) {}
|
||||
|
||||
enum ENodeChangeType
|
||||
{
|
||||
eNodeChangeType_Added,
|
||||
eNodeChangeType_Removed,
|
||||
eNodeChangeType_Expanded,
|
||||
eNodeChangeType_Collapsed,
|
||||
eNodeChangeType_Hidden,
|
||||
eNodeChangeType_Unhidden,
|
||||
eNodeChangeType_Enabled,
|
||||
eNodeChangeType_Disabled,
|
||||
eNodeChangeType_Muted,
|
||||
eNodeChangeType_Unmuted,
|
||||
eNodeChangeType_Selected,
|
||||
eNodeChangeType_Deselected,
|
||||
eNodeChangeType_SetAsActiveDirector,
|
||||
eNodeChangeType_NodeOwnerChanged
|
||||
};
|
||||
|
||||
// Called when a node is changed
|
||||
virtual void OnNodeChanged([[maybe_unused]] CTrackViewNode* pNode, [[maybe_unused]] ENodeChangeType type) {}
|
||||
|
||||
// Called when a node is added
|
||||
virtual void OnNodeRenamed([[maybe_unused]] CTrackViewNode* pNode, [[maybe_unused]] const char* pOldName) {}
|
||||
|
||||
// Called when selection of nodes changed
|
||||
virtual void OnNodeSelectionChanged([[maybe_unused]] CTrackViewSequence* pSequence) {}
|
||||
|
||||
// Called when selection of keys changed.
|
||||
virtual void OnKeySelectionChanged([[maybe_unused]] CTrackViewSequence* pSequence) {}
|
||||
|
||||
// Called when keys in a track changed
|
||||
virtual void OnKeysChanged([[maybe_unused]] CTrackViewSequence* pSequence) {}
|
||||
|
||||
// Called when a new key is added to a track
|
||||
virtual void OnKeyAdded([[maybe_unused]] CTrackViewKeyHandle& addedKeyHandle) {}
|
||||
};
|
||||
|
||||
struct ITrackViewSequenceManagerListener
|
||||
{
|
||||
virtual void OnSequenceAdded([[maybe_unused]] CTrackViewSequence* pSequence) {}
|
||||
virtual void OnSequenceRemoved([[maybe_unused]] CTrackViewSequence* pSequence) {}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This class represents a IAnimSequence in TrackView and contains
|
||||
// the editor side code for changing it
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
class CTrackViewSequence
|
||||
: public CTrackViewAnimNode
|
||||
, public IUndoManagerListener
|
||||
, public ITrackViewSequence
|
||||
, public ITrackViewSequenceManagerListener
|
||||
, public AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler
|
||||
{
|
||||
friend class CTrackViewSequenceManager;
|
||||
friend class CTrackViewNode;
|
||||
friend class CTrackViewAnimNode;
|
||||
friend class CTrackViewTrack;
|
||||
friend class CTrackViewSequenceNotificationContext;
|
||||
friend class CTrackViewSequenceNoNotificationContext;
|
||||
|
||||
// Undo friends
|
||||
friend class CUndoAnimNodeReparent;
|
||||
friend class CUndoTrackObject;
|
||||
friend class CUndoComponentEntityTrackObject;
|
||||
|
||||
public:
|
||||
CTrackViewSequence(IAnimSequence* pSequence);
|
||||
CTrackViewSequence(AZStd::intrusive_ptr<IAnimSequence>& sequence);
|
||||
~CTrackViewSequence();
|
||||
|
||||
// Called after de-serialization of IAnimSequence
|
||||
void Load() override;
|
||||
|
||||
// ITrackViewNode
|
||||
virtual ETrackViewNodeType GetNodeType() const override { return eTVNT_Sequence; }
|
||||
|
||||
virtual const char* GetName() const override { return m_pAnimSequence->GetName(); }
|
||||
virtual bool SetName(const char* pName) override;
|
||||
virtual bool CanBeRenamed() const override { return true; }
|
||||
|
||||
// Binding/Unbinding
|
||||
virtual void BindToEditorObjects() override;
|
||||
virtual void UnBindFromEditorObjects() override;
|
||||
virtual bool IsBoundToEditorObjects() const override;
|
||||
|
||||
// Time range
|
||||
void SetTimeRange(Range timeRange);
|
||||
Range GetTimeRange() const;
|
||||
|
||||
// Current time in sequence. Note that this can be different from the time
|
||||
// of the animation context, if this sequence is used as a sub sequence
|
||||
const float GetTime() const;
|
||||
|
||||
// CryMovie Flags
|
||||
void SetFlags(IAnimSequence::EAnimSequenceFlags flags);
|
||||
IAnimSequence::EAnimSequenceFlags GetFlags() const;
|
||||
|
||||
// Get sequence object in scene
|
||||
AZ::EntityId GetSequenceComponentEntityId() const { return m_pAnimSequence.get() ? m_pAnimSequence->GetSequenceEntityId() : AZ::EntityId(); }
|
||||
|
||||
// Check if this node belongs to a sequence
|
||||
bool IsAncestorOf(CTrackViewSequence* pSequence) const;
|
||||
|
||||
// Get single selected key if only one key is selected
|
||||
CTrackViewKeyHandle FindSingleSelectedKey();
|
||||
|
||||
// Get CryMovie sequence ID
|
||||
uint32 GetCryMovieId() const { return m_pAnimSequence->GetId(); }
|
||||
|
||||
// Rendering
|
||||
virtual void Render(const SAnimContext& animContext) override;
|
||||
|
||||
// Playback control
|
||||
virtual void Animate(const SAnimContext& animContext) override;
|
||||
void Resume() { m_pAnimSequence->Resume(); }
|
||||
void Pause() { m_pAnimSequence->Pause(); }
|
||||
void StillUpdate() { m_pAnimSequence->StillUpdate(); }
|
||||
|
||||
void OnLoop() { m_pAnimSequence->OnLoop(); }
|
||||
|
||||
// Active & deactivate
|
||||
void Activate() { m_pAnimSequence->Activate(); }
|
||||
void Deactivate() { m_pAnimSequence->Deactivate(); }
|
||||
void PrecacheData(const float time) { m_pAnimSequence->PrecacheData(time); }
|
||||
|
||||
// Begin & end cut scene
|
||||
void BeginCutScene(const bool bResetFx) const;
|
||||
void EndCutScene() const;
|
||||
|
||||
// Reset
|
||||
void Reset(const bool bSeekToStart) { m_pAnimSequence->Reset(bSeekToStart); }
|
||||
void ResetHard() { m_pAnimSequence->ResetHard(); }
|
||||
|
||||
void TimeChanged(float newTime) { m_pAnimSequence->TimeChanged(newTime); }
|
||||
|
||||
// Check if it's a group node
|
||||
virtual bool IsGroupNode() const override { return true; }
|
||||
|
||||
// Track Events (TODO: Undo?)
|
||||
int GetTrackEventsCount() const { return m_pAnimSequence->GetTrackEventsCount(); }
|
||||
const char* GetTrackEvent(int index) { return m_pAnimSequence->GetTrackEvent(index); }
|
||||
bool AddTrackEvent(const char* szEvent) { MarkAsModified(); return m_pAnimSequence->AddTrackEvent(szEvent); }
|
||||
bool RemoveTrackEvent(const char* szEvent) { MarkAsModified(); return m_pAnimSequence->RemoveTrackEvent(szEvent); }
|
||||
bool RenameTrackEvent(const char* szEvent, const char* szNewEvent) { MarkAsModified(); return m_pAnimSequence->RenameTrackEvent(szEvent, szNewEvent); }
|
||||
bool MoveUpTrackEvent(const char* szEvent) { MarkAsModified(); return m_pAnimSequence->MoveUpTrackEvent(szEvent); }
|
||||
bool MoveDownTrackEvent(const char* szEvent) { MarkAsModified(); return m_pAnimSequence->MoveDownTrackEvent(szEvent); }
|
||||
void ClearTrackEvents() { MarkAsModified(); m_pAnimSequence->ClearTrackEvents(); }
|
||||
|
||||
// Deletes all selected nodes (re-parents childs if group node gets deleted)
|
||||
void DeleteSelectedNodes();
|
||||
|
||||
// Select selected nodes in viewport
|
||||
void SelectSelectedNodesInViewport();
|
||||
|
||||
// Deletes all selected keys
|
||||
void DeleteSelectedKeys();
|
||||
|
||||
// Sync from/to base
|
||||
void SyncSelectedTracksToBase();
|
||||
void SyncSelectedTracksFromBase();
|
||||
|
||||
// Listeners
|
||||
void AddListener(ITrackViewSequenceListener* pListener);
|
||||
void RemoveListener(ITrackViewSequenceListener* pListener);
|
||||
|
||||
// Checks if this is the active sequence in TV
|
||||
bool IsActiveSequence() const;
|
||||
|
||||
// The root sequence node is always an active director
|
||||
virtual bool IsActiveDirector() const override { return true; }
|
||||
|
||||
// Copy keys to clipboard (in XML form)
|
||||
void CopyKeysToClipboard(const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks);
|
||||
|
||||
// Paste keys from clipboard. Tries to match the given data to the target track first,
|
||||
// then the target anim node and finally the whole sequence. If it doesn't find any
|
||||
// matching location, nothing will be pasted. Before pasting the given time offset is
|
||||
// applied to the keys.
|
||||
void PasteKeysFromClipboard(CTrackViewAnimNode* pTargetNode, CTrackViewTrack* pTargetTrack, const float timeOffset = 0.0f);
|
||||
|
||||
// Returns a vector of pairs that match the XML track nodes in the clipboard to the tracks in the sequence for pasting.
|
||||
// It is used by PasteKeysFromClipboard directly and to preview the locations of the to be pasted keys.
|
||||
typedef std::pair<CTrackViewTrack*, XmlNodeRef> TMatchedTrackLocation;
|
||||
std::vector<TMatchedTrackLocation> GetMatchedPasteLocations(XmlNodeRef clipboardContent, CTrackViewAnimNode* pTargetNode, CTrackViewTrack* pTargetTrack);
|
||||
|
||||
// Adjust the time range
|
||||
void AdjustKeysToTimeRange(Range newTimeRange);
|
||||
|
||||
// Clear all key selection
|
||||
void DeselectAllKeys();
|
||||
|
||||
// Offset all key selection
|
||||
void OffsetSelectedKeys(const float timeOffset);
|
||||
// Scale all selected keys by this offset.
|
||||
void ScaleSelectedKeys(const float timeOffset);
|
||||
//! Push all the keys which come after the first key in time among selected ones by this offset.
|
||||
void SlideKeys(const float timeOffset);
|
||||
//! Clone all selected keys
|
||||
void CloneSelectedKeys();
|
||||
|
||||
// Limit the time offset so as to keep all involved keys in range when offsetting.
|
||||
float ClipTimeOffsetForOffsetting(const float timeOffset);
|
||||
// Limit the time offset so as to keep all involved keys in range when scaling.
|
||||
float ClipTimeOffsetForScaling(const float timeOffset);
|
||||
// Limit the time offset so as to keep all involved keys in range when sliding.
|
||||
float ClipTimeOffsetForSliding(const float timeOffset);
|
||||
|
||||
// Notifications
|
||||
void OnSequenceSettingsChanged();
|
||||
void OnKeySelectionChanged();
|
||||
void OnKeysChanged();
|
||||
void OnKeyAdded(CTrackViewKeyHandle& addedKeyHandle);
|
||||
void OnNodeSelectionChanged();
|
||||
void OnNodeChanged(CTrackViewNode* pNode, ITrackViewSequenceListener::ENodeChangeType type);
|
||||
void OnNodeRenamed(CTrackViewNode* pNode, const char* pOldName);
|
||||
|
||||
// IAnimNodeOwner
|
||||
void MarkAsModified() override;
|
||||
// ~IAnimNodeOwner
|
||||
|
||||
SequenceType GetSequenceType() const
|
||||
{
|
||||
if (m_pAnimSequence.get())
|
||||
{
|
||||
return m_pAnimSequence->GetSequenceType();
|
||||
}
|
||||
else
|
||||
{
|
||||
return kSequenceTypeDefault;
|
||||
}
|
||||
}
|
||||
|
||||
void SetExpanded(bool expanded) override
|
||||
{
|
||||
if (m_pAnimSequence)
|
||||
{
|
||||
m_pAnimSequence->SetExpanded(expanded);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetExpanded() const override
|
||||
{
|
||||
return m_pAnimSequence ? m_pAnimSequence->GetExpanded() : true;
|
||||
}
|
||||
|
||||
// Called when the 'Record' button is pressed in the toolbar
|
||||
void SetRecording(bool enableRecording);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PropertyEditorEntityChangeNotificationBus handler
|
||||
void OnEntityComponentPropertyChanged(AZ::ComponentId /*changedComponentId*/) override;
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CTrackViewTrack* FindTrackById(unsigned int trackId);
|
||||
|
||||
std::vector<bool> SaveKeyStates() const;
|
||||
void RestoreKeyStates(const std::vector<bool>& keyStates);
|
||||
|
||||
// Helper function to find a sequence by entity id
|
||||
static CTrackViewSequence* LookUpSequenceByEntityId(const AZ::EntityId& sequenceId);
|
||||
|
||||
private:
|
||||
// These are used to avoid listener notification spam via CTrackViewSequenceNotificationContext.
|
||||
// For recursion there is a counter that increases on QueueListenerNotifications
|
||||
// and decreases on SubmitPendingListenerNotifcations
|
||||
// Only when the counter reaches 0 again SubmitPendingListenerNotifcations
|
||||
// will submit the notifications
|
||||
void QueueNotifications();
|
||||
// Used to cancel a previously queued notification.
|
||||
void DequeueNotifications();
|
||||
void SubmitPendingNotifcations(bool force = false);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// overrides for ITrackViewSequenceManagerListener
|
||||
void OnSequenceRemoved(CTrackViewSequence* pSequence) override;
|
||||
void OnSequenceAdded(CTrackViewSequence* pSequence) override;
|
||||
|
||||
// Called when an animation updates needs to be schedules
|
||||
void ForceAnimation();
|
||||
|
||||
virtual void CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks) override;
|
||||
|
||||
std::deque<CTrackViewTrack*> GetMatchingTracks(CTrackViewAnimNode* pAnimNode, XmlNodeRef trackNode);
|
||||
void GetMatchedPasteLocationsRec(std::vector<TMatchedTrackLocation>& locations, CTrackViewNode* pCurrentNode, XmlNodeRef clipboardNode);
|
||||
|
||||
virtual void BeginUndoTransaction();
|
||||
virtual void EndUndoTransaction();
|
||||
virtual void BeginRestoreTransaction();
|
||||
virtual void EndRestoreTransaction();
|
||||
|
||||
// For record mode on AZ::Entities - connect (or disconnect) to buses for notification of property changes
|
||||
void ConnectToBusesForRecording(const AZ::EntityId& entityIdForBus, bool enableConnection);
|
||||
|
||||
// Searches for current property vs. Track values for the given node and sets a key for all values that differ.
|
||||
// Returns the number of keys set
|
||||
int RecordTrackChangesForNode(CTrackViewAnimNode* componentNode);
|
||||
|
||||
// Current time when animated
|
||||
float m_time;
|
||||
|
||||
// Stores if sequence is bound
|
||||
bool m_bBoundToEditorObjects = false;
|
||||
|
||||
AZStd::intrusive_ptr<IAnimSequence> m_pAnimSequence;
|
||||
std::vector<ITrackViewSequenceListener*> m_sequenceListeners;
|
||||
|
||||
// Notification queuing
|
||||
unsigned int m_selectionRecursionLevel = 0;
|
||||
bool m_bNoNotifications = false;
|
||||
bool m_bQueueNotifications = false;
|
||||
bool m_bNodeSelectionChanged = false;
|
||||
bool m_bForceAnimation = false;
|
||||
bool m_bKeySelectionChanged = false;
|
||||
bool m_bKeysChanged = false;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
class CTrackViewSequenceNotificationContext
|
||||
{
|
||||
public:
|
||||
CTrackViewSequenceNotificationContext(CTrackViewSequence* pSequence)
|
||||
: m_pSequence(pSequence)
|
||||
{
|
||||
if (m_pSequence)
|
||||
{
|
||||
m_pSequence->QueueNotifications();
|
||||
}
|
||||
}
|
||||
|
||||
~CTrackViewSequenceNotificationContext()
|
||||
{
|
||||
if (m_pSequence)
|
||||
{
|
||||
m_pSequence->SubmitPendingNotifcations();
|
||||
}
|
||||
}
|
||||
|
||||
void Cancel()
|
||||
{
|
||||
if (m_pSequence)
|
||||
{
|
||||
m_pSequence->DequeueNotifications();
|
||||
}
|
||||
m_pSequence = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
CTrackViewSequence* m_pSequence;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
class CTrackViewSequenceNoNotificationContext
|
||||
{
|
||||
public:
|
||||
CTrackViewSequenceNoNotificationContext(CTrackViewSequence* pSequence)
|
||||
: m_pSequence(pSequence)
|
||||
, m_bNoNotificationsPreviously(false)
|
||||
{
|
||||
if (m_pSequence)
|
||||
{
|
||||
m_bNoNotificationsPreviously = m_pSequence->m_bNoNotifications;
|
||||
m_pSequence->m_bNoNotifications = true;
|
||||
}
|
||||
}
|
||||
|
||||
~CTrackViewSequenceNoNotificationContext()
|
||||
{
|
||||
if (m_pSequence)
|
||||
{
|
||||
m_pSequence->m_bNoNotifications = m_bNoNotificationsPreviously;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CTrackViewSequence* m_pSequence;
|
||||
|
||||
// Reentrance could happen if there are overlapping sub-sequences controlling
|
||||
// the same camera.
|
||||
bool m_bNoNotificationsPreviously;
|
||||
};
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWSEQUENCE_H
|
||||
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewSequenceManager.h"
|
||||
|
||||
// AzToolsFramework
|
||||
#include <AzToolsFramework/API/ComponentEntityObjectBus.h>
|
||||
#include <AzToolsFramework/API/EntityCompositionRequestBus.h>
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Bus/EditorSequenceComponentBus.h>
|
||||
#include <CryCommon/Maestro/Types/SequenceType.h>
|
||||
|
||||
// Editor
|
||||
#include "AnimationContext.h"
|
||||
#include "GameEngine.h"
|
||||
#include "Include/IObjectManager.h"
|
||||
#include "Objects/ObjectManager.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewSequenceManager::CTrackViewSequenceManager()
|
||||
{
|
||||
GetIEditor()->RegisterNotifyListener(this);
|
||||
|
||||
AZ::EntitySystemBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewSequenceManager::~CTrackViewSequenceManager()
|
||||
{
|
||||
AZ::EntitySystemBus::Handler::BusDisconnect();
|
||||
|
||||
GetIEditor()->UnregisterNotifyListener(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::OnEditorNotifyEvent(EEditorNotifyEvent event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case eNotify_OnBeginGameMode:
|
||||
ResumeAllSequences();
|
||||
break;
|
||||
case eNotify_OnCloseScene:
|
||||
// Fall through
|
||||
case eNotify_OnBeginLoad:
|
||||
m_bUnloadingLevel = true;
|
||||
break;
|
||||
case eNotify_OnEndNewScene:
|
||||
// Fall through
|
||||
case eNotify_OnEndSceneOpen:
|
||||
// Fall through
|
||||
case eNotify_OnEndLoad:
|
||||
// Fall through
|
||||
case eNotify_OnLayerImportEnd:
|
||||
m_bUnloadingLevel = false;
|
||||
SortSequences();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewSequence* CTrackViewSequenceManager::GetSequenceByName(QString name) const
|
||||
{
|
||||
for (auto iter = m_sequences.begin(); iter != m_sequences.end(); ++iter)
|
||||
{
|
||||
CTrackViewSequence* sequence = (*iter).get();
|
||||
|
||||
if (sequence->GetName() == name)
|
||||
{
|
||||
return sequence;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewSequence* CTrackViewSequenceManager::GetSequenceByEntityId(const AZ::EntityId& entityId) const
|
||||
{
|
||||
for (auto iter = m_sequences.begin(); iter != m_sequences.end(); ++iter)
|
||||
{
|
||||
CTrackViewSequence* sequence = (*iter).get();
|
||||
|
||||
if (sequence->GetSequenceComponentEntityId() == entityId)
|
||||
{
|
||||
return sequence;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewSequence* CTrackViewSequenceManager::GetSequenceByAnimSequence(IAnimSequence* pAnimSequence) const
|
||||
{
|
||||
for (auto iter = m_sequences.begin(); iter != m_sequences.end(); ++iter)
|
||||
{
|
||||
CTrackViewSequence* sequence = (*iter).get();
|
||||
|
||||
if (sequence->m_pAnimSequence == pAnimSequence)
|
||||
{
|
||||
return sequence;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewSequence* CTrackViewSequenceManager::GetSequenceByIndex(unsigned int index) const
|
||||
{
|
||||
if (index >= m_sequences.size())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return m_sequences[index].get();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::CreateSequence(QString name, [[maybe_unused]] SequenceType sequenceType)
|
||||
{
|
||||
CGameEngine* pGameEngine = GetIEditor()->GetGameEngine();
|
||||
if (!pGameEngine || !pGameEngine->IsLevelLoaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CTrackViewSequence* pExistingSequence = GetSequenceByName(name);
|
||||
if (pExistingSequence)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Create TrackView Sequence");
|
||||
|
||||
// create AZ::Entity at the current center of the viewport, but don't select it
|
||||
|
||||
// Store the current selection for selection restore after the sequence component is created
|
||||
AzToolsFramework::EntityIdList selectedEntities;
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(selectedEntities, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::GetSelectedEntities);
|
||||
|
||||
AZ::EntityId newEntityId; // initialized with InvalidEntityId
|
||||
EBUS_EVENT_RESULT(newEntityId, AzToolsFramework::EditorRequests::Bus, CreateNewEntity, AZ::EntityId());
|
||||
if (newEntityId.IsValid())
|
||||
{
|
||||
// set the entity name
|
||||
AZ::Entity* entity = nullptr;
|
||||
EBUS_EVENT_RESULT(entity, AZ::ComponentApplicationBus, FindEntity, newEntityId);
|
||||
if (entity)
|
||||
{
|
||||
entity->SetName(static_cast<const char*>(name.toUtf8().data()));
|
||||
}
|
||||
|
||||
// add the SequenceComponent. The SequenceComponent's Init() method will call OnCreateSequenceObject() which will actually create
|
||||
// the sequence and connect it
|
||||
// #TODO LY-21846: Use "SequenceService" to find component, rather than specific component-type.
|
||||
AzToolsFramework::EntityCompositionRequestBus::Broadcast(&AzToolsFramework::EntityCompositionRequests::AddComponentsToEntities, AzToolsFramework::EntityIdList{ newEntityId }, AZ::ComponentTypeList{ "{C02DC0E2-D0F3-488B-B9EE-98E28077EC56}" });
|
||||
|
||||
// restore the Editor selection
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::Bus::Events::SetSelectedEntities, selectedEntities);
|
||||
|
||||
undoBatch.MarkEntityDirty(newEntityId);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
IAnimSequence* CTrackViewSequenceManager::OnCreateSequenceObject(QString name, bool isLegacySequence, AZ::EntityId entityId)
|
||||
{
|
||||
// Drop legacy sequences on the floor, they are no longer supported.
|
||||
if (isLegacySequence)
|
||||
{
|
||||
GetIEditor()->GetMovieSystem()->LogUserNotificationMsg(AZStd::string::format("Legacy Sequences are no longer supported. Skipping '%s'.", name.toUtf8().data()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IAnimSequence* sequence = GetIEditor()->GetMovieSystem()->CreateSequence(name.toUtf8().data(), /*bload =*/ false, /*id =*/ 0U, SequenceType::SequenceComponent, entityId);
|
||||
AZ_Assert(sequence, "Failed to create sequence");
|
||||
AddTrackViewSequence(new CTrackViewSequence(sequence));
|
||||
|
||||
return sequence;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::OnSequenceActivated(const AZ::EntityId& entityId)
|
||||
{
|
||||
CAnimationContext* pAnimationContext = GetIEditor()->GetAnimation();
|
||||
if (pAnimationContext != nullptr)
|
||||
{
|
||||
pAnimationContext->OnSequenceActivated(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::OnCreateSequenceComponent(AZStd::intrusive_ptr<IAnimSequence>& sequence)
|
||||
{
|
||||
// Fix up the internal pointers in the sequence to match the deserialized structure
|
||||
sequence->InitPostLoad();
|
||||
|
||||
// Add the sequence to the movie system
|
||||
GetIEditor()->GetMovieSystem()->AddSequence(sequence.get());
|
||||
|
||||
// Create the TrackView Sequence
|
||||
CTrackViewSequence* newTrackViewSequence = new CTrackViewSequence(sequence);
|
||||
|
||||
AddTrackViewSequence(newTrackViewSequence);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::AddTrackViewSequence(CTrackViewSequence* sequenceToAdd)
|
||||
{
|
||||
m_sequences.push_back(std::unique_ptr<CTrackViewSequence>(sequenceToAdd));
|
||||
SortSequences();
|
||||
OnSequenceAdded(sequenceToAdd);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::DeleteSequence(CTrackViewSequence* sequence)
|
||||
{
|
||||
const int numSequences = m_sequences.size();
|
||||
for (int sequenceIndex = 0; sequenceIndex < numSequences; ++sequenceIndex)
|
||||
{
|
||||
if (m_sequences[sequenceIndex].get() == sequence)
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Delete TrackView Sequence");
|
||||
|
||||
// delete Sequence Component (and entity if there's no other components left on the entity except for the Transform Component)
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::EntityId entityId = sequence->m_pAnimSequence->GetSequenceEntityId();
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, entityId);
|
||||
if (entity)
|
||||
{
|
||||
const AZ::Uuid editorSequenceComponentTypeId(EditorSequenceComponentTypeId);
|
||||
AZ::Component* sequenceComponent = entity->FindComponent(editorSequenceComponentTypeId);
|
||||
if (sequenceComponent)
|
||||
{
|
||||
AZ::ComponentTypeList requiredComponents;
|
||||
AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult(requiredComponents, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetRequiredComponentTypes);
|
||||
const int numComponentToDeleteEntity = requiredComponents.size() + 1;
|
||||
|
||||
AZ::Entity::ComponentArrayType entityComponents = entity->GetComponents();
|
||||
if (entityComponents.size() == numComponentToDeleteEntity)
|
||||
{
|
||||
// if the entity only has required components + 1 (the found sequenceComponent), delete the Entity. No need to start undo here
|
||||
// AzToolsFramework::ToolsApplicationRequests::DeleteEntities will take care of that
|
||||
AzToolsFramework::EntityIdList entitiesToDelete;
|
||||
entitiesToDelete.push_back(entityId);
|
||||
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::DeleteEntities, entitiesToDelete);
|
||||
}
|
||||
else
|
||||
{
|
||||
// just remove the sequence component from the entity
|
||||
CUndo undo("Delete TrackView Sequence");
|
||||
|
||||
AzToolsFramework::EntityCompositionRequestBus::Broadcast(&AzToolsFramework::EntityCompositionRequests::RemoveComponents, AZ::Entity::ComponentArrayType{ sequenceComponent });
|
||||
}
|
||||
|
||||
undoBatch.MarkEntityDirty(entityId);
|
||||
}
|
||||
}
|
||||
|
||||
// sequence was deleted, we can stop searching
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::RenameNode(CTrackViewAnimNode* animNode, const char* newName) const
|
||||
{
|
||||
AZ::EntityId entityId;
|
||||
CTrackViewSequence* sequence = animNode->GetSequence();
|
||||
|
||||
AZ_Assert(sequence, "Nodes should never have a null sequence.");
|
||||
|
||||
if (animNode->IsBoundToEditorObjects())
|
||||
{
|
||||
if (animNode->GetNodeType() == eTVNT_Sequence)
|
||||
{
|
||||
CTrackViewSequence* sequenceNode = static_cast<CTrackViewSequence*>(animNode);
|
||||
entityId = sequenceNode->GetSequenceComponentEntityId();
|
||||
}
|
||||
else if (animNode->GetNodeType() == eTVNT_AnimNode)
|
||||
{
|
||||
entityId = animNode->GetNodeEntityId();
|
||||
}
|
||||
}
|
||||
|
||||
if (entityId.IsValid())
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("ModifyEntityName");
|
||||
AZ::Entity* entity = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationBus::Events::FindEntity, entityId);
|
||||
entity->SetName(newName);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
else
|
||||
{
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Rename TrackView Node");
|
||||
animNode->SetName(newName);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
}
|
||||
|
||||
void CTrackViewSequenceManager::RemoveSequenceInternal(CTrackViewSequence* sequence)
|
||||
{
|
||||
std::unique_ptr<CTrackViewSequence> storedTrackViewSequence;
|
||||
|
||||
for (auto iter = m_sequences.begin(); iter != m_sequences.end(); ++iter)
|
||||
{
|
||||
std::unique_ptr<CTrackViewSequence>& currentSequence = *iter;
|
||||
|
||||
if (currentSequence.get() == sequence)
|
||||
{
|
||||
// Hang onto this until we finish this function.
|
||||
currentSequence.swap(storedTrackViewSequence);
|
||||
|
||||
// Remove from CryMovie and TrackView
|
||||
m_sequences.erase(iter);
|
||||
IMovieSystem* pMovieSystem = GetIEditor()->GetMovieSystem();
|
||||
pMovieSystem->RemoveSequence(sequence->m_pAnimSequence.get());
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OnSequenceRemoved(sequence);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::OnDeleteSequenceEntity(const AZ::EntityId& entityId)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetSequenceByEntityId(entityId);
|
||||
assert(sequence);
|
||||
|
||||
if (sequence)
|
||||
{
|
||||
const bool bUndoWasSuspended = GetIEditor()->IsUndoSuspended();
|
||||
bool isDuringUndo = false;
|
||||
|
||||
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(isDuringUndo, &AzToolsFramework::ToolsApplicationRequests::Bus::Events::IsDuringUndoRedo);
|
||||
|
||||
if (bUndoWasSuspended)
|
||||
{
|
||||
GetIEditor()->ResumeUndo();
|
||||
}
|
||||
|
||||
RemoveSequenceInternal(sequence);
|
||||
|
||||
if (bUndoWasSuspended)
|
||||
{
|
||||
GetIEditor()->SuspendUndo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::SortSequences()
|
||||
{
|
||||
std::stable_sort(m_sequences.begin(), m_sequences.end(),
|
||||
[](const std::unique_ptr<CTrackViewSequence>& a, const std::unique_ptr<CTrackViewSequence>& b) -> bool
|
||||
{
|
||||
QString aName = a.get()->GetName();
|
||||
QString bName = b.get()->GetName();
|
||||
return aName < bName;
|
||||
});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::ResumeAllSequences()
|
||||
{
|
||||
for (auto iter = m_sequences.begin(); iter != m_sequences.end(); ++iter)
|
||||
{
|
||||
CTrackViewSequence* sequence = (*iter).get();
|
||||
if (sequence)
|
||||
{
|
||||
sequence->Resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::OnSequenceAdded(CTrackViewSequence* sequence)
|
||||
{
|
||||
for (auto iter = m_listeners.begin(); iter != m_listeners.end(); ++iter)
|
||||
{
|
||||
(*iter)->OnSequenceAdded(sequence);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::OnSequenceRemoved(CTrackViewSequence* sequence)
|
||||
{
|
||||
for (auto iter = m_listeners.begin(); iter != m_listeners.end(); ++iter)
|
||||
{
|
||||
(*iter)->OnSequenceRemoved(sequence);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewSequenceManager::OnDataBaseItemEvent([[maybe_unused]] IDataBaseItem* pItem, EDataBaseItemEvent event)
|
||||
{
|
||||
if (event != EDataBaseItemEvent::EDB_ITEM_EVENT_ADD)
|
||||
{
|
||||
const uint numSequences = m_sequences.size();
|
||||
|
||||
for (uint i = 0; i < numSequences; ++i)
|
||||
{
|
||||
m_sequences[i]->UpdateDynamicParams();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewAnimNodeBundle CTrackViewSequenceManager::GetAllRelatedAnimNodes(const AZ::EntityId entityId) const
|
||||
{
|
||||
CTrackViewAnimNodeBundle nodeBundle;
|
||||
|
||||
const uint sequenceCount = GetCount();
|
||||
|
||||
for (uint sequenceIndex = 0; sequenceIndex < sequenceCount; ++sequenceIndex)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetSequenceByIndex(sequenceIndex);
|
||||
nodeBundle.AppendAnimNodeBundle(sequence->GetAllOwnedNodes(entityId));
|
||||
}
|
||||
|
||||
return nodeBundle;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewAnimNode* CTrackViewSequenceManager::GetActiveAnimNode(const AZ::EntityId entityId) const
|
||||
{
|
||||
CTrackViewAnimNodeBundle nodeBundle = GetAllRelatedAnimNodes(entityId);
|
||||
|
||||
const uint nodeCount = nodeBundle.GetCount();
|
||||
for (uint nodeIndex = 0; nodeIndex < nodeCount; ++nodeIndex)
|
||||
{
|
||||
CTrackViewAnimNode* animNode = nodeBundle.GetNode(nodeIndex);
|
||||
if (animNode->IsActive())
|
||||
{
|
||||
return animNode;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CTrackViewSequenceManager::OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name)
|
||||
{
|
||||
CTrackViewAnimNodeBundle bundle;
|
||||
|
||||
// entity or component entity sequence object
|
||||
bundle = GetAllRelatedAnimNodes(entityId);
|
||||
|
||||
// GetAllRelatedAnimNodes only accounts for entities in the sequences, not the sequence entities themselves. We additionally check
|
||||
// for sequence entities that have object as their entity object for renaming
|
||||
const uint sequenceCount = GetCount();
|
||||
for (uint sequenceIndex = 0; sequenceIndex < sequenceCount; ++sequenceIndex)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetSequenceByIndex(sequenceIndex);
|
||||
if (entityId == sequence->GetSequenceComponentEntityId())
|
||||
{
|
||||
bundle.AppendAnimNode(sequence);
|
||||
}
|
||||
}
|
||||
|
||||
const uint numAffectedNodes = bundle.GetCount();
|
||||
for (uint i = 0; i < numAffectedNodes; ++i)
|
||||
{
|
||||
CTrackViewAnimNode* animNode = bundle.GetNode(i);
|
||||
animNode->SetName(name.c_str());
|
||||
}
|
||||
|
||||
if (numAffectedNodes > 0)
|
||||
{
|
||||
GetIEditor()->Notify(eNotify_OnReloadTrackView);
|
||||
}
|
||||
}
|
||||
|
||||
void CTrackViewSequenceManager::OnEntityDestruction(const AZ::EntityId& entityId)
|
||||
{
|
||||
// we handle pre-delete instead of delete because GetAllRelatedAnimNodes() uses the ObjectManager to find node owners
|
||||
CTrackViewAnimNodeBundle bundle = GetAllRelatedAnimNodes(entityId);
|
||||
|
||||
const uint numAffectedAnimNodes = bundle.GetCount();
|
||||
for (uint i = 0; i < numAffectedAnimNodes; ++i)
|
||||
{
|
||||
CTrackViewAnimNode* animNode = bundle.GetNode(i);
|
||||
animNode->OnEntityRemoved();
|
||||
}
|
||||
|
||||
if (numAffectedAnimNodes > 0)
|
||||
{
|
||||
// Only reload track view if the object being deleted has related anim nodes.
|
||||
GetIEditor()->Notify(eNotify_OnReloadTrackView);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWSEQUENCEMANAGER_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWSEQUENCEMANAGER_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "TrackViewSequence.h"
|
||||
#include "IDataBaseManager.h"
|
||||
|
||||
#include <AzCore/Component/EntityBus.h>
|
||||
|
||||
class CTrackViewSequenceManager
|
||||
: public IEditorNotifyListener
|
||||
, public IDataBaseManagerListener
|
||||
, public ITrackViewSequenceManager
|
||||
, public AZ::EntitySystemBus::Handler
|
||||
{
|
||||
public:
|
||||
CTrackViewSequenceManager();
|
||||
~CTrackViewSequenceManager();
|
||||
|
||||
virtual void OnEditorNotifyEvent(EEditorNotifyEvent event);
|
||||
|
||||
unsigned int GetCount() const { return m_sequences.size(); }
|
||||
|
||||
void CreateSequence(QString name, SequenceType sequenceType);
|
||||
void DeleteSequence(CTrackViewSequence* pSequence);
|
||||
|
||||
void RenameNode(CTrackViewAnimNode* pAnimNode, const char* newName) const;
|
||||
|
||||
CTrackViewSequence* GetSequenceByName(QString name) const override;
|
||||
CTrackViewSequence* GetSequenceByEntityId(const AZ::EntityId& entityId) const override;
|
||||
CTrackViewSequence* GetSequenceByIndex(unsigned int index) const;
|
||||
CTrackViewSequence* GetSequenceByAnimSequence(IAnimSequence* pAnimSequence) const;
|
||||
|
||||
CTrackViewAnimNodeBundle GetAllRelatedAnimNodes(AZ::EntityId entityId) const;
|
||||
CTrackViewAnimNode* GetActiveAnimNode(AZ::EntityId entityId) const;
|
||||
|
||||
void AddListener(ITrackViewSequenceManagerListener* pListener) { stl::push_back_unique(m_listeners, pListener); }
|
||||
void RemoveListener(ITrackViewSequenceManagerListener* pListener) { stl::find_and_erase(m_listeners, pListener); }
|
||||
|
||||
// ITrackViewSequenceManager Overrides
|
||||
// Callback from SequenceObject
|
||||
IAnimSequence* OnCreateSequenceObject(QString name, bool isLegacySequence = true, AZ::EntityId entityId = AZ::EntityId()) override;
|
||||
void OnDeleteSequenceEntity(const AZ::EntityId& entityId) override;
|
||||
void OnCreateSequenceComponent(AZStd::intrusive_ptr<IAnimSequence>& sequence) override;
|
||||
void OnSequenceActivated(const AZ::EntityId& entityId) override;
|
||||
//~ ITrackViewSequenceManager Overrides
|
||||
|
||||
private:
|
||||
void AddTrackViewSequence(CTrackViewSequence* sequenceToAdd);
|
||||
void RemoveSequenceInternal(CTrackViewSequence* sequence);
|
||||
|
||||
void SortSequences();
|
||||
void ResumeAllSequences();
|
||||
|
||||
void OnSequenceAdded(CTrackViewSequence* pSequence);
|
||||
void OnSequenceRemoved(CTrackViewSequence* pSequence);
|
||||
|
||||
virtual void OnDataBaseItemEvent(IDataBaseItem* pItem, EDataBaseItemEvent event);
|
||||
|
||||
// AZ::EntitySystemBus
|
||||
void OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name) override;
|
||||
void OnEntityDestruction(const AZ::EntityId& entityId) override;
|
||||
|
||||
std::vector<ITrackViewSequenceManagerListener*> m_listeners;
|
||||
std::vector<std::unique_ptr<CTrackViewSequence> > m_sequences;
|
||||
|
||||
// Set to hold sequences that existed when undo transaction began
|
||||
std::set<CTrackViewSequence*> m_transactionSequences;
|
||||
|
||||
bool m_bUnloadingLevel;
|
||||
|
||||
// Used to handle object attach/detach
|
||||
std::unordered_map<CTrackViewNode*, Matrix34> m_prevTransforms;
|
||||
};
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWSEQUENCEMANAGER_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWSPLINECTRL_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWSPLINECTRL_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <IMovieSystem.h>
|
||||
#include "Controls/SplineCtrlEx.h"
|
||||
#include <functional>
|
||||
|
||||
class CTrackViewTrack;
|
||||
|
||||
/** A customized spline control for CTrackViewGraph.
|
||||
*/
|
||||
class CTrackViewSplineCtrl
|
||||
: public SplineWidget
|
||||
{
|
||||
friend class CUndoTrackViewSplineCtrl;
|
||||
public:
|
||||
CTrackViewSplineCtrl(QWidget* parent);
|
||||
virtual ~CTrackViewSplineCtrl();
|
||||
|
||||
virtual void ClearSelection();
|
||||
|
||||
void AddSpline(ISplineInterpolator* pSpline, CTrackViewTrack* pTrack, const QColor& color);
|
||||
void AddSpline(ISplineInterpolator * pSpline, CTrackViewTrack * pTrack, QColor anColorArray[4]);
|
||||
|
||||
const std::vector<CTrackViewTrack*>& GetTracks() const { return m_tracks; }
|
||||
void RemoveAllSplines();
|
||||
|
||||
void OnUserCommand(UINT cmd);
|
||||
bool IsUnifiedKeyCurrentlySelected() const;
|
||||
bool IsKeysFrozen() const { return m_bKeysFreeze; }
|
||||
bool IsTangentsFrozen() const { return m_bTangentsFreeze; }
|
||||
|
||||
void SetPlayCallback(const std::function<void()>& callback);
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
bool event(QEvent* event) override;
|
||||
void wheelEvent(QWheelEvent* event) override;
|
||||
|
||||
private:
|
||||
virtual void SelectKey(ISplineInterpolator* pSpline, int nKey, int nDimension, bool bSelect) override;
|
||||
virtual void SelectRectangle(const QRect& rc, bool bSelect) override;
|
||||
|
||||
std::vector<CTrackViewTrack*> m_tracks;
|
||||
|
||||
virtual bool GetTangentHandlePts(QPoint& inTangentPt, QPoint& pt, QPoint& outTangentPt,
|
||||
int nSpline, int nKey, int nDimension) override;
|
||||
void ComputeIncomingTangentAndEaseTo(float& ds, float& easeTo, QPoint inTangentPt,
|
||||
int nSpline, int nKey, int nDimension);
|
||||
void ComputeOutgoingTangentAndEaseFrom(float& dd, float& easeFrom, QPoint outTangentPt,
|
||||
int nSpline, int nKey, int nDimension);
|
||||
void AdjustTCB(float d_tension, float d_continuity, float d_bias);
|
||||
void MoveSelectedTangentHandleTo(const QPoint& point);
|
||||
|
||||
virtual ISplineCtrlUndo* CreateSplineCtrlUndoObject(std::vector<ISplineInterpolator*>& splineContainer);
|
||||
|
||||
bool m_bKeysFreeze;
|
||||
bool m_bTangentsFreeze;
|
||||
bool m_stashedRecordModeWhenDraggingTime;
|
||||
|
||||
std::function<void()> m_playCallback;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWSPLINECTRL_H
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewTimeline.h"
|
||||
|
||||
// Editor
|
||||
#include "AnimationContext.h"
|
||||
|
||||
namespace TrackView
|
||||
{
|
||||
void CTrackViewTimelineWidget::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
m_stashedRecordModeWhileTimeDragging = GetIEditor()->GetAnimation()->IsRecordMode();
|
||||
GetIEditor()->GetAnimation()->SetRecording(false); // disable recording while dragging time
|
||||
|
||||
TimelineWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void CTrackViewTimelineWidget::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
TimelineWidget::mouseReleaseEvent(event);
|
||||
|
||||
if (m_stashedRecordModeWhileTimeDragging)
|
||||
{
|
||||
GetIEditor()->GetAnimation()->SetRecording(true); // restore recording
|
||||
m_stashedRecordModeWhileTimeDragging = false; // reset stash
|
||||
}
|
||||
}
|
||||
} // namespace TrackView
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Controls/TimelineCtrl.h"
|
||||
|
||||
namespace TrackView
|
||||
{
|
||||
/** A customized timeline widget for CTrackViewGraph.
|
||||
*/
|
||||
class CTrackViewTimelineWidget
|
||||
: public TimelineWidget
|
||||
{
|
||||
public:
|
||||
|
||||
CTrackViewTimelineWidget(QWidget* parent = nullptr)
|
||||
: TimelineWidget(parent)
|
||||
, m_stashedRecordModeWhileTimeDragging(false) {};
|
||||
virtual ~CTrackViewTimelineWidget() = default;
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
|
||||
private:
|
||||
bool m_stashedRecordModeWhileTimeDragging;
|
||||
};
|
||||
} // namespace TrackView
|
||||
@@ -0,0 +1,829 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewTrack.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimParamType.h>
|
||||
|
||||
// Editor
|
||||
#include "TrackViewSequence.h"
|
||||
#include "TrackViewNodeFactories.h"
|
||||
#include "TrackViewUndo.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrackBundle::AppendTrack(CTrackViewTrack* pTrack)
|
||||
{
|
||||
// Check if newly added key has different type than existing ones
|
||||
if (m_bAllOfSameType && m_tracks.size() > 0)
|
||||
{
|
||||
const CTrackViewTrack* pLastTrack = m_tracks.back();
|
||||
|
||||
if (pTrack->GetParameterType() != pLastTrack->GetParameterType()
|
||||
|| pTrack->GetCurveType() != pLastTrack->GetCurveType()
|
||||
|| pTrack->GetValueType() != pLastTrack->GetValueType())
|
||||
{
|
||||
m_bAllOfSameType = false;
|
||||
}
|
||||
}
|
||||
|
||||
stl::push_back_unique(m_tracks, pTrack);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrackBundle::AppendTrackBundle(const CTrackViewTrackBundle& bundle)
|
||||
{
|
||||
for (auto iter = bundle.m_tracks.begin(); iter != bundle.m_tracks.end(); ++iter)
|
||||
{
|
||||
AppendTrack(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
bool CTrackViewTrackBundle::RemoveTrack(CTrackViewTrack* trackToRemove)
|
||||
{
|
||||
return stl::find_and_erase(m_tracks, trackToRemove);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewTrack::CTrackViewTrack(IAnimTrack* pTrack, CTrackViewAnimNode* pTrackAnimNode,
|
||||
CTrackViewNode* pParentNode, bool bIsSubTrack, unsigned int subTrackIndex)
|
||||
: CTrackViewNode(pParentNode)
|
||||
, m_pAnimTrack(pTrack)
|
||||
, m_pTrackAnimNode(pTrackAnimNode)
|
||||
, m_bIsSubTrack(bIsSubTrack)
|
||||
, m_subTrackIndex(subTrackIndex)
|
||||
{
|
||||
// Search for child tracks
|
||||
const unsigned int subTrackCount = m_pAnimTrack->GetSubTrackCount();
|
||||
for (unsigned int subTrackI = 0; subTrackI < subTrackCount; ++subTrackI)
|
||||
{
|
||||
IAnimTrack* pSubTrack = m_pAnimTrack->GetSubTrack(subTrackI);
|
||||
|
||||
CTrackViewTrackFactory trackFactory;
|
||||
CTrackViewTrack* pNewTVTrack = trackFactory.BuildTrack(pSubTrack, pTrackAnimNode, this, true, subTrackI);
|
||||
m_childNodes.push_back(std::unique_ptr<CTrackViewNode>(pNewTVTrack));
|
||||
}
|
||||
|
||||
m_bIsCompoundTrack = subTrackCount > 0;
|
||||
|
||||
// Connect bus to listen for OnStart/StopPlayInEditor events
|
||||
AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
CTrackViewTrack::~CTrackViewTrack()
|
||||
{
|
||||
AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewAnimNode* CTrackViewTrack::GetAnimNode() const
|
||||
{
|
||||
return m_pTrackAnimNode;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewTrack::SnapTimeToPrevKey(float& time) const
|
||||
{
|
||||
CTrackViewKeyHandle prevKey = const_cast<CTrackViewTrack*>(this)->GetPrevKey(time);
|
||||
|
||||
if (prevKey.IsValid())
|
||||
{
|
||||
time = prevKey.GetTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewTrack::SnapTimeToNextKey(float& time) const
|
||||
{
|
||||
CTrackViewKeyHandle prevKey = const_cast<CTrackViewTrack*>(this)->GetNextKey(time);
|
||||
|
||||
if (prevKey.IsValid())
|
||||
{
|
||||
time = prevKey.GetTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SetExpanded(bool expanded)
|
||||
{
|
||||
if (m_pAnimTrack)
|
||||
{
|
||||
CTrackViewSequence* sequence = GetSequence();
|
||||
if (nullptr != sequence)
|
||||
{
|
||||
if (GetExpanded() != expanded)
|
||||
{
|
||||
m_pAnimTrack->SetExpanded(expanded);
|
||||
|
||||
if (expanded)
|
||||
{
|
||||
sequence->OnNodeChanged(this, ITrackViewSequenceListener::eNodeChangeType_Expanded);
|
||||
}
|
||||
else
|
||||
{
|
||||
sequence->OnNodeChanged(this, ITrackViewSequenceListener::eNodeChangeType_Collapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewTrack::GetExpanded() const
|
||||
{
|
||||
return (m_pAnimTrack) ? m_pAnimTrack->GetExpanded() : false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewTrack::GetPrevKey(const float time)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle;
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
const float startTime = time;
|
||||
float closestTime = -std::numeric_limits<float>::max();
|
||||
|
||||
const int numKeys = m_pAnimTrack->GetNumKeys();
|
||||
for (int i = 0; i < numKeys; ++i)
|
||||
{
|
||||
const float keyTime = m_pAnimTrack->GetKeyTime(i);
|
||||
if (keyTime < startTime && keyTime > closestTime)
|
||||
{
|
||||
keyHandle = CTrackViewKeyHandle(this, i);
|
||||
closestTime = keyTime;
|
||||
}
|
||||
}
|
||||
|
||||
return keyHandle;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewTrack::GetNextKey(const float time)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle;
|
||||
|
||||
const float startTime = time;
|
||||
float closestTime = std::numeric_limits<float>::max();
|
||||
|
||||
const int numKeys = m_pAnimTrack->GetNumKeys();
|
||||
for (int i = 0; i < numKeys; ++i)
|
||||
{
|
||||
const float keyTime = m_pAnimTrack->GetKeyTime(i);
|
||||
if (keyTime > startTime && keyTime < closestTime)
|
||||
{
|
||||
keyHandle = CTrackViewKeyHandle(this, i);
|
||||
closestTime = keyTime;
|
||||
}
|
||||
}
|
||||
|
||||
return keyHandle;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyBundle CTrackViewTrack::GetSelectedKeys()
|
||||
{
|
||||
CTrackViewKeyBundle bundle;
|
||||
|
||||
if (m_bIsCompoundTrack)
|
||||
{
|
||||
for (auto iter = m_childNodes.begin(); iter != m_childNodes.end(); ++iter)
|
||||
{
|
||||
bundle.AppendKeyBundle((*iter)->GetSelectedKeys());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bundle = GetKeys(true, -std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyBundle CTrackViewTrack::GetAllKeys()
|
||||
{
|
||||
CTrackViewKeyBundle bundle;
|
||||
|
||||
if (m_bIsCompoundTrack)
|
||||
{
|
||||
for (auto iter = m_childNodes.begin(); iter != m_childNodes.end(); ++iter)
|
||||
{
|
||||
bundle.AppendKeyBundle((*iter)->GetAllKeys());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bundle = GetKeys(false, -std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyBundle CTrackViewTrack::GetKeysInTimeRange(const float t0, const float t1)
|
||||
{
|
||||
CTrackViewKeyBundle bundle;
|
||||
|
||||
if (m_bIsCompoundTrack)
|
||||
{
|
||||
for (auto iter = m_childNodes.begin(); iter != m_childNodes.end(); ++iter)
|
||||
{
|
||||
bundle.AppendKeyBundle((*iter)->GetKeysInTimeRange(t0, t1));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bundle = GetKeys(false, t0, t1);
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyBundle CTrackViewTrack::GetKeys(const bool bOnlySelected, const float t0, const float t1)
|
||||
{
|
||||
CTrackViewKeyBundle bundle;
|
||||
|
||||
const int keyCount = m_pAnimTrack->GetNumKeys();
|
||||
for (int keyIndex = 0; keyIndex < keyCount; ++keyIndex)
|
||||
{
|
||||
const float keyTime = m_pAnimTrack->GetKeyTime(keyIndex);
|
||||
const bool timeRangeOk = (t0 <= keyTime && keyTime <= t1);
|
||||
|
||||
if ((!bOnlySelected || IsKeySelected(keyIndex)) && timeRangeOk)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle(this, keyIndex);
|
||||
bundle.AppendKey(keyHandle);
|
||||
}
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewTrack::CreateKey(const float time)
|
||||
{
|
||||
const int keyIndex = m_pAnimTrack->CreateKey(time);
|
||||
GetSequence()->OnKeysChanged();
|
||||
CTrackViewKeyHandle createdKeyHandle(this, keyIndex);
|
||||
GetSequence()->OnKeyAdded(createdKeyHandle);
|
||||
|
||||
return createdKeyHandle;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SlideKeys(const float time0, const float timeOffset)
|
||||
{
|
||||
for (int i = 0; i < m_pAnimTrack->GetNumKeys(); ++i)
|
||||
{
|
||||
float keyTime = m_pAnimTrack->GetKeyTime(i);
|
||||
if (keyTime >= time0)
|
||||
{
|
||||
m_pAnimTrack->SetKeyTime(i, keyTime + timeOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::OffsetKeyPosition(const Vec3& offset)
|
||||
{
|
||||
// Use the CUndoComponentEntityTrackObject here and not the AZ Undo system because
|
||||
// the Editor movement system uses CUndo as part of its move function (canceling last frame of undo whilst dragging).
|
||||
CUndo::Record(new CUndoComponentEntityTrackObject(this));
|
||||
m_pAnimTrack->OffsetKeyPosition(offset);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::UpdateKeyDataAfterParentChanged(const AZ::Transform& oldParentWorldTM, const AZ::Transform& newParentWorldTM)
|
||||
{
|
||||
AZStd::unique_ptr<AzToolsFramework::ScopedUndoBatch> undoBatch;
|
||||
|
||||
if (!AzToolsFramework::UndoRedoOperationInProgress())
|
||||
{
|
||||
undoBatch = AZStd::make_unique<AzToolsFramework::ScopedUndoBatch>("Update Key Data After Parent Changed");
|
||||
}
|
||||
|
||||
m_pAnimTrack->UpdateKeyDataAfterParentChanged(oldParentWorldTM, newParentWorldTM);
|
||||
|
||||
if (undoBatch.get())
|
||||
{
|
||||
undoBatch->MarkEntityDirty(GetSequence()->GetSequenceComponentEntityId());
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewTrack::GetKey(unsigned int index)
|
||||
{
|
||||
if (index < GetKeyCount())
|
||||
{
|
||||
return CTrackViewKeyHandle(this, index);
|
||||
}
|
||||
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyConstHandle CTrackViewTrack::GetKey(unsigned int index) const
|
||||
{
|
||||
if (index < GetKeyCount())
|
||||
{
|
||||
return CTrackViewKeyConstHandle(this, index);
|
||||
}
|
||||
|
||||
return CTrackViewKeyConstHandle();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewTrack::GetKeyByTime(const float time)
|
||||
{
|
||||
if (m_bIsCompoundTrack)
|
||||
{
|
||||
// Search key in sub tracks
|
||||
unsigned int currentIndex = 0;
|
||||
|
||||
unsigned int childCount = GetChildCount();
|
||||
for (unsigned int i = 0; i < childCount; ++i)
|
||||
{
|
||||
CTrackViewTrack* pChildTrack = static_cast<CTrackViewTrack*>(GetChild(i));
|
||||
|
||||
int keyIndex = pChildTrack->m_pAnimTrack->FindKey(time);
|
||||
if (keyIndex >= 0)
|
||||
{
|
||||
return CTrackViewKeyHandle(this, currentIndex + keyIndex);
|
||||
}
|
||||
|
||||
currentIndex += pChildTrack->GetKeyCount();
|
||||
}
|
||||
}
|
||||
|
||||
int keyIndex = m_pAnimTrack->FindKey(time);
|
||||
|
||||
if (keyIndex < 0)
|
||||
{
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
return CTrackViewKeyHandle(this, keyIndex);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewTrack::GetNearestKeyByTime(const float time)
|
||||
{
|
||||
int minDelta = std::numeric_limits<int>::max();
|
||||
|
||||
const unsigned int keyCount = GetKeyCount();
|
||||
for (unsigned int i = 0; i < keyCount; ++i)
|
||||
{
|
||||
CTrackViewKeyHandle keyHandle = GetKey(i);
|
||||
|
||||
const int deltaT = abs((int)keyHandle.GetTime() - (int)time);
|
||||
|
||||
// If deltaT got larger since last key, then the last key
|
||||
// was the key with minimum temporal distance to the given time
|
||||
if (deltaT > minDelta)
|
||||
{
|
||||
return CTrackViewKeyHandle(this, i - 1);
|
||||
}
|
||||
|
||||
minDelta = std::min(minDelta, deltaT);
|
||||
}
|
||||
|
||||
// If we didn't return above and there are keys, then the
|
||||
// last key needs to be the one with minimum distance
|
||||
if (keyCount > 0)
|
||||
{
|
||||
return CTrackViewKeyHandle(this, keyCount - 1);
|
||||
}
|
||||
|
||||
// No keys
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::GetKeyValueRange(float& min, float& max) const
|
||||
{
|
||||
m_pAnimTrack->GetKeyValueRange(min, max);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
ColorB CTrackViewTrack::GetCustomColor() const
|
||||
{
|
||||
return m_pAnimTrack->GetCustomColor();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SetCustomColor(ColorB color)
|
||||
{
|
||||
m_pAnimTrack->SetCustomColor(color);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewTrack::HasCustomColor() const
|
||||
{
|
||||
return m_pAnimTrack->HasCustomColor();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::ClearCustomColor()
|
||||
{
|
||||
m_pAnimTrack->ClearCustomColor();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
IAnimTrack::EAnimTrackFlags CTrackViewTrack::GetFlags() const
|
||||
{
|
||||
return (IAnimTrack::EAnimTrackFlags)m_pAnimTrack->GetFlags();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewTrackMemento CTrackViewTrack::GetMemento() const
|
||||
{
|
||||
CTrackViewTrackMemento memento;
|
||||
memento.m_serializedTrackState = XmlHelpers::CreateXmlNode("TrackState");
|
||||
m_pAnimTrack->Serialize(memento.m_serializedTrackState, false);
|
||||
return memento;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::RestoreFromMemento(const CTrackViewTrackMemento& memento)
|
||||
{
|
||||
// We're going to de-serialize, so this is const safe
|
||||
XmlNodeRef& xmlNode = const_cast<XmlNodeRef&>(memento.m_serializedTrackState);
|
||||
m_pAnimTrack->Serialize(xmlNode, true);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
const char* CTrackViewTrack::GetName() const
|
||||
{
|
||||
CTrackViewNode* pParentNode = GetParentNode();
|
||||
|
||||
if (pParentNode->GetNodeType() == eTVNT_Track)
|
||||
{
|
||||
CTrackViewTrack* pParentTrack = static_cast<CTrackViewTrack*>(pParentNode);
|
||||
return pParentTrack->m_pAnimTrack->GetSubTrackName(m_subTrackIndex);
|
||||
}
|
||||
|
||||
return GetAnimNode()->GetParamName(GetParameterType());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SetDisabled(bool bDisabled)
|
||||
{
|
||||
if (bDisabled)
|
||||
{
|
||||
m_pAnimTrack->SetFlags(m_pAnimTrack->GetFlags() | IAnimTrack::eAnimTrackFlags_Disabled);
|
||||
GetSequence()->OnNodeChanged(this, ITrackViewSequenceListener::eNodeChangeType_Disabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pAnimTrack->SetFlags(m_pAnimTrack->GetFlags() & ~IAnimTrack::eAnimTrackFlags_Disabled);
|
||||
GetSequence()->OnNodeChanged(this, ITrackViewSequenceListener::eNodeChangeType_Enabled);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewTrack::IsDisabled() const
|
||||
{
|
||||
return m_pAnimTrack->GetFlags() & IAnimTrack::eAnimTrackFlags_Disabled;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SetMuted(bool bMuted)
|
||||
{
|
||||
if (UsesMute())
|
||||
{
|
||||
if (bMuted)
|
||||
{
|
||||
m_pAnimTrack->SetFlags(m_pAnimTrack->GetFlags() | IAnimTrack::eAnimTrackFlags_Muted);
|
||||
GetSequence()->OnNodeChanged(this, ITrackViewSequenceListener::eNodeChangeType_Muted);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pAnimTrack->SetFlags(m_pAnimTrack->GetFlags() & ~IAnimTrack::eAnimTrackFlags_Muted);
|
||||
GetSequence()->OnNodeChanged(this, ITrackViewSequenceListener::eNodeChangeType_Unmuted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Returns whether the track is muted, or false if the track does not use muting
|
||||
bool CTrackViewTrack::IsMuted() const
|
||||
{
|
||||
return m_pAnimTrack->UsesMute() ? (m_pAnimTrack->GetFlags() & IAnimTrack::eAnimTrackFlags_Muted) : false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SetKey(unsigned int keyIndex, IKey* pKey)
|
||||
{
|
||||
m_pAnimTrack->SetKey(keyIndex, pKey);
|
||||
m_pTrackAnimNode->GetSequence()->OnKeysChanged();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::GetKey(unsigned int keyIndex, IKey* pKey) const
|
||||
{
|
||||
m_pAnimTrack->GetKey(keyIndex, pKey);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SelectKey(unsigned int keyIndex, bool bSelect)
|
||||
{
|
||||
const bool bWasSelected = m_pAnimTrack->IsKeySelected(keyIndex);
|
||||
|
||||
m_pAnimTrack->SelectKey(keyIndex, bSelect);
|
||||
|
||||
if (bSelect != bWasSelected)
|
||||
{
|
||||
m_pTrackAnimNode->GetSequence()->OnKeySelectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SetKeyTime(const int index, const float time, bool notifyListeners)
|
||||
{
|
||||
const float bOldTime = m_pAnimTrack->GetKeyTime(index);
|
||||
|
||||
m_pAnimTrack->SetKeyTime(index, time);
|
||||
|
||||
if (notifyListeners && (bOldTime != time))
|
||||
{
|
||||
// The keys were just make invalid by the above SetKeyTime(), so sort them now
|
||||
// to make sure they are ready to be used. Only do this when notifyListeners
|
||||
// is set so client callers can batch up a bunch of SetKeyTime calls if desired.
|
||||
m_pAnimTrack->SortKeys();
|
||||
|
||||
m_pTrackAnimNode->GetSequence()->OnKeysChanged();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
float CTrackViewTrack::GetKeyTime(const int index) const
|
||||
{
|
||||
return m_pAnimTrack->GetKeyTime(index);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::RemoveKey(const int index)
|
||||
{
|
||||
m_pAnimTrack->RemoveKey(index);
|
||||
m_pTrackAnimNode->GetSequence()->OnKeysChanged();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
int CTrackViewTrack::CloneKey(const int index)
|
||||
{
|
||||
int newIndex = m_pAnimTrack->CloneKey(index);
|
||||
m_pTrackAnimNode->GetSequence()->OnKeysChanged();
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SelectKeys(const bool bSelected)
|
||||
{
|
||||
m_pTrackAnimNode->GetSequence()->QueueNotifications();
|
||||
|
||||
if (!m_bIsCompoundTrack)
|
||||
{
|
||||
unsigned int keyCount = GetKeyCount();
|
||||
for (unsigned int i = 0; i < keyCount; ++i)
|
||||
{
|
||||
m_pAnimTrack->SelectKey(i, bSelected);
|
||||
m_pTrackAnimNode->GetSequence()->OnKeySelectionChanged();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Affect sub tracks
|
||||
unsigned int childCount = GetChildCount();
|
||||
for (unsigned int childIndex = 0; childIndex < childCount; ++childIndex)
|
||||
{
|
||||
CTrackViewTrack* pChildTrack = static_cast<CTrackViewTrack*>(GetChild(childIndex));
|
||||
pChildTrack->SelectKeys(bSelected);
|
||||
m_pTrackAnimNode->GetSequence()->OnKeySelectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
m_pTrackAnimNode->GetSequence()->SubmitPendingNotifcations();
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewTrack::IsKeySelected(unsigned int keyIndex) const
|
||||
{
|
||||
if (m_pAnimTrack)
|
||||
{
|
||||
return m_pAnimTrack->IsKeySelected(keyIndex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SetSortMarkerKey(unsigned int keyIndex, bool enabled)
|
||||
{
|
||||
if (m_pAnimTrack)
|
||||
{
|
||||
return m_pAnimTrack->SetSortMarkerKey(keyIndex, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
bool CTrackViewTrack::IsSortMarkerKey(unsigned int keyIndex) const
|
||||
{
|
||||
if (m_pAnimTrack)
|
||||
{
|
||||
return m_pAnimTrack->IsSortMarkerKey(keyIndex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewKeyHandle CTrackViewTrack::GetSubTrackKeyHandle(unsigned int index) const
|
||||
{
|
||||
// Return handle to sub track key
|
||||
unsigned int childCount = GetChildCount();
|
||||
for (unsigned int childIndex = 0; childIndex < childCount; ++childIndex)
|
||||
{
|
||||
CTrackViewTrack* pChildTrack = static_cast<CTrackViewTrack*>(GetChild(childIndex));
|
||||
|
||||
const unsigned int childKeyCount = pChildTrack->GetKeyCount();
|
||||
if (index < childKeyCount)
|
||||
{
|
||||
return pChildTrack->GetKey(index);
|
||||
}
|
||||
|
||||
index -= childKeyCount;
|
||||
}
|
||||
|
||||
return CTrackViewKeyHandle();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::SetAnimationLayerIndex(const int index)
|
||||
{
|
||||
if (m_pAnimTrack)
|
||||
{
|
||||
m_pAnimTrack->SetAnimationLayerIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
int CTrackViewTrack::GetAnimationLayerIndex() const
|
||||
{
|
||||
return m_pAnimTrack->GetAnimationLayerIndex();
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::OnStartPlayInEditor()
|
||||
{
|
||||
// remap any AZ::EntityId's used in tracks
|
||||
if (m_pAnimTrack)
|
||||
{
|
||||
// OnStopPlayInEditor clears this as well, but we clear it here in case OnStartPlayInEditor() is called multiple times before OnStopPlayInEditor()
|
||||
m_paramTypeToStashedEntityIdMap.clear();
|
||||
|
||||
CAnimParamType trackParamType = m_pAnimTrack->GetParameterType();
|
||||
const AnimParamType paramType = trackParamType.GetType();
|
||||
if (paramType == AnimParamType::Camera || paramType == AnimParamType::Sequence)
|
||||
{
|
||||
ISelectKey selectKey;
|
||||
ISequenceKey sequenceKey;
|
||||
IKey* key = nullptr;
|
||||
|
||||
for (int i = 0; i < m_pAnimTrack->GetNumKeys(); i++)
|
||||
{
|
||||
AZ::EntityId entityIdToRemap;
|
||||
|
||||
if (paramType == AnimParamType::Camera)
|
||||
{
|
||||
m_pAnimTrack->GetKey(i, &selectKey);
|
||||
entityIdToRemap = selectKey.cameraAzEntityId;
|
||||
key = &selectKey;
|
||||
}
|
||||
else if (paramType == AnimParamType::Sequence)
|
||||
{
|
||||
m_pAnimTrack->GetKey(i, &sequenceKey);
|
||||
entityIdToRemap = sequenceKey.sequenceEntityId;
|
||||
key = &sequenceKey;
|
||||
}
|
||||
|
||||
// stash the entity Id for restore in OnStopPlayInEditor
|
||||
m_paramTypeToStashedEntityIdMap[trackParamType].push_back(entityIdToRemap);
|
||||
|
||||
if (entityIdToRemap.IsValid())
|
||||
{
|
||||
AZ::EntityId remappedId;
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(&AzToolsFramework::EditorEntityContextRequestBus::Events::MapEditorIdToRuntimeId, entityIdToRemap, remappedId);
|
||||
|
||||
// remap
|
||||
if (paramType == AnimParamType::Camera)
|
||||
{
|
||||
selectKey.cameraAzEntityId = remappedId;
|
||||
}
|
||||
else if (paramType == AnimParamType::Sequence)
|
||||
{
|
||||
sequenceKey.sequenceEntityId = remappedId;
|
||||
}
|
||||
m_pAnimTrack->SetKey(i, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::OnStopPlayInEditor()
|
||||
{
|
||||
// restore any AZ::EntityId's remapped in OnStartPlayInEditor
|
||||
if (m_pAnimTrack && m_paramTypeToStashedEntityIdMap.size())
|
||||
{
|
||||
CAnimParamType trackParamType = m_pAnimTrack->GetParameterType();
|
||||
const AnimParamType paramType = trackParamType.GetType();
|
||||
|
||||
if (paramType == AnimParamType::Camera || paramType == AnimParamType::Sequence)
|
||||
{
|
||||
for (int i = 0; i < m_pAnimTrack->GetNumKeys(); i++)
|
||||
{
|
||||
ISelectKey selectKey;
|
||||
ISequenceKey sequenceKey;
|
||||
IKey* key = nullptr;
|
||||
|
||||
// restore entityIds
|
||||
if (paramType == AnimParamType::Camera)
|
||||
{
|
||||
m_pAnimTrack->GetKey(i, &selectKey);
|
||||
selectKey.cameraAzEntityId = m_paramTypeToStashedEntityIdMap[trackParamType][i];
|
||||
key = &selectKey;
|
||||
}
|
||||
else if (paramType == AnimParamType::Sequence)
|
||||
{
|
||||
m_pAnimTrack->GetKey(i, &sequenceKey);
|
||||
sequenceKey.sequenceEntityId = m_paramTypeToStashedEntityIdMap[trackParamType][i];
|
||||
key = &sequenceKey;
|
||||
}
|
||||
m_pAnimTrack->SetKey(i, key);
|
||||
}
|
||||
}
|
||||
// clear the StashedEntityIdMap now that we've consumed it
|
||||
m_paramTypeToStashedEntityIdMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks)
|
||||
{
|
||||
if (bOnlyFromSelectedTracks && !IsSelected())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetKeyCount() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (bOnlySelectedKeys)
|
||||
{
|
||||
CTrackViewKeyBundle keyBundle = GetSelectedKeys();
|
||||
if (keyBundle.GetKeyCount() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
XmlNodeRef childNode = xmlNode->newChild("Track");
|
||||
childNode->setAttr("name", GetName());
|
||||
GetParameterType().SaveToXml(childNode);
|
||||
childNode->setAttr("valueType", static_cast<int>(GetValueType()));
|
||||
|
||||
m_pAnimTrack->SerializeSelection(childNode, false, bOnlySelectedKeys);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CTrackViewTrack::PasteKeys(XmlNodeRef xmlNode, const float timeOffset)
|
||||
{
|
||||
|
||||
CTrackViewSequence* sequence = GetSequence();
|
||||
AZ_Assert(sequence, "Expected sequence not to be null.");
|
||||
|
||||
AzToolsFramework::ScopedUndoBatch undoBatch("Paste Keys");
|
||||
m_pAnimTrack->SerializeSelection(xmlNode, true, true, timeOffset);
|
||||
undoBatch.MarkEntityDirty(sequence->GetSequenceComponentEntityId());
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWTRACK_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWTRACK_H
|
||||
#pragma once
|
||||
|
||||
#include "IMovieSystem.h"
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
|
||||
#include "TrackViewNode.h"
|
||||
|
||||
class CTrackViewAnimNode;
|
||||
enum class AnimValueType;
|
||||
|
||||
// Represents a bundle of tracks
|
||||
class CTrackViewTrackBundle
|
||||
{
|
||||
public:
|
||||
CTrackViewTrackBundle()
|
||||
: m_bAllOfSameType(true)
|
||||
, m_bHasRotationTrack(false) {}
|
||||
|
||||
unsigned int GetCount() const { return m_tracks.size(); }
|
||||
CTrackViewTrack* GetTrack(const unsigned int index) { return m_tracks[index]; }
|
||||
const CTrackViewTrack* GetTrack(const unsigned int index) const { return m_tracks[index]; }
|
||||
|
||||
void AppendTrack(CTrackViewTrack* pTrack);
|
||||
void AppendTrackBundle(const CTrackViewTrackBundle& bundle);
|
||||
|
||||
bool RemoveTrack(CTrackViewTrack* pTrackToRemove);
|
||||
|
||||
bool IsOneTrack() const;
|
||||
bool AreAllOfSameType() const { return m_bAllOfSameType; }
|
||||
bool HasRotationTrack() const { return m_bHasRotationTrack; }
|
||||
|
||||
private:
|
||||
bool m_bAllOfSameType;
|
||||
bool m_bHasRotationTrack;
|
||||
std::vector<CTrackViewTrack*> m_tracks;
|
||||
};
|
||||
|
||||
// Track Memento for Undo/Redo
|
||||
class CTrackViewTrackMemento
|
||||
{
|
||||
private:
|
||||
friend class CTrackViewTrack;
|
||||
XmlNodeRef m_serializedTrackState;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// This class represents a IAnimTrack in TrackView and contains
|
||||
// the editor side code for changing it
|
||||
//
|
||||
// It does *not* have ownership of the IAnimTrack, therefore deleting it
|
||||
// will not destroy the CryMovie track
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
class CTrackViewTrack
|
||||
: public CTrackViewNode
|
||||
, public ITrackViewKeyBundle
|
||||
, public AzToolsFramework::EditorEntityContextNotificationBus::Handler
|
||||
{
|
||||
friend class CTrackViewKeyHandle;
|
||||
friend class CTrackViewKeyConstHandle;
|
||||
friend class CTrackViewKeyBundle;
|
||||
|
||||
public:
|
||||
CTrackViewTrack(IAnimTrack* pTrack, CTrackViewAnimNode* pTrackAnimNode, CTrackViewNode* pParentNode,
|
||||
bool bIsSubTrack = false, unsigned int subTrackIndex = 0);
|
||||
~CTrackViewTrack();
|
||||
|
||||
CTrackViewAnimNode* GetAnimNode() const;
|
||||
|
||||
// Name getter
|
||||
virtual const char* GetName() const;
|
||||
|
||||
// CTrackViewNode
|
||||
virtual ETrackViewNodeType GetNodeType() const override { return eTVNT_Track; }
|
||||
|
||||
// Check for compound/sub track
|
||||
bool IsCompoundTrack() const { return m_bIsCompoundTrack; }
|
||||
|
||||
// Sub track index
|
||||
bool IsSubTrack() const { return m_bIsSubTrack; }
|
||||
unsigned int GetSubTrackIndex() const { return m_subTrackIndex; }
|
||||
|
||||
// Snap time value to prev/next key in track
|
||||
virtual bool SnapTimeToPrevKey(float& time) const override;
|
||||
virtual bool SnapTimeToNextKey(float& time) const override;
|
||||
|
||||
// Expanded state interface
|
||||
void SetExpanded(bool expanded) override;
|
||||
bool GetExpanded() const override;
|
||||
|
||||
// Key getters
|
||||
virtual unsigned int GetKeyCount() const override { return m_pAnimTrack->GetNumKeys(); }
|
||||
virtual CTrackViewKeyHandle GetKey(unsigned int index) override;
|
||||
virtual CTrackViewKeyConstHandle GetKey(unsigned int index) const;
|
||||
|
||||
virtual CTrackViewKeyHandle GetKeyByTime(const float time);
|
||||
virtual CTrackViewKeyHandle GetNearestKeyByTime(const float time);
|
||||
|
||||
virtual CTrackViewKeyBundle GetSelectedKeys() override;
|
||||
virtual CTrackViewKeyBundle GetAllKeys() override;
|
||||
virtual CTrackViewKeyBundle GetKeysInTimeRange(const float t0, const float t1) override;
|
||||
|
||||
// Key modifications
|
||||
virtual CTrackViewKeyHandle CreateKey(const float time);
|
||||
virtual void SlideKeys(const float time0, const float timeOffset);
|
||||
void OffsetKeyPosition(const Vec3& offset);
|
||||
void UpdateKeyDataAfterParentChanged(const AZ::Transform& oldParentWorldTM, const AZ::Transform& newParentWorldTM);
|
||||
|
||||
// Value getters
|
||||
template <class Type>
|
||||
void GetValue(const float time, Type& value, bool applyMultiplier) const
|
||||
{
|
||||
assert (m_pAnimTrack.get());
|
||||
return m_pAnimTrack->GetValue(time, value, applyMultiplier);
|
||||
}
|
||||
template <class Type>
|
||||
void GetValue(const float time, Type& value) const
|
||||
{
|
||||
assert(m_pAnimTrack.get());
|
||||
return m_pAnimTrack->GetValue(time, value);
|
||||
}
|
||||
|
||||
void GetKeyValueRange(float& min, float& max) const;
|
||||
|
||||
// Type getters
|
||||
const CAnimParamType& GetParameterType() const { return m_pAnimTrack->GetParameterType(); }
|
||||
AnimValueType GetValueType() const { return m_pAnimTrack->GetValueType(); }
|
||||
EAnimCurveType GetCurveType() const { return m_pAnimTrack->GetCurveType(); }
|
||||
|
||||
// Mask
|
||||
bool IsMasked(uint32 mask) const { return m_pAnimTrack->IsMasked(mask); }
|
||||
|
||||
// Flag getter
|
||||
IAnimTrack::EAnimTrackFlags GetFlags() const;
|
||||
|
||||
// Spline getter
|
||||
ISplineInterpolator* GetSpline() const { return m_pAnimTrack->GetSpline(); }
|
||||
|
||||
// Color
|
||||
ColorB GetCustomColor() const;
|
||||
void SetCustomColor(ColorB color);
|
||||
bool HasCustomColor() const;
|
||||
void ClearCustomColor();
|
||||
|
||||
// Memento
|
||||
virtual CTrackViewTrackMemento GetMemento() const;
|
||||
virtual void RestoreFromMemento(const CTrackViewTrackMemento& memento);
|
||||
|
||||
// Disabled state
|
||||
virtual void SetDisabled(bool bDisabled) override;
|
||||
virtual bool IsDisabled() const override;
|
||||
|
||||
// Muted state
|
||||
void SetMuted(bool bMuted);
|
||||
bool IsMuted() const;
|
||||
|
||||
// Returns if the contained AnimTrack responds to muting
|
||||
bool UsesMute() const { return m_pAnimTrack.get() ? m_pAnimTrack->UsesMute() : false; }
|
||||
|
||||
// Key selection
|
||||
virtual void SelectKeys(const bool bSelected) override;
|
||||
|
||||
// Paste from XML representation with time offset
|
||||
void PasteKeys(XmlNodeRef xmlNode, const float timeOffset);
|
||||
|
||||
// Key types
|
||||
virtual bool AreAllKeysOfSameType() const override { return true; }
|
||||
|
||||
// Animation layer index
|
||||
void SetAnimationLayerIndex(const int index);
|
||||
int GetAnimationLayerIndex() const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AzToolsFramework::EditorEntityContextNotificationBus implementation
|
||||
void OnStartPlayInEditor() override;
|
||||
void OnStopPlayInEditor() override;
|
||||
//~AzToolsFramework::EditorEntityContextNotificationBus implementation
|
||||
|
||||
IAnimTrack* GetAnimTrack() const { return m_pAnimTrack.get(); }
|
||||
|
||||
unsigned int GetId() const
|
||||
{
|
||||
return m_pAnimTrack->GetId();
|
||||
}
|
||||
|
||||
void SetId(unsigned int id)
|
||||
{
|
||||
m_pAnimTrack->SetId(id);
|
||||
}
|
||||
|
||||
private:
|
||||
CTrackViewKeyHandle GetPrevKey(const float time);
|
||||
CTrackViewKeyHandle GetNextKey(const float time);
|
||||
|
||||
// Those are called from CTrackViewKeyHandle
|
||||
void SetKey(unsigned int keyIndex, IKey* pKey);
|
||||
void GetKey(unsigned int keyIndex, IKey* pKey) const;
|
||||
|
||||
void SelectKey(unsigned int keyIndex, bool bSelect);
|
||||
bool IsKeySelected(unsigned int keyIndex) const;
|
||||
|
||||
void SetSortMarkerKey(unsigned int keyIndex, bool enabled);
|
||||
bool IsSortMarkerKey(unsigned int keyIndex) const;
|
||||
|
||||
void SetKeyTime(const int index, const float time, bool notifyListeners = true);
|
||||
float GetKeyTime(const int index) const;
|
||||
|
||||
void RemoveKey(const int index);
|
||||
int CloneKey(const int index);
|
||||
|
||||
CTrackViewKeyBundle GetKeys(bool bOnlySelected, float t0, float t1);
|
||||
CTrackViewKeyHandle GetSubTrackKeyHandle(unsigned int index) const;
|
||||
|
||||
// Copy selected keys to XML representation for clipboard
|
||||
virtual void CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks) override;
|
||||
|
||||
bool m_bIsCompoundTrack;
|
||||
bool m_bIsSubTrack;
|
||||
unsigned int m_subTrackIndex;
|
||||
AZStd::intrusive_ptr<IAnimTrack> m_pAnimTrack;
|
||||
CTrackViewAnimNode* m_pTrackAnimNode;
|
||||
|
||||
// used to stash AZ Entity ID's stored in track keys when entering/exiting AI/Physic or Ctrl-G game modes
|
||||
AZStd::unordered_map<CAnimParamType, AZStd::vector<AZ::EntityId>> m_paramTypeToStashedEntityIdMap;
|
||||
};
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWTRACK_H
|
||||
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CTrackViewTrackPropsDlg</class>
|
||||
<widget class="QWidget" name="CTrackViewTrackPropsDlg">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>112</width>
|
||||
<height>35</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="CTrackViewDoubleSpinBox" name="TIME">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>0.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Time:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="PREVNEXT">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CTrackViewDoubleSpinBox</class>
|
||||
<extends>QDoubleSpinBox</extends>
|
||||
<header location="global">TrackView/TrackViewDoubleSpinBox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "TrackViewUndo.h"
|
||||
|
||||
// CryCommon
|
||||
#include <CryCommon/Maestro/Types/AnimNodeType.h>
|
||||
|
||||
// Editor
|
||||
#include "TrackView/TrackViewAnimNode.h"
|
||||
#include "TrackView/TrackViewSequence.h"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CUndoComponentEntityTrackObject::CUndoComponentEntityTrackObject(CTrackViewTrack* track)
|
||||
{
|
||||
AZ_Assert(track, "Expected a valid track");
|
||||
if (track)
|
||||
{
|
||||
m_trackName = track->GetName();
|
||||
AZ_Assert(!m_trackName.empty(), "Expected a valid track name");
|
||||
|
||||
CTrackViewAnimNode* animNode = track->GetAnimNode();
|
||||
AZ_Assert(animNode, "Expected a valid anim node");
|
||||
if (animNode)
|
||||
{
|
||||
m_trackComponentId = animNode->GetComponentId();
|
||||
AZ_Assert(m_trackComponentId != AZ::InvalidComponentId, "Expected a valid track component id");
|
||||
|
||||
CTrackViewSequence* sequence = track->GetSequence();
|
||||
AZ_Assert(sequence, "Expected to find the sequence");
|
||||
if (sequence)
|
||||
{
|
||||
m_sequenceId = sequence->GetSequenceComponentEntityId();
|
||||
AZ_Assert(m_sequenceId.IsValid(), "Expected a valid sequence id");
|
||||
|
||||
AnimNodeType nodeType = animNode->GetType();
|
||||
AZ_Assert(nodeType == AnimNodeType::Component, "Expected a this node to be a AnimNodeType::Component type");
|
||||
if (nodeType == AnimNodeType::Component)
|
||||
{
|
||||
CTrackViewAnimNode* parentAnimNode = static_cast<CTrackViewAnimNode*>(animNode->GetParentNode());
|
||||
AZ_Assert(parentAnimNode, "Expected a valid parent node");
|
||||
if (parentAnimNode)
|
||||
{
|
||||
m_entityId = parentAnimNode->GetAzEntityId();
|
||||
AZ_Assert(m_entityId.IsValid(), "Expected a valid sequence id");
|
||||
|
||||
// Store undo info.
|
||||
m_undo = track->GetMemento();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
CTrackViewTrack* CUndoComponentEntityTrackObject::FindTrack(CTrackViewSequence* sequence)
|
||||
{
|
||||
AZ_Assert(sequence, "Expected to find the sequence");
|
||||
|
||||
CTrackViewTrack* track = nullptr;
|
||||
CTrackViewTrackBundle allTracks = sequence->GetAllTracks();
|
||||
for (int trackIndex = 0; trackIndex < allTracks.GetCount(); trackIndex++)
|
||||
{
|
||||
CTrackViewTrack* curTrack = allTracks.GetTrack(trackIndex);
|
||||
if (curTrack->GetAnimNode() && curTrack->GetAnimNode()->GetComponentId() == m_trackComponentId)
|
||||
{
|
||||
if (0 == azstricmp(curTrack->GetName(), m_trackName.c_str()))
|
||||
{
|
||||
CTrackViewAnimNode* parentAnimNode = static_cast<CTrackViewAnimNode*>(curTrack->GetAnimNode()->GetParentNode());
|
||||
if (parentAnimNode && parentAnimNode->GetAzEntityId() == m_entityId)
|
||||
{
|
||||
track = curTrack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return track;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CUndoComponentEntityTrackObject::Undo(bool bUndo)
|
||||
{
|
||||
CTrackViewSequence* sequence = CTrackViewSequence::LookUpSequenceByEntityId(m_sequenceId);
|
||||
AZ_Assert(sequence, "Expected to find the sequence");
|
||||
if (sequence)
|
||||
{
|
||||
CTrackViewTrack* track = FindTrack(sequence);
|
||||
AZ_Assert(track, "Expected to find track");
|
||||
{
|
||||
CTrackViewSequenceNoNotificationContext context(sequence);
|
||||
|
||||
if (bUndo)
|
||||
{
|
||||
m_redo = track->GetMemento();
|
||||
}
|
||||
|
||||
// Undo track state.
|
||||
track->RestoreFromMemento(m_undo);
|
||||
}
|
||||
|
||||
if (bUndo)
|
||||
{
|
||||
sequence->OnKeysChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
sequence->ForceAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CUndoComponentEntityTrackObject::Redo()
|
||||
{
|
||||
CTrackViewSequence* sequence = CTrackViewSequence::LookUpSequenceByEntityId(m_sequenceId);
|
||||
AZ_Assert(sequence, "Expected to find the sequence");
|
||||
if (sequence)
|
||||
{
|
||||
CTrackViewTrack* track = FindTrack(sequence);
|
||||
AZ_Assert(track, "Expected to find track");
|
||||
|
||||
// Redo track state.
|
||||
track->RestoreFromMemento(m_redo);
|
||||
|
||||
sequence->OnKeysChanged();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWUNDO_H
|
||||
#define CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWUNDO_H
|
||||
#pragma once
|
||||
|
||||
#include "TrackViewTrack.h"
|
||||
|
||||
#include "Undo/IUndoObject.h"
|
||||
|
||||
class CTrackViewSequence;
|
||||
|
||||
/** Undo object stored when track is modified for component entity.
|
||||
* Stores ids, not raw pointers.
|
||||
*/
|
||||
class CUndoComponentEntityTrackObject
|
||||
: public IUndoObject
|
||||
{
|
||||
public:
|
||||
CUndoComponentEntityTrackObject(CTrackViewTrack* track);
|
||||
|
||||
protected:
|
||||
virtual int GetSize() override { return sizeof(*this); }
|
||||
virtual QString GetDescription() override { return "Undo Component Entity Track Modify"; };
|
||||
|
||||
virtual void Undo(bool bUndo) override;
|
||||
virtual void Redo() override;
|
||||
|
||||
private:
|
||||
|
||||
// Helper function to get a pointer to the track based.
|
||||
CTrackViewTrack* FindTrack(CTrackViewSequence* sequence);
|
||||
|
||||
// Internal state are id's used to uniquely identify
|
||||
// a track. This does not store pointers to tracks because
|
||||
// those can change when an AZ::Undo event happens and the entity
|
||||
// is reloaded.
|
||||
AZ::EntityId m_sequenceId;
|
||||
AZ::EntityId m_entityId;
|
||||
AZStd::string m_trackName;
|
||||
AZ::ComponentId m_trackComponentId;
|
||||
|
||||
CTrackViewTrackMemento m_undo;
|
||||
CTrackViewTrackMemento m_redo;
|
||||
};
|
||||
|
||||
#endif // CRYINCLUDE_EDITOR_TRACKVIEW_TRACKVIEWUNDO_H
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:29d6b3e5d2288365b6038fc8ddeadedb4998924eceb9feb9f124eb46c31da4ef
|
||||
size 143
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:72115aee4f8baa0ee796170de94461624fba38675a3e9138d6ca0efd3fcd733b
|
||||
size 164
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a064e400b30d4de5d96ce15d54c3a55a1ec655a025479ec34966903d87c1e945
|
||||
size 446
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3a9123cfc2ec39e086593e0e4c5edfefeb81e55f7742a1fe55107b7d8b8116b1
|
||||
size 364
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:98d6abe0694969813e40777c30ed08b37ee8b1e21d3b101c6ae1cc73f0f7f203
|
||||
size 144
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ba30d39cc19a5f154334ed58b0c620adc0d2b8699817ab47140e67ca817fb946
|
||||
size 143
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3ccfd91d032179c9275309a63d0418bfacc57764153947affc25b502bde79b93
|
||||
size 147
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3394b7e757f82234362c12f2dc5b032b1030c448768a453642b324d05ac21504
|
||||
size 151
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a80f1e8aaf99a56e71af5acee471c44e39862710bbd42bbdc71ad2ed36ca19c9
|
||||
size 147
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2c1141caf31b2d01f193ff5dcf9b1edab8ccbb0fc824c6ebc4594f0ea4032284
|
||||
size 138
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9e58c21845c00ecc27dcf06b33b08e4975e06ff123161730324fb5f99de369f8
|
||||
size 158
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b52d11739a7e9cca6788151806e7824e9b6c847dad3a201962f3f3daadc67474
|
||||
size 159
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7bc6d1fe7f8184f230a1e438c0bcfec266f2ac77f7b3364d654006ff01ac031c
|
||||
size 152
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:56d75cb3865d0eefa9d8c0794f2bfaaa73cd8a366310d8032eff6de63932901b
|
||||
size 130
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3f127ce50a93699fac340cc1cf162f35b4d93dc9ec74e3653ade5f0aef2c0e77
|
||||
size 142
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:96e1d00b1654e25446db63fb9375a908dd7415644bed13c626b45a4ec1e5d9e1
|
||||
size 172
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5e13418febcdd2e86b10e2bea62fe026b4009b649e0d1013dc84c6c4a4f401ed
|
||||
size 145
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:49a61fefdb2a0a7d218a7064a1afa1584511ff3b2a3787a176a2d4783b69eb0d
|
||||
size 125
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:03a118a63529650f7d0734b385d15431e1c70fe51b324601c6765981521b5479
|
||||
size 140
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3537913eb762f1c4bd8bcd87b5b195e76074dd0e3efd9a41af27717bdcce9b3d
|
||||
size 138
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f121ac550ea7128d744ecb142676302875b6ae7ecf76ca8a933bf332cbdf28e9
|
||||
size 189
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:49ac756007e7f372f1f8b9c3e5254f5bb88a5d66c2317e70423c9c91703fc530
|
||||
size 206
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:466b762cadb338b348be0fc7e5eab2473c3305e964f16c0bbf4f7d6691f3b987
|
||||
size 226
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f8f29f4af9cc488160dd9c179995b175696b2cfb77a14d4c3e39b8b0b1d8ff6b
|
||||
size 227
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:df0c0ef69e861fc95391b63231ab378e32bd8634f1646d7c3442d8d6ded498b2
|
||||
size 226
|
||||
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:51121c832d78c50a390e5fdc676d8a100f9271415365a174ab6f30d92d520ab5
|
||||
size 394
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user