/* * 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 #if !defined(Q_MOC_RUN) #include #include #include "Viewport.h" #include "Objects/DisplayContext.h" #include "Undo/Undo.h" #include "Util/PredefinedAspectRatios.h" #include "EditorViewportSettings.h" #include "EditorModularViewportCameraComposer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #include #include // forward declarations. class CBaseObject; class QMenu; class QKeyEvent; struct ray_hit; struct IRenderMesh; struct IVariable; namespace AZ::ViewportHelpers { class EditorEntityNotifications; } //namespace AZ::ViewportHelpers namespace AtomToolsFramework { class RenderViewportWidget; class ModularViewportCameraController; } // namespace AtomToolsFramework namespace AzToolsFramework { class ManipulatorManager; } //! Viewport settings for the EditorViewportWidget struct EditorViewportSettings : public AzToolsFramework::ViewportInteraction::ViewportSettingsRequestBus::Handler { void Connect(AzFramework::ViewportId viewportId); void Disconnect(); // ViewportSettingsRequestBus overrides ... bool GridSnappingEnabled() const override; float GridSize() const override; bool ShowGrid() const override; bool AngleSnappingEnabled() const override; float AngleStep() const override; float ManipulatorLineBoundWidth() const override; float ManipulatorCircleBoundWidth() const override; bool StickySelectEnabled() const override; AZ::Vector3 DefaultEditorCameraPosition() const override; }; // EditorViewportWidget window AZ_PUSH_DISABLE_DLL_EXPORT_BASECLASS_WARNING AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING class SANDBOX_API EditorViewportWidget final : public QtViewport , private IEditorNotifyListener , private IUndoManagerListener , private Camera::EditorCameraRequestBus::Handler , private Camera::CameraNotificationBus::Handler , private AzFramework::InputSystemCursorConstraintRequestBus::Handler , private AzToolsFramework::ViewportInteraction::MainEditorViewportInteractionRequestBus::Handler , private AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Handler , private AzFramework::AssetCatalogEventBus::Handler , private AZ::RPI::SceneNotificationBus::Handler { AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING Q_OBJECT public: EditorViewportWidget(const QString& name, QWidget* parent = nullptr); ~EditorViewportWidget() override; static const GUID& GetClassID() { return QtViewport::GetClassID(); } static EditorViewportWidget* GetPrimaryViewport(); // Used by ViewPan in some circumstances void ConnectViewportInteractionRequestBus(); void DisconnectViewportInteractionRequestBus(); // QtViewport/IDisplayViewport/CViewport // These methods are made public in the derived class because they are called with an object whose static type is known to be this class type. void SetFOV(float fov) override; float GetFOV() const override; private: //////////////////////////////////////////////////////////////////////// // Private types ... enum class ViewSourceType { None, CameraComponent, ViewSourceTypesCount, }; enum class PlayInEditorState { Editor, Starting, Started }; enum class KeyPressedState { AllUp, PressedThisFrame, PressedInPreviousFrame, }; //////////////////////////////////////////////////////////////////////// // Method overrides ... // QWidget overrides ... void focusOutEvent(QFocusEvent* event) override; void keyPressEvent(QKeyEvent* event) override; bool event(QEvent* event) override; void resizeEvent(QResizeEvent* event) override; void paintEvent(QPaintEvent* event) override; void mousePressEvent(QMouseEvent* event) override; // QtViewport/IDisplayViewport/CViewport overrides ... EViewportType GetType() const override { return ET_ViewportCamera; } void SetType([[maybe_unused]] EViewportType type) override { assert(type == ET_ViewportCamera); }; AzToolsFramework::ViewportInteraction::MouseInteraction BuildMouseInteraction( Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, const QPoint& point) override; void SetViewportId(int id) override; QPoint WorldToView(const Vec3& wp) const override; QPoint WorldToViewParticleEditor(const Vec3& wp, int width, int height) const override; Vec3 WorldToView3D(const Vec3& wp, int nFlags = 0) const override; Vec3 ViewToWorld(const QPoint& vp, bool* collideWithTerrain = nullptr, bool onlyTerrain = false, bool bSkipVegetation = false, bool bTestRenderMesh = false, bool* collideWithObject = nullptr) const override; void ViewToWorldRay(const QPoint& vp, Vec3& raySrc, Vec3& rayDir) const override; Vec3 ViewToWorldNormal(const QPoint& vp, bool onlyTerrain, bool bTestRenderMesh = false) override; float GetScreenScaleFactor(const Vec3& worldPoint) const override; float GetScreenScaleFactor(const CCamera& camera, const Vec3& object_position) override; float GetAspectRatio() const override; bool HitTest(const QPoint& point, HitContext& hitInfo) override; bool IsBoundsVisible(const AABB& box) const override; void CenterOnSelection() override; void CenterOnAABB(const AABB& aabb) override; void CenterOnSliceInstance() override; void OnTitleMenu(QMenu* menu) override; void SetViewTM(const Matrix34& tm) override; const Matrix34& GetViewTM() const override; void Update() override; void UpdateContent(int flags) override; // SceneNotificationBus overrides ... void OnBeginPrepareRender() override; // Camera::CameraNotificationBus overrides ... void OnActiveViewChanged(const AZ::EntityId&) override; // IEditorEventListener overrides ... void OnEditorNotifyEvent(EEditorNotifyEvent event) override; // AzToolsFramework::EditorEntityContextNotificationBus overrides ... // note: handler moved to cpp to resolve link issues in unity builds void OnStartPlayInEditor(); void OnStopPlayInEditor(); void OnStartPlayInEditorBegin(); // IUndoManagerListener void BeginUndoTransaction() override; void EndUndoTransaction() override; // AzFramework::InputSystemCursorConstraintRequestBus overrides ... void* GetSystemCursorConstraintWindow() const override; // AzToolsFramework::MainEditorViewportInteractionRequestBus overrides ... AZ::EntityId PickEntity(const AzFramework::ScreenPoint& point) override; AZ::Vector3 PickTerrain(const AzFramework::ScreenPoint& point) override; float TerrainHeight(const AZ::Vector2& position) override; bool ShowingWorldSpace() override; QWidget* GetWidgetForViewportContextMenu() override; // EditorEntityViewportInteractionRequestBus overrides ... void FindVisibleEntities(AZStd::vector& visibleEntities) override; // Camera::EditorCameraRequestBus overrides ... void SetViewFromEntityPerspective(const AZ::EntityId& entityId) override; void SetViewAndMovementLockFromEntityPerspective(const AZ::EntityId& entityId, bool lockCameraMovement) override; AZ::EntityId GetCurrentViewEntityId() override; bool GetActiveCameraPosition(AZ::Vector3& cameraPos) override; bool GetActiveCameraState(AzFramework::CameraState& cameraState) override; //////////////////////////////////////////////////////////////////////// // Private helpers... void SetViewTM(const Matrix34& tm, bool bMoveOnly); void RenderSnapMarker(); void RenderAll(); // Update the safe frame, safe action, safe title, and borders rectangles based on // viewport size and target aspect ratio. void UpdateSafeFrame(); // Draw safe frame, safe action, safe title rectangles and borders. void RenderSafeFrame(); // Draw one of the safe frame rectangles with the desired color. void RenderSafeFrame(const QRect& frame, float r, float g, float b, float a); // Draw a selected region if it has been selected void RenderSelectedRegion(); bool RayRenderMeshIntersection(IRenderMesh* pRenderMesh, const Vec3& vInPos, const Vec3& vInDir, Vec3& vOutPos, Vec3& vOutNormal) const; bool AddCameraMenuItems(QMenu* menu); void ResizeView(int width, int height); void HideCursor(); void ShowCursor(); double WidgetToViewportFactor() const; bool ShouldPreviewFullscreen() const; void StartFullscreenPreview(); void StopFullscreenPreview(); void OnMenuResolutionCustom(); void OnMenuCreateCameraEntityFromCurrentView(); void OnMenuSelectCurrentCamera(); // From a series of input primitives, compose a complete mouse interaction. AzToolsFramework::ViewportInteraction::MouseInteraction BuildMouseInteractionInternal( AzToolsFramework::ViewportInteraction::MouseButtons buttons, AzToolsFramework::ViewportInteraction::KeyboardModifiers modifiers, const AzToolsFramework::ViewportInteraction::MousePick& mousePick) const; // Given a point in the viewport, return the pick ray into the scene. // note: The argument passed to parameter **point**, originating // from a Qt event, must first be passed to WidgetToViewport before being // passed to BuildMousePick. AzToolsFramework::ViewportInteraction::MousePick BuildMousePick(const QPoint& point) const; bool CheckRespondToInput() const; void BuildDragDropContext(AzQtComponents::ViewportDragContext& context, const QPoint& pt) override; void SetAsActiveViewport(); void PushDisableRendering(); void PopDisableRendering(); bool IsRenderingDisabled() const; void RestoreViewportAfterGameMode(); void UpdateScene(); void SetDefaultCamera(); void SetSelectedCamera(); bool IsSelectedCamera() const; void SetComponentCamera(const AZ::EntityId& entityId); void SetEntityAsCamera(const AZ::EntityId& entityId, bool lockCameraMovement = false); void SetFirstComponentCamera(); void PostCameraSet(); // This switches the active camera to the next one in the list of (default, all custom cams). void CycleCamera(); AzFramework::CameraState GetCameraState(); AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition); QPoint WidgetToViewport(const QPoint& point) const; QPoint ViewportToWidget(const QPoint& point) const; QSize WidgetToViewport(const QSize& size) const; const DisplayContext& GetDisplayContext() const { return m_displayContext; } CBaseObject* GetCameraObject() const; void UnProjectFromScreen(float sx, float sy, float sz, float* px, float* py, float* pz) const; void ProjectToScreen(float ptx, float pty, float ptz, float* sx, float* sy, float* sz) const; AZ::RPI::ViewPtr GetCurrentAtomView() const; //////////////////////////////////////////////////////////////////////// // Members ... friend class AZ::ViewportHelpers::EditorEntityNotifications; AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING // Singleton for the primary viewport static EditorViewportWidget* m_pPrimaryViewport; // The simulation (play-game in editor) state PlayInEditorState m_playInEditorState = PlayInEditorState::Editor; // Whether we are doing a full screen game preview (play-game in editor) or a regular one bool m_inFullscreenPreview = false; // The entity ID of the current camera for this viewport, or invalid if the default editor camera AZ::EntityId m_viewEntityId; // Determines also if the current camera for this viewport is default editor camera ViewSourceType m_viewSourceType = ViewSourceType::None; // During play game in editor, holds the editor entity ID of the last AZ::EntityId m_viewEntityIdCachedForEditMode; // The editor camera TM before switching to game mode Matrix34 m_preGameModeViewTM; // Disables rendering during some periods of time, e.g. undo/redo, resize events uint m_disableRenderingCount = 0; // Determines if the viewport needs updating (false when out of focus for example) bool m_bUpdateViewport = false; // Avoid re-entering PostCameraSet->OnActiveViewChanged->PostCameraSet bool m_sendingOnActiveChanged = false; // Legacy... KeyPressedState m_pressedKeyState = KeyPressedState::AllUp; // The last camera matrix of the default editor camera, used when switching back to editor camera to restore the right TM Matrix34 m_defaultViewTM; // The name to use for the default editor camera const QString m_defaultViewName; // Note that any attempts to draw anything with this object will crash. Exists here for legacy "reasons" DisplayContext m_displayContext; // Reentrancy guard for on paint events bool m_isOnPaint = false; // Shapes of various safe frame helpers which can be displayed in the editor QRect m_safeFrame; QRect m_safeAction; QRect m_safeTitle; // Aspect ratios available in the title bar CPredefinedAspectRatios m_predefinedAspectRatios; // Is the cursor hidden or displayed? bool m_bCursorHidden = false; // Shim for QtViewport, which used to be responsible for visibility queries in the editor, // these are now forwarded to EntityVisibilityQuery AzFramework::EntityVisibilityQuery m_entityVisibilityQuery; // Handlers for grid snapping/editor event callbacks SandboxEditor::GridSnappingChangedEvent::Handler m_gridSnappingHandler; AZStd::unique_ptr m_editorViewportSettingsCallbacks; // Used for some legacy logic which lets the widget release a grabbed keyboard at the right times // Unclear if it's still necessary. QSet m_keyDown; // This widget holds a reference to the manipulator manage because its responsible for drawing manipulators AZStd::shared_ptr m_manipulatorManager; AZStd::unique_ptr m_editorModularViewportCameraComposer; // Helper for getting EditorEntityNotificationBus events AZStd::unique_ptr m_editorEntityNotifications; // The widget to which Atom will actually render AtomToolsFramework::RenderViewportWidget* m_renderViewport = nullptr; // Atom debug display AzFramework::DebugDisplayRequests* m_debugDisplay = nullptr; // Type to return current state of editor viewport settings EditorViewportSettings m_editorViewportSettings; // The default view created for the viewport context, which is used as the "Editor Camera" AZ::RPI::ViewPtr m_defaultView; // The name to set on the viewport context when this viewport widget is set as the active one AZ::Name m_defaultViewportContextName; // DO NOT USE THIS! It exists only to satisfy the signature of the base class method GetViewTm mutable Matrix34 m_viewTmStorage; AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING };