@ -6,42 +6,23 @@
*
*
*/
*/
# include <Atom/Bootstrap/BootstrapRequestBus.h>
# include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
# include <Atom/RHI/RHISystemInterface.h>
# include <Atom/RPI.Public/View.h>
# include <Atom/RPI.Public/ViewportContext.h>
# include <Atom/RPI.Public/ViewportContext.h>
# include <Atom/RPI.Public/ViewportContextBus.h>
# include <Atom/RPI.Public/ViewportContextBus.h>
# include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
# include <Atom/RPI.Public/View.h>
# include <AzCore/Console/Console.h>
# include <AzCore/Math/MathUtils.h>
# include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
# include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
# include <AzFramework/Viewport/ViewportControllerList.h>
# include <AzFramework/Viewport/ViewportControllerList.h>
# include <AzFramework/Viewport/ViewportScreen.h>
# include <AzFramework/Viewport/ViewportScreen.h>
# include <AzToolsFramework/Viewport/ViewportTypes.h>
# include <AzToolsFramework/Viewport/ViewportTypes.h>
# include <AzCore/Math/MathUtils.h>
# include <Atom/RHI/RHISystemInterface.h>
# include <Atom/Bootstrap/BootstrapRequestBus.h>
# include <QApplication>
# include <QApplication>
# include <QBoxLayout>
# include <QCursor>
# include <QCursor>
# include <QMouseEvent>
# include <QBoxLayout>
# include <QScreen>
# include <QTimer>
# include <QWindow>
# include <QWindow>
# include <QMouseEvent>
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
namespace AtomToolsFramework
{
{
@ -49,12 +30,6 @@ namespace AtomToolsFramework
: QWidget ( parent )
: QWidget ( parent )
, AzFramework : : InputChannelEventListener ( AzFramework : : InputChannelEventListener : : GetPriorityDefault ( ) )
, 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 )
if ( shouldInitializeViewportContext )
{
{
InitializeViewportContext ( ) ;
InitializeViewportContext ( ) ;
@ -63,24 +38,13 @@ namespace AtomToolsFramework
setUpdatesEnabled ( false ) ;
setUpdatesEnabled ( false ) ;
setFocusPolicy ( Qt : : FocusPolicy : : WheelFocus ) ;
setFocusPolicy ( Qt : : FocusPolicy : : WheelFocus ) ;
setMouseTracking ( true ) ;
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 )
bool RenderViewportWidget : : InitializeViewportContext ( AzFramework : : ViewportId id )
{
{
if ( m_viewportContext ! = nullptr )
if ( m_viewportContext ! = nullptr )
{
{
AZ_Assert (
AZ_Assert ( id = = AzFramework : : InvalidViewportId | | m_viewportContext - > GetId ( ) = = id , " Attempted to reinitialize RenderViewportWidget with a different ID " ) ;
id = = AzFramework : : InvalidViewportId | | m_viewportContext - > GetId ( ) = = id ,
" Attempted to reinitialize RenderViewportWidget with a different ID " ) ;
return true ;
return true ;
}
}
@ -95,7 +59,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.
// 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 ;
AZ : : RPI : : ViewportContextRequestsInterface : : CreationParameters params ;
params . device = AZ : : RHI : : RHISystemInterface : : Get ( ) - > GetDevice ( ) ;
params . device = AZ : : RHI : : RHISystemInterface : : Get ( ) - > GetDevice ( ) ;
params . windowHandle = GetNativeWindowHandle ( ) ;
params . windowHandle = reinterpret_cast < AzFramework : : NativeWindowHandle > ( winId ( ) ) ;
params . id = id ;
params . id = id ;
AzFramework : : WindowRequestBus : : Handler : : BusConnect ( params . windowHandle ) ;
AzFramework : : WindowRequestBus : : Handler : : BusConnect ( params . windowHandle ) ;
m_viewportContext = viewportContextManager - > CreateViewportContext ( AZ : : Name ( ) , params ) ;
m_viewportContext = viewportContextManager - > CreateViewportContext ( AZ : : Name ( ) , params ) ;
@ -116,46 +80,29 @@ namespace AtomToolsFramework
AzFramework : : InputChannelEventListener : : Connect ( ) ;
AzFramework : : InputChannelEventListener : : Connect ( ) ;
AZ : : TickBus : : Handler : : BusConnect ( ) ;
AZ : : TickBus : : Handler : : BusConnect ( ) ;
AzFramework : : WindowRequestBus : : Handler : : BusConnect ( params . windowHandle ) ;
AzFramework : : WindowRequestBus : : Handler : : BusConnect ( params . windowHandle ) ;
AZ : : Render : : Bootstrap : : NotificationBus : : Handler : : BusConnect ( ) ;
AtomToolsFramework : : RenderViewportWidgetNotificationBus : : Handler : : BusConnect ( ) ;
m_inputChannelMapper = new AzToolsFramework : : QtEventToAzInputMapper ( this , id ) ;
m_inputChannelMapper = new AzToolsFramework : : QtEventToAzInputMapper ( this , id ) ;
// Forward input events to our controller list.
// Forward input events to our controller list.
QObject : : connect (
QObject : : connect ( m_inputChannelMapper , & AzToolsFramework : : QtEventToAzInputMapper : : InputChannelUpdated , this ,
m_inputChannelMapper , & AzToolsFramework : : QtEventToAzInputMapper : : InputChannelUpdated , this ,
[ this ] ( const AzFramework : : InputChannel * inputChannel , QEvent * event )
[ this ] ( const AzFramework : : InputChannel * inputChannel , QEvent * event )
{
AzFramework : : NativeWindowHandle windowId = reinterpret_cast < AzFramework : : NativeWindowHandle > ( winId ( ) ) ;
if ( m_controllerList - > HandleInputChannelEvent ( AzFramework : : ViewportControllerInputEvent { GetId ( ) , windowId , * inputChannel } ) )
{
{
const AzFramework : : NativeWindowHandle windowId = GetNativeWindowHandle ( ) ;
// If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate.
if ( m_controllerList - > HandleInputChannelEvent (
if ( event )
AzFramework : : ViewportControllerInputEvent { GetId ( ) , windowId , * inputChannel } ) )
{
{
// If the controller handled the input event, mark the event as accepted so it doesn't continue to propagate.
event - > setAccepted ( true ) ;
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 ;
return true ;
}
}
RenderViewportWidget : : ~ RenderViewportWidget ( )
RenderViewportWidget : : ~ RenderViewportWidget ( )
{
{
if ( m_lastFocusedViewport . Get ( ) = = this )
{
m_lastFocusedViewport . Set ( nullptr ) ;
}
AzFramework : : WindowRequestBus : : Handler : : BusDisconnect ( ) ;
AzFramework : : WindowRequestBus : : Handler : : BusDisconnect ( ) ;
AZ : : TickBus : : Handler : : BusDisconnect ( ) ;
AZ : : TickBus : : Handler : : BusDisconnect ( ) ;
AzFramework : : InputChannelEventListener : : Disconnect ( ) ;
AzFramework : : InputChannelEventListener : : Disconnect ( ) ;
@ -234,22 +181,17 @@ namespace AtomToolsFramework
bool shouldConsumeEvent = true ;
bool shouldConsumeEvent = true ;
const bool eventHandled = m_controllerList - > HandleInputChannelEvent ( { GetId ( ) , GetNativeWindowHandle ( ) , inputChannel } ) ;
AzFramework : : NativeWindowHandle windowId = reinterpret_cast < AzFramework : : NativeWindowHandle > ( winId ( ) ) ;
const bool eventHandled = m_controllerList - > HandleInputChannelEvent ( { GetId ( ) , windowId , 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
// 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.
// need), consume it.
return eventHandled & & shouldConsumeEvent ;
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_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 )
void RenderViewportWidget : : resizeEvent ( [[maybe_unused]] QResizeEvent * event )
@ -277,75 +219,6 @@ namespace AtomToolsFramework
m_mousePosition = event - > localPos ( ) ;
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 ( )
void RenderViewportWidget : : SendWindowResizeEvent ( )
{
{
// Scale the size by the DPI of the platform to
// Scale the size by the DPI of the platform to
@ -353,14 +226,8 @@ namespace AtomToolsFramework
const QSize uiWindowSize = size ( ) ;
const QSize uiWindowSize = size ( ) ;
const QSize windowSize = uiWindowSize * devicePixelRatioF ( ) ;
const QSize windowSize = uiWindowSize * devicePixelRatioF ( ) ;
AzFramework : : WindowNotificationBus : : Event (
const AzFramework : : NativeWindowHandle windowId = reinterpret_cast < AzFramework : : NativeWindowHandle > ( winId ( ) ) ;
GetNativeWindowHandle ( ) , & AzFramework : : WindowNotifications : : OnWindowResized , windowSize . width ( ) , windowSize . height ( ) ) ;
AzFramework : : WindowNotificationBus : : Event ( windowId , & AzFramework : : WindowNotifications : : OnWindowResized , windowSize . width ( ) , windowSize . height ( ) ) ;
}
void RenderViewportWidget : : NotifyUpdateRefreshRate ( )
{
AzFramework : : WindowNotificationBus : : Event (
GetNativeWindowHandle ( ) , & AzFramework : : WindowNotificationBus : : Events : : OnRefreshRateChanged , GetDisplayRefreshRate ( ) ) ;
}
}
AZ : : Name RenderViewportWidget : : GetCurrentContextName ( ) const
AZ : : Name RenderViewportWidget : : GetCurrentContextName ( ) const
@ -418,7 +285,9 @@ namespace AtomToolsFramework
// Build camera state from Atom camera transforms
// Build camera state from Atom camera transforms
AzFramework : : CameraState cameraState = AzFramework : : CreateCameraFromWorldFromViewMatrix (
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 ( ) ) ;
AzFramework : : SetCameraClippingVolumeFromPerspectiveFovMatrixRH ( cameraState , currentView - > GetViewToClipMatrix ( ) ) ;
// Convert from Z-up
// Convert from Z-up
@ -430,7 +299,8 @@ namespace AtomToolsFramework
AzFramework : : ScreenPoint RenderViewportWidget : : ViewportWorldToScreen ( const AZ : : Vector3 & worldPosition )
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 ) ;
return AzFramework : : ScreenPoint ( 0 , 0 ) ;
}
}
@ -443,10 +313,12 @@ namespace AtomToolsFramework
const auto & cameraProjection = m_viewportContext - > GetCameraProjectionMatrix ( ) ;
const auto & cameraProjection = m_viewportContext - > GetCameraProjectionMatrix ( ) ;
const auto & cameraView = m_viewportContext - > GetCameraViewMatrix ( ) ;
const auto & cameraView = m_viewportContext - > GetCameraViewMatrix ( ) ;
const AZ : : Vector4 normalizedScreenPosition { screenPosition . m_x * 2.f / width ( ) - 1.0f ,
const AZ : : Vector4 normalizedScreenPosition {
( height ( ) - screenPosition . m_y ) * 2.f / height ( ) - 1.0f ,
screenPosition . m_x * 2.f / width ( ) - 1.0f ,
1.f - depth , // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
( height ( ) - screenPosition . m_y ) * 2.f / height ( ) - 1.0f ,
1.f } ;
1.f - depth , // [GFX TODO] [ATOM-1501] Currently we always assume reverse depth
1.f
} ;
AZ : : Matrix4x4 worldFromScreen = cameraProjection * cameraView ;
AZ : : Matrix4x4 worldFromScreen = cameraProjection * cameraView ;
worldFromScreen . InvertFull ( ) ;
worldFromScreen . InvertFull ( ) ;
@ -475,7 +347,7 @@ namespace AtomToolsFramework
AZ : : Vector3 rayDirection = pos1 . value ( ) - pos0 . value ( ) ;
AZ : : Vector3 rayDirection = pos1 . value ( ) - pos0 . value ( ) ;
rayDirection . Normalize ( ) ;
rayDirection . Normalize ( ) ;
return AzToolsFramework : : ViewportInteraction : : ProjectedViewportRay { rayOrigin , rayDirection } ;
return AzToolsFramework : : ViewportInteraction : : ProjectedViewportRay { rayOrigin , rayDirection } ;
}
}
float RenderViewportWidget : : DeviceScalingFactor ( )
float RenderViewportWidget : : DeviceScalingFactor ( )
@ -505,12 +377,12 @@ namespace AtomToolsFramework
AzFramework : : WindowSize RenderViewportWidget : : GetClientAreaSize ( ) const
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 )
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 ) ;
resize ( targetSize ) ;
}
}
@ -520,7 +392,7 @@ namespace AtomToolsFramework
return false ;
return false ;
}
}
void RenderViewportWidget : : SetFullScreenState ( [[maybe_unused]] bool fullScreenState )
void RenderViewportWidget : : SetFullScreenState ( [[maybe_unused]] bool fullScreenState )
{
{
// The RenderViewportWidget does not currently support full screen.
// The RenderViewportWidget does not currently support full screen.
}
}
@ -543,20 +415,11 @@ namespace AtomToolsFramework
uint32_t RenderViewportWidget : : GetDisplayRefreshRate ( ) const
uint32_t RenderViewportWidget : : GetDisplayRefreshRate ( ) const
{
{
return static_cast < uint32_t > ( screen ( ) - > refreshRate ( ) ) ;
return 60 ;
}
}
uint32_t RenderViewportWidget : : GetSyncInterval ( ) const
uint32_t RenderViewportWidget : : GetSyncInterval ( ) const
{
{
uint32_t interval = 1 ;
return 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