You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Sandbox/Editor/TimeOfDayDialog.cpp

1444 lines
51 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "EditorDefs.h"
#include "TimeOfDayDialog.h"
// Qt
#include <QMessageBox>
// AzToolsFramework
#include <AzToolsFramework/API/ViewPaneOptions.h>
// CryCommon
#include <CryCommon/ITimeOfDay.h>
// Editor
#include "Settings.h"
#include "Controls/CurveEditorCtrl.h"
#include "Mission.h"
#include "CryEditDoc.h"
#include "Clipboard.h"
#include "QtViewPaneManager.h"
#include "Undo/Undo.h"
#include "LyViewPaneNames.h"
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
#include <ui_TimeOfDayDialog.h>
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
#define PANE_LAYOUT_SECTION _T("DockingPaneLayouts\\TimeOfDay")
#define PANE_LAYOUT_VERSION_ENTRY _T("PaneLayoutVersion")
namespace TimeOfDayDetails
{
const float kEpsilon = 0.00001f;
const int kTimeOfDayDialogLayoutVersion = 0x0002; // bump this up on every substantial pane layout change
static void SetKeyTangentType(ISplineInterpolator* pSpline, int key, ESplineKeyTangentType type)
{
int flags = (pSpline->GetKeyFlags(key) & ~SPLINE_KEY_TANGENT_IN_MASK) & ~SPLINE_KEY_TANGENT_OUT_MASK;
pSpline->SetKeyFlags(key, flags | (type << SPLINE_KEY_TANGENT_IN_SHIFT) | (type << SPLINE_KEY_TANGENT_OUT_SHIFT));
}
static QTime qTimeFromFloat(float time)
{
// The float time goes from 0.0 - 23.98 (since max time is 23:59), so
// convert this to seconds so we can construct a QTime object from that
int seconds = (time * 60.0f) * 60;
return QTime(0, 0).addSecs(seconds);
}
static float floatFromQTime(const QTime& time)
{
return static_cast<float>(time.msecsSinceStartOfDay() / 60000) / 60.0;
}
AZ_INLINE static bool SkipUserInterface(int value)
{
// Check for obsolete parameters that we still want to keep around to migrate legacy data to new data
// but don't want to display in the UI
const ITimeOfDay::ETimeOfDayParamID enumValue = static_cast<ITimeOfDay::ETimeOfDayParamID>(value);
// Split the check into two parts to try to keep the logic clear.
// The First set of parameters are always checked...
bool skipParameter = (enumValue == ITimeOfDay::PARAM_HDR_DYNAMIC_POWER_FACTOR) ||
(enumValue == ITimeOfDay::PARAM_TERRAIN_OCCL_MULTIPLIER) ||
(enumValue == ITimeOfDay::PARAM_SUN_COLOR_MULTIPLIER);
return skipParameter;
}
}
CHDRPane::CHDRPane(CTimeOfDayDialog* pTODDlg)
: QWidget(pTODDlg)
, m_pTODDlg(pTODDlg)
, m_pVars(new CVarBlock)
{
assert(m_pTODDlg);
#if !defined(NDEBUG)
bool ok =
#endif
Init();
assert(ok);
}
bool CHDRPane::Init()
{
m_filmCurveCtrl = new CCurveEditorCtrl(this);
m_filmCurveCtrl->SetControlPointCount(21);
m_filmCurveCtrl->SetMouseEnable(false);
m_filmCurveCtrl->SetPadding(16);
m_filmCurveCtrl->SetFlags(
CCurveEditorCtrl::eFlag_ShowVerticalRuler |
CCurveEditorCtrl::eFlag_ShowHorizontalRuler |
CCurveEditorCtrl::eFlag_ShowCursorAlways |
CCurveEditorCtrl::eFlag_ShowVerticalRulerText |
CCurveEditorCtrl::eFlag_ShowHorizontalRulerText |
CCurveEditorCtrl::eFlag_ShowPaddingBorder);
m_filmCurveCtrl->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_propsCtrl = new ReflectedPropertyControl(this);
m_propsCtrl->Setup();
QVBoxLayout* l = new QVBoxLayout;
l->setMargin(0);
l->addWidget(m_filmCurveCtrl);
l->addWidget(m_propsCtrl);
setLayout(l);
m_propsCtrl->SetSelChangeCallback(AZStd::bind(&CHDRPane::OnPropertySelected, this, AZStd::placeholders::_1));
return true;
}
void CHDRPane::OnPropertySelected(IVariable *pVar)
{
if (pVar && pVar->GetType() == IVariable::ARRAY)
{
pVar = nullptr;
}
emit propertySelected(pVar);
}
bool CHDRPane::GetFilmCurveParams(float& shoulderScale, float& midScale, float& toeScale, float& whitePoint) const
{
int checked = 0;
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
for (int i = 0; pTimeOfDay->GetVariableCount(); ++i)
{
ITimeOfDay::SVariableInfo varInfo;
bool ok = pTimeOfDay->GetVariableInfo(i, varInfo);
if (ok == false)
{
continue;
}
if (TimeOfDayDetails::SkipUserInterface(varInfo.nParamId))
{
continue;
}
switch (varInfo.nParamId)
{
case ITimeOfDay::PARAM_HDR_FILMCURVE_SHOULDER_SCALE:
shoulderScale = varInfo.fValue[0];
++checked;
break;
case ITimeOfDay::PARAM_HDR_FILMCURVE_LINEAR_SCALE:
midScale = varInfo.fValue[0];
++checked;
break;
case ITimeOfDay::PARAM_HDR_FILMCURVE_TOE_SCALE:
toeScale = varInfo.fValue[0];
++checked;
break;
case ITimeOfDay::PARAM_HDR_FILMCURVE_WHITEPOINT:
whitePoint = varInfo.fValue[0];
++checked;
break;
}
if (checked == 4)
{
return true;
}
}
return false;
}
static float EvalFilmCurve(float x, float ss, float ms, float ts)
{
return (x * (ss * 6.2f * x + 0.5f * ms)) / max<float>((x * (ss * 6.2f * x + 1.7f) + ts * 0.06f), TimeOfDayDetails::kEpsilon);
}
void CHDRPane::UpdateFilmCurve()
{
float shoulderScale = 0, midScale = 0, toeScale = 0, whitePoint = 0;
#if !defined(NDEBUG)
bool ok =
#endif
GetFilmCurveParams(shoulderScale, midScale, toeScale, whitePoint);
assert(ok);
const float minX = -4.0f, minY = 0.0f, maxX = 4.0f;
float maxY = 1.0f, stepY = 0.1f;
int numSamplePoints = m_filmCurveCtrl->GetControlPointCount();
for (int i = 0; i < numSamplePoints; ++i)
{
float t = static_cast<float>(i) / (numSamplePoints - 1);
float logX = minX + ((maxX - minX) * t);
float x = powf(10.0f, logX); // Conventionally, the x domain is logarithmic.
float v = EvalFilmCurve(x, shoulderScale, midScale, toeScale) /
max<float>(EvalFilmCurve(whitePoint, shoulderScale, midScale, toeScale), TimeOfDayDetails::kEpsilon);
v = powf(v, 2.2f); // converting to a linear space
// Update the maximum Y so that a proper domain can be set later.
if (v > maxY)
{
maxY = ceil(v / stepY) * stepY;
}
m_filmCurveCtrl->SetControlPoint(i, Vec2(logX, v));
}
// maxY is not fixed, so adjust Y grid count properly according to it.
const UINT gridX = 4; // X grid is fixed.
UINT gridY = static_cast<UINT>(maxY / stepY);
while (gridY > 20) // > 20 means too many, so reduce the count properly.
{
gridY = (gridY + 9) / 10;
stepY *= 10.0f;
}
maxY = stepY * gridY;
// Also prepare labels for the grid since the default labeling is improper
// especially for the X axis due to its log scale.
QStringList labelsX, labelsY;
for (int i = 0; i <= gridX; ++i)
{
QString label;
label.asprintf("%.4g", powf(10.0f, minX + (maxX - minX) * static_cast<float>(i) / gridX));
labelsX.push_back(label);
}
for (int i = 0; i <= gridY; ++i)
{
QString label;
label.asprintf("%.1f", i * stepY);
labelsY.push_back(label);
}
m_filmCurveCtrl->SetGrid(gridX, gridY, labelsX, labelsY);
m_filmCurveCtrl->MarkY(1.0f); // Mark the output of 1 so that users can quickly recognize where the clamping happens.
m_filmCurveCtrl->SetDomainBounds(minX, minY, maxX, maxY);
m_filmCurveCtrl->update();
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Adapter for Multi element interpolators that allow to split it to several
// different interpolators for each element separately.
//////////////////////////////////////////////////////////////////////////
class CMultiElementSplineInterpolatorAdapter
: public ISplineInterpolator
{
public:
CMultiElementSplineInterpolatorAdapter()
: m_pInterpolator(0)
, m_element(0) {}
CMultiElementSplineInterpolatorAdapter(ISplineInterpolator* pSpline, int element)
{
m_pInterpolator = pSpline;
m_element = element;
}
// Dimension of the spline from 0 to 3, number of parameters used in ValueType.
virtual int GetNumDimensions() { return m_pInterpolator->GetNumDimensions(); }
virtual int InsertKey(float time, ValueType value)
{
ValueType v = {0, 0, 0, 0};
v[m_element] = value[0];
return m_pInterpolator->InsertKey(time, v);
};
virtual void RemoveKey(int key) { m_pInterpolator->RemoveKey(key); };
virtual void FindKeysInRange(float startTime, float endTime, int& firstFoundKey, int& numFoundKeys)
{ m_pInterpolator->FindKeysInRange(startTime, endTime, firstFoundKey, numFoundKeys); }
virtual void RemoveKeysInRange(float startTime, float endTime) { m_pInterpolator->RemoveKeysInRange(startTime, endTime); }
virtual int GetKeyCount() { return m_pInterpolator->GetKeyCount(); }
virtual void SetKeyTime(int key, float time) { return m_pInterpolator->SetKeyTime(key, time); };
virtual float GetKeyTime(int key) { return m_pInterpolator->GetKeyTime(key); }
virtual void SetKeyValue(int key, ValueType value)
{
ValueType v = {0, 0, 0, 0};
m_pInterpolator->GetKeyValue(key, v);
v[m_element] = value[0];
m_pInterpolator->SetKeyValue(key, v);
}
virtual bool GetKeyValue(int key, ValueType& value)
{
ValueType v = {0, 0, 0, 0};
v[m_element] = value[0];
return m_pInterpolator->GetKeyValue(key, value);
value[0] = v[m_element];
}
virtual void SetKeyInTangent([[maybe_unused]] int key, [[maybe_unused]] ValueType tin) {};
virtual void SetKeyOutTangent([[maybe_unused]] int key, [[maybe_unused]] ValueType tout) {};
virtual void SetKeyTangents([[maybe_unused]] int key, [[maybe_unused]] ValueType tin, [[maybe_unused]] ValueType tout) {};
virtual bool GetKeyTangents([[maybe_unused]] int key, [[maybe_unused]] ValueType& tin, [[maybe_unused]] ValueType& tout) { return false; };
// Changes key flags, @see ESplineKeyFlags
virtual void SetKeyFlags(int key, int flags) { return m_pInterpolator->SetKeyFlags(key, flags); };
// Retrieve key flags, @see ESplineKeyFlags
virtual int GetKeyFlags(int key) { return m_pInterpolator->GetKeyFlags(key); }
virtual void Interpolate(float time, ValueType& value)
{
m_pInterpolator->Interpolate(time, value);
value[0] = value[m_element];
};
virtual void SerializeSpline(XmlNodeRef& node, bool bLoading) { return m_pInterpolator->SerializeSpline(node, bLoading); };
virtual ISplineBackup* Backup() { return m_pInterpolator->Backup(); };
virtual void Restore(ISplineBackup* pBackup) { return m_pInterpolator->Restore(pBackup); };
public:
ISplineInterpolator* m_pInterpolator;
int m_element;
};
//////////////////////////////////////////////////////////////////////////
class CTimeOfDaySplineSet
: public ISplineSet
{
public:
void AddSpline(ISplineInterpolator* pSpline) { m_splines.push_back(pSpline); };
void RemoveAllSplines() { m_splines.clear(); }
virtual ISplineInterpolator* GetSplineFromID(const string& id)
{
int i = atoi(id.c_str());
if (i >= 0 && i < (int)m_splines.size())
{
return m_splines[i];
}
return 0;
};
virtual string GetIDFromSpline(ISplineInterpolator* pSpline)
{
for (int i = 0; i < (int)m_splines.size(); i++)
{
if (m_splines[i] == pSpline)
{
string s;
s.Format("%d", i);
return s;
}
}
return "";
}
virtual int GetSplineCount() const { return (int)m_splines.size(); }
virtual int GetKeyCountAtTime(float time, float threshold) const
{
int count = 0;
for (int i = 0; i < (int)m_splines.size(); i++)
{
if (m_splines[i]->FindKey(time, threshold) > 0)
{
count++;
}
}
return count;
}
public:
std::vector<ISplineInterpolator*> m_splines;
};
//////////////////////////////////////////////////////////////////////////
CTimeOfDayDialog::CTimeOfDayDialog(QWidget* parent /* = nullptr */)
: QMainWindow(parent)
, m_ui(new Ui::TimeOfDayDialog)
, m_timelineCtrl(new TimelineWidget(this))
, m_pHDRPane(new CHDRPane(this))
{
gEnv->pSystem->GetISystemEventDispatcher()->RegisterListener(this);
GetIEditor()->RegisterNotifyListener(this);
m_ui->setupUi(this);
m_ui->parameters->Setup();
splitDockWidget(m_ui->hdrPaneDock, m_ui->tasksDock, Qt::Horizontal);
// Calculate our maximum time from the slider (23:59)
m_maxTime = m_ui->timelineSlider->maximum() / 60.0f;
Init();
}
//////////////////////////////////////////////////////////////////////////
CTimeOfDayDialog::~CTimeOfDayDialog()
{
m_alive = false;
GetIEditor()->UnregisterNotifyListener(this);
GetIEditor()->GetUndoManager()->RemoveListener(this);
gEnv->pSystem->GetISystemEventDispatcher()->RemoveListener(this);
QSettings settings;
settings.beginGroup(QStringLiteral("EnvironmentEditor"));
settings.setValue(QStringLiteral("state"), saveState());
}
const GUID& CTimeOfDayDialog::GetClassID()
{
// {85FB1272-D858-4ca5-ABB4-04D484ABF51E}
static const GUID guid = {
0x85fb1272, 0xd858, 0x4ca5, { 0xab, 0xb4, 0x4, 0xd4, 0x84, 0xab, 0xf5, 0x1e }
};
return guid;
}
void CTimeOfDayDialog::RegisterViewClass()
{
AzToolsFramework::ViewPaneOptions options;
options.paneRect = QRect(100, 100, 1500, 800);
options.canHaveMultipleInstances = true;
options.isDockable = true;
AzToolsFramework::RegisterViewPane<CTimeOfDayDialog>(LyViewPane::TimeOfDayEditor, LyViewPane::CategoryOther, options);
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::UpdateValues()
{
if (!m_alive)
{
return;
}
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
ITimeOfDay::SAdvancedInfo advInfo;
pTimeOfDay->GetAdvancedInfo(advInfo);
RefreshPropertiesValues();
SetTimeRange(advInfo.fStartTime, advInfo.fEndTime, advInfo.fAnimSpeed);
UpdateUI(false);
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam)
{
switch (event)
{
case ESYSTEM_EVENT_TIME_OF_DAY_SET:
// We update the UI in response to a system event (instead of with direct callbacks in the dialog) because time could be set by any of the dialog,
// e_TimeOfDay cvar, a Flow Graph Node or Track View.
UpdateUI();
break;
default:
// do nothing
break;
}
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::Init()
{
// Load toolbar images for the main toolbar
m_ui->actionUndo->setIcon(QIcon(":/TimeOfDay/main-00.png"));
m_ui->actionRedo->setIcon(QIcon(":/TimeOfDay/main-01.png"));
m_ui->actionImportFile->setIcon(QIcon(":/TimeOfDay/main-02.png"));
m_ui->actionExportFile->setIcon(QIcon(":/TimeOfDay/main-03.png"));
m_ui->actionPlayPause->setIcon(QIcon(":/TimeOfDay/main-04.png"));
m_ui->actionSetTimeTo0000->setIcon(QIcon(":/TimeOfDay/main-05.png"));
m_ui->actionSetTimeTo0600->setIcon(QIcon(":/TimeOfDay/main-06.png"));
m_ui->actionSetTimeTo1200->setIcon(QIcon(":/TimeOfDay/main-07.png"));
m_ui->actionSetTimeTo1800->setIcon(QIcon(":/TimeOfDay/main-08.png"));
m_ui->actionSetTimeTo2400->setIcon(QIcon(":/TimeOfDay/main-09.png"));
m_ui->actionStartStopRecording->setIcon(QIcon(":/TimeOfDay/main-10.png"));
m_ui->actionHold->setIcon(QIcon(":/TimeOfDay/main-11.png"));
m_ui->actionFetch->setIcon(QIcon(":/TimeOfDay/main-12.png"));
// Load the images for the spline edit toolbar
m_ui->tangentsToAutoButton->setIcon(QIcon(":/Common/spline_edit-00.png"));
m_ui->inTangentToZeroButton->setIcon(QIcon(":/Common/spline_edit-01.png"));
m_ui->inTangentToStepButton->setIcon(QIcon(":/Common/spline_edit-02.png"));
m_ui->inTangentToLinearButton->setIcon(QIcon(":/Common/spline_edit-03.png"));
m_ui->outTangentToZerobutton->setIcon(QIcon(":/Common/spline_edit-04.png"));
m_ui->outTangentToStepButton->setIcon(QIcon(":/Common/spline_edit-05.png"));
m_ui->outTangentToLinearButton->setIcon(QIcon(":/Common/spline_edit-06.png"));
m_ui->fitSplinesHorizontalButton->setIcon(QIcon(":/Common/spline_edit-07.png"));
m_ui->fitSplinesVerticalButton->setIcon(QIcon(":/Common/spline_edit-08.png"));
m_ui->splineSnapGridX->setIcon(QIcon(":/Common/spline_edit-09.png"));
m_ui->splineSnapGridY->setIcon(QIcon(":/Common/spline_edit-10.png"));
m_ui->previousKeyButton->setIcon(QIcon(":/Common/spline_edit-14.png"));
m_ui->nextKeyButton->setIcon(QIcon(":/Common/spline_edit-15.png"));
m_ui->removeAllExceptSelectedButton->setIcon(QIcon(":/Common/spline_edit-16.png"));
m_timelineCtrl->SetTicksTextScale(24.0f);
m_timelineCtrl->SetTimeRange(Range(0, 1));
m_ui->spline->SetDefaultKeyTangentType(SPLINE_KEY_TANGENT_LINEAR);
m_ui->spline->SetTimelineCtrl(m_timelineCtrl);
m_ui->spline->SetTimeRange(Range(0, 1.0f));
m_ui->spline->SetValueRange(Range(-1.0f, 1.0f));
m_ui->spline->SetMinTimeEpsilon(0.00001f);
m_ui->spline->SetTooltipValueScale(24, 1);
m_ui->colorGradient->SetNoZoom(false);
m_ui->colorGradient->SetTimeRange(0, 1.0f);
m_ui->colorGradient->LockFirstAndLastKeys(true);
m_ui->colorGradient->SetTooltipValueScale(24, 1);
CreateProperties();
UpdateValues();
UpdateUI();
QSettings settings;
settings.beginGroup(QStringLiteral("EnvironmentEditor"));
QByteArray state = settings.value(QStringLiteral("state")).toByteArray();
if (!state.isEmpty())
{
restoreState(state);
}
ResetSpline(0);
m_ui->hdrPaneDock->setWidget(m_pHDRPane);
m_pHDRPane->UpdateFilmCurve();
QString copyAllLabel(tr("Copy All Parameters"));
QString pasteAllLabel(tr("Paste All Parameters"));
m_ui->parameters->AddCustomPopupMenuItem(copyAllLabel, AZStd::bind(&CTimeOfDayDialog::CopyAllProperties, this));
m_ui->parameters->AddCustomPopupMenuItem(pasteAllLabel, AZStd::bind(&CTimeOfDayDialog::PasteAllProperties, this));
m_pHDRPane->properties().AddCustomPopupMenuItem(copyAllLabel, AZStd::bind(&CTimeOfDayDialog::CopyAllProperties, this));
m_pHDRPane->properties().AddCustomPopupMenuItem(pasteAllLabel, AZStd::bind(&CTimeOfDayDialog::PasteAllProperties, this));
m_ui->parameters->SetSelChangeCallback(AZStd::bind(&CTimeOfDayDialog::OnPropertySelected, this, AZStd::placeholders::_1));
connect(m_pHDRPane, &CHDRPane::propertySelected, this, &CTimeOfDayDialog::HdrPropertySelected);
m_pHDRPane->properties().SetUpdateCallback(AZStd::bind(&CTimeOfDayDialog::OnUpdateProperties, this, AZStd::placeholders::_1));
m_ui->parameters->SetUpdateCallback(AZStd::bind(&CTimeOfDayDialog::OnUpdateProperties, this, AZStd::placeholders::_1));
connect(m_ui->importFromFileClickable, &QLabel::linkActivated, this, &CTimeOfDayDialog::OnImport);
connect(m_ui->exportToFileClickable, &QLabel::linkActivated, this, &CTimeOfDayDialog::OnExport);
connect(m_ui->resetValuesClickable, &QLabel::linkActivated, this, &CTimeOfDayDialog::OnResetToDefaultValues);
connect(m_ui->expandAllClickable, &QLabel::linkActivated, this, &CTimeOfDayDialog::OnExpandAll);
connect(m_ui->collapseAllClickable, &QLabel::linkActivated, this, &CTimeOfDayDialog::OnCollapseAll);
connect(m_ui->currentTimeEdit, &QTimeEdit::timeChanged, this, [=](const QTime& time) { SetTime(TimeOfDayDetails::floatFromQTime(time)); });
connect(m_ui->startTimeEdit, &QTimeEdit::timeChanged, this, &CTimeOfDayDialog::StartTimeChanged);
connect(m_ui->endTimeEdit, &QTimeEdit::timeChanged, this, &CTimeOfDayDialog::EndTimeChanged);
auto doubleValueChanged = static_cast<void(QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged);
connect(m_ui->playSpeedDoubleSpinBox, doubleValueChanged, this, &CTimeOfDayDialog::OnChangeTimeAnimSpeed);
connect(m_ui->playClickable, &QLabel::linkActivated, this, [=]() { m_ui->actionPlayPause->setChecked(true); });
connect(m_ui->stopClickable, &QLabel::linkActivated, this, [=]() { m_ui->actionPlayPause->setChecked(false); });
connect(m_ui->forceSkyUpdateCheckBox, &QCheckBox::stateChanged, this, [=](int state) { gSettings.bForceSkyUpdate = state == Qt::Checked; });
connect(m_ui->actionUndo, &QAction::triggered, this, &CTimeOfDayDialog::OnUndo);
connect(m_ui->actionRedo, &QAction::triggered, this, &CTimeOfDayDialog::OnRedo);
connect(m_ui->actionImportFile, &QAction::triggered, this, &CTimeOfDayDialog::OnImport);
connect(m_ui->actionExportFile, &QAction::triggered, this, &CTimeOfDayDialog::OnExport);
connect(m_ui->actionSetTimeTo0000, &QAction::triggered, this, [=]() { SetTime(0); });
connect(m_ui->actionSetTimeTo0600, &QAction::triggered, this, [=]() { SetTime(6); });
connect(m_ui->actionSetTimeTo1200, &QAction::triggered, this, [=]() { SetTime(12); });
connect(m_ui->actionSetTimeTo1800, &QAction::triggered, this, [=]() { SetTime(18); });
connect(m_ui->actionSetTimeTo2400, &QAction::triggered, this, [=]() { SetTime(m_maxTime); });
connect(m_ui->actionHold, &QAction::triggered, this, &CTimeOfDayDialog::OnHold);
connect(m_ui->actionFetch, &QAction::triggered, this, &CTimeOfDayDialog::OnFetch);
connect(m_ui->tangentsToAutoButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_TANGENT_AUTO); });
connect(m_ui->inTangentToZeroButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_TANGENT_IN_ZERO); });
connect(m_ui->inTangentToStepButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_TANGENT_IN_STEP); });
connect(m_ui->inTangentToLinearButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_TANGENT_IN_LINEAR); });
connect(m_ui->outTangentToZerobutton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_TANGENT_OUT_ZERO); });
connect(m_ui->outTangentToStepButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_TANGENT_OUT_STEP); });
connect(m_ui->outTangentToLinearButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_TANGENT_OUT_LINEAR); });
connect(m_ui->fitSplinesHorizontalButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_SPLINE_FIT_X); });
connect(m_ui->fitSplinesVerticalButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_SPLINE_FIT_Y); });
connect(m_ui->splineSnapGridX, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_SPLINE_SNAP_GRID_X); });
connect(m_ui->splineSnapGridY, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_SPLINE_SNAP_GRID_Y); });
connect(m_ui->previousKeyButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_SPLINE_PREVIOUS_KEY); });
connect(m_ui->nextKeyButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_SPLINE_NEXT_KEY); });
connect(m_ui->removeAllExceptSelectedButton, &QAbstractButton::clicked, this, [=]() { m_ui->spline->OnUserCommand(ID_SPLINE_FLATTEN_ALL); });
connect(m_ui->timelineSlider, &AzQtComponents::SliderInt::valueChanged, this, [=](int value) { SetTime(value / 60.0f); });
connect(m_ui->spline, &SplineWidget::beforeChange, this, &CTimeOfDayDialog::OnBeforeSplineChange);
connect(m_ui->spline, &SplineWidget::change, this, [=]() { OnSplineChange(m_ui->spline); });
connect(m_ui->spline, &SplineWidget::scrollZoomRequested, this, &CTimeOfDayDialog::OnSplineCtrlScrollZoom);
connect(m_ui->spline, &SplineWidget::timeChange, this, &CTimeOfDayDialog::OnTimelineCtrlChange);
connect(m_ui->spline, &SplineWidget::keySelectionChange, this, [=]() { SetTimeFromActiveKey(); });
connect(m_ui->colorGradient, &CColorGradientCtrl::beforeChange, this, &CTimeOfDayDialog::OnBeforeSplineChange);
connect(m_ui->colorGradient, &CColorGradientCtrl::change, this, [=]() { OnSplineChange(m_ui->colorGradient); });
connect(m_ui->colorGradient, &CColorGradientCtrl::activeKeyChange, this, [=]() { SetTimeFromActiveKey(true); });
//connect(m_timelineCtrl.data(), &TimelineWidget::startChange, this, &CTimeOfDayDialog::OnBeforeSplineChange);
connect(m_timelineCtrl, &TimelineWidget::change, this, &CTimeOfDayDialog::OnTimelineCtrlChange);
//ITimeOfDay *pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
//m_ui->currentTimeEdit->setTime(qTimeFromFloat(pTimeOfDay->GetTime()));
GetIEditor()->GetUndoManager()->AddListener(this);
}
void CTimeOfDayDialog::HdrPropertySelected(IVariable* v)
{
if (v)
{
m_ui->parameters->ClearSelection();
}
ResetSpline(v);
}
void CTimeOfDayDialog::StartTimeChanged([[maybe_unused]] const QTime& time)
{
float converted = TimeOfDayDetails::floatFromQTime(m_ui->startTimeEdit->time());
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
ITimeOfDay::SAdvancedInfo advInfo;
pTimeOfDay->GetAdvancedInfo(advInfo);
advInfo.fStartTime = converted;
pTimeOfDay->SetAdvancedInfo(advInfo);
}
void CTimeOfDayDialog::EndTimeChanged([[maybe_unused]] const QTime& time)
{
float converted = TimeOfDayDetails::floatFromQTime(m_ui->endTimeEdit->time());
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
ITimeOfDay::SAdvancedInfo advInfo;
pTimeOfDay->GetAdvancedInfo(advInfo);
advInfo.fEndTime = converted;
pTimeOfDay->SetAdvancedInfo(advInfo);
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::CreateProperties()
{
m_pVars = new CVarBlock;
std::map<QString, IVariable*> groups;
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
for (int i = 0; i < pTimeOfDay->GetVariableCount(); i++)
{
ITimeOfDay::SVariableInfo varInfo;
if (!pTimeOfDay->GetVariableInfo(i, varInfo))
{
continue;
}
if (TimeOfDayDetails::SkipUserInterface(varInfo.nParamId))
{
continue;
}
if (!varInfo.pInterpolator)
{
continue;
}
IVariable* pGroupVar = stl::find_in_map(groups, varInfo.group, 0);
if (!pGroupVar)
{
// Create new group
pGroupVar = new CVariableArray();
pGroupVar->SetName(varInfo.group);
pGroupVar->SetUserData(-1);
if (strcmp(varInfo.group, "HDR") == 0) // HDR parameters should go into the separate HDR pane.
{
m_pHDRPane->variables()->AddVariable(pGroupVar);
}
else
{
m_pVars->AddVariable(pGroupVar);
}
groups[varInfo.group] = pGroupVar;
}
IVariable* pVar = 0;
if (varInfo.type == ITimeOfDay::TYPE_COLOR)
{
//////////////////////////////////////////////////////////////////////////
// Add Var.
pVar = new CVariable<Vec3>();
pVar->SetDataType(IVariable::DT_COLOR);
pVar->Set(Vec3(varInfo.fValue[0], varInfo.fValue[1], varInfo.fValue[2]));
}
else if (varInfo.type == ITimeOfDay::TYPE_FLOAT)
{
// Add Var.
pVar = new CVariable<float>();
pVar->Set(varInfo.fValue[0]);
pVar->SetLimits(varInfo.fValue[1], varInfo.fValue[2]);
}
if (pVar)
{
pVar->SetName(varInfo.name);
pVar->SetHumanName(varInfo.displayName);
pGroupVar->AddVariable(pVar);
pVar->SetUserData(i);
}
}
m_ui->parameters->AddVarBlock(m_pVars);
m_ui->parameters->ExpandAll();
m_ui->parameters->EnableNotifyWithoutValueChange(true);
m_pHDRPane->properties().AddVarBlock(m_pHDRPane->variables());
m_pHDRPane->properties().ExpandAll();
m_pHDRPane->properties().EnableNotifyWithoutValueChange(true);
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnBeforeSplineChange()
{
if (CUndo::IsRecording())
{
CUndo::Record(new CUndoTimeOfDayObject());
}
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnSplineChange(const QWidget* source)
{
RefreshPropertiesValues();
if (source == m_ui->spline)
{
// Update the time of day settings on spline changes (e.g. keys being moved)
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
bool bForceUpdate = m_ui->forceSkyUpdateCheckBox->isChecked();
pTimeOfDay->Update(true, bForceUpdate);
m_timelineCtrl->update();
m_ui->colorGradient->update();
}
else if (source == m_timelineCtrl)
{
m_ui->colorGradient->update();
m_ui->spline->update();
}
else
{
m_ui->spline->SplinesChanged();
m_ui->spline->update();
m_timelineCtrl->update();
}
if (m_ui->spline->GetSplineCount() > 0)
{
ISplineInterpolator* pSpline = m_ui->spline->GetSpline(0);
if (NULL != pSpline)
{
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
const uint numVars = pTimeOfDay->GetVariableCount();
for (uint i = 0; i < numVars; ++i)
{
ITimeOfDay::SVariableInfo varInfo;
pTimeOfDay->GetVariableInfo(i, varInfo);
}
}
}
}
/**
* Update our time based on the currently active key
*/
void CTimeOfDayDialog::SetTimeFromActiveKey(bool useColorGradient)
{
if (m_ui->spline->GetSplineCount() < 1)
{
return;
}
ISplineInterpolator* pSpline = m_ui->spline->GetSpline(0);
if (!pSpline)
{
return;
}
int activeKey = -1;
if (useColorGradient)
{
// If this method was triggered from our color gradient control, then
// retrieve its active key
activeKey = m_ui->colorGradient->GetActiveKey();
}
else
{
// Otherwise this method was triggered from our main spline control, so
// we need to find the selected key by cycling through its keys
int numKeys = pSpline->GetKeyCount();
for (int i = 0; i < numKeys; ++i)
{
if (pSpline->IsKeySelectedAtAnyDimension(i))
{
activeKey = i;
break;
}
}
}
if (activeKey == -1)
{
return;
}
SetTime(pSpline->GetKeyTime(activeKey) * m_maxTime);
}
//////////////////////////////////////////////////////////////////////////
float CTimeOfDayDialog::GetTime() const
{
// This used to get the time from GetIEditor()->GetDocument()->GetCurrentMission()->GetTime(); but that seems like legacy CryEngine, so we're
// switching to grabbing it from the 3DEngine if possible
float time = .0f;
if (gEnv->p3DEngine->GetTimeOfDay())
{
time = gEnv->p3DEngine->GetTimeOfDay()->GetTime();
}
return time;
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::SetTimeRange(float fTimeStart, float fTimeEnd, float fSpeed)
{
m_ui->startTimeEdit->setTime(TimeOfDayDetails::qTimeFromFloat(fTimeStart));
m_ui->endTimeEdit->setTime(TimeOfDayDetails::qTimeFromFloat(fTimeEnd));
m_ui->playSpeedDoubleSpinBox->setValue(fSpeed);
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
ITimeOfDay::SAdvancedInfo advInfo;
pTimeOfDay->GetAdvancedInfo(advInfo);
advInfo.fStartTime = fTimeStart;
advInfo.fEndTime = fTimeEnd;
advInfo.fAnimSpeed = fSpeed;
pTimeOfDay->SetAdvancedInfo(advInfo);
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::RefreshPropertiesValues()
{
m_ui->parameters->EnableUpdateCallback(false);
m_pHDRPane->properties().EnableUpdateCallback(false);
// Interpolate internal values
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
for (int i = 0, numVars = pTimeOfDay->GetVariableCount(); i < numVars; i++)
{
ITimeOfDay::SVariableInfo varInfo;
if (!pTimeOfDay->GetVariableInfo(i, varInfo))
{
continue;
}
if (TimeOfDayDetails::SkipUserInterface(varInfo.nParamId))
{
continue;
}
IVariable* pVar = FindVariable(varInfo.name);
if (!pVar)
{
continue;
}
switch (varInfo.type)
{
case ITimeOfDay::TYPE_FLOAT:
pVar->Set(varInfo.fValue[0]);
break;
case ITimeOfDay::TYPE_COLOR:
pVar->Set(Vec3(varInfo.fValue[0], varInfo.fValue[1], varInfo.fValue[2]));
break;
}
}
m_ui->parameters->EnableUpdateCallback(true);
m_pHDRPane->properties().EnableUpdateCallback(true);
m_pHDRPane->UpdateFilmCurve();
// Notify that time of day values changed.
GetIEditor()->Notify(eNotify_OnTimeOfDayChange);
}
void CTimeOfDayDialog::UpdateUI(bool updateProperties)
{
float timeOfDayInHours = GetTime();
// update the Current Time edit field and Time Of Day Time Slider
QTime qTime = TimeOfDayDetails::qTimeFromFloat(timeOfDayInHours);
QSignalBlocker sliderBlocker(m_ui->timelineSlider);
QSignalBlocker editBlocker(m_ui->currentTimeEdit);
int v = qTime.msecsSinceStartOfDay();
v /= 60000;
m_ui->timelineSlider->setValue(v);
m_ui->currentTimeEdit->setTime(qTime);
m_ui->spline->SetTimeMarker(timeOfDayInHours / m_maxTime);
m_ui->colorGradient->SetTimeMarker(timeOfDayInHours / m_maxTime);
if (updateProperties)
{
RefreshPropertiesValues();
}
else
{
GetIEditor()->Notify(eNotify_OnTimeOfDayChange);
}
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::SetTime(float time)
{
const bool bForceUpdate = m_ui->forceSkyUpdateCheckBox->isChecked();
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
// This is probably legacy and deprecated, but leaving it here just in case it's needed by some legacy game.
if (GetIEditor()->GetDocument()->GetCurrentMission())
{
GetIEditor()->GetDocument()->GetCurrentMission()->SetTime(time);
}
// pTimeOfDay->SetTime will trigger a ESYSTEM_EVENT_TIME_OF_DAY_SET, which in turn will result in UpdateUI() being called
pTimeOfDay->SetTime(time, bForceUpdate);
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnEditorNotifyEvent(EEditorNotifyEvent event)
{
switch (event)
{
case eNotify_OnCloseScene:
case eNotify_OnBeginNewScene:
case eNotify_OnBeginSceneOpen:
{
// prevent crash during redraw which can happen before eNotify_OnEndSceneOpen
m_ui->spline->RemoveAllSplines();
m_ui->colorGradient->SetSpline(0);
}
break;
case eNotify_OnEndSceneOpen:
case eNotify_OnEndNewScene:
{
UpdateValues();
m_pHDRPane->properties().ClearSelection();
if (ReflectedPropertyItem* pSelectedItem = m_ui->parameters->GetSelectedItem())
{
if (IVariable* pVar = pSelectedItem->GetVariable())
{
ResetSpline(pVar);
}
}
}
break;
case eNotify_OnIdleUpdate:
if (m_ui->actionPlayPause->isChecked())
{
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
float fHour = pTimeOfDay->GetTime();
ITimeOfDay::SAdvancedInfo advInfo;
pTimeOfDay->GetAdvancedInfo(advInfo);
// get the TOD cycle speed from UI
advInfo.fAnimSpeed = m_ui->playSpeedDoubleSpinBox->value();
float dt = gEnv->pTimer->GetFrameTime();
float fTime = fHour + dt * advInfo.fAnimSpeed;
if (fTime > advInfo.fEndTime)
{
fTime = advInfo.fStartTime;
}
if (fTime < advInfo.fStartTime)
{
fTime = advInfo.fEndTime;
}
SetTime(fTime);
}
break;
}
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnTimelineCtrlChange()
{
float fTime = m_timelineCtrl->GetTimeMarker();
SetTime(fTime * m_maxTime);
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnChangeTimeAnimSpeed(double value)
{
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
ITimeOfDay::SAdvancedInfo advInfo;
pTimeOfDay->GetAdvancedInfo(advInfo);
// set current speed based on if we animating it currently or not
advInfo.fAnimSpeed = value;
pTimeOfDay->SetAdvancedInfo(advInfo);
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnSplineCtrlScrollZoom()
{
if (m_ui->spline && m_ui->colorGradient)
{
m_ui->colorGradient->SetZoom(m_ui->spline->GetZoom().x);
m_ui->colorGradient->SetOrigin(m_ui->spline->GetScrollOffset().x);
m_ui->colorGradient->update();
}
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnImport()
{
char szFilters[] = "Time Of Day Settings (*.xml);;Time Of Day Settings Old (*.tod)";
QString fileName;
if (CFileUtil::SelectFile(szFilters, GetIEditor()->GetLevelFolder(), fileName))
{
XmlNodeRef root = GetISystem()->LoadXmlFromFile(fileName.toStdString().c_str());
if (root)
{
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
float fTime = GetTime();
pTimeOfDay->Serialize(root, true);
pTimeOfDay->SetTime(fTime, true);
UpdateValues();
}
}
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnExport()
{
char szFilters[] = "Time Of Day Settings (*.xml)";
QString fileName;
if (CFileUtil::SelectSaveFile(szFilters, "xml", GetIEditor()->GetLevelFolder(), fileName))
{
// Write the light settings into the archive
XmlNodeRef node = XmlHelpers::CreateXmlNode("TimeOfDay");
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
pTimeOfDay->Serialize(node, false);
XmlHelpers::SaveXmlNode(GetIEditor()->GetFileUtil(), node, fileName.toStdString().c_str());
}
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnExpandAll()
{
m_ui->parameters->ExpandAll();
m_pHDRPane->properties().ExpandAll();
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnResetToDefaultValues()
{
auto answer = QMessageBox::question(QApplication::activeWindow(), "Reset Values", "Are you sure you want to reset all values to their default values?");
if (answer == QMessageBox::Yes)
{
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
// Load the default time of day settings and use those to reset the time of day.
XmlNodeRef root = GetISystem()->LoadXmlFromFile("default_time_of_day.xml");
if (root)
{
pTimeOfDay->Serialize(root, true);
}
else
{
QMessageBox::warning(QApplication::activeWindow(), "Reset Values", "Unable to read default time of day file (Editor/default_time_of_day.xml), initializing variables to default values.", QMessageBox::Ok);
// If for some reason the file is missing or corrupted, recreate the variables with their default states.
// Note that these variables may be out of sync with the default_time_of_day.xml file.
pTimeOfDay->ResetVariables();
}
ITimeOfDay::SAdvancedInfo advInfo;
pTimeOfDay->GetAdvancedInfo(advInfo);
SetTimeRange(advInfo.fStartTime, advInfo.fEndTime, advInfo.fAnimSpeed);
RefreshPropertiesValues();
m_pHDRPane->properties().ClearSelection();
ReflectedPropertyItem* selectedItem = m_ui->parameters->GetSelectedItem();
if (selectedItem)
{
IVariable* var = selectedItem->GetVariable();
if (var)
{
ResetSpline(var);
}
}
}
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnCollapseAll()
{
m_ui->parameters->CollapseAll();
m_pHDRPane->properties().CollapseAll();
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnUpdateProperties(IVariable* pVar)
{
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
int nIndex = -1;
if (pVar)
{
nIndex = pVar->GetUserData().toInt();
}
if (nIndex != -1)
{
ITimeOfDay::SVariableInfo varInfo;
if (pTimeOfDay->GetVariableInfo(nIndex, varInfo))
{
float fTime = GetTime();
float fSplineTime = fTime / m_maxTime;
const float cNearestKeySearchEpsilon = 0.00001f;
int nKey = varInfo.pInterpolator->FindKey(fSplineTime, cNearestKeySearchEpsilon);
int nLastKey = varInfo.pInterpolator->GetKeyCount() - 1;
if (CUndo::IsRecording())
{
CUndo::Record(new CUndoTimeOfDayObject());
}
switch (varInfo.type)
{
case ITimeOfDay::TYPE_FLOAT:
{
float fVal = 0;
pVar->Get(fVal);
if (m_ui->actionStartStopRecording->isChecked())
{
if (nKey < 0)
{
nKey = varInfo.pInterpolator->InsertKeyFloat(fSplineTime, fVal);
}
else
{
varInfo.pInterpolator->SetKeyValueFloat(nKey, fVal);
if (nKey == 0)
{
varInfo.pInterpolator->SetKeyValueFloat(nLastKey, fVal);
}
else if (nKey == nLastKey)
{
varInfo.pInterpolator->SetKeyValueFloat(0, fVal);
}
}
if (m_ui->spline && m_ui->spline->GetDefaultKeyTangentType() != SPLINE_KEY_TANGENT_NONE)
{
TimeOfDayDetails::SetKeyTangentType(varInfo.pInterpolator, nKey, m_ui->spline->GetDefaultKeyTangentType());
}
}
float v3[3] = {fVal, varInfo.fValue[1], varInfo.fValue[2]};
pTimeOfDay->SetVariableValue(nIndex, v3);
}
break;
case ITimeOfDay::TYPE_COLOR:
{
Vec3 vVal;
pVar->Get(vVal);
float v3[3] = {vVal.x, vVal.y, vVal.z};
if (m_ui->actionStartStopRecording->isChecked())
{
if (nKey < 0)
{
nKey = varInfo.pInterpolator->InsertKeyFloat3(fSplineTime, v3);
}
else
{
varInfo.pInterpolator->SetKeyValueFloat3(nKey, v3);
if (nKey == 0)
{
varInfo.pInterpolator->SetKeyValueFloat3(nLastKey, v3);
}
else if (nKey == nLastKey)
{
varInfo.pInterpolator->SetKeyValueFloat3(0, v3);
}
}
if (m_ui->spline && m_ui->spline->GetDefaultKeyTangentType() != SPLINE_KEY_TANGENT_NONE)
{
TimeOfDayDetails::SetKeyTangentType(varInfo.pInterpolator, nKey, m_ui->spline->GetDefaultKeyTangentType());
}
}
pTimeOfDay->SetVariableValue(nIndex, v3);
m_ui->colorGradient->update();
}
break;
}
if (m_ui->spline)
{
m_ui->spline->update();
}
if (varInfo.nParamId == ITimeOfDay::PARAM_HDR_FILMCURVE_SHOULDER_SCALE
|| varInfo.nParamId == ITimeOfDay::PARAM_HDR_FILMCURVE_LINEAR_SCALE
|| varInfo.nParamId == ITimeOfDay::PARAM_HDR_FILMCURVE_TOE_SCALE
|| varInfo.nParamId == ITimeOfDay::PARAM_HDR_FILMCURVE_WHITEPOINT)
{
m_pHDRPane->UpdateFilmCurve();
}
bool bForceUpdate = m_ui->forceSkyUpdateCheckBox->isChecked();
pTimeOfDay->Update(false, bForceUpdate);
GetIEditor()->Notify(eNotify_OnTimeOfDayChange);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnPropertySelected(IVariable *pVar)
{
if (pVar)
{
m_pHDRPane->properties().ClearSelection();
}
if (pVar && pVar->GetType() == IVariable::ARRAY)
{
pVar = nullptr;
}
ResetSpline(pVar);
}
void CTimeOfDayDialog::ResetSpline(IVariable* pVar)
{
if (pVar)
{
ITimeOfDay* pTimeOfDay = gEnv->p3DEngine->GetTimeOfDay();
ITimeOfDay::SVariableInfo varInfo;
int index = pVar->GetUserData().toInt();
if (!pTimeOfDay->GetVariableInfo(index, varInfo))
{
return;
}
m_ui->spline->SetTimeRange(Range(0, 1.0f));
m_ui->spline->RemoveAllSplines();
if (varInfo.type == ITimeOfDay::TYPE_COLOR)
{
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->spline->AddSpline(varInfo.pInterpolator, 0, afColorArray);
m_ui->spline->SetValueRange(Range(0, 1));
m_ui->colorGradient->SetSpline(varInfo.pInterpolator, TRUE);
m_ui->colorGradient->setEnabled(true);
m_ui->colorGradient->update();
}
else
{
m_ui->colorGradient->setEnabled(false);
m_ui->colorGradient->SetSpline(0);
m_ui->colorGradient->update();
m_ui->spline->SetValueRange(Range(varInfo.fValue[1], varInfo.fValue[2]));
m_ui->spline->AddSpline(varInfo.pInterpolator, 0, QColor(0, 255, 0));
}
m_ui->spline->SetSplineSet(0);
m_ui->spline->FitSplineToViewWidth();
m_ui->spline->FitSplineHeightToValueRange();
}
else
{
m_ui->spline->RemoveAllSplines();
m_ui->colorGradient->setEnabled(false);
m_ui->colorGradient->SetSpline(0);
}
m_ui->spline->update();
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnHold()
{
XmlNodeRef node = XmlHelpers::CreateXmlNode("TimeOfDay");
GetIEditor()->Get3DEngine()->GetTimeOfDay()->Serialize(node, false);
node->saveToFile((Path::GetUserSandboxFolder() + "TimeOfDayHold.xml").toUtf8().data());
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnFetch()
{
XmlNodeRef node = XmlHelpers::LoadXmlFromFile((Path::GetUserSandboxFolder() + "TimeOfDayHold.xml").toUtf8().data());
if (node)
{
GetIEditor()->Get3DEngine()->GetTimeOfDay()->Serialize(node, true);
UpdateValues();
UpdateUI();
}
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnUndo()
{
GetIEditor()->Undo();
m_ui->spline->update();
m_ui->colorGradient->update();
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::OnRedo()
{
GetIEditor()->Redo();
m_ui->spline->update();
m_ui->colorGradient->update();
}
//////////////////////////////////////////////////////////////////////////
IVariable* CTimeOfDayDialog::FindVariable(const char* name) const
{
IVariable* pVar = m_pVars->FindVariable(name);
if (!pVar)
{
pVar = m_pHDRPane->variables()->FindVariable(name);
}
return pVar;
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::CopyAllProperties()
{
CClipboard clipboard(this);
XmlNodeRef collectionNode = XmlHelpers::CreateXmlNode("PropertyCtrls");
ReflectedPropertyItem* pRoot = m_ui->parameters->GetRootItem();
if (pRoot) // Main properties
{
XmlNodeRef rootNode = collectionNode->newChild("PropertyCtrl");
for (int i = 0; i < pRoot->GetChildCount(); ++i)
{
m_ui->parameters->CopyItem(rootNode, pRoot->GetChild(i), true);
}
}
pRoot = m_pHDRPane->properties().GetRootItem();
if (pRoot) // HDR properties
{
XmlNodeRef rootNode = collectionNode->newChild("PropertyCtrl");
for (int i = 0; i < pRoot->GetChildCount(); ++i)
{
m_pHDRPane->properties().CopyItem(rootNode, pRoot->GetChild(i), true);
}
}
clipboard.Put(collectionNode);
}
//////////////////////////////////////////////////////////////////////////
void CTimeOfDayDialog::PasteAllProperties()
{
CClipboard clipboard(this);
CUndo undo("Paste Properties");
XmlNodeRef collectionNode = clipboard.Get();
if (collectionNode != NULL && collectionNode->isTag("PropertyCtrls")
&& collectionNode->getChildCount() == 2)
{
// Main properties
XmlNodeRef rootNode = collectionNode->getChild(0);
m_ui->parameters->SetValuesFromNode(rootNode);
// HDR properties
rootNode = collectionNode->getChild(1);
m_pHDRPane->properties().SetValuesFromNode(rootNode);
}
}
void CTimeOfDayDialog::SignalNumUndoRedo(const unsigned int& numUndo, const unsigned int& numRedo)
{
m_ui->actionUndo->setEnabled(numUndo > 0);
m_ui->actionRedo->setEnabled(numRedo > 0);
}
void CTimeOfDayDialog::resizeEvent([[maybe_unused]] QResizeEvent* event)
{
if (m_ui->spline->GetSplineCount() == 0)
{
m_ui->spline->FitSplineToViewWidth();
m_ui->spline->FitSplineToViewHeight();
}
}
CUndoTimeOfDayObject::CUndoTimeOfDayObject()
{
m_undo = XmlHelpers::CreateXmlNode("Undo");
GetIEditor()->Get3DEngine()->GetTimeOfDay()->Serialize(m_undo, false);
}
void CUndoTimeOfDayObject::Undo(bool bUndo)
{
if (bUndo)
{
m_redo = XmlHelpers::CreateXmlNode("Redo");
GetIEditor()->Get3DEngine()->GetTimeOfDay()->Serialize(m_redo, false);
}
GetIEditor()->Get3DEngine()->GetTimeOfDay()->Serialize(m_undo, true);
UpdateTimeOfDayDialog();
}
void CUndoTimeOfDayObject::Redo()
{
GetIEditor()->Get3DEngine()->GetTimeOfDay()->Serialize(m_redo, true);
UpdateTimeOfDayDialog();
}
void CUndoTimeOfDayObject::UpdateTimeOfDayDialog()
{
CTimeOfDayDialog* targetDialog = FindViewPane<CTimeOfDayDialog>(CTimeOfDayDialog::ClassName());
if (targetDialog != nullptr)
{
targetDialog->UpdateValues();
}
}
#include <moc_TimeOfDayDialog.cpp>