You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
427 lines
14 KiB
C++
427 lines
14 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
#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;
|
|
}
|