Merge branch 'development' into cmake/warn_virtual

Signed-off-by: Esteban Papp <81431996+amznestebanpapp@users.noreply.github.com>
This commit is contained in:
Esteban Papp
2021-09-14 10:28:58 -07:00
58 changed files with 1096 additions and 661 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ enum
{
// in milliseconds
GameModeIdleFrequency = 0,
EditorModeIdleFrequency = 1,
EditorModeIdleFrequency = 0,
InactiveModeFrequency = 10,
UninitializedFrequency = 9999,
};
-4
View File
@@ -77,10 +77,6 @@ namespace
// This closes the current document (level)
currentLevel->OnNewDocument();
// Then we freeze the viewport's input
AzToolsFramework::ViewportInteraction::ViewportFreezeRequestBus::Broadcast(
&AzToolsFramework::ViewportInteraction::ViewportFreezeRequestBus::Events::FreezeViewportInput, true);
// Then we need to tell the game engine there is no level to render anymore
if (GetIEditor()->GetGameEngine())
{
+2 -22
View File
@@ -669,16 +669,6 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event)
case eNotify_OnEndSceneSave:
PopDisableRendering();
break;
case eNotify_OnBeginLoad: // disables viewport input when starting to load an existing level
case eNotify_OnBeginCreate: // disables viewport input when starting to create a new level
m_freezeViewportInput = true;
break;
case eNotify_OnEndLoad: // enables viewport input when finished loading an existing level
case eNotify_OnEndCreate: // enables viewport input when finished creating a new level
m_freezeViewportInput = false;
break;
}
}
@@ -962,16 +952,6 @@ AzFramework::ScreenPoint EditorViewportWidget::ViewportWorldToScreen(const AZ::V
return m_renderViewport->ViewportWorldToScreen(worldPosition);
}
bool EditorViewportWidget::IsViewportInputFrozen()
{
return m_freezeViewportInput;
}
void EditorViewportWidget::FreezeViewportInput(bool freeze)
{
m_freezeViewportInput = freeze;
}
QWidget* EditorViewportWidget::GetWidgetForViewportContextMenu()
{
return this;
@@ -1057,9 +1037,9 @@ void EditorViewportWidget::SetViewportId(int id)
void EditorViewportWidget::ConnectViewportInteractionRequestBus()
{
AzToolsFramework::ViewportInteraction::ViewportFreezeRequestBus::Handler::BusConnect(GetViewportId());
AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler::BusConnect(GetViewportId());
AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusConnect(GetViewportId());
AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusConnect();
m_viewportUi.ConnectViewportUiBus(GetViewportId());
AzFramework::InputSystemCursorConstraintRequestBus::Handler::BusConnect();
@@ -1070,9 +1050,9 @@ void EditorViewportWidget::DisconnectViewportInteractionRequestBus()
AzFramework::InputSystemCursorConstraintRequestBus::Handler::BusDisconnect();
m_viewportUi.DisconnectViewportUiBus();
AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler::BusDisconnect();
AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler::BusDisconnect();
AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler::BusDisconnect();
AzToolsFramework::ViewportInteraction::ViewportFreezeRequestBus::Handler::BusDisconnect();
}
namespace AZ::ViewportHelpers
-8
View File
@@ -89,7 +89,6 @@ class SANDBOX_API EditorViewportWidget final
, private Camera::EditorCameraRequestBus::Handler
, private Camera::CameraNotificationBus::Handler
, private AzFramework::InputSystemCursorConstraintRequestBus::Handler
, private AzToolsFramework::ViewportInteraction::ViewportFreezeRequestBus::Handler
, private AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler
, private AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler
, private AzToolsFramework::ViewportInteraction::EditorModifierKeyRequestBus::Handler
@@ -202,10 +201,6 @@ private:
// AzFramework::InputSystemCursorConstraintRequestBus overrides ...
void* GetSystemCursorConstraintWindow() const override;
// AzToolsFramework::ViewportFreezeRequestBus overrides ...
bool IsViewportInputFrozen() override;
void FreezeViewportInput(bool freeze) override;
// AzToolsFramework::MainEditorViewportInteractionRequestBus overrides ...
AZ::EntityId PickEntity(const AzFramework::ScreenPoint& point) override;
AZ::Vector3 PickTerrain(const AzFramework::ScreenPoint& point) override;
@@ -387,9 +382,6 @@ private:
// Unclear if it's still necessary.
QSet<int> m_keyDown;
// State for ViewportFreezeRequestBus, currently does nothing
bool m_freezeViewportInput = false;
// This widget holds a reference to the manipulator manage because its responsible for drawing manipulators
AZStd::shared_ptr<AzToolsFramework::ManipulatorManager> m_manipulatorManager;
-90
View File
@@ -191,94 +191,4 @@ ConsoleTextEdit:focus,
border-width: 0px;
border-color: #e9e9e9;
border-style: solid;
}
/* Welcome Screen styling */
WelcomeScreenDialog QLabel
{
font-size: 12px;
color: #FFFFFF;
line-height: 20px;
background-color: transparent;
margin: 0;
}
WelcomeScreenDialog QLabel#currentProjectLabel
{
margin-top: 10px;
}
WelcomeScreenDialog QPushButton
{
font-size: 14px;
line-height: 16px;
}
WelcomeScreenDialog QWidget#articleViewContainerRoot
{
background: #444444;
}
WelcomeScreenDialog QWidget#levelViewFTUEContainer
{
background: #282828;
}
QTableWidget#recentLevelTable::item {
background-color: rgb(64,64,64);
margin-bottom: 4px;
margin-top: 4px;
}
/* Particle Editor */
#NumParticlesLabel
{
margin-top: 6px;
}
#LibrarySearchIcon
{
max-width: 16px;
max-height: 16px;
qproperty-iconSize: 16px 16px;
}
#ClosePrefabDialog, #SavePrefabDialog
{
min-width : 640px;
}
#SaveDependentPrefabsCard
{
margin: 0px 15px 10px 15px;
}
#PrefabSavedMessageFrame{
border: 1px solid green;
margin: 10px 15px 10px 15px;
border-radius: 2px;
padding: 5px 2px 5px 2px;
}
#ClosePrefabDialog #PrefabSaveWarningFrame
{
border: 1px solid orange;
margin: 10px 15px 10px 15px;
border-radius: 2px;
padding: 5px 2px 5px 2px;
color : white;
}
#SavePrefabDialog #FooterSeparatorLine
{
color: gray;
}
#SavePrefabDialog #PrefabSavePreferenceHint
{
font: italic;
color: #999999;
}
@@ -36,6 +36,9 @@
#include "CryEdit.h"
#include "Viewport.h"
// Atom Renderer
#include <Atom/RPI.Public/RPISystemInterface.h>
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
#include <TrackView/ui_SequenceBatchRenderDialog.h>
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
@@ -1234,6 +1237,13 @@ void CSequenceBatchRenderDialog::OnKickIdleTimout()
{
componentApplication->TickSystem();
}
// Directly tick the renderer, as it's no longer part of the system tick
if (auto rpiSystem = AZ::RPI::RPISystemInterface::Get())
{
rpiSystem->SimulationTick();
rpiSystem->RenderTick();
}
}
}
@@ -74,6 +74,8 @@
#include <AzCore/Module/Environment.h>
#include <AzCore/std/string/conversions.h>
AZ_CVAR(float, g_simulation_tick_rate, 0, nullptr, AZ::ConsoleFunctorFlags::Null, "The rate at which the game simulation tick loop runs, or 0 for as fast as possible");
static void PrintEntityName(const AZ::ConsoleCommandContainer& arguments)
{
if (arguments.empty())
@@ -1394,6 +1396,23 @@ namespace AZ
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick");
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
}
// If tick rate limiting is on, ensure (1 / g_simulation_tick_rate) ms has elapsed since the last frame,
// sleeping if there's still time remaining.
if (g_simulation_tick_rate > 0.f)
{
now = AZStd::chrono::system_clock::now();
// Work in microsecond durations here as that's the native measurement time for time_point
constexpr float microsecondsPerSecond = 1000.f * 1000.f;
const AZStd::chrono::microseconds timeBudgetPerTick(static_cast<int>(microsecondsPerSecond / g_simulation_tick_rate));
AZStd::chrono::microseconds timeUntilNextTick = m_currentTime + timeBudgetPerTick - now;
if (timeUntilNextTick.count() > 0)
{
AZStd::this_thread::sleep_for(timeUntilNextTick);
}
}
}
}
@@ -46,6 +46,8 @@ namespace AZ
TICK_PRE_RENDER = 750, ///< Suggested tick handler position to update render-related data.
TICK_RENDER = 800, ///< Suggested tick handler position for rendering.
TICK_DEFAULT = 1000, ///< Default tick handler position when the handler is constructed.
TICK_UI = 2000, ///< Suggested tick handler position for UI components.
@@ -39,6 +39,8 @@ namespace AzManipulatorTestFramework
DerivedDispatcherT* MouseLButtonDown();
//! Set the left mouse button up.
DerivedDispatcherT* MouseLButtonUp();
//! Send a double click event.
DerivedDispatcherT* MouseLButtonDoubleClick();
//! Set the keyboard modifier button down.
DerivedDispatcherT* KeyboardModifierDown(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier);
//! Set the keyboard modifier button up.
@@ -71,6 +73,7 @@ namespace AzManipulatorTestFramework
virtual void CameraStateImpl(const AzFramework::CameraState& cameraState) = 0;
virtual void MouseLButtonDownImpl() = 0;
virtual void MouseLButtonUpImpl() = 0;
virtual void MouseLButtonDoubleClickImpl() = 0;
virtual void MousePositionImpl(const AzFramework::ScreenPoint& position) = 0;
virtual void KeyboardModifierDownImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) = 0;
virtual void KeyboardModifierUpImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) = 0;
@@ -167,7 +170,7 @@ namespace AzManipulatorTestFramework
template<typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::MouseLButtonDown()
{
Log("%s", "Mouse left button down");
Log("Mouse left button down");
MouseLButtonDownImpl();
return static_cast<DerivedDispatcherT*>(this);
}
@@ -175,11 +178,19 @@ namespace AzManipulatorTestFramework
template<typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::MouseLButtonUp()
{
Log("%s", "Mouse left button up");
Log("Mouse left button up");
MouseLButtonUpImpl();
return static_cast<DerivedDispatcherT*>(this);
}
template<typename DerivedDispatcherT>
DerivedDispatcherT* ActionDispatcher<DerivedDispatcherT>::MouseLButtonDoubleClick()
{
Log("Mouse left button double click");
MouseLButtonDoubleClickImpl();
return static_cast<DerivedDispatcherT*>(this);
}
template<typename DerivedDispatcherT>
const char* ActionDispatcher<DerivedDispatcherT>::KeyboardModifierString(
const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier)
@@ -58,6 +58,7 @@ namespace AzManipulatorTestFramework
void CameraStateImpl(const AzFramework::CameraState& cameraState) override;
void MouseLButtonDownImpl() override;
void MouseLButtonUpImpl() override;
void MouseLButtonDoubleClickImpl() override;
void MousePositionImpl(const AzFramework::ScreenPoint& position) override;
void KeyboardModifierDownImpl(const KeyboardModifier& keyModifier) override;
void KeyboardModifierUpImpl(const KeyboardModifier& keyModifier) override;
@@ -1,55 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzManipulatorTestFramework/AzManipulatorTestFramework.h>
#include <AzManipulatorTestFramework/ActionDispatcher.h>
#include <AzManipulatorTestFramework/ImmediateModeActionDispatcher.h>
#include <AzCore/std/containers/list.h>
#include <AzCore/std/functional.h>
namespace AzManipulatorTestFramework
{
//! Buffers actions to be dispatched upon a call to Execute().
class RetainedModeActionDispatcher
: public ActionDispatcher<RetainedModeActionDispatcher>
{
public:
explicit RetainedModeActionDispatcher(ManipulatorViewportInteraction& viewportManipulatorInteraction);
//! Execute the sequence of actions and lock the dispatcher from adding further actions.
RetainedModeActionDispatcher* Execute();
//! Reset the sequence of actions and unlock the dispatcher from adding further actions.
RetainedModeActionDispatcher* ResetSequence();
protected:
// ActionDispatcher ...
void EnableSnapToGridImpl() override;
void DisableSnapToGridImpl() override;
void GridSizeImpl(float size) override;
void CameraStateImpl(const AzFramework::CameraState& cameraState) override;
void MouseLButtonDownImpl() override;
void MouseLButtonUpImpl() override;
void MousePositionImpl(const AzFramework::ScreenPoint& position) override;
void KeyboardModifierDownImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) override;
void KeyboardModifierUpImpl(const AzToolsFramework::ViewportInteraction::KeyboardModifier& keyModifier) override;
void ExpectManipulatorBeingInteractedImpl() override;
void ExpectManipulatorNotBeingInteractedImpl() override;
void SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform) override;
void SetSelectedEntityImpl(AZ::EntityId entity) override;
void SetSelectedEntitiesImpl(const AzToolsFramework::EntityIdList& entities) override;
void EnterComponentModeImpl(const AZ::Uuid& uuid) override;
private:
using Action = AZStd::function<void()>;
void AddActionToSequence(Action&& action);
ImmediateModeActionDispatcher m_dispatcher;
AZStd::list<Action> m_actions;
bool m_locked = false;
};
} // namespace AzManipulatorTestFramework
@@ -83,7 +83,17 @@ namespace AzManipulatorTestFramework
void ImmediateModeActionDispatcher::MouseLButtonUpImpl()
{
GetMouseInteractionEvent()->m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::Up;
m_viewportManipulatorInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*GetMouseInteractionEvent());
m_viewportManipulatorInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*m_event);
ToggleOff(GetMouseInteractionEvent()->m_mouseInteraction.m_mouseButtons.m_mouseButtons, MouseButton::Left);
// the mouse position will be the same as the previous event, thus the delta will be 0
MouseMoveAfterButton();
}
void ImmediateModeActionDispatcher::MouseLButtonDoubleClickImpl()
{
GetMouseInteractionEvent()->m_mouseEvent = AzToolsFramework::ViewportInteraction::MouseEvent::DoubleClick;
ToggleOn(GetMouseInteractionEvent()->m_mouseInteraction.m_mouseButtons.m_mouseButtons, MouseButton::Left);
m_viewportManipulatorInteraction.GetManipulatorManager().ConsumeMouseInteractionEvent(*m_event);
ToggleOff(GetMouseInteractionEvent()->m_mouseInteraction.m_mouseButtons.m_mouseButtons, MouseButton::Left);
// the mouse position will be the same as the previous event, thus the delta will be 0
MouseMoveAfterButton();
@@ -1,129 +0,0 @@
/*
* 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 <AzManipulatorTestFramework/RetainedModeActionDispatcher.h>
namespace AzManipulatorTestFramework
{
using KeyboardModifier = AzToolsFramework::ViewportInteraction::KeyboardModifier;
RetainedModeActionDispatcher::RetainedModeActionDispatcher(
ManipulatorViewportInteraction& viewportManipulatorInteraction)
: m_dispatcher(viewportManipulatorInteraction)
{
}
void RetainedModeActionDispatcher::AddActionToSequence(Action&& action)
{
if (m_locked)
{
const char* error = "Couldn't add action to sequence, dispatcher is locked (you must call ResetSequence() \
before adding actions to this dispatcher)";
Log("%s", error);
AZ_Assert(false, "Error: %s", error);
}
m_actions.emplace_back(action);
}
void RetainedModeActionDispatcher::EnableSnapToGridImpl()
{
AddActionToSequence([=]() { m_dispatcher.EnableSnapToGrid(); });
}
void RetainedModeActionDispatcher::DisableSnapToGridImpl()
{
AddActionToSequence([=]() { m_dispatcher.DisableSnapToGrid(); });
}
void RetainedModeActionDispatcher::GridSizeImpl(float size)
{
AddActionToSequence([=]() { m_dispatcher.GridSize(size); });
}
void RetainedModeActionDispatcher::CameraStateImpl(const AzFramework::CameraState& cameraState)
{
AddActionToSequence([=]() { m_dispatcher.CameraState(cameraState); });
}
void RetainedModeActionDispatcher::MouseLButtonDownImpl()
{
AddActionToSequence([=]() { m_dispatcher.MouseLButtonDown(); });
}
void RetainedModeActionDispatcher::MouseLButtonUpImpl()
{
AddActionToSequence([=]() { m_dispatcher.MouseLButtonUp(); });
}
void RetainedModeActionDispatcher::MousePositionImpl(const AzFramework::ScreenPoint& position)
{
AddActionToSequence([=]() { m_dispatcher.MousePosition(position); });
}
void RetainedModeActionDispatcher::KeyboardModifierDownImpl(const KeyboardModifier& keyModifier)
{
AddActionToSequence([=]() { m_dispatcher.KeyboardModifierDown(keyModifier); });
}
void RetainedModeActionDispatcher::KeyboardModifierUpImpl(const KeyboardModifier& keyModifier)
{
AddActionToSequence([=]() { m_dispatcher.KeyboardModifierUp(keyModifier); });
}
void RetainedModeActionDispatcher::ExpectManipulatorBeingInteractedImpl()
{
AddActionToSequence([=]() { m_dispatcher.ExpectManipulatorBeingInteracted(); });
}
void RetainedModeActionDispatcher::ExpectManipulatorNotBeingInteractedImpl()
{
AddActionToSequence([=]() { m_dispatcher.ExpectManipulatorNotBeingInteracted(); });
}
void RetainedModeActionDispatcher::SetEntityWorldTransformImpl(AZ::EntityId entityId, const AZ::Transform& transform)
{
AddActionToSequence([=]() { m_dispatcher.SetEntityWorldTransform(entityId, transform); });
}
void RetainedModeActionDispatcher::SetSelectedEntityImpl(AZ::EntityId entity)
{
AddActionToSequence([=]() { m_dispatcher.SetSelectedEntity(entity); });
}
void RetainedModeActionDispatcher::SetSelectedEntitiesImpl(const AzToolsFramework::EntityIdList& entities)
{
AddActionToSequence([=]() { m_dispatcher.SetSelectedEntities(entities); });
}
void RetainedModeActionDispatcher::EnterComponentModeImpl(const AZ::Uuid& uuid)
{
AddActionToSequence([=]() { m_dispatcher.EnterComponentMode(uuid); });
}
RetainedModeActionDispatcher* RetainedModeActionDispatcher::ResetSequence()
{
Log("%s", "Resetting the action sequence");
m_actions.clear();
m_dispatcher.ResetEvent();
m_locked = false;
return this;
}
RetainedModeActionDispatcher* RetainedModeActionDispatcher::Execute()
{
Log("Executing %u actions", m_actions.size());
for (auto& action : m_actions)
{
action();
}
m_dispatcher.ResetEvent();
m_locked = true;
return this;
}
} // namespace AzManipulatorTestFramework
@@ -14,12 +14,10 @@ set(FILES
Include/AzManipulatorTestFramework/DirectManipulatorViewportInteraction.h
Include/AzManipulatorTestFramework/IndirectManipulatorViewportInteraction.h
Include/AzManipulatorTestFramework/ImmediateModeActionDispatcher.h
Include/AzManipulatorTestFramework/RetainedModeActionDispatcher.h
Include/AzManipulatorTestFramework/AzManipulatorTestFrameworkUtils.h
Source/ViewportInteraction.cpp
Source/DirectManipulatorViewportInteraction.cpp
Source/IndirectManipulatorViewportInteraction.cpp
Source/ImmediateModeActionDispatcher.cpp
Source/RetainedModeActionDispatcher.cpp
Source/AzManipulatorTestFrameworkUtils.cpp
)
@@ -2461,6 +2461,18 @@ namespace AzQtComponents
placeholderRect.translate(0, -margins.bottom());
}
// Also adjust the placeholderRect by the relative dpi change from the original screen, since setGeometry uses the screen's
// virtualGeometry!
QScreen* fromScreen = dock->screen();
QScreen* toScreen = Utilities::ScreenAtPoint(placeholderRect.topLeft());
if (fromScreen != toScreen)
{
qreal factorRatio = QHighDpiScaling::factor(fromScreen) / QHighDpiScaling::factor(toScreen);
placeholderRect.setWidth(aznumeric_cast<int>(aznumeric_cast<qreal>(placeholderRect.width()) * factorRatio));
placeholderRect.setHeight(aznumeric_cast<int>(aznumeric_cast<qreal>(placeholderRect.height()) * factorRatio));
}
// Place the floating dock widget
makeDockWidgetFloating(dock, placeholderRect);
clearDraggingState();
@@ -169,6 +169,10 @@ namespace AzQtComponents
initializeSearchPaths(application, engineRootPath);
initializeFonts();
QFont defaultFont("Open Sans");
defaultFont.setPixelSize(12);
QApplication::setFont(defaultFont);
m_titleBarOverdrawHandler = TitleBarOverdrawHandler::createHandler(application, this);
// The window decoration wrappers require the titlebar overdraw handler
@@ -221,24 +221,6 @@ namespace AzToolsFramework
using ViewportSettingsNotificationBus = AZ::EBus<ViewportSettingNotifications, ViewportEBusTraits>;
//! Requests to freeze the Viewport Input
//! Added to prevent a bug with the legacy CryEngine Viewport code that would
//! keep doing raycast tests even when no level is loaded, causing a crash.
class ViewportFreezeRequests
{
public:
//! Return if Viewport Input is frozen
virtual bool IsViewportInputFrozen() = 0;
//! Sets the Viewport Input freeze state
virtual void FreezeViewportInput(bool freeze) = 0;
protected:
~ViewportFreezeRequests() = default;
};
//! Type to inherit to implement ViewportFreezeRequests.
using ViewportFreezeRequestBus = AZ::EBus<ViewportFreezeRequests, ViewportEBusTraits>;
//! Viewport requests that are only guaranteed to be serviced by the Main Editor viewport.
class MainEditorViewportInteractionRequests
{
@@ -1770,6 +1770,12 @@ namespace AzToolsFramework
return false;
}
void EditorTransformComponentSelection::ChangeSelectedEntity(const AZ::EntityId entityId)
{
DeselectEntities();
SelectDeselect(entityId);
}
bool EditorTransformComponentSelection::HandleMouseInteraction(const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
{
AZ_PROFILE_FUNCTION(AzToolsFramework);
@@ -1821,202 +1827,239 @@ namespace AzToolsFramework
return true;
}
// double click to deselect all
if (Input::DeselectAll(mouseInteraction))
if (ed_viewportStickySelect)
{
// note: even if m_selectedEntityIds is technically empty, we
// may still have an entity selected that was clicked in the
// entity outliner - we still want to make sure the deselect all
// action clears the selection
DeselectEntities();
return false;
// double click to deselect all
if (Input::DeselectAll(mouseInteraction))
{
// note: even if m_selectedEntityIds is technically empty, we
// may still have an entity selected that was clicked in the
// entity outliner - we still want to make sure the deselect all
// action clears the selection
DeselectEntities();
return false;
}
}
// select/deselect (add/remove) entities with ctrl held
if (Input::AdditiveIndividualSelect(clickOutcome, mouseInteraction))
{
if (SelectDeselect(entityIdUnderCursor))
{
if (m_selectedEntityIds.empty())
{
m_pivotOverrideFrame.Reset();
}
return false;
}
}
if (!m_selectedEntityIds.empty())
{
// select/deselect (add/remove) entities with ctrl held
if (Input::AdditiveIndividualSelect(clickOutcome, mouseInteraction))
{
if (SelectDeselect(entityIdUnderCursor))
{
if (m_selectedEntityIds.empty())
{
m_pivotOverrideFrame.Reset();
}
return false;
}
}
// group copying/alignment to specific entity - 'ditto' position/orientation for group
if (Input::GroupDitto(mouseInteraction))
if (Input::GroupDitto(mouseInteraction) && PerformGroupDitto(entityIdUnderCursor))
{
if (entityIdUnderCursor.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM);
switch (m_mode)
{
case Mode::Rotation:
CopyOrientationToSelectedEntitiesGroup(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetUniformScale());
break;
case Mode::Translation:
CopyTranslationToSelectedEntitiesGroup(worldFromLocal.GetTranslation());
break;
default:
// do nothing
break;
}
return false;
}
return false;
}
// individual copying/alignment to specific entity - 'ditto' position/orientation for individual
if (Input::IndividualDitto(mouseInteraction))
if (Input::IndividualDitto(mouseInteraction) && PerformIndividualDitto(entityIdUnderCursor))
{
if (entityIdUnderCursor.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM);
switch (m_mode)
{
case Mode::Rotation:
CopyOrientationToSelectedEntitiesIndividual(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetUniformScale());
break;
case Mode::Translation:
CopyTranslationToSelectedEntitiesIndividual(worldFromLocal.GetTranslation());
break;
default:
// do nothing
break;
}
return false;
}
return false;
}
// try snapping to the terrain (if in Translation mode) and entity wasn't picked
if (Input::SnapTerrain(mouseInteraction))
{
for (AZ::EntityId entityId : m_selectedEntityIds)
{
ScopedUndoBatch::MarkEntityDirty(entityId);
}
if (m_mode == Mode::Translation)
{
const AZ::Vector3 finalSurfacePosition = PickTerrainPosition(mouseInteraction.m_mouseInteraction);
// handle modifier alternatives
if (Input::IndividualDitto(mouseInteraction))
{
CopyTranslationToSelectedEntitiesIndividual(finalSurfacePosition);
}
else if (Input::GroupDitto(mouseInteraction))
{
CopyTranslationToSelectedEntitiesGroup(finalSurfacePosition);
}
}
else if (m_mode == Mode::Rotation)
{
// handle modifier alternatives
if (Input::IndividualDitto(mouseInteraction))
{
CopyOrientationToSelectedEntitiesIndividual(AZ::Quaternion::CreateIdentity());
}
else if (Input::GroupDitto(mouseInteraction))
{
CopyOrientationToSelectedEntitiesGroup(AZ::Quaternion::CreateIdentity());
}
}
PerformSnapToTerrain(mouseInteraction);
return false;
}
// set manipulator pivot override translation or orientation (update manipulators)
if (Input::ManipulatorDitto(mouseInteraction))
{
if (m_entityIdManipulators.m_manipulators)
{
ScopedUndoBatch undoBatch(s_dittoManipulatorUndoRedoDesc);
auto manipulatorCommand =
AZStd::make_unique<EntityManipulatorCommand>(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName);
if (entityIdUnderCursor.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityIdUnderCursor, &AZ::TransformBus::Events::GetWorldTM);
// set orientation/translation to match picked entity
switch (m_mode)
{
case Mode::Rotation:
OverrideManipulatorOrientation(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Translation:
OverrideManipulatorTranslation(worldFromLocal.GetTranslation());
break;
case Mode::Scale:
// do nothing
break;
default:
break;
}
// only update pivot override when in translation or rotation mode
switch (m_mode)
{
case Mode::Rotation:
m_pivotOverrideFrame.m_pickTypes |= OptionalFrame::PickType::Orientation;
[[fallthrough]];
case Mode::Translation:
m_pivotOverrideFrame.m_pickTypes |= OptionalFrame::PickType::Translation;
m_pivotOverrideFrame.m_pickedEntityIdOverride = entityIdUnderCursor;
break;
case Mode::Scale:
// do nothing
break;
default:
break;
}
}
else
{
// match the same behavior as if we pressed Ctrl+R to reset the manipulator
DelegateClearManipulatorOverride();
}
manipulatorCommand->SetManipulatorAfter(EntityManipulatorCommand::State(
BuildPivotOverride(m_pivotOverrideFrame.HasTranslationOverride(), m_pivotOverrideFrame.HasOrientationOverride()),
m_entityIdManipulators.m_manipulators->GetLocalTransform(), entityIdUnderCursor));
manipulatorCommand->SetParent(undoBatch.GetUndoBatch());
manipulatorCommand.release();
}
PerformManipulatorDitto(entityIdUnderCursor);
return false;
}
return false;
if (ed_viewportStickySelect)
{
return false;
}
}
// standard toggle selection
if (Input::IndividualSelect(clickOutcome))
{
SelectDeselect(entityIdUnderCursor);
if (!ed_viewportStickySelect)
{
ChangeSelectedEntity(entityIdUnderCursor);
}
else
{
SelectDeselect(entityIdUnderCursor);
}
}
return false;
}
bool EditorTransformComponentSelection::PerformGroupDitto(const AZ::EntityId entityId)
{
if (entityId.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
switch (m_mode)
{
case Mode::Rotation:
CopyOrientationToSelectedEntitiesGroup(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetUniformScale());
break;
case Mode::Translation:
CopyTranslationToSelectedEntitiesGroup(worldFromLocal.GetTranslation());
break;
default:
// do nothing
break;
}
return true;
}
return false;
}
bool EditorTransformComponentSelection::PerformIndividualDitto(const AZ::EntityId entityId)
{
if (entityId.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
switch (m_mode)
{
case Mode::Rotation:
CopyOrientationToSelectedEntitiesIndividual(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(worldFromLocal.GetUniformScale());
break;
case Mode::Translation:
CopyTranslationToSelectedEntitiesIndividual(worldFromLocal.GetTranslation());
break;
default:
// do nothing
break;
}
return true;
}
return false;
}
void EditorTransformComponentSelection::PerformSnapToTerrain(const ViewportInteraction::MouseInteractionEvent& mouseInteraction)
{
for (AZ::EntityId entityId : m_selectedEntityIds)
{
ScopedUndoBatch::MarkEntityDirty(entityId);
}
if (m_mode == Mode::Translation)
{
const AZ::Vector3 finalSurfacePosition = PickTerrainPosition(mouseInteraction.m_mouseInteraction);
// handle modifier alternatives
if (Input::IndividualDitto(mouseInteraction))
{
CopyTranslationToSelectedEntitiesIndividual(finalSurfacePosition);
}
else if (Input::GroupDitto(mouseInteraction))
{
CopyTranslationToSelectedEntitiesGroup(finalSurfacePosition);
}
}
else if (m_mode == Mode::Rotation)
{
// handle modifier alternatives
if (Input::IndividualDitto(mouseInteraction))
{
CopyOrientationToSelectedEntitiesIndividual(AZ::Quaternion::CreateIdentity());
}
else if (Input::GroupDitto(mouseInteraction))
{
CopyOrientationToSelectedEntitiesGroup(AZ::Quaternion::CreateIdentity());
}
}
}
void EditorTransformComponentSelection::PerformManipulatorDitto(const AZ::EntityId entityId)
{
if (m_entityIdManipulators.m_manipulators)
{
ScopedUndoBatch undoBatch(s_dittoManipulatorUndoRedoDesc);
auto manipulatorCommand =
AZStd::make_unique<EntityManipulatorCommand>(CreateManipulatorCommandStateFromSelf(), s_manipulatorUndoRedoName);
if (entityId.IsValid())
{
AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
AZ::TransformBus::EventResult(worldFromLocal, entityId, &AZ::TransformBus::Events::GetWorldTM);
// set orientation/translation to match picked entity
switch (m_mode)
{
case Mode::Rotation:
OverrideManipulatorOrientation(QuaternionFromTransformNoScaling(worldFromLocal));
break;
case Mode::Translation:
OverrideManipulatorTranslation(worldFromLocal.GetTranslation());
break;
case Mode::Scale:
// do nothing
break;
default:
break;
}
// only update pivot override when in translation or rotation mode
switch (m_mode)
{
case Mode::Rotation:
m_pivotOverrideFrame.m_pickTypes |= OptionalFrame::PickType::Orientation;
[[fallthrough]];
case Mode::Translation:
m_pivotOverrideFrame.m_pickTypes |= OptionalFrame::PickType::Translation;
m_pivotOverrideFrame.m_pickedEntityIdOverride = entityId;
break;
case Mode::Scale:
// do nothing
break;
default:
break;
}
}
else
{
// match the same behavior as if we pressed Ctrl+R to reset the manipulator
DelegateClearManipulatorOverride();
}
manipulatorCommand->SetManipulatorAfter(EntityManipulatorCommand::State(
BuildPivotOverride(m_pivotOverrideFrame.HasTranslationOverride(), m_pivotOverrideFrame.HasOrientationOverride()),
m_entityIdManipulators.m_manipulators->GetLocalTransform(), entityId));
manipulatorCommand->SetParent(undoBatch.GetUndoBatch());
manipulatorCommand.release();
}
}
template<typename T>
static void AddAction(
AZStd::vector<AZStd::unique_ptr<QAction>>& actions,
@@ -207,6 +207,7 @@ namespace AzToolsFramework
void SetSelectedEntities(const EntityIdList& entityIds);
void DeselectEntities();
bool SelectDeselect(AZ::EntityId entityId);
void ChangeSelectedEntity(AZ::EntityId entityId);
void RefreshSelectedEntityIds();
void RefreshSelectedEntityIds(const EntityIdList& selectedEntityIds);
@@ -298,6 +299,11 @@ namespace AzToolsFramework
void SetEntityLocalRotation(AZ::EntityId entityId, const AZ::Vector3& localRotation);
void SetEntityLocalRotation(AZ::EntityId entityId, const AZ::Quaternion& localRotation);
bool PerformGroupDitto(AZ::EntityId entityId);
bool PerformIndividualDitto(AZ::EntityId entityId);
void PerformManipulatorDitto(AZ::EntityId entityId);
void PerformSnapToTerrain(const ViewportInteraction::MouseInteractionEvent& mouseInteraction);
//! Responsible for keeping the space cluster in sync with the current reference frame.
void UpdateSpaceCluster(ReferenceFrame referenceFrame);
@@ -614,7 +614,7 @@ namespace UnitTest
using EditorTransformComponentSelectionViewportPickingManipulatorTestFixture =
IndirectCallManipulatorViewportInteractionFixtureMixin<EditorTransformComponentSelectionViewportPickingFixture>;
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, SingleClickWithNoSelectionWillSelectEntity)
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, StickySingleClickWithNoSelectionWillSelectEntity)
{
AzToolsFramework::ed_viewportStickySelect = true;
@@ -637,19 +637,44 @@ namespace UnitTest
EXPECT_THAT(selectedEntitiesAfter.front(), Eq(m_entityId1));
}
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, SingleClickOffEntityWithSelectionWillNotDeselectEntity)
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, UnstickySingleClickWithNoSelectionWillSelectEntity)
{
AzToolsFramework::ed_viewportStickySelect = false;
PositionEntities();
PositionCamera(m_cameraState);
using ::testing::Eq;
auto selectedEntitiesBefore = SelectedEntities();
EXPECT_TRUE(selectedEntitiesBefore.empty());
// calculate the position in screen space of the initial entity position
const auto entity1ScreenPosition = AzFramework::WorldToScreen(m_entity1WorldTranslation, m_cameraState);
// click the entity in the viewport
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity1ScreenPosition)->MouseLButtonDown()->MouseLButtonUp();
// entity is selected
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_THAT(selectedEntitiesAfter.size(), Eq(1));
EXPECT_THAT(selectedEntitiesAfter.front(), Eq(m_entityId1));
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
StickySingleClickOffEntityWithSelectionWillNotDeselectEntity)
{
AzToolsFramework::ed_viewportStickySelect = true;
PositionEntities();
PositionCamera(m_cameraState);
// position in space above the entity
// position in space above the entities
const auto clickOffPositionWorld = AZ::Vector3(5.0f, 15.0f, 12.0f);
AzToolsFramework::SelectEntity(m_entityId1);
// calculate the position in screen space of the initial position of the entity
// calculate the screen space position of the click
const auto clickOffPositionScreen = AzFramework::WorldToScreen(clickOffPositionWorld, m_cameraState);
// click the empty space in the viewport
@@ -662,9 +687,32 @@ namespace UnitTest
EXPECT_THAT(selectedEntitiesAfter.front(), Eq(m_entityId1));
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, UnstickySingleClickOffEntityWithSelectionWillDeselectEntity)
{
AzToolsFramework::ed_viewportStickySelect = false;
PositionEntities();
PositionCamera(m_cameraState);
AzToolsFramework::SelectEntity(m_entityId1);
// position in space above the entities
const auto clickOffPositionWorld = AZ::Vector3(5.0f, 15.0f, 12.0f);
// calculate the screen space position of the click
const auto clickOffPositionScreen = AzFramework::WorldToScreen(clickOffPositionWorld, m_cameraState);
// click the empty space in the viewport
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(clickOffPositionScreen)->MouseLButtonDown()->MouseLButtonUp();
// entity was deselected
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_TRUE(selectedEntitiesAfter.empty());
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
SingleClickOnNewEntityWithSelectionWillNotChangeSelectedEntity)
StickySingleClickOnNewEntityWithSelectionWillNotChangeSelectedEntity)
{
AzToolsFramework::ed_viewportStickySelect = true;
@@ -688,7 +736,31 @@ namespace UnitTest
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
CtrlSingleClickOnNewEntityWithSelectionWillAppendSelectedEntityToSelection)
UnstickySingleClickOnNewEntityWithSelectionWillChangeSelectedEntity)
{
AzToolsFramework::ed_viewportStickySelect = false;
PositionEntities();
PositionCamera(m_cameraState);
AzToolsFramework::SelectEntity(m_entityId1);
// calculate the position in screen space of the second entity
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
// click the entity in the viewport
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(entity2ScreenPosition)->MouseLButtonDown()->MouseLButtonUp();
// entity selection was changed
using ::testing::Eq;
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_THAT(selectedEntitiesAfter.size(), Eq(1));
EXPECT_THAT(selectedEntitiesAfter.front(), Eq(m_entityId2));
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
StickyCtrlSingleClickOnNewEntityWithSelectionWillAppendSelectedEntityToSelection)
{
AzToolsFramework::ed_viewportStickySelect = true;
@@ -715,7 +787,34 @@ namespace UnitTest
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
CtrlSingleClickOnEntityInSelectionWillRemoveEntityFromSelection)
UnstickyCtrlSingleClickOnNewEntityWithSelectionWillAppendSelectedEntityToSelection)
{
AzToolsFramework::ed_viewportStickySelect = false;
PositionEntities();
PositionCamera(m_cameraState);
AzToolsFramework::SelectEntity(m_entityId1);
// calculate the position in screen space of the second entity
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
// click the entity in the viewport
m_actionDispatcher->CameraState(m_cameraState)
->MousePosition(entity2ScreenPosition)
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
->MouseLButtonDown()
->MouseLButtonUp();
// entity selection was changed (one entity selected to two)
using ::testing::UnorderedElementsAre;
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1, m_entityId2));
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
StickyCtrlSingleClickOnEntityInSelectionWillRemoveEntityFromSelection)
{
AzToolsFramework::ed_viewportStickySelect = true;
@@ -740,7 +839,36 @@ namespace UnitTest
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1));
}
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, BoxSelectWithNoInitialSelectionAddsEntitiesToSelection)
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
UnstickyCtrlSingleClickOnEntityInSelectionWillRemoveEntityFromSelection)
{
AzToolsFramework::ed_viewportStickySelect = false;
PositionEntities();
PositionCamera(m_cameraState);
AzToolsFramework::SelectEntities({ m_entityId1, m_entityId2 });
// calculate the position in screen space of the second entity
const auto entity2ScreenPosition = AzFramework::WorldToScreen(m_entity2WorldTranslation, m_cameraState);
// click the entity in the viewport
m_actionDispatcher->CameraState(m_cameraState)
->MousePosition(entity2ScreenPosition)
->KeyboardModifierDown(AzToolsFramework::ViewportInteraction::KeyboardModifier::Control)
->MouseLButtonDown()
->MouseLButtonUp();
// entity selection was changed (entity2 was deselected)
using ::testing::UnorderedElementsAre;
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_THAT(selectedEntitiesAfter, UnorderedElementsAre(m_entityId1));
}
TEST_F(
EditorTransformComponentSelectionViewportPickingManipulatorTestFixture,
BoxSelectWithNoInitialSelectionAddsEntitiesToSelection)
{
AzToolsFramework::ed_viewportStickySelect = true;
@@ -835,6 +963,32 @@ namespace UnitTest
EXPECT_TRUE(selectedEntitiesAfter.empty());
}
TEST_F(EditorTransformComponentSelectionViewportPickingManipulatorTestFixture, StickyDoubleClickWithSelectionWillDeselectEntities)
{
AzToolsFramework::ed_viewportStickySelect = true;
PositionEntities();
PositionCamera(m_cameraState);
AzToolsFramework::SelectEntities({ m_entityId1, m_entityId2, m_entityId3 });
using ::testing::UnorderedElementsAre;
auto selectedEntitiesBefore = SelectedEntities();
EXPECT_THAT(selectedEntitiesBefore, UnorderedElementsAre(m_entityId1, m_entityId2, m_entityId3));
// position in space above the entities
const auto clickOffPositionWorld = AZ::Vector3(5.0f, 15.0f, 12.0f);
// calculate the screen space position of the click
const auto clickOffPositionScreen = AzFramework::WorldToScreen(clickOffPositionWorld, m_cameraState);
// double click to deselect entities
m_actionDispatcher->CameraState(m_cameraState)->MousePosition(clickOffPositionScreen)->MouseLButtonDoubleClick();
// no entities are selected
auto selectedEntitiesAfter = SelectedEntities();
EXPECT_TRUE(selectedEntitiesAfter.empty());
}
using EditorTransformComponentSelectionManipulatorTestFixture =
IndirectCallManipulatorViewportInteractionFixtureMixin<EditorTransformComponentSelectionFixture>;
@@ -1150,7 +1150,7 @@ namespace AZ
return BuildResult::CompilationFailed;
}
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (readJsonResult.IsSuccess())
{
@@ -1171,7 +1171,7 @@ namespace AZ
AZStd::string outputFile = m_inputFilePath;
AzFramework::StringFunc::Path::ReplaceExtension(outputFile, outputExtension);
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(outputFile, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (readJsonResult.IsSuccess())
{
@@ -556,7 +556,7 @@ namespace AZ
shaderAssetCreator.SetRenderStates(renderStates);
}
Outcome<AZStd::string, AZStd::string> hlslSourceCodeOutcome = Utils::ReadFile(hlslFullPath, AZ::RPI::JsonUtils::AtomMaxFileSize);
Outcome<AZStd::string, AZStd::string> hlslSourceCodeOutcome = Utils::ReadFile(hlslFullPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!hlslSourceCodeOutcome.IsSuccess())
{
AZ_Error(
@@ -52,7 +52,7 @@ namespace AZ
{
RPI::ShaderSourceData shaderSourceData;
auto document = JsonSerializationUtils::ReadJsonFile(fullPathToJsonFile, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto document = JsonSerializationUtils::ReadJsonFile(fullPathToJsonFile, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!document.IsSuccess())
{
@@ -128,7 +128,7 @@ namespace AZ
AZStd::unordered_map<int, Outcome<rapidjson::Document, AZStd::string>> outcomes;
for (int i : indicesOfInterest)
{
outcomes[i] = JsonSerializationUtils::ReadJsonFile(pathOfJsonFiles[i], AZ::RPI::JsonUtils::AtomMaxFileSize);
outcomes[i] = JsonSerializationUtils::ReadJsonFile(pathOfJsonFiles[i], AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!outcomes[i].IsSuccess())
{
AZ_Error(builderName, false, "%s", outcomes[i].GetError().c_str());
@@ -623,7 +623,7 @@ namespace AZ
StructData inputStruct;
inputStruct.m_id = "";
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToIaJson, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToIaJson, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderBuilderUtilityName, false, "%s", jsonOutcome.GetError().c_str());
@@ -716,7 +716,7 @@ namespace AZ
StructData outputStruct;
outputStruct.m_id = "";
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToOmJson, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(pathToOmJson, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderBuilderUtilityName, false, "%s", jsonOutcome.GetError().c_str());
@@ -478,7 +478,7 @@ namespace AZ
RPI::Ptr<RPI::ShaderOptionGroupLayout> shaderOptionGroupLayout = RPI::ShaderOptionGroupLayout::Create();
// The shader options define what options are available, what are the allowed values/range
// for each option and what is its default value.
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(optionsGroupJsonPath, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(optionsGroupJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
@@ -509,7 +509,7 @@ namespace AZ
}
auto functionsJsonPath = functionsJsonPathOutcome.TakeValue();
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(functionsJsonPath, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(functionsJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
@@ -541,7 +541,7 @@ namespace AZ
}
auto srgJsonPath = srgJsonPathOutcome.TakeValue();
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(srgJsonPath, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(srgJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
@@ -598,7 +598,7 @@ namespace AZ
}
auto bindingsJsonPath = bindingsJsonPathOutcome.TakeValue();
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(bindingsJsonPath, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto jsonOutcome = JsonSerializationUtils::ReadJsonFile(bindingsJsonPath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!jsonOutcome.IsSuccess())
{
AZ_Error(ShaderVariantAssetBuilderName, false, "%s", jsonOutcome.GetError().c_str());
@@ -630,7 +630,7 @@ namespace AZ
}
hlslSourcePath = hlslSourcePathOutcome.TakeValue();
Outcome<AZStd::string, AZStd::string> hlslSourceOutcome = Utils::ReadFile(hlslSourcePath, AZ::RPI::JsonUtils::AtomMaxFileSize);
Outcome<AZStd::string, AZStd::string> hlslSourceOutcome = Utils::ReadFile(hlslSourcePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!hlslSourceOutcome.IsSuccess())
{
AZ_Error(
@@ -56,7 +56,8 @@ namespace AZ
//////////////////////////////////////////////////////////////////////////
virtual void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) = 0;
virtual void OnBootstrapSceneReady([[maybe_unused]]AZ::RPI::Scene* bootstrapScene){}
virtual void OnFrameRateLimitChanged([[maybe_unused]]float fpsLimit){}
};
using NotificationBus = AZ::EBus<Notification>;
} // namespace Bootstrap
@@ -23,6 +23,8 @@ namespace AZ::Render::Bootstrap
virtual AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) = 0;
virtual bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) = 0;
virtual float GetFrameRateLimit() const = 0;
virtual void SetFrameRateLimit(float fpsLimit) = 0;
protected:
~Request() = default;
@@ -41,7 +41,14 @@
#include <AzCore/Console/IConsole.h>
#include <BootstrapSystemComponent_Traits_Platform.h>
static void OnFrameRateLimitChanged(const float& fpsLimit)
{
AZ::Render::Bootstrap::RequestBus::Broadcast(
&AZ::Render::Bootstrap::RequestBus::Events::SetFrameRateLimit, fpsLimit);
}
AZ_CVAR(AZ::CVarFixedString, r_default_pipeline_name, AZ_TRAIT_BOOTSTRAPSYSTEMCOMPONENT_PIPELINE_NAME, nullptr, AZ::ConsoleFunctorFlags::DontReplicate, "Default Render pipeline name");
AZ_CVAR(float, r_fps_limit, 0, OnFrameRateLimitChanged, AZ::ConsoleFunctorFlags::Null, "The maximum framerate to render at, or 0 for unlimited");
namespace AZ
{
@@ -342,6 +349,22 @@ namespace AZ
return true;
}
float BootstrapSystemComponent::GetFrameRateLimit() const
{
return r_fps_limit;
}
void BootstrapSystemComponent::SetFrameRateLimit(float fpsLimit)
{
r_fps_limit = fpsLimit;
if (m_viewportContext)
{
m_viewportContext->SetFpsLimit(r_fps_limit);
}
Render::Bootstrap::NotificationBus::Broadcast(
&Render::Bootstrap::NotificationBus::Events::OnFrameRateLimitChanged, fpsLimit);
}
void BootstrapSystemComponent::CreateDefaultRenderPipeline()
{
EnsureDefaultRenderPipelineInstalledForScene(m_defaultScene, m_viewportContext);
@@ -381,23 +404,11 @@ namespace AZ
}
void BootstrapSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
{
// Temp: When running in the launcher without the legacy renderer
// we need to call RenderTick on the viewport context each frame.
if (m_viewportContext)
{
AZ::ApplicationTypeQuery appType;
ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Events::QueryApplicationType, appType);
if (appType.IsGame())
{
m_viewportContext->RenderTick();
}
}
}
{ }
int BootstrapSystemComponent::GetTickOrder()
{
return TICK_LAST;
return TICK_PRE_RENDER;
}
void BootstrapSystemComponent::OnWindowClosed()
@@ -69,6 +69,8 @@ namespace AZ
// Render::Bootstrap::RequestBus::Handler overrides ...
AZ::RPI::ScenePtr GetOrCreateAtomSceneFromAzScene(AzFramework::Scene* scene) override;
bool EnsureDefaultRenderPipelineInstalledForScene(AZ::RPI::ScenePtr scene, AZ::RPI::ViewportContextPtr viewportContext) override;
float GetFrameRateLimit() const override;
void SetFrameRateLimit(float fpsLimit) override;
protected:
// Component overrides ...
@@ -144,7 +144,7 @@ namespace AZ
// Try to lock here, the shutdownMutex will only be contested when the CpuProfiler is shutting down.
if (m_shutdownMutex.try_lock_shared())
{
if (m_enabled)
if (m_enabled && ms_threadLocalStorage != nullptr)
{
ms_threadLocalStorage->RegionStackPopBack();
}
@@ -22,7 +22,7 @@ namespace AZ
{
//! Protects from allocating too much memory. The choice of a 1MB threshold is arbitrary.
//! If you need to work with larger files, please use AZ::IO directly instead of these utility functions.
inline constexpr size_t AtomMaxFileSize = 1024 * 1024;
inline constexpr size_t DefaultMaxFileSize = 1024 * 1024;
// Declarations...
@@ -43,7 +43,7 @@ namespace AZ
{
objectData = ObjectType();
auto loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(path, AtomMaxFileSize);
auto loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(path, DefaultMaxFileSize);
if (!loadOutcome.IsSuccess())
{
AZ_Error("AZ::RPI::JsonUtils", false, "%s", loadOutcome.GetError().c_str());
@@ -161,19 +161,25 @@ namespace AZ
//! Add this RenderPipeline to RPI system's RenderTick and it will be rendered whenever
//! the RPI system's RenderTick is called.
//! The RenderPipeline is rendered per RenderTick by default unless AddToRenderTickOnce() was called.
//! The RenderPipeline is rendered per RenderTick by default.
void AddToRenderTick();
//! Add this RenderPipeline to RPI system's RenderTick and it will be rendered every RenderTick
//! after the specified interval has elapsed since the last rendered frame.
//! @param renderInterval The desired time between rendered frames, in seconds.
void AddToRenderTickAtInterval(AZStd::chrono::duration<float> renderInterval);
//! Disable render for this RenderPipeline
void RemoveFromRenderTick();
~RenderPipeline();
enum class RenderMode : uint8_t
{
RenderEveryTick, // Render at each RPI system render tick
RenderOnce, // Render once in next RPI system render tick
NoRender // Render disabled.
RenderEveryTick, //!< Render at each RPI system render tick.
RenderAtTargetRate, //!< Render on RPI system render tick after a target refresh rate interval has passed.
RenderOnce, //!< Render once in next RPI system render tick.
NoRender //!< Render disabled.
};
//! Get current render mode
@@ -185,6 +191,12 @@ namespace AZ
//! Get draw filter mask
RHI::DrawFilterMask GetDrawFilterMask() const;
using FrameNotificationEvent = AZ::Event<>;
//! Notifies a listener when a frame is about to be prepared for render, before SRGs are bound.
void ConnectPrepareFrameHandler(FrameNotificationEvent::Handler& handler);
//! Notifies a listener when the rendering of a frame has finished
void ConnectEndFrameHandler(FrameNotificationEvent::Handler& handler);
private:
RenderPipeline() = default;
@@ -202,8 +214,11 @@ namespace AZ
void OnAddedToScene(Scene* scene);
void OnRemovedFromScene(Scene* scene);
// Called before this pipeline is about to be rendered and before SRGs are bound.
void OnPrepareFrame();
// Called when this pipeline is about to be rendered
void OnStartFrame(const TickTimeInfo& tick);
void OnStartFrame();
// Called when the rendering of current frame is finished.
void OnFrameEnd();
@@ -228,8 +243,14 @@ namespace AZ
PipelineViewMap m_pipelineViewsByTag;
/// The system time when the last time this pipeline render was started
float m_lastRenderStartTime = 0;
// The system time when the last time this pipeline render was started
AZStd::chrono::system_clock::time_point m_lastRenderStartTime;
// The current system time, as of OnPrepareFrame's execution.
AZStd::chrono::system_clock::time_point m_lastRenderRequestTime;
// The target time between renders when m_renderMode is RenderMode::RenderAtTargetRate
AZStd::chrono::duration<float> m_targetRefreshRate;
// RenderPipeline's name id, it will be used to identify the render pipeline when it's added to a Scene
RenderPipelineId m_nameId;
@@ -259,7 +280,11 @@ namespace AZ
RHI::DrawFilterTag m_drawFilterTag;
// A mask to filter draw items submitted by passes of this render pipeline.
// This mask is created from the value of m_drawFilterTag.
RHI::DrawFilterMask m_drawFilterMask = 0;
RHI::DrawFilterMask m_drawFilterMask = 0;
// Events for notification on render state
FrameNotificationEvent m_prepareFrameEvent;
FrameNotificationEvent m_endFrameEvent;
};
} // namespace RPI
@@ -67,6 +67,9 @@ namespace AZ
//! Notifies when the PrepareRender phase is ending
virtual void OnEndPrepareRender() {}
//! Notifies when the render tick for a given frame has finished.
virtual void OnFrameEnd() {}
};
using SceneNotificationBus = AZ::EBus<SceneNotification>;
@@ -51,9 +51,21 @@ namespace AZ
//! Sets the root scene associated with this viewport.
//! This does not provide a default render pipeline, one must be provided to enable rendering.
void SetRenderScene(ScenePtr scene);
//! Runs one simulation and render tick and renders a frame to this viewport's window.
//! @note This is likely to be replaced by a tick management system in the RPI.
void RenderTick();
//! Gets the maximum frame rate this viewport context's pipeline can render at, 0 for unlimited.
//! The target framerate for the pipeline will be determined by this frame limit and the
//! vsync settings for the current window.
float GetFpsLimit() const;
//! Sets the maximum frame rate this viewport context's pipeline can render at, 0 for unlimited.
//! The target framerate for the pipeline will be determined by this frame limit and the
//! vsync settings for the current window.
void SetFpsLimit(float fpsLimit);
//! Gets the target frame rate for this viewport context.
//! This returns the lowest of either the current VSync refresh rate
//! or 0 for an unlimited frame rate (if there's no FPS limit and vsync is off).
float GetTargetFrameRate() const;
//! Gets the current name of this ViewportContext.
//! This name is used to tie this ViewportContext to its View stack, and ViewportContexts may be
@@ -74,19 +86,28 @@ namespace AZ
//! \see AzFramework::WindowRequests::GetDpiScaleFactor
float GetDpiScalingFactor() const;
//! Gets the current vsync interval, as a divisor of the current refresh rate.
//! A value of 0 indicates that vsync is disabled.
uint32_t GetVsyncInterval() const;
//! Gets the current display refresh rate, in frames per second.
uint32_t GetRefreshRate() const;
// SceneNotificationBus interface overrides...
//! Ensures our default view remains set when our scene's render pipelines are modified.
void OnRenderPipelineAdded(RenderPipelinePtr pipeline) override;
//! Ensures our default view remains set when our scene's render pipelines are modified.
void OnRenderPipelineRemoved(RenderPipeline* pipeline) override;
//! OnBeginPrepareRender is forwarded to our RenderTick notification to allow subscribers to do rendering.
void OnBeginPrepareRender() override;
// WindowNotificationBus interface overrides...
//! Used to fire a notification when our window resizes.
void OnWindowResized(uint32_t width, uint32_t height) override;
//! Used to fire a notification when our window DPI changes.
void OnDpiScaleFactorChanged(float dpiScaleFactor) override;
//! Used to fire a notification when our vsync interval changes.
void OnVsyncIntervalChanged(uint32_t interval) override;
//! Used to fire a notification when our refresh rate changes.
void OnRefreshRateChanged(uint32_t refreshRate) override;
using SizeChangedEvent = AZ::Event<AzFramework::WindowSize>;
//! Notifies consumers when the viewport size has changed.
@@ -98,6 +119,12 @@ namespace AZ
//! Alternatively, connect to ViewportContextNotificationsBus and listen to ViewportContextNotifications::OnViewportDpiScalingChanged.
void ConnectDpiScalingFactorChangedHandler(ScalarChangedEvent::Handler& handler);
using UintChangedEvent = AZ::Event<uint32_t>;
//! Notifies consumers when the vsync interval has changed.
void ConnectVsyncIntervalChangedHandler(UintChangedEvent::Handler& handler);
//! Notifies consumers when the refresh rate has changed.
void ConnectRefreshRateChangedHandler(UintChangedEvent::Handler& handler);
using MatrixChangedEvent = AZ::Event<const AZ::Matrix4x4&>;
//! Notifies consumers when the view matrix has changed.
void ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler);
@@ -139,15 +166,24 @@ namespace AZ
void SetDefaultView(ViewPtr view);
// Ensures our render pipeline's default camera matches ours.
void UpdatePipelineView();
// Ensures our render pipeline refresh rate matches our refresh rate.
void UpdatePipelineRefreshRate();
// Resets the current pipeline reference and ensures pipeline events are disconnected.
void ResetCurrentPipeline();
ScenePtr m_rootScene;
WindowContextSharedPtr m_windowContext;
ViewPtr m_defaultView;
AzFramework::WindowSize m_viewportSize;
float m_viewportDpiScaleFactor = 1.0f;
uint32_t m_vsyncInterval = 1;
uint32_t m_refreshRate = 60;
float m_fpsLimit = 0.f;
SizeChangedEvent m_sizeChangedEvent;
ScalarChangedEvent m_dpiScalingFactorChangedEvent;
UintChangedEvent m_vsyncIntervalChangedEvent;
UintChangedEvent m_refreshRateChangedEvent;
MatrixChangedEvent m_viewMatrixChangedEvent;
MatrixChangedEvent::Handler m_onViewMatrixChangedHandler;
MatrixChangedEvent m_projectionMatrixChangedEvent;
@@ -157,6 +193,9 @@ namespace AZ
ViewChangedEvent m_defaultViewChangedEvent;
ViewportIdEvent m_aboutToBeDestroyedEvent;
AZ::Event<>::Handler m_prepareFrameHandler;
AZ::Event<>::Handler m_endFrameHandler;
ViewportContextManager* m_manager;
RenderPipelinePtr m_currentPipeline;
Name m_name;
@@ -110,11 +110,13 @@ namespace AZ
virtual void OnViewportSizeChanged(AzFramework::WindowSize size){AZ_UNUSED(size);}
//! Called when the window DPI scaling changes for a given viewport context.
virtual void OnViewportDpiScalingChanged(float dpiScale){AZ_UNUSED(dpiScale);}
//! Called when the active view for a given viewport context name changes.
//! Called when the active view changes for a given viewport context.
virtual void OnViewportDefaultViewChanged(AZ::RPI::ViewPtr view){AZ_UNUSED(view);}
//! Called when the viewport is to be rendered.
//! Add draws to this functions if they only need to be rendered to this viewport.
virtual void OnRenderTick(){};
//! Add draws to this function if they only need to be rendered to this viewport.
virtual void OnRenderTick(){}
//! Called when the viewport finishes rendering a frame.
virtual void OnFrameEnd(){}
protected:
~ViewportContextNotifications() = default;
@@ -152,7 +152,7 @@ namespace AZ
AZStd::string fullSourcePath;
AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), fullSourcePath, true);
auto loadOutcome = JsonSerializationUtils::ReadJsonFile(fullSourcePath, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto loadOutcome = JsonSerializationUtils::ReadJsonFile(fullSourcePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!loadOutcome.IsSuccess())
{
AZ_Error(MaterialBuilderName, false, "%s", loadOutcome.GetError().c_str());
@@ -299,7 +299,7 @@ namespace AZ
AZStd::string fullSourcePath;
AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.data(), request.m_sourceFile.data(), fullSourcePath, true);
auto loadOutcome = JsonSerializationUtils::ReadJsonFile(fullSourcePath, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto loadOutcome = JsonSerializationUtils::ReadJsonFile(fullSourcePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!loadOutcome.IsSuccess())
{
AZ_Error(MaterialBuilderName, false, "Failed to load material file: %s", loadOutcome.GetError().c_str());
@@ -68,7 +68,7 @@ namespace AZ
{
AZStd::string materialTypePath = AssetUtils::ResolvePathReference(jsonFileLoadContext->GetFilePath(), materialSourceData->m_materialType);
auto materialTypeJson = JsonSerializationUtils::ReadJsonFile(materialTypePath, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto materialTypeJson = JsonSerializationUtils::ReadJsonFile(materialTypePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!materialTypeJson.IsSuccess())
{
AZStd::string failureMessage;
@@ -65,7 +65,7 @@ namespace AZ
AZ::Outcome<rapidjson::Document, AZStd::string> loadOutcome;
if (document == nullptr)
{
loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(filePath, AZ::RPI::JsonUtils::AtomMaxFileSize);
loadOutcome = AZ::JsonSerializationUtils::ReadJsonFile(filePath, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!loadOutcome.IsSuccess())
{
AZ_Error("AZ::RPI::JsonUtils", false, "%s", loadOutcome.GetError().c_str());
@@ -14,6 +14,9 @@
#include <RPI.Private/RPISystemComponent.h>
#include <Atom/RHI/Factory.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <AzCore/Asset/AssetManager.h>
#include <AzCore/IO/IOUtils.h>
@@ -93,20 +96,29 @@ namespace AZ
}
m_rpiSystem.Initialize(m_rpiDescriptor);
AZ::SystemTickBus::Handler::BusConnect();
AZ::TickBus::Handler::BusConnect();
}
void RPISystemComponent::Deactivate()
{
AZ::SystemTickBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
m_rpiSystem.Shutdown();
}
void RPISystemComponent::OnSystemTick()
void RPISystemComponent::OnTick([[maybe_unused]]float deltaTime, [[maybe_unused]]ScriptTimePoint time)
{
if (deltaTime == 0.f)
{
return;
}
m_rpiSystem.SimulationTick();
m_rpiSystem.RenderTick();
}
int RPISystemComponent::GetTickOrder()
{
return AZ::ComponentTickBus::TICK_RENDER;
}
} // namespace RPI
} // namespace AZ
@@ -32,7 +32,7 @@ namespace AZ
*/
class RPISystemComponent final
: public AZ::Component
, public AZ::SystemTickBus::Handler
, private AZ::TickBus::Handler
{
public:
AZ_COMPONENT(RPISystemComponent, "{83E301F3-7A0C-4099-B530-9342B91B1BC0}");
@@ -50,8 +50,9 @@ namespace AZ
private:
RPISystemComponent(const RPISystemComponent&) = delete;
// SystemTickBus overrides...
void OnSystemTick() override;
// TickBus overrides...
void OnTick(float deltaTime, ScriptTimePoint time) override;
int GetTickOrder() override;
RPISystem m_rpiSystem;
@@ -93,8 +93,11 @@ namespace AZ
void Pass::SetEnabled(bool enabled)
{
m_flags.m_enabled = enabled;
OnHierarchyChange();
if (m_flags.m_enabled != enabled)
{
m_flags.m_enabled = enabled;
OnHierarchyChange();
}
}
bool Pass::IsEnabled() const
@@ -301,6 +301,26 @@ namespace AZ
m_drawFilterMask = 0;
}
void RenderPipeline::OnPrepareFrame()
{
m_lastRenderRequestTime = AZStd::chrono::system_clock::now();
// If we're attempting to render at a target interval, check to see if we're within
// 1ms of that interval, enabling rendering only if we are.
if (m_renderMode == RenderMode::RenderAtTargetRate)
{
constexpr AZStd::chrono::duration<float> updateThresholdMs(0.001f);
const bool shouldRender =
m_lastRenderRequestTime - m_lastRenderStartTime + updateThresholdMs >= m_targetRefreshRate;
m_rootPass->SetEnabled(shouldRender);
}
if (NeedsRender())
{
m_prepareFrameEvent.Signal();
}
}
void RenderPipeline::OnPassModified()
{
if (m_needsPassRecreate)
@@ -375,11 +395,11 @@ namespace AZ
m_scene->RemoveRenderPipeline(m_nameId);
}
void RenderPipeline::OnStartFrame(const TickTimeInfo& tick)
void RenderPipeline::OnStartFrame()
{
AZ_PROFILE_FUNCTION(RPI);
m_lastRenderStartTime = tick.m_currentGameTime;
m_lastRenderStartTime = m_lastRenderRequestTime;
OnPassModified();
@@ -407,6 +427,7 @@ namespace AZ
{
RemoveFromRenderTick();
}
m_endFrameEvent.Signal();
}
void RenderPipeline::CollectPersistentViews(AZStd::map<ViewPtr, RHI::DrawListMask>& outViewMasks) const
@@ -489,6 +510,13 @@ namespace AZ
m_renderMode = RenderMode::RenderEveryTick;
}
void RenderPipeline::AddToRenderTickAtInterval(AZStd::chrono::duration<float> renderInterval)
{
m_rootPass->SetEnabled(false);
m_renderMode = RenderMode::RenderAtTargetRate;
m_targetRefreshRate = renderInterval;
}
void RenderPipeline::RemoveFromRenderTick()
{
m_renderMode = RenderMode::NoRender;
@@ -502,7 +530,7 @@ namespace AZ
bool RenderPipeline::NeedsRender() const
{
return m_renderMode != RenderMode::NoRender;
return m_rootPass->IsEnabled();
}
RHI::DrawFilterTag RenderPipeline::GetDrawFilterTag() const
@@ -515,6 +543,16 @@ namespace AZ
return m_drawFilterMask;
}
void RenderPipeline::ConnectPrepareFrameHandler(FrameNotificationEvent::Handler& handler)
{
handler.Connect(m_prepareFrameEvent);
}
void RenderPipeline::ConnectEndFrameHandler(FrameNotificationEvent::Handler& handler)
{
handler.Connect(m_endFrameEvent);
}
void RenderPipeline::SetDrawFilterTag(RHI::DrawFilterTag tag)
{
m_drawFilterTag = tag;
+17 -4
View File
@@ -420,7 +420,7 @@ namespace AZ
}
}
void Scene::PrepareRender(const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
void Scene::PrepareRender([[maybe_unused]]const TickTimeInfo& tickInfo, RHI::JobPolicy jobPolicy)
{
AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: PrepareRender");
@@ -432,20 +432,27 @@ namespace AZ
SceneNotificationBus::Event(GetId(), &SceneNotification::OnBeginPrepareRender);
// Get active pipelines which need to be rendered and notify them frame started
// Get active pipelines which need to be rendered and notify them of an impending frame.
AZStd::vector<RenderPipelinePtr> activePipelines;
{
AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene: OnStartFrame");
AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene: OnPrepareFrame");
for (auto& pipeline : m_pipelines)
{
pipeline->OnPrepareFrame();
if (pipeline->NeedsRender())
{
activePipelines.push_back(pipeline);
pipeline->OnStartFrame(tickInfo);
}
}
}
// Get active pipelines which need to be rendered and notify them frame started
for (const auto& pipeline : activePipelines)
{
AZ_ATOM_PROFILE_TIME_GROUP_REGION("RPI", "Scene: OnStartFrame");
pipeline->OnStartFrame();
}
// Return if there is no active render pipeline
if (activePipelines.empty())
{
@@ -587,10 +594,12 @@ namespace AZ
void Scene::OnFrameEnd()
{
AZ_ATOM_PROFILE_FUNCTION("RPI", "Scene: OnFrameEnd");
bool didRender = false;
for (auto& pipeline : m_pipelines)
{
if (pipeline->NeedsRender())
{
didRender = true;
pipeline->OnFrameEnd();
}
}
@@ -598,6 +607,10 @@ namespace AZ
{
fp->OnRenderEnd();
}
if (didRender)
{
SceneNotificationBus::Event(GetId(), &SceneNotification::OnFrameEnd);
}
}
void Scene::UpdateSrgs()
@@ -241,7 +241,10 @@ namespace AZ
{
AZ_PROFILE_FUNCTION(RPI);
m_drawListContext.FinalizeLists();
SortFinalizedDrawLists();
if (m_passesByDrawList)
{
SortFinalizedDrawLists();
}
}
void View::SortFinalizedDrawLists()
@@ -25,14 +25,13 @@ namespace AZ
, m_viewportSize(1, 1)
{
m_windowContext->Initialize(device, nativeWindow);
AzFramework::WindowRequestBus::EventResult(
m_viewportSize,
nativeWindow,
&AzFramework::WindowRequestBus::Events::GetClientAreaSize);
AzFramework::WindowRequestBus::EventResult(
m_viewportDpiScaleFactor,
nativeWindow,
&AzFramework::WindowRequestBus::Events::GetDpiScaleFactor);
AzFramework::WindowRequestBus::Event(nativeWindow, [this](AzFramework::WindowRequestBus::Events* window)
{
m_viewportSize = window->GetClientAreaSize();
m_viewportDpiScaleFactor = window->GetDpiScaleFactor();
m_vsyncInterval = window->GetSyncInterval();
m_refreshRate = window->GetDisplayRefreshRate();
});
AzFramework::WindowNotificationBus::Handler::BusConnect(nativeWindow);
AzFramework::ViewportRequestBus::Handler::BusConnect(id);
@@ -46,6 +45,20 @@ namespace AZ
m_viewMatrixChangedEvent.Signal(matrix);
});
m_prepareFrameHandler = RenderPipeline::FrameNotificationEvent::Handler(
[this]()
{
ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick);
ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick);
});
m_endFrameHandler = RenderPipeline::FrameNotificationEvent::Handler(
[this]()
{
ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnFrameEnd);
ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnFrameEnd);
});
SetRenderScene(renderScene);
}
@@ -111,26 +124,38 @@ namespace AZ
{
SceneNotificationBus::Handler::BusConnect(m_rootScene->GetId());
}
m_currentPipeline.reset();
ResetCurrentPipeline();
UpdatePipelineView();
UpdatePipelineRefreshRate();
}
m_sceneChangedEvent.Signal(scene);
}
void ViewportContext::RenderTick()
float ViewportContext::GetFpsLimit() const
{
// add the current pipeline to next render tick if it's not already added.
if (m_currentPipeline && m_currentPipeline->GetRenderMode() != RenderPipeline::RenderMode::RenderOnce)
{
m_currentPipeline->AddToRenderTickOnce();
}
return m_fpsLimit;
}
void ViewportContext::OnBeginPrepareRender()
void ViewportContext::SetFpsLimit(float fpsLimit)
{
ViewportContextNotificationBus::Event(GetName(), &ViewportContextNotificationBus::Events::OnRenderTick);
ViewportContextIdNotificationBus::Event(GetId(), &ViewportContextIdNotificationBus::Events::OnRenderTick);
m_fpsLimit = fpsLimit;
UpdatePipelineRefreshRate();
}
float ViewportContext::GetTargetFrameRate() const
{
float targetFrameRate = GetFpsLimit();
const AZ::u32 vsyncInterval = GetVsyncInterval();
if (vsyncInterval != 0)
{
const float vsyncFrameRate = static_cast<float>(GetRefreshRate()) / static_cast<float>(vsyncInterval);
if (targetFrameRate == 0.f || vsyncFrameRate < targetFrameRate)
{
targetFrameRate = vsyncFrameRate;
}
}
return targetFrameRate;
}
AZ::Name ViewportContext::GetName() const
@@ -158,6 +183,16 @@ namespace AZ
return m_viewportDpiScaleFactor;
}
uint32_t ViewportContext::GetVsyncInterval() const
{
return m_vsyncInterval;
}
uint32_t ViewportContext::GetRefreshRate() const
{
return m_refreshRate;
}
void ViewportContext::ConnectSizeChangedHandler(SizeChangedEvent::Handler& handler)
{
handler.Connect(m_sizeChangedEvent);
@@ -168,6 +203,16 @@ namespace AZ
handler.Connect(m_dpiScalingFactorChangedEvent);
}
void ViewportContext::ConnectVsyncIntervalChangedHandler(UintChangedEvent::Handler& handler)
{
handler.Connect(m_vsyncIntervalChangedEvent);
}
void ViewportContext::ConnectRefreshRateChangedHandler(UintChangedEvent::Handler& handler)
{
handler.Connect(m_refreshRateChangedEvent);
}
void ViewportContext::ConnectViewMatrixChangedHandler(MatrixChangedEvent::Handler& handler)
{
handler.Connect(m_viewMatrixChangedEvent);
@@ -263,12 +308,43 @@ namespace AZ
m_currentPipelineChangedEvent.Signal(m_currentPipeline);
}
if (auto pipeline = GetCurrentPipeline())
if (m_currentPipeline)
{
pipeline->SetDefaultView(m_defaultView);
if (!m_prepareFrameHandler.IsConnected())
{
m_currentPipeline->ConnectPrepareFrameHandler(m_prepareFrameHandler);
m_currentPipeline->ConnectEndFrameHandler(m_endFrameHandler);
}
m_currentPipeline->SetDefaultView(m_defaultView);
}
}
void ViewportContext::UpdatePipelineRefreshRate()
{
if (!m_currentPipeline)
{
return;
}
const float refreshRate = GetTargetFrameRate();
// If we have a truly unlimited framerate, just render every tick
if (refreshRate == 0.f)
{
m_currentPipeline->AddToRenderTick();
}
else
{
m_currentPipeline->AddToRenderTickAtInterval(AZStd::chrono::duration<float>(1.f / refreshRate));
}
}
void ViewportContext::ResetCurrentPipeline()
{
m_prepareFrameHandler.Disconnect();
m_endFrameHandler.Disconnect();
m_currentPipeline.reset();
}
RenderPipelinePtr ViewportContext::GetCurrentPipeline()
{
return m_currentPipeline;
@@ -281,8 +357,9 @@ namespace AZ
// in the event prioritization is added later
if (pipeline->GetWindowHandle() == m_windowContext->GetWindowHandle())
{
m_currentPipeline.reset();
ResetCurrentPipeline();
UpdatePipelineView();
UpdatePipelineRefreshRate();
}
}
@@ -290,8 +367,9 @@ namespace AZ
{
if (m_currentPipeline.get() == pipeline)
{
m_currentPipeline.reset();
ResetCurrentPipeline();
UpdatePipelineView();
UpdatePipelineRefreshRate();
}
}
@@ -305,10 +383,30 @@ namespace AZ
}
}
void ViewportContext::OnRefreshRateChanged(uint32_t refreshRate)
{
if (m_refreshRate != refreshRate)
{
m_refreshRate = refreshRate;
m_refreshRateChangedEvent.Signal(m_refreshRate);
UpdatePipelineRefreshRate();
}
}
void ViewportContext::OnDpiScaleFactorChanged(float dpiScaleFactor)
{
m_viewportDpiScaleFactor = dpiScaleFactor;
m_dpiScalingFactorChangedEvent.Signal(dpiScaleFactor);
}
void ViewportContext::OnVsyncIntervalChanged(uint32_t interval)
{
if (m_vsyncInterval != interval)
{
m_vsyncInterval = interval;
m_vsyncIntervalChangedEvent.Signal(m_vsyncInterval);
UpdatePipelineRefreshRate();
}
}
} // namespace RPI
} // namespace AZ
@@ -10,6 +10,7 @@
#include <QWidget>
#include <QElapsedTimer>
#include <QPointer>
#include <Atom/RPI.Public/Base.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/Input/QtEventToAzInputManager.h>
@@ -21,6 +22,8 @@
#include <AzFramework/Windowing/WindowBus.h>
#include <AzCore/Component/TickBus.h>
#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
#include <AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h>
namespace AtomToolsFramework
{
@@ -35,6 +38,8 @@ namespace AtomToolsFramework
, public AzFramework::WindowRequestBus::Handler
, protected AzFramework::InputChannelEventListener
, protected AZ::TickBus::Handler
, protected AZ::Render::Bootstrap::NotificationBus::Handler
, protected AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler
{
public:
//! Creates a RenderViewportWidget.
@@ -121,6 +126,7 @@ namespace AtomToolsFramework
// AZ::TickBus::Handler ...
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
int GetTickOrder() override;
// QWidget ...
void resizeEvent(QResizeEvent *event) override;
@@ -128,9 +134,21 @@ namespace AtomToolsFramework
void enterEvent(QEvent* event) override;
void leaveEvent(QEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override;
void focusInEvent(QFocusEvent* event) override;
// AZ::Render::Bootstrap::NotificationBus::Handler ...
void OnFrameRateLimitChanged(float fpsLimit) override;
// AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler ...
void OnInactiveViewportFrameRateChanged(float fpsLimit) override;
private:
AzFramework::NativeWindowHandle GetNativeWindowHandle() const;
void UpdateFrameRate();
void SetScreen(QScreen* screen);
void SendWindowResizeEvent();
void NotifyUpdateRefreshRate();
// The underlying ViewportContext, our entry-point to the Atom RPI.
AZ::RPI::ViewportContextPtr m_viewportContext;
@@ -153,5 +171,11 @@ namespace AtomToolsFramework
AZ::ScriptTimePoint m_time;
// Maps our internal Qt events into AzFramework InputChannels for our ViewportControllerList.
AzToolsFramework::QtEventToAzInputMapper* m_inputChannelMapper = nullptr;
// Stores our current screen, used for tracking the current refresh rate.
QScreen* m_screen = nullptr;
// Stores the last RenderViewportWidget that has received user focus.
// This is used for optional framerate throtting for "inactive" viewports via the
// ed_inactive_viewport_fps_limit CVAR.
AZ::EnvironmentVariable<RenderViewportWidget*> m_lastFocusedViewport;
};
} //namespace AtomToolsFramework
@@ -0,0 +1,35 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
namespace AtomToolsFramework
{
//! Provides an interface for providing notifications specific to RenderViewportWidget.
//! @note Most behaviors in RenderViewportWidget are handled by its underyling
//! ViewportContext, this bus is specifically for functionality exclusive to the
//! Qt layer provided by RenderViewportWidget.
class RenderViewportWidgetNotifications : public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
//! Triggered when the idle frame rate limit for inactive viewports changed.
//! Controlled by the ed_inactive_viewport_fps_limit CVAR.
//! Active viewports are controlled by the r_fps_limit CVAR.
virtual void OnInactiveViewportFrameRateChanged([[maybe_unused]]float fpsLimit){}
protected:
~RenderViewportWidgetNotifications() = default;
};
using RenderViewportWidgetNotificationBus = AZ::EBus<RenderViewportWidgetNotifications>;
} // namespace AtomToolsFramework
@@ -6,23 +6,42 @@
*
*/
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
#include <Atom/Bootstrap/BootstrapRequestBus.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/View.h>
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
#include <AzCore/Console/Console.h>
#include <AzCore/Math/MathUtils.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Viewport/ViewportControllerList.h>
#include <AzFramework/Viewport/ViewportScreen.h>
#include <AzToolsFramework/Viewport/ViewportTypes.h>
#include <AzCore/Math/MathUtils.h>
#include <Atom/RHI/RHISystemInterface.h>
#include <Atom/Bootstrap/BootstrapRequestBus.h>
#include <QApplication>
#include <QCursor>
#include <QBoxLayout>
#include <QWindow>
#include <QCursor>
#include <QMouseEvent>
#include <QScreen>
#include <QTimer>
#include <QWindow>
static void OnInactiveViewportFrameRateChanged(const float& fpsLimit)
{
AtomToolsFramework::RenderViewportWidgetNotificationBus::Broadcast(
&AtomToolsFramework::RenderViewportWidgetNotificationBus::Events::OnInactiveViewportFrameRateChanged, fpsLimit);
}
AZ_CVAR(
float,
ed_inactive_viewport_fps_limit,
0,
OnInactiveViewportFrameRateChanged,
AZ::ConsoleFunctorFlags::Null,
"The maximum framerate to render viewports that don't have focus at");
static constexpr const char* LastFocusedViewportVariableName = "AtomToolsFramework::RenderViewportWidget::LastFocusedViewport";
namespace AtomToolsFramework
{
@@ -30,6 +49,12 @@ namespace AtomToolsFramework
: QWidget(parent)
, AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDefault())
{
m_lastFocusedViewport = AZ::Environment::FindVariable<RenderViewportWidget*>(LastFocusedViewportVariableName);
if (!m_lastFocusedViewport)
{
m_lastFocusedViewport = AZ::Environment::CreateVariable<RenderViewportWidget*>(LastFocusedViewportVariableName, nullptr);
}
if (shouldInitializeViewportContext)
{
InitializeViewportContext();
@@ -38,13 +63,24 @@ namespace AtomToolsFramework
setUpdatesEnabled(false);
setFocusPolicy(Qt::FocusPolicy::WheelFocus);
setMouseTracking(true);
// Wait a frame for our window handle to be constructed, then wire up our screen change signals.
QTimer::singleShot(
0,
[this]()
{
QObject::connect(windowHandle(), &QWindow::screenChanged, this, &RenderViewportWidget::SetScreen);
});
SetScreen(screen());
}
bool RenderViewportWidget::InitializeViewportContext(AzFramework::ViewportId id)
{
if (m_viewportContext != nullptr)
{
AZ_Assert(id == AzFramework::InvalidViewportId || m_viewportContext->GetId() == id, "Attempted to reinitialize RenderViewportWidget with a different ID");
AZ_Assert(
id == AzFramework::InvalidViewportId || m_viewportContext->GetId() == id,
"Attempted to reinitialize RenderViewportWidget with a different ID");
return true;
}
@@ -59,7 +95,7 @@ namespace AtomToolsFramework
// Before we do anything else, we must create a ViewportContext which will give us a ViewportId if we didn't manually specify one.
AZ::RPI::ViewportContextRequestsInterface::CreationParameters params;
params.device = AZ::RHI::RHISystemInterface::Get()->GetDevice();
params.windowHandle = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
params.windowHandle = GetNativeWindowHandle();
params.id = id;
AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle);
m_viewportContext = viewportContextManager->CreateViewportContext(AZ::Name(), params);
@@ -80,29 +116,46 @@ namespace AtomToolsFramework
AzFramework::InputChannelEventListener::Connect();
AZ::TickBus::Handler::BusConnect();
AzFramework::WindowRequestBus::Handler::BusConnect(params.windowHandle);
AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
AtomToolsFramework::RenderViewportWidgetNotificationBus::Handler::BusConnect();
m_inputChannelMapper = new AzToolsFramework::QtEventToAzInputMapper(this, id);
// Forward input events to our controller list.
QObject::connect(m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this,
QObject::connect(
m_inputChannelMapper, &AzToolsFramework::QtEventToAzInputMapper::InputChannelUpdated, this,
[this](const AzFramework::InputChannel* inputChannel, QEvent* event)
{
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
if (m_controllerList->HandleInputChannelEvent(AzFramework::ViewportControllerInputEvent{GetId(), windowId, *inputChannel}))
{
// If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate.
if (event)
const AzFramework::NativeWindowHandle windowId = GetNativeWindowHandle();
if (m_controllerList->HandleInputChannelEvent(
AzFramework::ViewportControllerInputEvent{ GetId(), windowId, *inputChannel }))
{
event->setAccepted(true);
// If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate.
if (event)
{
event->setAccepted(true);
}
}
}
});
});
// Update our target frame rate. If we're the only viewport, become active.
if (m_lastFocusedViewport.Get() == nullptr)
{
m_lastFocusedViewport.Set(this);
}
UpdateFrameRate();
return true;
}
RenderViewportWidget::~RenderViewportWidget()
{
if (m_lastFocusedViewport.Get() == this)
{
m_lastFocusedViewport.Set(nullptr);
}
AzFramework::WindowRequestBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
AzFramework::InputChannelEventListener::Disconnect();
@@ -181,17 +234,22 @@ namespace AtomToolsFramework
bool shouldConsumeEvent = true;
AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
const bool eventHandled = m_controllerList->HandleInputChannelEvent({GetId(), windowId, inputChannel});
const bool eventHandled = m_controllerList->HandleInputChannelEvent({ GetId(), GetNativeWindowHandle(), inputChannel });
// If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might need), consume it.
// If our controllers handled the event and it's one we can safely consume (i.e. it's not an Ended event that other viewports might
// need), consume it.
return eventHandled && shouldConsumeEvent;
}
void RenderViewportWidget::OnTick([[maybe_unused]]float deltaTime, AZ::ScriptTimePoint time)
void RenderViewportWidget::OnTick([[maybe_unused]] float deltaTime, AZ::ScriptTimePoint time)
{
m_time = time;
m_controllerList->UpdateViewport({GetId(), AzFramework::FloatSeconds(deltaTime), m_time});
m_controllerList->UpdateViewport({ GetId(), AzFramework::FloatSeconds(deltaTime), m_time });
}
int RenderViewportWidget::GetTickOrder()
{
return AZ::ComponentTickBus::TICK_PRE_RENDER;
}
void RenderViewportWidget::resizeEvent([[maybe_unused]] QResizeEvent* event)
@@ -236,6 +294,75 @@ namespace AtomToolsFramework
m_mousePosition = event->localPos();
}
void RenderViewportWidget::focusInEvent([[maybe_unused]] QFocusEvent* event)
{
RenderViewportWidget* lastFocusedViewport = m_lastFocusedViewport.Get();
if (lastFocusedViewport == this)
{
return;
}
RenderViewportWidget* previousFocusWidget = lastFocusedViewport;
m_lastFocusedViewport.Set(this);
// Ensure this viewport and whatever viewport last had focus (if any) respect
// the active / inactive viewport frame rate settings.
UpdateFrameRate();
if (previousFocusWidget != nullptr)
{
previousFocusWidget->UpdateFrameRate();
}
}
void RenderViewportWidget::OnFrameRateLimitChanged([[maybe_unused]] float fpsLimit)
{
UpdateFrameRate();
}
void RenderViewportWidget::OnInactiveViewportFrameRateChanged([[maybe_unused]] float fpsLimit)
{
UpdateFrameRate();
}
AzFramework::NativeWindowHandle RenderViewportWidget::GetNativeWindowHandle() const
{
return reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
}
void RenderViewportWidget::UpdateFrameRate()
{
if (ed_inactive_viewport_fps_limit > 0.f && m_lastFocusedViewport.Get() != this)
{
m_viewportContext->SetFpsLimit(ed_inactive_viewport_fps_limit);
}
else
{
float fpsLimit = 0.f;
AZ::Render::Bootstrap::RequestBus::BroadcastResult(fpsLimit, &AZ::Render::Bootstrap::RequestBus::Events::GetFrameRateLimit);
m_viewportContext->SetFpsLimit(fpsLimit);
}
}
void RenderViewportWidget::SetScreen(QScreen* screen)
{
if (m_screen != screen)
{
if (m_screen)
{
QObject::disconnect(m_screen, &QScreen::refreshRateChanged, this, &RenderViewportWidget::NotifyUpdateRefreshRate);
}
if (screen)
{
QObject::connect(m_screen, &QScreen::refreshRateChanged, this, &RenderViewportWidget::NotifyUpdateRefreshRate);
}
NotifyUpdateRefreshRate();
m_screen = screen;
}
}
void RenderViewportWidget::SendWindowResizeEvent()
{
// Scale the size by the DPI of the platform to
@@ -243,11 +370,17 @@ namespace AtomToolsFramework
const QSize uiWindowSize = size();
const QSize windowSize = uiWindowSize * devicePixelRatioF();
const AzFramework::NativeWindowHandle windowId = reinterpret_cast<AzFramework::NativeWindowHandle>(winId());
AzFramework::WindowNotificationBus::Event(windowId, &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height());
AzFramework::WindowNotificationBus::Event(
GetNativeWindowHandle(), &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height());
m_windowResizedEvent = false;
}
void RenderViewportWidget::NotifyUpdateRefreshRate()
{
AzFramework::WindowNotificationBus::Event(
GetNativeWindowHandle(), &AzFramework::WindowNotificationBus::Events::OnRefreshRateChanged, GetDisplayRefreshRate());
}
AZ::Name RenderViewportWidget::GetCurrentContextName() const
{
return m_viewportContext->GetName();
@@ -303,9 +436,7 @@ namespace AtomToolsFramework
// Build camera state from Atom camera transforms
AzFramework::CameraState cameraState = AzFramework::CreateCameraFromWorldFromViewMatrix(
currentView->GetViewToWorldMatrix(),
AZ::Vector2{aznumeric_cast<float>(width()), aznumeric_cast<float>(height())}
);
currentView->GetViewToWorldMatrix(), AZ::Vector2{ aznumeric_cast<float>(width()), aznumeric_cast<float>(height()) });
AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, currentView->GetViewToClipMatrix());
// Convert from Z-up
@@ -317,8 +448,7 @@ namespace AtomToolsFramework
AzFramework::ScreenPoint RenderViewportWidget::ViewportWorldToScreen(const AZ::Vector3& worldPosition)
{
if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView();
currentView == nullptr)
if (AZ::RPI::ViewPtr currentView = m_viewportContext->GetDefaultView(); currentView == nullptr)
{
return AzFramework::ScreenPoint(0, 0);
}
@@ -331,12 +461,10 @@ namespace AtomToolsFramework
const auto& cameraProjection = m_viewportContext->GetCameraProjectionMatrix();
const auto& cameraView = m_viewportContext->GetCameraViewMatrix();
const AZ::Vector4 normalizedScreenPosition {
screenPosition.m_x * 2.f / width() - 1.0f,
(height() - screenPosition.m_y) * 2.f / height() - 1.0f,
1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
1.f
};
const AZ::Vector4 normalizedScreenPosition{ screenPosition.m_x * 2.f / width() - 1.0f,
(height() - screenPosition.m_y) * 2.f / height() - 1.0f,
1.f - depth, // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
1.f };
AZ::Matrix4x4 worldFromScreen = cameraProjection * cameraView;
worldFromScreen.InvertFull();
@@ -365,7 +493,7 @@ namespace AtomToolsFramework
AZ::Vector3 rayDirection = pos1.value() - pos0.value();
rayDirection.Normalize();
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{rayOrigin, rayDirection};
return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{ rayOrigin, rayDirection };
}
float RenderViewportWidget::DeviceScalingFactor()
@@ -395,12 +523,12 @@ namespace AtomToolsFramework
AzFramework::WindowSize RenderViewportWidget::GetClientAreaSize() const
{
return AzFramework::WindowSize{aznumeric_cast<uint32_t>(width()), aznumeric_cast<uint32_t>(height())};
return AzFramework::WindowSize{ aznumeric_cast<uint32_t>(width()), aznumeric_cast<uint32_t>(height()) };
}
void RenderViewportWidget::ResizeClientArea(AzFramework::WindowSize clientAreaSize)
{
const QSize targetSize = QSize{aznumeric_cast<int>(clientAreaSize.m_width), aznumeric_cast<int>(clientAreaSize.m_height)};
const QSize targetSize = QSize{ aznumeric_cast<int>(clientAreaSize.m_width), aznumeric_cast<int>(clientAreaSize.m_height) };
resize(targetSize);
}
@@ -410,7 +538,7 @@ namespace AtomToolsFramework
return false;
}
void RenderViewportWidget::SetFullScreenState([[maybe_unused]]bool fullScreenState)
void RenderViewportWidget::SetFullScreenState([[maybe_unused]] bool fullScreenState)
{
// The RenderViewportWidget does not currently support full screen.
}
@@ -433,11 +561,20 @@ namespace AtomToolsFramework
uint32_t RenderViewportWidget::GetDisplayRefreshRate() const
{
return 60;
return static_cast<uint32_t>(screen()->refreshRate());
}
uint32_t RenderViewportWidget::GetSyncInterval() const
{
return 1;
uint32_t interval = 1;
// Get vsync_interval from AzFramework::NativeWindow, which owns it.
// NativeWindow also handles broadcasting OnVsyncIntervalChanged to all
// WindowNotificationBus listeners.
if (auto console = AZ::Interface<AZ::IConsole>::Get())
{
console->GetCvarValue<uint32_t>("vsync_interval", interval);
}
return interval;
}
} //namespace AtomToolsFramework
} // namespace AtomToolsFramework
@@ -28,6 +28,7 @@ set(FILES
Include/AtomToolsFramework/Util/MaterialPropertyUtil.h
Include/AtomToolsFramework/Util/Util.h
Include/AtomToolsFramework/Viewport/RenderViewportWidget.h
Include/AtomToolsFramework/Viewport/RenderViewportWidgetNotificationBus.h
Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h
Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h
Include/AtomToolsFramework/Window/AtomToolsMainWindow.h
@@ -115,7 +115,7 @@ namespace AZ
{
rapidjson::Document jsonDoc;
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(pathToAssetListJson, AZ::RPI::JsonUtils::AtomMaxFileSize);
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(pathToAssetListJson, AZ::RPI::JsonUtils::DefaultMaxFileSize);
if (!readJsonResult.IsSuccess())
{
@@ -183,6 +183,15 @@ namespace AZ::Render
DrawFramerate();
}
void AtomViewportDisplayInfoSystemComponent::OnFrameEnd()
{
auto currentTime = AZStd::chrono::system_clock::now();
if (!m_fpsHistory.empty())
{
m_fpsHistory.back().m_endFrameTime = currentTime;
}
}
AtomBridge::ViewportInfoDisplayState AtomViewportDisplayInfoSystemComponent::GetDisplayState() const
{
return aznumeric_cast<AtomBridge::ViewportInfoDisplayState>(r_displayInfo.operator int());
@@ -248,11 +257,11 @@ namespace AZ::Render
void AtomViewportDisplayInfoSystemComponent::UpdateFramerate()
{
auto currentTime = AZStd::chrono::system_clock::now();
while (!m_fpsHistory.empty() && (currentTime - m_fpsHistory.front()) > m_fpsInterval)
while (!m_fpsHistory.empty() && (currentTime - m_fpsHistory.front().m_beginFrameTime) > m_fpsInterval)
{
m_fpsHistory.pop_front();
}
m_fpsHistory.push_back(currentTime);
m_fpsHistory.push_back(FrameTimingInfo(currentTime));
}
void AtomViewportDisplayInfoSystemComponent::DrawFramerate()
@@ -261,25 +270,31 @@ namespace AZ::Render
double minFPS = DBL_MAX;
double maxFPS = 0;
AZStd::chrono::duration<double> deltaTime;
AZStd::chrono::milliseconds totalFrameMS(0);
for (const auto& time : m_fpsHistory)
{
if (lastTime.has_value())
{
deltaTime = time - lastTime.value();
deltaTime = time.m_beginFrameTime - lastTime.value();
double fps = AZStd::chrono::seconds(1) / deltaTime;
minFPS = AZStd::min(minFPS, fps);
maxFPS = AZStd::max(maxFPS, fps);
}
lastTime = time;
lastTime = time.m_beginFrameTime;
if (time.m_endFrameTime.has_value())
{
totalFrameMS += time.m_endFrameTime.value() - time.m_beginFrameTime;
}
}
double averageFPS = 0;
double averageFrameMs = 0;
if (m_fpsHistory.size() > 1)
{
deltaTime = m_fpsHistory.back() - m_fpsHistory.front();
averageFPS = AZStd::chrono::seconds(m_fpsHistory.size()) / deltaTime;
averageFrameMs = 1000.0f/averageFPS;
deltaTime = m_fpsHistory.back().m_beginFrameTime - m_fpsHistory.front().m_beginFrameTime;
averageFPS = AZStd::chrono::seconds(m_fpsHistory.size() - 1) / deltaTime;
averageFrameMs = aznumeric_cast<double>(totalFrameMS.count()) / (m_fpsHistory.size() - 1);
}
const double frameIntervalSeconds = m_fpsInterval.count();
@@ -288,7 +303,7 @@ namespace AZ::Render
AZStd::string::format(
"FPS %.1f [%.0f..%.0f], %.1fms/frame, avg over %.1fs",
averageFPS,
minFPS,
minFPS == DBL_MAX ? 0.0 : minFPS,
maxFPS,
averageFrameMs,
frameIntervalSeconds),
@@ -45,6 +45,7 @@ namespace AZ
// AZ::RPI::ViewportContextNotificationBus::Handler overrides...
void OnRenderTick() override;
void OnFrameEnd() override;
// AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler overrides...
AtomBridge::ViewportInfoDisplayState GetDisplayState() const override;
@@ -61,6 +62,8 @@ namespace AZ
void DrawPassInfo();
void DrawFramerate();
void UpdateScene(AZ::RPI::ScenePtr scene);
static constexpr float BaseFontSize = 0.7f;
AZStd::string m_rendererDescription;
@@ -68,7 +71,17 @@ namespace AZ
AzFramework::FontDrawInterface* m_fontDrawInterface = nullptr;
float m_lineSpacing;
AZStd::chrono::duration<double> m_fpsInterval = AZStd::chrono::seconds(1);
AZStd::deque<AZStd::chrono::system_clock::time_point> m_fpsHistory;
struct FrameTimingInfo
{
AZStd::chrono::system_clock::time_point m_beginFrameTime;
AZStd::optional<AZStd::chrono::system_clock::time_point> m_endFrameTime;
explicit FrameTimingInfo(AZStd::chrono::system_clock::time_point beginFrameTime)
: m_beginFrameTime(beginFrameTime)
{
}
};
AZStd::deque<FrameTimingInfo> m_fpsHistory;
AZStd::optional<AZStd::chrono::system_clock::time_point> m_lastMemoryUpdate;
bool m_updateRootPassQuery = true;
};
+2 -1
View File
@@ -46,6 +46,7 @@ namespace UnitTest
{
provided.push_back(AZ_CRC("ShapeService", 0xe86aa5fe));
provided.push_back(AZ_CRC("BoxShapeService", 0x946a0032));
provided.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService"));
}
static void GetIncompatibleServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& incompatible)
@@ -74,7 +75,7 @@ namespace UnitTest
Terrain::TerrainSystemServiceRequestBus::Handler::BusDisconnect();
}
void SetWorldBounds(const AZ::Aabb& worldBounds) override
void SetWorldBounds([[maybe_unused]] const AZ::Aabb& worldBounds) override
{
}
@@ -9,15 +9,15 @@
# shared by other platforms:
ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf)
ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023)
ly_associate_package(PACKAGE_NAME RapidXML-1.13-multiplatform TARGETS RapidXML PACKAGE_HASH 510b3c12f8872c54b34733e34f2f69dd21837feafa55bfefa445c98318d96ebf)
ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246)
ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2)
ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418)
ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665)
ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS glad PACKAGE_HASH ff97ee9664e97d0854b52a3734c2289329d9f2b4cd69478df6d0ca1f1c9392ee)
ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5)
# platform-specific:
ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-android TARGETS freetype PACKAGE_HASH 74dd75382688323c3a2a5090f473840b5d7e9d2aed1a4fcdff05ed2a09a664f2)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.14-android TARGETS tiff PACKAGE_HASH a9b30a1980946390c2fad0ed94562476a1d7ba8c1f36934ae140a89c54a8efd0)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-android TARGETS tiff PACKAGE_HASH 252b99e5886ec59fdccf38603c1399dd3fc02d878641aba35a7f8d2504065a06)
ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-android TARGETS freetype PACKAGE_HASH df9e4d559ea0f03b0666b48c79813b1cd4d9624429148a249865de9f5c2c11cd)
ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev6-android TARGETS AWSNativeSDK PACKAGE_HASH 1624ba9aaf03d001ed0ffc57d2f945ff82590e75a7ea868de35043cf673e82fb)
ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-android TARGETS Lua PACKAGE_HASH 1f638e94a17a87fe9e588ea456d5893876094b4db191234380e4c4eb9e06c300)
ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-android TARGETS PhysX PACKAGE_HASH b8cb6aa46b2a21671f6cb1f6a78713a3ba88824d0447560ff5ce6c01014b9f43)
+3 -3
View File
@@ -12,7 +12,7 @@ ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform
ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326)
ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf)
ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023)
ly_associate_package(PACKAGE_NAME RapidXML-1.13-multiplatform TARGETS RapidXML PACKAGE_HASH 510b3c12f8872c54b34733e34f2f69dd21837feafa55bfefa445c98318d96ebf)
ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246)
ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev2-multiplatform TARGETS pybind11 PACKAGE_HASH d8012f907b6c54ac990b899a0788280857e7c93a9595405a28114b48c354eb1b)
ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2)
ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418)
@@ -25,8 +25,8 @@ ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform
# platform-specific:
ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-linux TARGETS AWSGameLiftServerSDK PACKAGE_HASH a8149a95bd100384af6ade97e2b21a56173740d921e6c3da8188cd51554d39af)
ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-linux TARGETS freetype PACKAGE_HASH 9ad246873067717962c6b780d28a5ce3cef3321b73c9aea746a039c798f52e93)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-linux TARGETS tiff PACKAGE_HASH ae92b4d3b189c42ef644abc5cac865d1fb2eb7cb5622ec17e35642b00d1a0a76)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-linux TARGETS tiff PACKAGE_HASH 19791da0a370470a6c187199f97c2c46efcc2d89146e2013775fb3600fd7317d)
ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-linux TARGETS freetype PACKAGE_HASH 3f10c703d9001ecd2bb51a3bd003d3237c02d8f947ad0161c0252fdc54cbcf97)
ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev6-linux TARGETS AWSNativeSDK PACKAGE_HASH 490291e4c8057975c3ab86feb971b8a38871c58bac5e5d86abdd1aeb7141eec4)
ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-linux TARGETS Lua PACKAGE_HASH 1adc812abe3dd0dbb2ca9756f81d8f0e0ba45779ac85bf1d8455b25c531a38b0)
ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-linux TARGETS PhysX PACKAGE_HASH a110249cbef4f266b0002c4ee9a71f59f373040cefbe6b82f1e1510c811edde6)
+3 -3
View File
@@ -12,7 +12,7 @@ ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform
ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326)
ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf)
ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023)
ly_associate_package(PACKAGE_NAME RapidXML-1.13-multiplatform TARGETS RapidXML PACKAGE_HASH 510b3c12f8872c54b34733e34f2f69dd21837feafa55bfefa445c98318d96ebf)
ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246)
ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev2-multiplatform TARGETS pybind11 PACKAGE_HASH d8012f907b6c54ac990b899a0788280857e7c93a9595405a28114b48c354eb1b)
ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2)
ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418)
@@ -27,8 +27,8 @@ ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform
# platform-specific:
ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-mac TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 3f77367dbb0342136ec4ebbd44bc1fedf7198089a0f83c5631248530769b2be6)
ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-mac TARGETS SPIRVCross PACKAGE_HASH 78c6376ed2fd195b9b1f5fb2b56e5267a32c3aa21fb399e905308de470eb4515)
ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-mac-ios TARGETS freetype PACKAGE_HASH 67b4f57aed92082d3fd7c16aa244a7d908d90122c296b0a63f73e0a0b8761977)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-mac-ios TARGETS tiff PACKAGE_HASH a23ae1f8991a29f8e5df09d6d5b00d7768a740f90752cef465558c1768343709)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-mac TARGETS tiff PACKAGE_HASH b6f3040319f5bfe465d7e3f9b12ceed0dc951e66e05562beaac1c8da3b1b5d3f)
ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-mac TARGETS freetype PACKAGE_HASH f159b346ac3251fb29cb8dd5f805c99b0015ed7fdb3887f656945ca701a61d0d)
ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev5-mac TARGETS AWSNativeSDK PACKAGE_HASH ffb890bd9cf23afb429b9214ad9bac1bf04696f07a0ebb93c42058c482ab2f01)
ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev6-mac TARGETS Lua PACKAGE_HASH b9079fd35634774c9269028447562c6b712dbc83b9c64975c095fd423ff04c08)
ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-mac TARGETS PhysX PACKAGE_HASH 5e092a11d5c0a50c4dd99bb681a04b566a4f6f29aa08443d9bffc8dc12c27c8e)
@@ -12,7 +12,7 @@ ly_associate_package(PACKAGE_NAME assimp-5.0.1-rev11-multiplatform
ly_associate_package(PACKAGE_NAME ASTCEncoder-2017_11_14-rev2-multiplatform TARGETS ASTCEncoder PACKAGE_HASH c240ffc12083ee39a5ce9dc241de44d116e513e1e3e4cc1d05305e7aa3bdc326)
ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf)
ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023)
ly_associate_package(PACKAGE_NAME RapidXML-1.13-multiplatform TARGETS RapidXML PACKAGE_HASH 510b3c12f8872c54b34733e34f2f69dd21837feafa55bfefa445c98318d96ebf)
ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246)
ly_associate_package(PACKAGE_NAME pybind11-2.4.3-rev2-multiplatform TARGETS pybind11 PACKAGE_HASH d8012f907b6c54ac990b899a0788280857e7c93a9595405a28114b48c354eb1b)
ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2)
ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418)
@@ -28,8 +28,8 @@ ly_associate_package(PACKAGE_NAME PVRTexTool-4.24.0-rev4-multiplatform
ly_associate_package(PACKAGE_NAME AWSGameLiftServerSDK-3.4.1-rev1-windows TARGETS AWSGameLiftServerSDK PACKAGE_HASH a0586b006e4def65cc25f388de17dc475e417dc1e6f9d96749777c88aa8271b0)
ly_associate_package(PACKAGE_NAME DirectXShaderCompilerDxc-1.6.2104-o3de-rev3-windows TARGETS DirectXShaderCompilerDxc PACKAGE_HASH 803e10b94006b834cbbdd30f562a8ddf04174c2cb6956c8399ec164ef8418d1f)
ly_associate_package(PACKAGE_NAME SPIRVCross-2021.04.29-rev1-windows TARGETS SPIRVCross PACKAGE_HASH 7d601ea9d625b1d509d38bd132a1f433d7e895b16adab76bac6103567a7a6817)
ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-windows TARGETS freetype PACKAGE_HASH 88dedc86ccb8c92f14c2c033e51ee7d828fa08eafd6475c6aa963938a99f4bf3)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.14-windows TARGETS tiff PACKAGE_HASH ab60d1398e4e1e375ec0f1a00cdb1d812a07c0096d827db575ce52dd6d714207)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-windows TARGETS tiff PACKAGE_HASH ff03464ca460fc34a8406b2a0c548ad221b10e40480b0abb954f1e649c20bad0)
ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-windows TARGETS freetype PACKAGE_HASH 9809255f1c59b07875097aa8d8c6c21c97c47a31fb35e30f2bb93188e99a85ff)
ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev4-windows TARGETS AWSNativeSDK PACKAGE_HASH a900e80f7259e43aed5c847afee2599ada37f29db70505481397675bcbb6c76c)
ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-windows TARGETS Lua PACKAGE_HASH 136faccf1f73891e3fa3b95f908523187792e56f5b92c63c6a6d7e72d1158d40)
ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-windows TARGETS PhysX PACKAGE_HASH 0c5ffbd9fa588e5cf7643721a7cfe74d0fe448bf82252d39b3a96d06dfca2298)
+3 -3
View File
@@ -9,7 +9,7 @@
# shared by other platforms:
ly_associate_package(PACKAGE_NAME md5-2.0-multiplatform TARGETS md5 PACKAGE_HASH 29e52ad22c78051551f78a40c2709594f0378762ae03b417adca3f4b700affdf)
ly_associate_package(PACKAGE_NAME RapidJSON-1.1.0-rev1-multiplatform TARGETS RapidJSON PACKAGE_HASH 2f5e26ecf86c3b7a262753e7da69ac59928e78e9534361f3d00c1ad5879e4023)
ly_associate_package(PACKAGE_NAME RapidXML-1.13-multiplatform TARGETS RapidXML PACKAGE_HASH 510b3c12f8872c54b34733e34f2f69dd21837feafa55bfefa445c98318d96ebf)
ly_associate_package(PACKAGE_NAME RapidXML-1.13-rev1-multiplatform TARGETS RapidXML PACKAGE_HASH 4b7b5651e47cfd019b6b295cc17bb147b65e53073eaab4a0c0d20a37ab74a246)
ly_associate_package(PACKAGE_NAME cityhash-1.1-multiplatform TARGETS cityhash PACKAGE_HASH 0ace9e6f0b2438c5837510032d2d4109125845c0efd7d807f4561ec905512dd2)
ly_associate_package(PACKAGE_NAME expat-2.1.0-multiplatform TARGETS expat PACKAGE_HASH 452256acd1fd699cef24162575b3524fccfb712f5321c83f1df1ce878de5b418)
ly_associate_package(PACKAGE_NAME zstd-1.35-multiplatform TARGETS zstd PACKAGE_HASH 45d466c435f1095898578eedde85acf1fd27190e7ea99aeaa9acfd2f09e12665)
@@ -17,8 +17,8 @@ ly_associate_package(PACKAGE_NAME glad-2.0.0-beta-rev2-multiplatform TARGETS gla
ly_associate_package(PACKAGE_NAME lux_core-2.2-rev5-multiplatform TARGETS lux_core PACKAGE_HASH c8c13cf7bc351643e1abd294d0841b24dee60e51647dff13db7aec396ad1e0b5)
# platform-specific:
ly_associate_package(PACKAGE_NAME freetype-2.10.4.14-mac-ios TARGETS freetype PACKAGE_HASH 67b4f57aed92082d3fd7c16aa244a7d908d90122c296b0a63f73e0a0b8761977)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-mac-ios TARGETS tiff PACKAGE_HASH a23ae1f8991a29f8e5df09d6d5b00d7768a740f90752cef465558c1768343709)
ly_associate_package(PACKAGE_NAME tiff-4.2.0.15-rev2-ios TARGETS tiff PACKAGE_HASH d864beb0c955a55f28c2a993843afb2ecf6e01519ddfc857cedf34fc5db68d49)
ly_associate_package(PACKAGE_NAME freetype-2.10.4.16-ios TARGETS freetype PACKAGE_HASH 3ac3c35e056ae4baec2e40caa023d76a7a3320895ef172b6655e9261b0dc2e29)
ly_associate_package(PACKAGE_NAME AWSNativeSDK-1.7.167-rev3-ios TARGETS AWSNativeSDK PACKAGE_HASH 1246219a213ccfff76b526011febf521586d44dbc1753e474f8fb5fd861654a4)
ly_associate_package(PACKAGE_NAME Lua-5.3.5-rev5-ios TARGETS Lua PACKAGE_HASH c2d3c4e67046c293049292317a7d60fdb8f23effeea7136aefaef667163e5ffe)
ly_associate_package(PACKAGE_NAME PhysX-4.1.2.29882248-rev3-ios TARGETS PhysX PACKAGE_HASH b1bbc1fc068d2c6e1eb18eecd4e8b776adc516833e8da3dcb1970cef2a8f0cbd)
+11 -1
View File
@@ -14,6 +14,16 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin CACHE PATH "Build dir
# We install outside of the binary dir because our install support muliple platforms to
# be installed together. We also have an exclusion rule in the AP that filters out the
# "install" folder to avoid the AP picking it up
unset(define_with_force)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install CACHE PATH "Install directory" FORCE)
set(define_with_force FORCE)
endif()
set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install CACHE PATH "Install directory" ${define_with_force})
cmake_path(ABSOLUTE_PATH CMAKE_BINARY_DIR NORMALIZE OUTPUT_VARIABLE cmake_binary_dir_normalized)
cmake_path(ABSOLUTE_PATH CMAKE_INSTALL_PREFIX NORMALIZE OUTPUT_VARIABLE cmake_install_prefix_normalized)
cmake_path(COMPARE ${cmake_binary_dir_normalized} EQUAL ${cmake_install_prefix_normalized} are_paths_equal)
if(are_paths_equal)
message(FATAL_ERROR "Binary dir is the same path as install prefix, indicate a different install prefix with "
"CMAKE_INSTALL_PREFIX or a different binary dir with -B <binary dir>")
endif()