From 10faddb113333a77221ff3df8be4b619fe318332 Mon Sep 17 00:00:00 2001 From: alexpete Date: Fri, 16 Apr 2021 12:05:11 -0700 Subject: [PATCH] Integrating github/staging through commit ef88e6e --- CMakeLists.txt | 4 - .../Common/PerInstanceConstantBufferPool.cpp | 4 + .../CryEngine/RenderDll/Common/RenderMesh.cpp | 1 + Code/Framework/AzCore/AzCore/Math/Vector2.cpp | 4 +- .../Entity/EntityDebugDisplayBus.h | 2 - .../AzFramework/Font/FontInterface.h | 85 + .../AzFramework/Viewport/ScreenGeometry.h | 13 + .../AzFramework/Viewport/ViewportScreen.cpp | 27 +- .../AzFramework/Viewport/ViewportScreen.h | 5 + .../AzFramework/azframework_files.cmake | 1 + .../EditorTransformComponentSelection.cpp | 45 +- .../Editor/Objects/DisplayContextShared.inl | 22 - .../SandboxIntegration.cpp | 20 - .../SandboxIntegration.h | 2 - ...enticationNotificationBusBehaviorHandler.h | 69 +- .../AuthenticationProviderManager.h | 22 +- .../AuthenticationProviderScriptCanvasBus.h | 103 + .../AuthenticationProviderTypes.h | 8 + ...horizationNotificationBusBehaviorHandler.h | 11 +- ...ManagementNotificationBusBehaviorHandler.h | 49 +- .../AuthenticationProviderBus.h | 10 +- .../Authentication/AuthenticationTokens.h | 15 +- .../Authorization/ClientAuthAWSCredentials.h | 36 +- .../AWSCognitoUserManagementBus.h | 5 +- .../Source/AWSClientAuthSystemComponent.cpp | 44 +- .../AWSCognitoAuthenticationProvider.cpp | 2 +- .../AuthenticationProviderManager.cpp | 87 +- .../Authentication/AuthenticationTokens.cpp | 26 + .../AWSCognitoAuthorizationController.cpp | 6 +- .../AWSCognitoUserManagementController.cpp | 2 +- .../AuthenticationProviderManagerMock.h | 55 + ...tionProviderManagerScriptCanvasBusTest.cpp | 261 ++ .../AuthenticationProviderManagerTest.cpp | 48 +- .../Code/awsclientauth_files.cmake | 1 + .../Code/awsclientauth_test_files.cmake | 2 + .../cdk/auth/cognito_identity_pool_role.py | 3 +- .../Code/Source/AuxGeom/AuxGeomDrawQueue.cpp | 10 +- .../Code/Source/AuxGeom/AuxGeomDrawQueue.h | 2 +- .../Atom/RPI.Public/AuxGeom/AuxGeomDraw.h | 2 +- .../AtomDebugDisplayViewportInterface.cpp | 2301 ++++++++++------- .../AtomDebugDisplayViewportInterface.h | 55 +- .../AtomLyIntegration/AtomFont/AtomFont.h | 37 +- .../AtomLyIntegration/AtomFont/FFont.h | 58 +- .../AtomFont/Code/Source/AtomFont.cpp | 78 +- .../AtomFont/Code/Source/FFont.cpp | 268 +- .../CoreLights/AreaLightComponentConfig.h | 3 + .../CoreLights/AreaLightComponentConfig.cpp | 5 + .../AreaLightComponentController.cpp | 9 + .../Source/CoreLights/DiskLightDelegate.cpp | 46 +- .../CoreLights/EditorAreaLightComponent.cpp | 57 +- .../Source/CoreLights/LightDelegateBase.h | 5 + .../Source/CoreLights/LightDelegateBase.inl | 6 + .../CoreLights/LightDelegateInterface.h | 3 + .../CoreLights/SimpleSpotLightDelegate.cpp | 35 +- .../CoreLights/SimpleSpotLightDelegate.h | 4 +- .../AtomShim_RenderAuxGeom.cpp | 4 +- cmake/FindTarget.cmake.in | 45 + cmake/Findo3de.cmake | 25 +- cmake/Findo3de.cmake.in | 36 + cmake/Platform/Common/Install_common.cmake | 11 +- 60 files changed, 2959 insertions(+), 1246 deletions(-) create mode 100644 Code/Framework/AzFramework/AzFramework/Font/FontInterface.h create mode 100644 Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderScriptCanvasBus.h create mode 100644 Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerMock.h create mode 100644 Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp create mode 100644 cmake/FindTarget.cmake.in create mode 100644 cmake/Findo3de.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index c09cfc9588..6da92f9c2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,15 +23,11 @@ endif() include(cmake/Version.cmake) -set(INSTALLED_ENGINE TRUE) - if(NOT PROJECT_NAME) project(O3DE LANGUAGES C CXX VERSION ${LY_VERSION_STRING} ) - - set(INSTALLED_ENGINE FALSE) endif() include(cmake/Initialize.cmake) diff --git a/Code/CryEngine/RenderDll/Common/PerInstanceConstantBufferPool.cpp b/Code/CryEngine/RenderDll/Common/PerInstanceConstantBufferPool.cpp index 7fa69f6026..f2475c0b48 100644 --- a/Code/CryEngine/RenderDll/Common/PerInstanceConstantBufferPool.cpp +++ b/Code/CryEngine/RenderDll/Common/PerInstanceConstantBufferPool.cpp @@ -274,6 +274,10 @@ void PerInstanceConstantBufferPool::SetConstantBuffer(SRendItem* renderItem) deviceManager.BindConstantBuffer(eHWSC_Vertex, m_PooledIndirectConstantBuffer[indirectId], eConstantBufferShaderSlot_SPIIndex); deviceManager.BindConstantBuffer(eHWSC_Pixel, m_PooledIndirectConstantBuffer[indirectId], eConstantBufferShaderSlot_SPIIndex); #else + AZ::u32 itemIndex = directId % SPI_NUM_INSTS_PER_CB; + AZ::u32 first[1] = {itemIndex * static_cast(sizeof(HLSL_PerInstanceConstantBuffer))}; + AZ::u32 count[1] = {static_cast(sizeof(HLSL_PerInstanceConstantBuffer))}; + deviceManager.BindConstantBuffer(eHWSC_Vertex, m_PooledConstantBuffer[bufferIndex], eConstantBufferShaderSlot_SPI, first[0], count[0]); deviceManager.BindConstantBuffer(eHWSC_Pixel, m_PooledConstantBuffer[bufferIndex], eConstantBufferShaderSlot_SPI, first[0], count[0]); #endif diff --git a/Code/CryEngine/RenderDll/Common/RenderMesh.cpp b/Code/CryEngine/RenderDll/Common/RenderMesh.cpp index 10bbfbf0e6..357731fc6d 100644 --- a/Code/CryEngine/RenderDll/Common/RenderMesh.cpp +++ b/Code/CryEngine/RenderDll/Common/RenderMesh.cpp @@ -755,6 +755,7 @@ lSysUpdate: buffer_handle_t nVB = ~0u; # if BUFFER_ENABLE_DIRECT_ACCESS && !defined(NULL_RENDERER) nVB = MS->m_nID; + int nFrame = gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nFillThreadID].m_nFrameUpdateID; if ((nVB != ~0u && (MS->m_nFrameCreate != nFrame || MS->m_nElements != m_nVerts)) || !CRenderer::CV_r_buffer_enable_lockless_updates) # endif goto lSysCreate; diff --git a/Code/Framework/AzCore/AzCore/Math/Vector2.cpp b/Code/Framework/AzCore/AzCore/Math/Vector2.cpp index bc5f6ecdad..c2a3a934b0 100644 --- a/Code/Framework/AzCore/AzCore/Math/Vector2.cpp +++ b/Code/Framework/AzCore/AzCore/Math/Vector2.cpp @@ -167,14 +167,14 @@ namespace AZ } } - AZ_MATH_INLINE Vector2::Vector2(const Vector3& source) + Vector2::Vector2(const Vector3& source) : m_x(source.GetX()) , m_y(source.GetY()) { } - AZ_MATH_INLINE Vector2::Vector2(const Vector4& source) + Vector2::Vector2(const Vector4& source) : m_x(source.GetX()) , m_y(source.GetY()) { diff --git a/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h b/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h index a5d3e657f5..f84f0276e1 100644 --- a/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h +++ b/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h @@ -105,8 +105,6 @@ namespace AzFramework virtual bool SetDrawInFrontMode(bool bOn) { (void)bOn; return false; } virtual AZ::u32 GetState() { return 0; } virtual AZ::u32 SetState(AZ::u32 state) { (void)state; return 0; } - virtual AZ::u32 SetStateFlag(AZ::u32 state) { (void)state; return 0; } - virtual AZ::u32 ClearStateFlag(AZ::u32 state) { (void)state; return 0; } virtual void PushMatrix(const AZ::Transform& tm) { (void)tm; } virtual void PopMatrix() {} diff --git a/Code/Framework/AzFramework/AzFramework/Font/FontInterface.h b/Code/Framework/AzFramework/AzFramework/Font/FontInterface.h new file mode 100644 index 0000000000..7c5bcce6d6 --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Font/FontInterface.h @@ -0,0 +1,85 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AzFramework +{ + using FontId = uint32_t; + static constexpr FontId InvalidFontId = 0xffffffffu; + + enum class TextHorizontalAlignment : uint16_t + { + Left, + Right, + Center + }; + + enum class TextVerticalAlignment : uint16_t + { + Top, + Bottom, + Center, + }; + + //! Standard parameters for drawing text on screen + struct TextDrawParameters + { + ViewportId m_drawViewportId = InvalidViewportId; //! Viewport to draw into + AZ::Vector3 m_position; //! world space position for 3d draws, screen space x,y,depth for 2d. + AZ::Color m_color = AZ::Colors::White; //! Color to draw the text + AZ::Vector2 m_scale = AZ::Vector2(1.0f); //! font scale + TextHorizontalAlignment m_hAlign = TextHorizontalAlignment::Left; //! Horizontal text alignment + TextVerticalAlignment m_vAlign = TextVerticalAlignment::Top; //! Vertical text alignment + bool m_monospace = false; //! disable character proportional spacing + bool m_depthTest = false; //! Test character against the depth buffer + bool m_virtual800x600ScreenSize = true; //! Text placement and size are scaled relative to a virtual 800x600 resolution + bool m_scaleWithWindow = false; //! Font gets bigger as the window gets bigger + bool m_multiline = true; //! text respects ascii newline characters + }; + + class FontDrawInterface + { + public: + AZ_RTTI(FontDrawInterface, "{545A7C14-CB3E-4A5B-B435-13EA606708EE}"); + + FontDrawInterface() = default; + virtual ~FontDrawInterface() = default; + + virtual void DrawScreenAlignedText2d( + const TextDrawParameters& params, + const AZStd::string_view& string) = 0; + virtual void DrawScreenAlignedText3d( + const TextDrawParameters& params, + const AZStd::string_view& string) = 0; + }; + + class FontQueryInterface + { + public: + AZ_RTTI(FontQueryInterface, "{4BDD8520-EBC1-4680-B25E-421BDF31750F}"); + + FontQueryInterface() = default; + virtual ~FontQueryInterface() = default; + + FontId GetFontId(const AZStd::string_view& fontName) const {return FontId(AZ::Crc32(fontName));} + virtual FontDrawInterface* GetFontDrawInterface(FontId) const = 0; + virtual FontDrawInterface* GetDefaultFontDrawInterface() const = 0; + + }; +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h b/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h index 1b570ebb8e..d3ae4e16f3 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h @@ -14,6 +14,7 @@ #include #include +#include #include namespace AZ @@ -133,6 +134,18 @@ namespace AzFramework return !operator==(lhs, rhs); } + inline ScreenPoint ScreenPointFromNDC(const AZ::Vector3& screenNDC, const AZ::Vector2& viewportSize) + { + return ScreenPoint( + aznumeric_caster(std::round(screenNDC.GetX() * viewportSize.GetX())), + aznumeric_caster(std::round((1.0f - screenNDC.GetY()) * viewportSize.GetY()))); + } + + inline AZ::Vector2 NDCFromScreenPoint(const ScreenPoint& screenPoint, const AZ::Vector2& viewportSize) + { + return AZ::Vector2(aznumeric_cast(screenPoint.m_x), viewportSize.GetY() - aznumeric_cast(screenPoint.m_y)) / viewportSize; + } + //! Return an AZ::Vector2 from a ScreenPoint. inline AZ::Vector2 Vector2FromScreenPoint(const ScreenPoint& screenPoint) { diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp index 3ca16897ba..5d2d02a398 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp @@ -101,20 +101,25 @@ namespace AzFramework cameraState.m_nearClip, cameraState.m_farClip); } - ScreenPoint WorldToScreen( - const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection, - const AZ::Vector2& viewportSize) + AZ::Vector3 WorldToScreenNDC( + const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection) { // transform the world space position to clip space const auto clipSpacePosition = cameraProjection * cameraView * AZ::Vector3ToVector4(worldPosition, 1.0f); // transform the clip space position to ndc space (perspective divide) const auto ndcPosition = clipSpacePosition / clipSpacePosition.GetW(); // transform ndc space from <-1,1> to <0, 1> range - const auto ndcNormalizedPosition = (AZ::Vector4ToVector2(ndcPosition) + AZ::Vector2::CreateOne()) * 0.5f; + return (AZ::Vector4ToVector3(ndcPosition) + AZ::Vector3::CreateOne()) * 0.5f; + } + + + ScreenPoint WorldToScreen( + const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection, + const AZ::Vector2& viewportSize) + { + const auto ndcNormalizedPosition = WorldToScreenNDC(worldPosition, cameraView, cameraProjection); // scale ndc position by screen dimensions to return screen position - return ScreenPoint( - aznumeric_caster(std::round(ndcNormalizedPosition.GetX() * viewportSize.GetX())), - aznumeric_caster(std::round(viewportSize.GetY() - (ndcNormalizedPosition.GetY() * viewportSize.GetY())))); + return ScreenPointFromNDC(ndcNormalizedPosition, viewportSize); } ScreenPoint WorldToScreen(const AZ::Vector3& worldPosition, const CameraState& cameraState) @@ -127,12 +132,8 @@ namespace AzFramework const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView, const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize) { - const auto screenHeight = viewportSize.GetY(); - const auto flippedScreenPosition = - AZ::Vector2(aznumeric_caster(screenPosition.m_x), aznumeric_caster(screenHeight - screenPosition.m_y)); - - // convert screen space coordinates to <-1,1> range - const auto ndcPosition = (flippedScreenPosition / viewportSize) * 2.0f - AZ::Vector2::CreateOne(); + // convert screen space coordinates from <0, 1> to <-1,1> range + const auto ndcPosition = NDCFromScreenPoint(screenPosition, viewportSize) * 2.0f - AZ::Vector2::CreateOne(); // transform ndc space position to clip space const auto clipSpacePosition = inverseCameraProjection * Vector2ToVector4(ndcPosition, -1.0f, 1.0f); diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h index 582e051bbb..a2c650465f 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h @@ -28,6 +28,11 @@ namespace AzFramework struct ScreenPoint; struct ViewportInfo; + //! Projects a position in world space to screen space normalized device coordinates for the given camera. + AZ::Vector3 WorldToScreenNDC( + const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection); + + //! Projects a position in world space to screen space for the given camera. ScreenPoint WorldToScreen(const AZ::Vector3& worldPosition, const CameraState& cameraState); diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake index b37c1b259f..cde2afb930 100644 --- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake +++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake @@ -145,6 +145,7 @@ set(FILES Components/NonUniformScaleComponent.cpp FileFunc/FileFunc.h FileFunc/FileFunc.cpp + Font/FontInterface.h Gem/GemInfo.cpp Gem/GemInfo.h StringFunc/StringFunc.h diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 83632708d9..433602e6d8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -53,7 +53,7 @@ namespace AzToolsFramework float, cl_viewportGizmoAxisLabelOffset, 1.15f, nullptr, AZ::ConsoleFunctorFlags::Null, "The offset of the label for the viewport axis gizmo"); AZ_CVAR( - float, cl_viewportGizmoAxisLabelSize, 2.0f, nullptr, AZ::ConsoleFunctorFlags::Null, + float, cl_viewportGizmoAxisLabelSize, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "The size of each label for the viewport axis gizmo"); AZ_CVAR( AZ::Vector2, cl_viewportGizmoAxisScreenPosition, AZ::Vector2(0.045f, 0.9f), nullptr, @@ -3434,19 +3434,22 @@ namespace AzToolsFramework const auto cameraProjection = AzFramework::CameraProjection(gizmoCameraState); // screen space offset to move the 2d gizmo around - const AZ::Vector3 screenPosition = - (AZ::Vector2ToVector3(cl_viewportGizmoAxisScreenPosition) - AZ::Vector3(0.5f, 0.5f, 0.0f)) * - AZ::Vector2ToVector3(gizmoCameraState.m_viewportSize); + const AZ::Vector2 screenOffset = AZ::Vector2(cl_viewportGizmoAxisScreenPosition) - AZ::Vector2(0.5f, 0.5f); // map from a position in world space (relative to the the gizmo camera near the origin) to a position in // screen space const auto calculateGizmoAxis = - [&cameraView, &cameraProjection, &gizmoCameraState, &screenPosition] - (const AZ::Vector3& position) + [&cameraView, &cameraProjection, &screenOffset] + (const AZ::Vector3& axis) { - return AZ::Vector2ToVector3(AzFramework::Vector2FromScreenPoint( - AzFramework::WorldToScreen( - position, cameraView, cameraProjection, gizmoCameraState.m_viewportSize))) + screenPosition; + auto result = AZ::Vector2( + AzFramework::WorldToScreenNDC( + axis, + cameraView, + cameraProjection) + ); + result.SetY(1.0f - result.GetY()); + return result + screenOffset; }; // get all important axis positions in screen space @@ -3456,31 +3459,31 @@ namespace AzToolsFramework const auto gizmoEndAxisY = calculateGizmoAxis(-AZ::Vector3::CreateAxisY() * lineLength); const auto gizmoEndAxisZ = calculateGizmoAxis(-AZ::Vector3::CreateAxisZ() * lineLength); - const AZ::Vector3 gizmoAxisX = gizmoEndAxisX - gizmoStart; - const AZ::Vector3 gizmoAxisY = gizmoEndAxisY - gizmoStart; - const AZ::Vector3 gizmoAxisZ = gizmoEndAxisZ - gizmoStart; + const AZ::Vector2 gizmoAxisX = gizmoEndAxisX - gizmoStart; + const AZ::Vector2 gizmoAxisY = gizmoEndAxisY - gizmoStart; + const AZ::Vector2 gizmoAxisZ = gizmoEndAxisZ - gizmoStart; // draw the axes of the gizmo debugDisplay.SetLineWidth(cl_viewportGizmoAxisLineWidth); debugDisplay.SetColor(AZ::Colors::Red); - debugDisplay.DrawLine(gizmoStart, gizmoEndAxisX); + debugDisplay.DrawLine2d(gizmoStart, gizmoEndAxisX, 1.0f); debugDisplay.SetColor(AZ::Colors::Lime); - debugDisplay.DrawLine(gizmoStart, gizmoEndAxisY); + debugDisplay.DrawLine2d(gizmoStart, gizmoEndAxisY, 1.0f); debugDisplay.SetColor(AZ::Colors::Blue); - debugDisplay.DrawLine(gizmoStart, gizmoEndAxisZ); + debugDisplay.DrawLine2d(gizmoStart, gizmoEndAxisZ, 1.0f); debugDisplay.SetLineWidth(1.0f); const float labelOffset = cl_viewportGizmoAxisLabelOffset; - const auto labelOffsetX = gizmoStart + gizmoAxisX * labelOffset; - const auto labelOffsetY = gizmoStart + gizmoAxisY * labelOffset; - const auto labelOffsetZ = gizmoStart + gizmoAxisZ * labelOffset; + const auto labelXScreenPosition = (gizmoStart + (gizmoAxisX * labelOffset)) * editorCameraState.m_viewportSize; + const auto labelYScreenPosition = (gizmoStart + (gizmoAxisY * labelOffset)) * editorCameraState.m_viewportSize; + const auto labelZScreenPosition = (gizmoStart + (gizmoAxisZ * labelOffset)) * editorCameraState.m_viewportSize; // draw the label of of each axis for the gizmo const float labelSize = cl_viewportGizmoAxisLabelSize; debugDisplay.SetColor(AZ::Colors::White); - debugDisplay.Draw2dTextLabel(labelOffsetX.GetX(), labelOffsetX.GetY(), labelSize, "X", true); - debugDisplay.Draw2dTextLabel(labelOffsetY.GetX(), labelOffsetY.GetY(), labelSize, "Y", true); - debugDisplay.Draw2dTextLabel(labelOffsetZ.GetX(), labelOffsetZ.GetY(), labelSize, "Z", true); + debugDisplay.Draw2dTextLabel(labelXScreenPosition.GetX(), labelXScreenPosition.GetY(), labelSize, "X", true); + debugDisplay.Draw2dTextLabel(labelYScreenPosition.GetX(), labelYScreenPosition.GetY(), labelSize, "Y", true); + debugDisplay.Draw2dTextLabel(labelZScreenPosition.GetX(), labelZScreenPosition.GetY(), labelSize, "Z", true); } void EditorTransformComponentSelection::DisplayViewportSelection2d( diff --git a/Code/Sandbox/Editor/Objects/DisplayContextShared.inl b/Code/Sandbox/Editor/Objects/DisplayContextShared.inl index a4baf1fe89..dd5c248357 100644 --- a/Code/Sandbox/Editor/Objects/DisplayContextShared.inl +++ b/Code/Sandbox/Editor/Objects/DisplayContextShared.inl @@ -1245,28 +1245,6 @@ uint32 DisplayContext::SetState(uint32 state) return old; } -//! Set a new render state flags. -//! @param returns previous render state. -uint32 DisplayContext::SetStateFlag(uint32 state) -{ - uint32 old = m_renderState; - m_renderState |= state; - m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags; - pRenderAuxGeom->SetRenderFlags(m_renderState); - return old; -} - -//! Clear specified flags in render state. -//! @param returns previous render state. -uint32 DisplayContext::ClearStateFlag(uint32 state) -{ - uint32 old = m_renderState; - m_renderState &= ~state; - m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags; - pRenderAuxGeom->SetRenderFlags(m_renderState); - return old; -} - ////////////////////////////////////////////////////////////////////////// void DisplayContext::DepthTestOff() { diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index e5311dbea9..d9e3d9bb8c 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -2777,26 +2777,6 @@ AZ::u32 SandboxIntegrationManager::SetState(AZ::u32 state) return 0; } -AZ::u32 SandboxIntegrationManager::SetStateFlag(AZ::u32 state) -{ - if (m_dc) - { - return m_dc->SetStateFlag(state); - } - - return 0; -} - -AZ::u32 SandboxIntegrationManager::ClearStateFlag(AZ::u32 state) -{ - if (m_dc) - { - return m_dc->ClearStateFlag(state); - } - - return 0; -} - void SandboxIntegrationManager::PushMatrix(const AZ::Transform& tm) { if (m_dc) diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h index e35fb5087a..36767605b2 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h @@ -268,8 +268,6 @@ private: bool SetDrawInFrontMode(bool bOn) override; AZ::u32 GetState() override; AZ::u32 SetState(AZ::u32 state) override; - AZ::u32 SetStateFlag(AZ::u32 state) override; - AZ::u32 ClearStateFlag(AZ::u32 state) override; void PushMatrix(const AZ::Transform& tm) override; void PopMatrix() override; diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h index c5e3c46cd4..c44327a5f2 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h @@ -12,6 +12,7 @@ #pragma once #include +#include namespace AWSClientAuth { @@ -28,74 +29,104 @@ namespace AWSClientAuth OnPasswordGrantMultiFactorConfirmSignInSuccess, OnPasswordGrantMultiFactorConfirmSignInFail, OnDeviceCodeGrantSignInSuccess, OnDeviceCodeGrantSignInFail, OnDeviceCodeGrantConfirmSignInSuccess, OnDeviceCodeGrantConfirmSignInFail, - OnRefreshTokensSuccess, OnRefreshTokensFail, - OnSignOut + OnRefreshTokensSuccess, OnRefreshTokensFail ); void OnPasswordGrantSingleFactorSignInSuccess(const AuthenticationTokens& authenticationToken) override { - Call(FN_OnPasswordGrantSingleFactorSignInSuccess, authenticationToken); + AZ::TickBus::QueueFunction([authenticationToken, this]() + { + Call(FN_OnPasswordGrantSingleFactorSignInSuccess, authenticationToken); + }); } void OnPasswordGrantSingleFactorSignInFail(const AZStd::string& error) override { - Call(FN_OnPasswordGrantSingleFactorSignInFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnPasswordGrantSingleFactorSignInFail, error); + }); } void OnPasswordGrantMultiFactorSignInSuccess() override { - Call(FN_OnPasswordGrantMultiFactorSignInSuccess); + AZ::TickBus::QueueFunction([this]() + { + Call(FN_OnPasswordGrantMultiFactorSignInSuccess); + }); } void OnPasswordGrantMultiFactorSignInFail(const AZStd::string& error) override { - Call(FN_OnPasswordGrantMultiFactorSignInFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnPasswordGrantMultiFactorSignInFail, error); + }); } void OnPasswordGrantMultiFactorConfirmSignInSuccess(const AuthenticationTokens& authenticationToken) override { - Call(FN_OnPasswordGrantMultiFactorConfirmSignInSuccess, authenticationToken); + AZ::TickBus::QueueFunction([authenticationToken, this]() + { + Call(FN_OnPasswordGrantMultiFactorConfirmSignInSuccess, authenticationToken); + }); } void OnPasswordGrantMultiFactorConfirmSignInFail(const AZStd::string& error) override { - Call(FN_OnPasswordGrantMultiFactorConfirmSignInFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnPasswordGrantMultiFactorConfirmSignInFail, error); + }); } void OnDeviceCodeGrantSignInSuccess( const AZStd::string& userCode, const AZStd::string& verificationUrl, const int codeExpiresInSeconds) override { - Call(FN_OnDeviceCodeGrantSignInSuccess, userCode, verificationUrl, codeExpiresInSeconds); + AZ::TickBus::QueueFunction([userCode, verificationUrl, codeExpiresInSeconds, this]() + { + Call(FN_OnDeviceCodeGrantSignInSuccess, userCode, verificationUrl, codeExpiresInSeconds); + }); } void OnDeviceCodeGrantSignInFail(const AZStd::string& error) override { - Call(FN_OnDeviceCodeGrantSignInFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnDeviceCodeGrantSignInFail, error); + }); } void OnDeviceCodeGrantConfirmSignInSuccess(const AuthenticationTokens& authenticationToken) override { - Call(FN_OnDeviceCodeGrantConfirmSignInSuccess, authenticationToken); + AZ::TickBus::QueueFunction([authenticationToken, this]() + { + Call(FN_OnDeviceCodeGrantConfirmSignInSuccess, authenticationToken); + }); } void OnDeviceCodeGrantConfirmSignInFail(const AZStd::string& error) override { - Call(FN_OnDeviceCodeGrantConfirmSignInFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnDeviceCodeGrantConfirmSignInFail, error); + }); } void OnRefreshTokensSuccess(const AuthenticationTokens& authenticationToken) override { - Call(FN_OnRefreshTokensSuccess, authenticationToken); + AZ::TickBus::QueueFunction([authenticationToken, this]() + { + Call(FN_OnRefreshTokensSuccess, authenticationToken); + }); } void OnRefreshTokensFail(const AZStd::string& error) override { - Call(FN_OnRefreshTokensFail, error); - } - - void OnSignOut(const ProviderNameEnum& provideName) override - { - Call(FN_OnSignOut, provideName); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnRefreshTokensFail, error); + }); } }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderManager.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderManager.h index a9a2f2ad6e..a09a96ba5c 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderManager.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderManager.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -23,7 +24,8 @@ namespace AWSClientAuth { //! Manages various authentication provider implementations and implements AuthenticationProvider Request bus. class AuthenticationProviderManager - : AuthenticationProviderRequestBus::Handler + : public AuthenticationProviderRequestBus::Handler + , public AuthenticationProviderScriptCanvasRequestBus::Handler { public: AZ_RTTI(AuthenticationProviderManager, "{45813BA5-9A46-4A2A-A923-C79CFBA0E63D}", IAuthenticationProviderRequests); @@ -43,6 +45,22 @@ namespace AWSClientAuth bool IsSignedIn(const ProviderNameEnum& providerName) override; bool SignOut(const ProviderNameEnum& providerName) override; AuthenticationTokens GetAuthenticationTokens(const ProviderNameEnum& providerName) override; + + // AuthenticationProviderScriptCanvasRequest interface + bool Initialize(const AZStd::vector& providerNames, const AZStd::string& settingsRegistryPath) override; + void PasswordGrantSingleFactorSignInAsync( + const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) override; + void PasswordGrantMultiFactorSignInAsync( + const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) override; + void PasswordGrantMultiFactorConfirmSignInAsync( + const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& confirmationCode) override; + void DeviceCodeGrantSignInAsync(const AZStd::string& providerName) override; + void DeviceCodeGrantConfirmSignInAsync(const AZStd::string& providerName) override; + void RefreshTokensAsync(const AZStd::string& providerName) override; + void GetTokensWithRefreshAsync(const AZStd::string& providerName) override; + bool IsSignedIn(const AZStd::string& providerName) override; + bool SignOut(const AZStd::string& providerName) override; + AuthenticationTokens GetAuthenticationTokens(const AZStd::string& providerName) override; virtual AZStd::unique_ptr CreateAuthenticationProviderObject(const ProviderNameEnum& providerName); AZStd::map> m_authenticationProvidersMap; @@ -50,9 +68,9 @@ namespace AWSClientAuth private: bool IsProviderInitialized(const ProviderNameEnum& providerName); void ResetProviders(); + ProviderNameEnum GetProviderNameEnum(AZStd::string name); AZStd::shared_ptr m_settingsRegistry; - }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderScriptCanvasBus.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderScriptCanvasBus.h new file mode 100644 index 0000000000..9ce508b497 --- /dev/null +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderScriptCanvasBus.h @@ -0,0 +1,103 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include +#include + +namespace AWSClientAuth +{ + //! Abstract class for authentication provider script canvas requests. + //! Private class to allow provide names to be string type instead of an enum as behavior context does not work well with enum's. + class IAuthenticationProviderScriptCanvasRequests + { + public: + AZ_TYPE_INFO(IAuthenticationProviderRequests, "{A8FD915F-9FF2-4BA3-8AA0-8CF7A94A323B}"); + + //! Parse the settings file for required settings for authentication providers. Instantiate and initialize authentication providers + //! @param providerNames List of provider names to instantiate and initialize for Authentication. + //! @param settingsRegistryPath Path for the settings registry file to use to configure providers. + //! @return bool True: if all providers initialized successfully. False: If any provider fails initialization. + virtual bool Initialize(const AZStd::vector& providerNames, const AZStd::string& settingsRegistryPath) = 0; + + //! Checks if user is signed in. + //! If access tokens are available and not expired. + //! @param providerName Provider to check signed in for + //! @return bool True if valid access token available, else False + virtual bool IsSignedIn(const AZStd::string& providerName) = 0; + + //! Get cached tokens from last last successful sign-in for the provider. + //! @param providerName Provider to get authentication tokens + //! @return AuthenticationTokens tokens from successful authentication. + virtual AuthenticationTokens GetAuthenticationTokens(const AZStd::string& providerName) = 0; + + // Below methods have corresponding notifications for success and failures. + + //! Call sign in endpoint for provider password grant flow. + //! @param providerName Provider to call sign in. + //! @param username Username to use to for sign in. + //! @param password Password to use to for sign in. + virtual void PasswordGrantSingleFactorSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) = 0; + + //! Call sign in endpoint for provider password grant multi factor authentication flow. + //! @param providerName Provider to call MFA sign in. + //! @param username Username to use for MFA sign in. + //! @param password Password to use for MFA sign in. + virtual void PasswordGrantMultiFactorSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) = 0; + + //! Call confirm endpoint for provider password grant multi factor authentication flow . + //! @param providerName Provider to call MFA confirm sign in. + //! @param username Username to use for MFA confirm. + //! @param confirmationCode Confirmation code (sent to email/text) to use for MFA confirm. + virtual void PasswordGrantMultiFactorConfirmSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& confirmationCode) = 0; + + //! Call code-pair endpoint for provider device grant flow. + //! @param providerName Provider to call device sign in. + virtual void DeviceCodeGrantSignInAsync(const AZStd::string& providerName) = 0; + + //! Call tokens endpoint for provider device grant flow. + //! @param providerName Provider to call device confirm sign in. + virtual void DeviceCodeGrantConfirmSignInAsync(const AZStd::string& providerName) = 0; + + //! Call refresh endpoint for provider refresh grant flow. + //! @param providerName Provider to call refresh tokens. + virtual void RefreshTokensAsync(const AZStd::string& providerName) = 0; + + //! Call refresh token if token not valid. If token valid, fires corresponding event. + //! @param providerName Provider to get access token for. + //! events: OnRefreshTokensSuccess, OnRefreshTokensFail + virtual void GetTokensWithRefreshAsync(const AZStd::string& providerName) = 0; + + //! Signs user out. + //! Clears all cached tokens. + //! @param providerName Provider to sign out. + //! @return bool True: Successfully sign out. + virtual bool SignOut(const AZStd::string& providerName) = 0; + + ////////////////////////////////////////////////////////////////////////// + }; + + //! Authentication Request bus for different supported providers. + class AuthenticationProviderScriptCanvasRequests + : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + using MutexType = AZ::NullMutex; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + ////////////////////////////////////////////////////////////////////////// + }; + using AuthenticationProviderScriptCanvasRequestBus = AZ::EBus; + +} // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h index 1e10e66307..8bd31d6aeb 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h @@ -15,6 +15,14 @@ namespace AWSClientAuth { + constexpr char ProvideNameEnumStringNone[] = "None"; + constexpr char ProvideNameEnumStringAWSCognitoIDP[] = "AWSCognitoIDP"; + constexpr char ProvideNameEnumStringLoginWithAmazon[] = "LoginWithAmazon"; + constexpr char ProvideNameEnumStringGoogle[] = "Google"; + constexpr char ProvideNameEnumStringApple[] = "Apple"; + constexpr char ProvideNameEnumStringFacebook[] = "Facebook"; + constexpr char ProvideNameEnumStringTwitch[] = "Twitch"; + //! Holds Login with Amazon provider serialized settings class LWAProviderSetting { diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h index f690445c26..e26896fa06 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h @@ -12,6 +12,7 @@ #pragma once #include +#include #include namespace AWSClientAuth @@ -28,12 +29,18 @@ namespace AWSClientAuth void OnRequestAWSCredentialsSuccess(const ClientAuthAWSCredentials& awsCredentials) override { - Call(FN_OnRequestAWSCredentialsSuccess, awsCredentials); + AZ::TickBus::QueueFunction([awsCredentials, this]() + { + Call(FN_OnRequestAWSCredentialsSuccess, awsCredentials); + }); } void OnRequestAWSCredentialsFail(const AZStd::string& error) override { - Call(FN_OnRequestAWSCredentialsFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnRequestAWSCredentialsFail, error); + }); } }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h b/Gems/AWSClientAuth/Code/Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h index 06f2ae6e58..f5c2ca7ed1 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h +++ b/Gems/AWSClientAuth/Code/Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h @@ -12,6 +12,7 @@ #pragma once #include +#include namespace AWSClientAuth { @@ -32,62 +33,86 @@ namespace AWSClientAuth void OnEmailSignUpSuccess(const AZStd::string& uuid) override { - Call(FN_OnEmailSignUpSuccess, uuid); + AZ::TickBus::QueueFunction([uuid, this]() { + Call(FN_OnEmailSignUpSuccess, uuid); + }); } void OnEmailSignUpFail(const AZStd::string& error) override { - Call(FN_OnEmailSignUpFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnEmailSignUpFail, error); + }); } void OnPhoneSignUpSuccess(const AZStd::string& uuid) override { - Call(FN_OnPhoneSignUpSuccess, uuid); + AZ::TickBus::QueueFunction([uuid, this]() { + Call(FN_OnPhoneSignUpSuccess, uuid); + }); } void OnPhoneSignUpFail(const AZStd::string& error) override { - Call(FN_OnPhoneSignUpFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnPhoneSignUpFail, error); + }); } void OnConfirmSignUpSuccess() override { - Call(FN_OnConfirmSignUpSuccess); + AZ::TickBus::QueueFunction([this]() { + Call(FN_OnConfirmSignUpSuccess); + }); } void OnConfirmSignUpFail(const AZStd::string& error) override { - Call(FN_OnConfirmSignUpFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnConfirmSignUpFail, error); + }); } void OnForgotPasswordSuccess() override { - Call(FN_OnForgotPasswordSuccess); + AZ::TickBus::QueueFunction([this]() { + Call(FN_OnForgotPasswordSuccess); + }); } void OnForgotPasswordFail(const AZStd::string& error) override { - Call(FN_OnForgotPasswordFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnForgotPasswordFail, error); + }); } void OnConfirmForgotPasswordSuccess() override { - Call(FN_OnConfirmForgotPasswordSuccess); + AZ::TickBus::QueueFunction([this]() { + Call(FN_OnConfirmForgotPasswordSuccess); + }); } void OnConfirmForgotPasswordFail(const AZStd::string& error) override { - Call(FN_OnConfirmForgotPasswordFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnConfirmForgotPasswordFail, error); + }); } void OnEnableMFASuccess() override { - Call(FN_OnEnableMFASuccess); + AZ::TickBus::QueueFunction([this]() { + Call(FN_OnEnableMFASuccess); + }); } void OnEnableMFAFail(const AZStd::string& error) override { - Call(FN_OnEnableMFAFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnEnableMFAFail, error); + }); } }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationProviderBus.h b/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationProviderBus.h index 693adf1e65..9e822849bc 100644 --- a/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationProviderBus.h +++ b/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationProviderBus.h @@ -16,7 +16,7 @@ namespace AWSClientAuth { - //@ Abstract class for authentication provider requests. + //! Abstract class for authentication provider requests. class IAuthenticationProviderRequests { public: @@ -35,32 +35,40 @@ namespace AWSClientAuth virtual bool IsSignedIn(const ProviderNameEnum& providerName) = 0; //! Get cached tokens from last last successful sign-in for the provider. + //! @param providerName Provider to get authentication tokens. + //! @return AuthenticationTokens tokens from successful authentication. virtual AuthenticationTokens GetAuthenticationTokens(const ProviderNameEnum& providerName) = 0; // Below methods have corresponding notifications for success and failures. //! Call sign in endpoint for provider password grant flow. + //! @param providerName Provider to call sign in. //! @param username Username to use to for sign in. //! @param password Password to use to for sign in. virtual void PasswordGrantSingleFactorSignInAsync(const ProviderNameEnum& providerName, const AZStd::string& username, const AZStd::string& password) = 0; //! Call sign in endpoint for provider password grant multi factor authentication flow. + //! @param providerName Provider to call MFA sign in. //! @param username Username to use for MFA sign in. //! @param password Password to use for MFA sign in. virtual void PasswordGrantMultiFactorSignInAsync(const ProviderNameEnum& providerName, const AZStd::string& username, const AZStd::string& password) = 0; //! Call confirm endpoint for provider password grant multi factor authentication flow . + //! @param providerName Provider to call MFA confirm sign in. //! @param username Username to use for MFA confirm. //! @param confirmationCode Confirmation code (sent to email/text) to use for MFA confirm. virtual void PasswordGrantMultiFactorConfirmSignInAsync(const ProviderNameEnum& providerName, const AZStd::string& username, const AZStd::string& confirmationCode) = 0; //! Call code-pair endpoint for provider device grant flow. + //! @param providerName Provider to call device sign in. virtual void DeviceCodeGrantSignInAsync(const ProviderNameEnum& providerName) = 0; //! Call tokens endpoint for provider device grant flow. + //! @param providerName Provider to call device confirm sign in. virtual void DeviceCodeGrantConfirmSignInAsync(const ProviderNameEnum& providerName) = 0; //! Call refresh endpoint for provider refresh grant flow. + //! @param providerName Provider to call refresh tokens. virtual void RefreshTokensAsync(const ProviderNameEnum& providerName) = 0; //! Call refresh token if token not valid. If token valid, fires corresponding event. diff --git a/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationTokens.h b/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationTokens.h index 80138efd1b..3bb781f262 100644 --- a/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationTokens.h +++ b/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationTokens.h @@ -11,20 +11,15 @@ */ #pragma once +#include #include #include +#include +#include namespace AWSClientAuth { - enum class ProviderNameEnum - { - None, - AWSCognitoIDP, - LoginWithAmazon, - Google, - Apple, - Facebook - }; + AZ_ENUM_CLASS(ProviderNameEnum, None, AWSCognitoIDP, LoginWithAmazon, Twitch, Google, Apple, Facebook); //! Used to share authentication tokens to caller and to AWSCognitoAuthorizationController. class AuthenticationTokens @@ -55,6 +50,8 @@ namespace AWSClientAuth //! @return Expiration time in seconds. int GetTokensExpireTimeSeconds() const; + static void Reflect(AZ::ReflectContext* context); + private: int m_tokensExpireTimeSeconds = 0; AZStd::string m_accessToken; diff --git a/Gems/AWSClientAuth/Code/Include/Public/Authorization/ClientAuthAWSCredentials.h b/Gems/AWSClientAuth/Code/Include/Public/Authorization/ClientAuthAWSCredentials.h index 71a5703efd..2daac42a49 100644 --- a/Gems/AWSClientAuth/Code/Include/Public/Authorization/ClientAuthAWSCredentials.h +++ b/Gems/AWSClientAuth/Code/Include/Public/Authorization/ClientAuthAWSCredentials.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include #include @@ -24,6 +24,14 @@ namespace AWSClientAuth { public: AZ_TYPE_INFO(ClientAuthAWSCredentials, "{02FB32C4-B94E-4084-9049-3DF32F87BD76}"); + ClientAuthAWSCredentials() = default; + ClientAuthAWSCredentials(const ClientAuthAWSCredentials& other) + : m_accessKeyId(other.m_accessKeyId) + , m_secretKey(other.m_secretKey) + , m_sessionToken(other.m_sessionToken) + + { + } ClientAuthAWSCredentials(const AZStd::string& accessKeyId, const AZStd::string& secretKey, const AZStd::string& sessionToken) { @@ -50,6 +58,32 @@ namespace AWSClientAuth return m_sessionToken; } + static void Reflect(AZ::ReflectContext* context) + { + auto serializeContext = azrtti_cast(context); + if (serializeContext) + { + serializeContext->Class() + ->Field("AWSAccessKeyId", &ClientAuthAWSCredentials::m_accessKeyId) + ->Field("AWSSecretKey", &ClientAuthAWSCredentials::m_secretKey) + ->Field("AWSSessionToken", &ClientAuthAWSCredentials::m_sessionToken); + } + + AZ::BehaviorContext* behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Category, "AWSClientAuth") + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Constructor() + ->Constructor() + ->Property("AWSAccessKeyId", BehaviorValueGetter(&ClientAuthAWSCredentials::m_accessKeyId), BehaviorValueSetter(&ClientAuthAWSCredentials::m_accessKeyId)) + ->Property("AWSSecretKey", BehaviorValueGetter(&ClientAuthAWSCredentials::m_secretKey), BehaviorValueSetter(&ClientAuthAWSCredentials::m_secretKey)) + ->Property("AWSSessionToken", BehaviorValueGetter(&ClientAuthAWSCredentials::m_sessionToken), BehaviorValueSetter(&ClientAuthAWSCredentials::m_sessionToken)); + } + } + private: AZStd::string m_accessKeyId; AZStd::string m_secretKey; diff --git a/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h b/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h index 89ddf0a999..aff68db365 100644 --- a/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h +++ b/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h @@ -22,11 +22,12 @@ namespace AWSClientAuth public: AZ_TYPE_INFO(IAWSCognitoUserManagementRequests, "{A4C90F21-7056-4827-8C6B-401E6945697D}"); - //! Initialize Cognito User pool. + //! Initialize Cognito User pool using settings from resource mappings. //! @param settingsRegistryPath settingsRegistryPath Path for the settings registry file to use. virtual bool Initialize() = 0; // Requests interface + //! Cognito user pool email sign up start. //! @param username User name to use for sign up. //! @param password Password to use for sign up. @@ -59,7 +60,7 @@ namespace AWSClientAuth virtual void EnableMFAAsync(const AZStd::string& accessToken) = 0; }; - //! Manages various authentication provider implementations and implements AuthenticationProvider Request bus. + //! Implements AWS Cognito user pool user management requests. class AWSCognitoUserManagementRequests : public AZ::EBusTraits { diff --git a/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp b/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp index 20efa354cc..008d56da0b 100644 --- a/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp +++ b/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp @@ -22,6 +22,11 @@ #include #include +namespace AZ +{ + AZ_TYPE_INFO_SPECIALIZE(AWSClientAuth::ProviderNameEnum, "{FB34B23A-B249-47A2-B1F1-C05284B50CCC}"); +} + namespace AWSClientAuth { constexpr char SerializeComponentName[] = "AWSClientAuth"; @@ -44,20 +49,35 @@ namespace AWSClientAuth AWSClientAuth::GoogleProviderSetting::Reflect(*serialize); } + AWSClientAuth::AuthenticationTokens::Reflect(context); + AWSClientAuth::ClientAuthAWSCredentials::Reflect(context); + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->EBus("AuthenticationProviderRequestBus") + behaviorContext->Enum<(int)ProviderNameEnum::None>("ProviderNameEnum_None") + ->Enum<(int)ProviderNameEnum::AWSCognitoIDP>("ProviderNameEnum_AWSCognitoIDP") + ->Enum<(int)ProviderNameEnum::LoginWithAmazon>("ProviderNameEnum_LoginWithAmazon") + ->Enum<(int)ProviderNameEnum::Google>("ProviderNameEnum_Google"); + + behaviorContext->EBus("AuthenticationProviderRequestBus") ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) - ->Event("Initialize", &AuthenticationProviderRequestBus::Events::Initialize) - ->Event("IsSignedIn", &AuthenticationProviderRequestBus::Events::IsSignedIn) - ->Event("GetAuthenticationTokens", &AuthenticationProviderRequestBus::Events::GetAuthenticationTokens) + ->Event("Initialize", &AuthenticationProviderScriptCanvasRequestBus::Events::Initialize) + ->Event("IsSignedIn", &AuthenticationProviderScriptCanvasRequestBus::Events::IsSignedIn) + ->Event("GetAuthenticationTokens", &AuthenticationProviderScriptCanvasRequestBus::Events::GetAuthenticationTokens) ->Event( - "PasswordGrantSingleFactorSignInAsync", &AuthenticationProviderRequestBus::Events::PasswordGrantSingleFactorSignInAsync) - ->Event("DeviceCodeGrantSignInAsync", &AuthenticationProviderRequestBus::Events::DeviceCodeGrantSignInAsync) - ->Event("DeviceCodeGrantConfirmSignInAsync", &AuthenticationProviderRequestBus::Events::DeviceCodeGrantConfirmSignInAsync) - ->Event("RefreshTokensAsync", &AuthenticationProviderRequestBus::Events::RefreshTokensAsync) - ->Event("GetTokensWithRefreshAsync", &AuthenticationProviderRequestBus::Events::GetTokensWithRefreshAsync) - ->Event("SignOut", &AuthenticationProviderRequestBus::Events::SignOut); + "PasswordGrantSingleFactorSignInAsync", + &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantSingleFactorSignInAsync) + ->Event( + "PasswordGrantMultiFactorSignInAsync", + &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantMultiFactorSignInAsync) + ->Event( + "PasswordGrantMultiFactorConfirmSignInAsync", + &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantMultiFactorConfirmSignInAsync) + ->Event("DeviceCodeGrantSignInAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::DeviceCodeGrantSignInAsync) + ->Event("DeviceCodeGrantConfirmSignInAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::DeviceCodeGrantConfirmSignInAsync) + ->Event("RefreshTokensAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::RefreshTokensAsync) + ->Event("GetTokensWithRefreshAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::GetTokensWithRefreshAsync) + ->Event("SignOut", &AuthenticationProviderScriptCanvasRequestBus::Events::SignOut); behaviorContext->EBus("AWSCognitoAuthorizationRequestBus") ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) @@ -77,11 +97,15 @@ namespace AWSClientAuth ->Event("ConfirmForgotPasswordAsync", &AWSCognitoUserManagementRequestBus::Events::ConfirmForgotPasswordAsync) ->Event("EnableMFAAsync", &AWSCognitoUserManagementRequestBus::Events::EnableMFAAsync); + behaviorContext->EBus("AuthenticationProviderNotificationBus") + ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Handler(); behaviorContext->EBus("AWSCognitoUserManagementNotificationBus") + ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Handler(); behaviorContext->EBus("AWSCognitoAuthorizationNotificationBus") + ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Handler(); } } diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp index eca5ba22c2..74865c0044 100644 --- a/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp @@ -40,7 +40,7 @@ namespace AWSClientAuth AZ_UNUSED(settingsRegistry); AWSCore::AWSResourceMappingRequestBus::BroadcastResult( m_cognitoAppClientId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoAppClientIdResourceMappingKey); - AZ_Warning("AWSCognitoAuthenticationProvider", m_cognitoAppClientId.empty(), "Missing Cognito App Client Id from resource mappings. Calls to Cognito will fail."); + AZ_Warning("AWSCognitoAuthenticationProvider", !m_cognitoAppClientId.empty(), "Missing Cognito App Client Id from resource mappings. Calls to Cognito will fail."); return !m_cognitoAppClientId.empty(); } diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp index 76d7c45c71..f6e5efd106 100644 --- a/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -25,12 +26,14 @@ namespace AWSClientAuth { AZ::Interface::Register(this); AuthenticationProviderRequestBus::Handler::BusConnect(); + AuthenticationProviderScriptCanvasRequestBus::Handler::BusConnect(); } AuthenticationProviderManager::~AuthenticationProviderManager() { ResetProviders(); m_settingsRegistry.reset(); + AuthenticationProviderScriptCanvasRequestBus::Handler::BusDisconnect(); AuthenticationProviderRequestBus::Handler::BusDisconnect(); AZ::Interface::Unregister(this); } @@ -38,12 +41,19 @@ namespace AWSClientAuth bool AuthenticationProviderManager::Initialize(const AZStd::vector& providerNames, const AZStd::string& settingsRegistryPath) { ResetProviders(); + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "File IO is not initialized."); + m_settingsRegistry.reset(); m_settingsRegistry = AZStd::make_shared(); - if (!m_settingsRegistry->MergeSettingsFile(settingsRegistryPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch)) + AZStd::array resolvedPath{}; + AZ::IO::FileIOBase::GetInstance()->ResolvePath(settingsRegistryPath.data(), resolvedPath.data(), resolvedPath.size()); + + + if (!m_settingsRegistry->MergeSettingsFile(resolvedPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch)) { - AZ_Error("AuthenticationProviderManager", true, "Error merging settings registry for path: %s", settingsRegistryPath.c_str()); + AZ_Error("AuthenticationProviderManager", true, "Error merging settings registry for path: %s", resolvedPath.data()); return false; } @@ -112,6 +122,7 @@ namespace AWSClientAuth { AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensFail , "Provider is not initialized"); + return; } AuthenticationTokens tokens = m_authenticationProvidersMap[providerName]->GetAuthenticationTokens(); @@ -181,5 +192,77 @@ namespace AWSClientAuth } } + ProviderNameEnum AuthenticationProviderManager::GetProviderNameEnum(AZStd::string name) + { + auto enumValue = ProviderNameEnumNamespace::FromStringToProviderNameEnum(name); + if (enumValue.has_value()) + { + return enumValue.value(); + } + AZ_Warning("AuthenticationProviderManager", true, "Incorrect string value for enum: %s", name.c_str()); + return ProviderNameEnum::None; + } + + bool AuthenticationProviderManager::Initialize( + const AZStd::vector& providerNames, const AZStd::string& settingsRegistryPath) + { + AZStd::vector providerNamesEnum; + for (auto name : providerNames) + { + providerNamesEnum.push_back(GetProviderNameEnum(name)); + } + return Initialize(providerNamesEnum, settingsRegistryPath); + } + + void AuthenticationProviderManager::PasswordGrantSingleFactorSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) + { + PasswordGrantSingleFactorSignInAsync(GetProviderNameEnum(providerName), username, password); + } + + void AuthenticationProviderManager::PasswordGrantMultiFactorSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) + { + PasswordGrantMultiFactorSignInAsync(GetProviderNameEnum(providerName), username, password); + } + + void AuthenticationProviderManager::PasswordGrantMultiFactorConfirmSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& confirmationCode) + { + PasswordGrantMultiFactorConfirmSignInAsync(GetProviderNameEnum(providerName), username, confirmationCode); + } + + void AuthenticationProviderManager::DeviceCodeGrantSignInAsync(const AZStd::string& providerName) + { + DeviceCodeGrantSignInAsync(GetProviderNameEnum(providerName)); + } + + void AuthenticationProviderManager::DeviceCodeGrantConfirmSignInAsync(const AZStd::string& providerName) + { + DeviceCodeGrantConfirmSignInAsync(GetProviderNameEnum(providerName)); + } + + void AuthenticationProviderManager::RefreshTokensAsync(const AZStd::string& providerName) + { + RefreshTokensAsync(GetProviderNameEnum(providerName)); + } + + void AuthenticationProviderManager::GetTokensWithRefreshAsync(const AZStd::string& providerName) + { + GetTokensWithRefreshAsync(GetProviderNameEnum(providerName)); + } + + bool AuthenticationProviderManager::IsSignedIn(const AZStd::string& providerName) + { + return IsSignedIn(GetProviderNameEnum(providerName)); + } + + bool AuthenticationProviderManager::SignOut(const AZStd::string& providerName) + { + return SignOut(GetProviderNameEnum(providerName)); + } + + AuthenticationTokens AuthenticationProviderManager::GetAuthenticationTokens(const AZStd::string& providerName) + { + return GetAuthenticationTokens(GetProviderNameEnum(providerName)); + } + } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationTokens.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationTokens.cpp index 9c078ad99c..737d6ae929 100644 --- a/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationTokens.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationTokens.cpp @@ -79,4 +79,30 @@ namespace AWSClientAuth { return m_tokensExpireTimeSeconds; } + + void AuthenticationTokens::Reflect(AZ::ReflectContext* context) + { + auto serializeContext = azrtti_cast(context); + if (serializeContext) + { + serializeContext->Class() + ->Field("AccessToken", &AuthenticationTokens::m_accessToken) + ->Field("OpenIdToken", &AuthenticationTokens::m_openIdToken) + ->Field("RefreshToken", &AuthenticationTokens::m_refreshToken); + } + + AZ::BehaviorContext* behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Category, "AWSClientAuth") + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Constructor() + ->Constructor() + ->Property("AccessToken", BehaviorValueGetter(&AuthenticationTokens::m_accessToken), BehaviorValueSetter(&AuthenticationTokens::m_accessToken)) + ->Property("OpenIdToken", BehaviorValueGetter(&AuthenticationTokens::m_openIdToken), BehaviorValueSetter(&AuthenticationTokens::m_accessToken)) + ->Property("RefreshToken", BehaviorValueGetter(&AuthenticationTokens::m_refreshToken), BehaviorValueSetter(&AuthenticationTokens::m_accessToken)); + } + } } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp b/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp index 4c10d968fc..5e2c07bdbb 100644 --- a/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp @@ -71,15 +71,15 @@ namespace AWSClientAuth if (m_awsAccountId.empty() || m_cognitoIdentityPoolId.empty()) { - AZ_Warning("AWSCognitoUserManagementController", m_awsAccountId.empty(), "Missing AWS account id in resource mappings."); - AZ_Warning("AWSCognitoUserManagementController", m_cognitoIdentityPoolId.empty(), "Missing Cognito Identity pool id in resource mappings."); + AZ_Warning("AWSCognitoAuthorizationController", !m_awsAccountId.empty(), "Missing AWS account id not configured."); + AZ_Warning("AWSCognitoAuthorizationController", !m_cognitoIdentityPoolId.empty(), "Missing Cognito Identity pool id in resource mappings."); return false; } AZStd::string userPoolId; AWSCore::AWSResourceMappingRequestBus::BroadcastResult( userPoolId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoUserPoolIdResourceMappingKey); - AZ_Warning("AWSCognitoUserManagementController", userPoolId.empty(), "Missing Cognito USer pool id in resource mappings. Cognito IDP authenticated identities will no work."); + AZ_Warning("AWSCognitoAuthorizationController", !userPoolId.empty(), "Missing Cognito User pool id in resource mappings. Cognito IDP authenticated identities will no work."); AZStd::string defaultRegion; AWSCore::AWSResourceMappingRequestBus::BroadcastResult( diff --git a/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp b/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp index 19d5d47d33..755b0e1f15 100644 --- a/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp +++ b/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp @@ -54,7 +54,7 @@ namespace AWSClientAuth AWSCore::AWSResourceMappingRequestBus::BroadcastResult( m_cognitoAppClientId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoAppClientIdResourceMappingKey); AZ_Warning( - "AWSCognitoUserManagementController", m_cognitoAppClientId.empty(), "Missing Cognito App Client Id from resource mappings. Calls to Cognito will fail."); + "AWSCognitoUserManagementController", !m_cognitoAppClientId.empty(), "Missing Cognito App Client Id from resource mappings. Calls to Cognito will fail."); return !m_cognitoAppClientId.empty(); } diff --git a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerMock.h b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerMock.h new file mode 100644 index 0000000000..e7b233c786 --- /dev/null +++ b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerMock.h @@ -0,0 +1,55 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include + +namespace AWSClientAuthUnitTest +{ + class AuthenticationProviderManagerLocalMock + : public AWSClientAuth::AuthenticationProviderManager + { + public: + using AWSClientAuth::AuthenticationProviderManager::DeviceCodeGrantConfirmSignInAsync; + using AWSClientAuth::AuthenticationProviderManager::DeviceCodeGrantSignInAsync; + using AWSClientAuth::AuthenticationProviderManager::GetAuthenticationTokens; + using AWSClientAuth::AuthenticationProviderManager::GetTokensWithRefreshAsync; + using AWSClientAuth::AuthenticationProviderManager::Initialize; + using AWSClientAuth::AuthenticationProviderManager::IsSignedIn; + using AWSClientAuth::AuthenticationProviderManager::m_authenticationProvidersMap; + using AWSClientAuth::AuthenticationProviderManager::PasswordGrantMultiFactorConfirmSignInAsync; + using AWSClientAuth::AuthenticationProviderManager::PasswordGrantMultiFactorSignInAsync; + using AWSClientAuth::AuthenticationProviderManager::PasswordGrantSingleFactorSignInAsync; + using AWSClientAuth::AuthenticationProviderManager::RefreshTokensAsync; + using AWSClientAuth::AuthenticationProviderManager::SignOut; + + AZStd::unique_ptr CreateAuthenticationProviderObjectMock( + const AWSClientAuth::ProviderNameEnum& providerName) + { + auto providerObject = AWSClientAuth::AuthenticationProviderManager::CreateAuthenticationProviderObject(providerName); + providerObject.reset(); + return AZStd::make_unique>(); + } + + AuthenticationProviderManagerLocalMock() + { + ON_CALL(*this, CreateAuthenticationProviderObject(testing::_)) + .WillByDefault(testing::Invoke(this, &AuthenticationProviderManagerLocalMock::CreateAuthenticationProviderObjectMock)); + } + + MOCK_METHOD1( + CreateAuthenticationProviderObject, + AZStd::unique_ptr(const AWSClientAuth::ProviderNameEnum&)); + }; +} // namespace AWSClientAuthUnitTest diff --git a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp new file mode 100644 index 0000000000..7673840299 --- /dev/null +++ b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp @@ -0,0 +1,261 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class AuthenticationProviderManagerScriptCanvasTest + : public AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture +{ +protected: + void SetUp() override + { + AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture::SetUp(); + + AWSClientAuth::LWAProviderSetting::Reflect(*m_serializeContext); + AWSClientAuth::GoogleProviderSetting::Reflect(*m_serializeContext); + + m_settingspath = AZStd::string::format("%s/%s/authenticationProvider.setreg", + m_testFolder->c_str(), AZ::SettingsRegistryInterface::RegistryFolder); + CreateTestFile("authenticationProvider.setreg" + , R"({ + "AWS": + { + "LoginWithAmazon": + { + "AppClientId": "TestLWAClientId", + "GrantType": "device_code", + "Scope": "profile", + "ResponseType": "device_code", + "OAuthCodeURL": "https://api.amazon.com/auth/o2/create/codepair", + "OAuthTokensURL": "https://oauth2.googleapis.com/token" + }, + "Google": + { + "AppClientId": "TestGoogleClientId", + "ClientSecret": "123", + "GrantType": "urn:ietf:params:oauth:grant-type:device_code", + "Scope": "profile", + "OAuthCodeURL": "https://oauth2.googleapis.com/device/code", + "OAuthTokensURL": "https://oauth2.googleapis.com/token" + } + } + })"); + + m_mockController = AZStd::make_unique>(); + } + + void TearDown() override + { + m_mockController.reset(); + AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture::TearDown(); + } + +public: + AZStd::unique_ptr> m_mockController; + AZStd::string m_settingspath; + AZStd::vector m_enabledProviderNames { AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP, + AWSClientAuth::ProvideNameEnumStringLoginWithAmazon, AWSClientAuth::ProvideNameEnumStringGoogle}; +}; + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, Initialize_Success) +{ + ASSERT_TRUE(m_mockController->Initialize(m_enabledProviderNames, m_settingspath)); + ASSERT_TRUE(m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP] != nullptr); +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, PasswordGrantSingleFactorSignInAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock *cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + + EXPECT_CALL(*cognitoProviderMock, PasswordGrantSingleFactorSignInAsync(testing::_, testing::_)).Times(1); + m_mockController->PasswordGrantSingleFactorSignInAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, PasswordGrantSingleFactorSignInAsync_Fail_NonConfiguredProviderError) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + m_mockController->PasswordGrantSingleFactorSignInAsync(AWSClientAuth::ProvideNameEnumStringApple, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, PasswordGrantMultiFactorSignInAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + testing::NiceMock* lwaProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::LoginWithAmazon].get(); + + EXPECT_CALL(*cognitoProviderMock, PasswordGrantMultiFactorSignInAsync(testing::_, testing::_)).Times(1); + m_mockController->PasswordGrantMultiFactorSignInAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + + EXPECT_CALL(*lwaProviderMock, PasswordGrantMultiFactorSignInAsync(testing::_, testing::_)).Times(1); + m_mockController->PasswordGrantMultiFactorSignInAsync(AWSClientAuth::ProvideNameEnumStringLoginWithAmazon, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, PasswordGrantMultiFactorConfirmSignInAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock *cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + testing::NiceMock *lwaProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::LoginWithAmazon].get(); + + EXPECT_CALL(*cognitoProviderMock, PasswordGrantMultiFactorConfirmSignInAsync(testing::_, testing::_)).Times(1); + m_mockController->PasswordGrantMultiFactorConfirmSignInAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + + EXPECT_CALL(*lwaProviderMock, PasswordGrantMultiFactorConfirmSignInAsync(testing::_, testing::_)).Times(1); + m_mockController->PasswordGrantMultiFactorConfirmSignInAsync(AWSClientAuth::ProvideNameEnumStringLoginWithAmazon, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, DeviceCodeGrantSignInAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + testing::NiceMock* lwaProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::LoginWithAmazon].get(); + + EXPECT_CALL(*cognitoProviderMock, DeviceCodeGrantSignInAsync()).Times(1); + m_mockController->DeviceCodeGrantSignInAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + EXPECT_CALL(*lwaProviderMock, DeviceCodeGrantSignInAsync()).Times(1); + m_mockController->DeviceCodeGrantSignInAsync(AWSClientAuth::ProvideNameEnumStringLoginWithAmazon); + + cognitoProviderMock = nullptr; +} + + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, DeviceCodeGrantConfirmSignInAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + testing::NiceMock* lwaProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::LoginWithAmazon].get(); + + EXPECT_CALL(*cognitoProviderMock, DeviceCodeGrantConfirmSignInAsync()).Times(1); + m_mockController->DeviceCodeGrantConfirmSignInAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + EXPECT_CALL(*lwaProviderMock, DeviceCodeGrantConfirmSignInAsync()).Times(1); + m_mockController->DeviceCodeGrantConfirmSignInAsync(AWSClientAuth::ProvideNameEnumStringLoginWithAmazon); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, RefreshTokenAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock *cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + testing::NiceMock *lwaProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::LoginWithAmazon].get(); + + EXPECT_CALL(*cognitoProviderMock, RefreshTokensAsync()).Times(1); + m_mockController->RefreshTokensAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + EXPECT_CALL(*lwaProviderMock, RefreshTokensAsync()).Times(1); + m_mockController->RefreshTokensAsync(AWSClientAuth::ProvideNameEnumStringLoginWithAmazon); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, GetTokensWithRefreshAsync_ValidToken_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + + AWSClientAuth::AuthenticationTokens tokens( + AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, + AWSClientAuth::ProviderNameEnum::AWSCognitoIDP, 600); + EXPECT_CALL(*cognitoProviderMock, GetAuthenticationTokens()).Times(1).WillOnce(testing::Return(tokens)); + EXPECT_CALL(*cognitoProviderMock, RefreshTokensAsync()).Times(0); + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnRefreshTokensSuccess(testing::_)).Times(1); + m_mockController->GetTokensWithRefreshAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, GetTokensWithRefreshAsync_InvalidToken_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + AWSClientAuth::AuthenticationTokens tokens; + EXPECT_CALL(*cognitoProviderMock, GetAuthenticationTokens()).Times(1).WillOnce(testing::Return(tokens)); + EXPECT_CALL(*cognitoProviderMock, RefreshTokensAsync()).Times(1); + m_mockController->GetTokensWithRefreshAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, GetTokensWithRefreshAsync_NotInitializedProvider_Fail) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnRefreshTokensSuccess(testing::_)).Times(0); + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnRefreshTokensFail(testing::_)).Times(1); + m_mockController->GetTokensWithRefreshAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, GetTokens_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + + AWSClientAuth::AuthenticationTokens tokens( + AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, + AWSClientAuth::ProviderNameEnum::AWSCognitoIDP, 60); + + EXPECT_CALL(*cognitoProviderMock, GetAuthenticationTokens()).Times(1).WillOnce(testing::Return(tokens)); + m_mockController->GetAuthenticationTokens(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, IsSignedIn_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + + AWSClientAuth::AuthenticationTokens tokens( + AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, + AWSClientAuth::ProviderNameEnum::AWSCognitoIDP, 60); + EXPECT_CALL(*cognitoProviderMock, GetAuthenticationTokens()).Times(1).WillOnce(testing::Return(tokens)); + m_mockController->IsSignedIn(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, SignOut_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* googleProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::Google].get(); + + EXPECT_CALL(*googleProviderMock, SignOut()).Times(1); + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnSignOut(testing::_)).Times(1); + m_mockController->SignOut(AWSClientAuth::ProvideNameEnumStringGoogle); + + googleProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, Initialize_Fail_InvalidPath) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + ASSERT_FALSE(m_mockController->Initialize(m_enabledProviderNames, "")); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); +} diff --git a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp index 9e7d189f5d..4b5bdfb841 100644 --- a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp +++ b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp @@ -10,8 +10,6 @@ * */ -#include -#include #include #include #include @@ -20,42 +18,7 @@ #include #include #include - -namespace AWSClientAuthUnitTest -{ - class AuthenticationProviderManagerLocalMock - : public AWSClientAuth::AuthenticationProviderManager - { - public: - using AWSClientAuth::AuthenticationProviderManager::m_authenticationProvidersMap; - using AWSClientAuth::AuthenticationProviderManager::Initialize; - using AWSClientAuth::AuthenticationProviderManager::PasswordGrantSingleFactorSignInAsync; - using AWSClientAuth::AuthenticationProviderManager::PasswordGrantMultiFactorSignInAsync; - using AWSClientAuth::AuthenticationProviderManager::PasswordGrantMultiFactorConfirmSignInAsync; - using AWSClientAuth::AuthenticationProviderManager::DeviceCodeGrantSignInAsync; - using AWSClientAuth::AuthenticationProviderManager::DeviceCodeGrantConfirmSignInAsync; - using AWSClientAuth::AuthenticationProviderManager::RefreshTokensAsync; - using AWSClientAuth::AuthenticationProviderManager::GetTokensWithRefreshAsync; - using AWSClientAuth::AuthenticationProviderManager::GetAuthenticationTokens; - using AWSClientAuth::AuthenticationProviderManager::SignOut; - using AWSClientAuth::AuthenticationProviderManager::IsSignedIn; - - AZStd::unique_ptr CreateAuthenticationProviderObjectMock(const AWSClientAuth::ProviderNameEnum& providerName) - { - auto providerObject = AWSClientAuth::AuthenticationProviderManager::CreateAuthenticationProviderObject(providerName); - providerObject.reset(); - return AZStd::make_unique>(); - } - - AuthenticationProviderManagerLocalMock() - { - ON_CALL(*this, CreateAuthenticationProviderObject(testing::_)).WillByDefault( - testing::Invoke(this, &AuthenticationProviderManagerLocalMock::CreateAuthenticationProviderObjectMock)); - } - - MOCK_METHOD1(CreateAuthenticationProviderObject, AZStd::unique_ptr(const AWSClientAuth::ProviderNameEnum&)); - }; -} +#include class AuthenticationProviderManagerTest @@ -239,6 +202,15 @@ TEST_F(AuthenticationProviderManagerTest, GetTokensWithRefreshAsync_InvalidToken cognitoProviderMock = nullptr; } +TEST_F(AuthenticationProviderManagerTest, GetTokensWithRefreshAsync_NotInitializedProvider_Fail) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnRefreshTokensSuccess(testing::_)).Times(0); + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnRefreshTokensFail(testing::_)).Times(1); + m_mockController->GetTokensWithRefreshAsync(AWSClientAuth::ProviderNameEnum::AWSCognitoIDP); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); +} + TEST_F(AuthenticationProviderManagerTest, GetTokens_Success) { m_mockController->Initialize(m_enabledProviderNames, m_settingspath); diff --git a/Gems/AWSClientAuth/Code/awsclientauth_files.cmake b/Gems/AWSClientAuth/Code/awsclientauth_files.cmake index 79da00076c..7e4734992f 100644 --- a/Gems/AWSClientAuth/Code/awsclientauth_files.cmake +++ b/Gems/AWSClientAuth/Code/awsclientauth_files.cmake @@ -20,6 +20,7 @@ set(FILES Include/Private/AWSClientAuthBus.h Include/Private/AWSClientAuthResourceMappingConstants.h Include/Private/Authentication/AuthenticationProviderTypes.h + Include/Private/Authentication/AuthenticationProviderScriptCanvasBus.h Include/Private/Authentication/AuthenticationProviderManager.h Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h diff --git a/Gems/AWSClientAuth/Code/awsclientauth_test_files.cmake b/Gems/AWSClientAuth/Code/awsclientauth_test_files.cmake index 6d3de7cc54..18aaa697dd 100644 --- a/Gems/AWSClientAuth/Code/awsclientauth_test_files.cmake +++ b/Gems/AWSClientAuth/Code/awsclientauth_test_files.cmake @@ -14,7 +14,9 @@ set(FILES Tests/AWSClientAuthGemTest.cpp Tests/AWSClientAuthSystemComponentTest.cpp + Tests/Authentication/AuthenticationProviderManagerMock.h Tests/Authentication/AuthenticationProviderManagerTest.cpp + Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp Tests/Authentication/AWSCognitoAuthenticationProviderTest.cpp Tests/Authentication/LWAAuthenticationProviderTest.cpp Tests/Authentication/GoogleAuthenticationProviderTest.cpp diff --git a/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py b/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py index 0ebef83eba..3a2e413617 100755 --- a/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py +++ b/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py @@ -56,8 +56,7 @@ class CognitoIdentityPoolRole: # basic permissions stack_statement = iam.PolicyStatement( actions=[ - 's3:Get*', - 's3:List*' + 's3:ListBuckets' ], effect=iam.Effect.ALLOW, resources=[ diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp index fd4b5b28d1..dc53498c8b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp @@ -289,7 +289,7 @@ namespace AZ void AuxGeomDrawQueue::DrawQuad( float width, float height, - const AZ::Transform& transform, + const AZ::Matrix3x4& transform, const AZ::Color& color, DrawStyle style, DepthTest depthTest, @@ -302,8 +302,8 @@ namespace AZ return; } - Transform noScaleTransform = transform; - noScaleTransform.ExtractScale(); + AZ::Matrix3x4 noScaleTransform = transform; + AZ::Vector3 scale = noScaleTransform.ExtractScale(); ShapeBufferEntry shape; shape.m_shapeType = ShapeType_Quad; @@ -311,9 +311,9 @@ namespace AZ shape.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite); shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull); shape.m_color = color; - shape.m_rotationMatrix = Matrix3x3::CreateFromTransform(noScaleTransform); + shape.m_rotationMatrix = Matrix3x3::CreateFromMatrix3x4(noScaleTransform); shape.m_position = transform.GetTranslation(); - shape.m_scale = transform.GetScale() * Vector3(width, 1.0f, height); + shape.m_scale = scale * Vector3(width, 1.0f, height); shape.m_pointSize = m_pointSize; shape.m_viewProjOverrideIndex = viewProjOverrideIndex; diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h index b959173ed1..53220c031d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h @@ -62,7 +62,7 @@ namespace AZ void DrawTriangles(const AuxGeomDynamicIndexedDrawArguments& args, FaceCullMode faceCull = FaceCullMode::None) override; // Fixed shape draws - void DrawQuad(float width, float height, const AZ::Transform& transform, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; + void DrawQuad(float width, float height, const AZ::Matrix3x4& transform, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawSphere(const AZ::Vector3& center, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawDisk(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawCone(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h index afba71a457..0e7f11e46e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h @@ -138,7 +138,7 @@ namespace AZ //! @param depthWrite If depth writing should be enabled //! @param faceCull Which (if any) facing triangles should be culled //! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused - virtual void DrawQuad(float width, float height, const AZ::Transform& transform, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0; + virtual void DrawQuad(float width, float height, const AZ::Matrix3x4& transform, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0; //! Draw a sphere. //! @param center The center of the sphere. diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index ec7aa17151..4cab7b8869 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp @@ -15,811 +15,1206 @@ #include #include #include +#include +#include #include #include #include -namespace AZ +#include + +namespace // unnamed namespace to hold copies of Cry AuxGeom state enum's, this is to avoid creating a dependency on IRenderAuxGeom.h { - namespace AtomBridge + // Notes: + // Don't change the xxxShift values, they need to match the values from legacy cry rendering + // This also applies to the individual flags in EAuxGeomPublicRenderflags_*! + // Remarks: + // Bits 0 - 22 are currently reserved for prim type and per draw call render parameters (point size, etc.) + // Check RenderAuxGeom.h in ../RenderDll/Common + enum EAuxGeomPublicRenderflagBitMasks { + e_Mode2D3DShift = 31, + e_Mode2D3DMask = 0x1 << e_Mode2D3DShift, - //////////////////////////////////////////////////////////////////////// - SingleColorDynamicSizeLineHelper::SingleColorDynamicSizeLineHelper( - int estimatedNumLineSegments - ) + e_AlphaBlendingShift = 29, + e_AlphaBlendingMask = 0x3 << e_AlphaBlendingShift, + + e_DrawInFrontShift = 28, + e_DrawInFrontMask = 0x1 << e_DrawInFrontShift, + + e_FillModeShift = 26, + e_FillModeMask = 0x3 << e_FillModeShift, + + e_CullModeShift = 24, + e_CullModeMask = 0x3 << e_CullModeShift, + + e_DepthWriteShift = 23, + e_DepthWriteMask = 0x1 << e_DepthWriteShift, + + e_DepthTestShift = 22, + e_DepthTestMask = 0x1 << e_DepthTestShift, + + e_PublicParamsMask = e_Mode2D3DMask | e_AlphaBlendingMask | e_DrawInFrontMask | e_FillModeMask | + e_CullModeMask | e_DepthWriteMask | e_DepthTestMask + }; + + // Notes: + // e_Mode2D renders in normalized [0.. 1] screen space. + // Don't change the xxxShift values blindly as they affect the rendering output + // that is two primitives have to be rendered after 3d primitives, alpha blended + // geometry have to be rendered after opaque ones, etc. + // This also applies to the individual flags in EAuxGeomPublicRenderflagBitMasks! + // Remarks: + // Bits 0 - 22 are currently reserved for prim type and per draw call render parameters (point size, etc.) + // Check RenderAuxGeom.h in ../RenderDll/Common + // See also: + // EAuxGeomPublicRenderflagBitMasks + enum EAuxGeomPublicRenderflags_Mode2D3D + { + e_Mode3D = 0x0 << e_Mode2D3DShift, + e_Mode2D = 0x1 << e_Mode2D3DShift, + }; + + // Notes: + // Don't change the xxxShift values blindly as they affect the rendering output + // that is two primitives have to be rendered after 3d primitives, alpha blended + // geometry have to be rendered after opaque ones, etc. + // This also applies to the individual flags in EAuxGeomPublicRenderflagBitMasks! + // Remarks: + // Bits 0 - 22 are currently reserved for prim type and per draw call render parameters (point size, etc.) + // Check RenderAuxGeom.h in ../RenderDll/Common + // See also: + // EAuxGeomPublicRenderflagBitMasks + enum EAuxGeomPublicRenderflags_AlphaBlendMode + { + e_AlphaNone = 0x0 << e_AlphaBlendingShift, + e_AlphaAdditive = 0x1 << e_AlphaBlendingShift, + e_AlphaBlended = 0x2 << e_AlphaBlendingShift, + }; + + // Notes: + // Don't change the xxxShift values blindly as they affect the rendering output + // that is two primitives have to be rendered after 3d primitives, alpha blended + // geometry have to be rendered after opaque ones, etc. + // This also applies to the individual flags in EAuxGeomPublicRenderflagBitMasks! + // Remarks: + // Bits 0 - 22 are currently reserved for prim type and per draw call render parameters (point size, etc.) + // Check RenderAuxGeom.h in ../RenderDll/Common + // See also: + // EAuxGeomPublicRenderflagBitMasks + enum EAuxGeomPublicRenderflags_DrawInFrontMode + { + e_DrawInFrontOff = 0x0 << e_DrawInFrontShift, + e_DrawInFrontOn = 0x1 << e_DrawInFrontShift, + }; + + // Notes: + // Don't change the xxxShift values blindly as they affect the rendering output + // that is two primitives have to be rendered after 3d primitives, alpha blended + // geometry have to be rendered after opaque ones, etc. + // This also applies to the individual flags in EAuxGeomPublicRenderflagBitMasks! + // Remarks: + // Bits 0 - 22 are currently reserved for prim type and per draw call render parameters (point size, etc.) + // Check RenderAuxGeom.h in ../RenderDll/Common + // See also: + // EAuxGeomPublicRenderflagBitMasks + enum EAuxGeomPublicRenderflags_FillMode + { + e_FillModeSolid = 0x0 << e_FillModeShift, + e_FillModeWireframe = 0x1 << e_FillModeShift, + e_FillModePoint = 0x2 << e_FillModeShift, + }; + + // Notes: + // Don't change the xxxShift values blindly as they affect the rendering output + // that is two primitives have to be rendered after 3d primitives, alpha blended + // geometry have to be rendered after opaque ones, etc. + // This also applies to the individual flags in EAuxGeomPublicRenderflagBitMasks! + // Remarks: + // Bits 0 - 22 are currently reserved for prim type and per draw call render parameters (point size, etc.) + // Check RenderAuxGeom.h in ../RenderDll/Common + // See also: + // EAuxGeomPublicRenderflagBitMasks + enum EAuxGeomPublicRenderflags_CullMode + { + e_CullModeNone = 0x0 << e_CullModeShift, + e_CullModeFront = 0x1 << e_CullModeShift, + e_CullModeBack = 0x2 << e_CullModeShift, + }; + + // Notes: + // Don't change the xxxShift values blindly as they affect the rendering output + // that is two primitives have to be rendered after 3d primitives, alpha blended + // geometry have to be rendered after opaque ones, etc. + // This also applies to the individual flags in EAuxGeomPublicRenderflagBitMasks! + // Remarks: + // Bits 0 - 22 are currently reserved for prim type and per draw call render parameters (point size, etc.) + // Check RenderAuxGeom.h in ../RenderDll/Common + // See also: + // EAuxGeomPublicRenderflagBitMasks + enum EAuxGeomPublicRenderflags_DepthWrite + { + e_DepthWriteOn = 0x0 << e_DepthWriteShift, + e_DepthWriteOff = 0x1 << e_DepthWriteShift, + }; + + // Notes: + // Don't change the xxxShift values blindly as they affect the rendering output + // that is two primitives have to be rendered after 3d primitives, alpha blended + // geometry have to be rendered after opaque ones, etc. + // This also applies to the individual flags in EAuxGeomPublicRenderflagBitMasks! + // Remarks: + // Bits 0 - 22 are currently reserved for prim type and per draw call render parameters (point size, etc.) + // Check RenderAuxGeom.h in ../RenderDll/Common + // See also: + // EAuxGeomPublicRenderflagBitMasks + enum EAuxGeomPublicRenderflags_DepthTest + { + e_DepthTestOn = 0x0 << e_DepthTestShift, + e_DepthTestOff = 0x1 << e_DepthTestShift, + }; +}; + +namespace AZ::AtomBridge +{ + + //////////////////////////////////////////////////////////////////////// + SingleColorDynamicSizeLineHelper::SingleColorDynamicSizeLineHelper( + int estimatedNumLineSegments + ) + { + m_points.reserve(estimatedNumLineSegments * 2); + } + + void SingleColorDynamicSizeLineHelper::AddLineSegment( + const AZ::Vector3& lineStart, + const AZ::Vector3& lineEnd + ) + { + m_points.push_back(lineStart); + m_points.push_back(lineEnd); + } + + void SingleColorDynamicSizeLineHelper::Draw( + AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, + const RenderState& rendState + ) const + { + if (auxGeomDrawPtr && !m_points.empty()) { - m_points.reserve(estimatedNumLineSegments * 2); + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = m_points.data(); + drawArgs.m_vertCount = aznumeric_cast(m_points.size()); + drawArgs.m_colors = &rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_size = rendState.m_lineWidth; + drawArgs.m_opacityType = rendState.m_opacityType; + drawArgs.m_depthTest = rendState.m_depthTest; + drawArgs.m_depthWrite = rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = rendState.m_viewProjOverrideIndex; + auxGeomDrawPtr->DrawLines( drawArgs ); } + } - void SingleColorDynamicSizeLineHelper::AddLineSegment( - const AZ::Vector3& lineStart, - const AZ::Vector3& lineEnd - ) + void SingleColorDynamicSizeLineHelper::Draw2d( + AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, + const RenderState& rendState + ) const + { + if (auxGeomDrawPtr && !m_points.empty()) { - m_points.push_back(lineStart); - m_points.push_back(lineEnd); + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = m_points.data(); + drawArgs.m_vertCount = aznumeric_cast(m_points.size()); + drawArgs.m_colors = &rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_size = rendState.m_lineWidth; + drawArgs.m_opacityType = rendState.m_opacityType; + drawArgs.m_depthTest = rendState.m_depthTest; + drawArgs.m_depthWrite = rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = auxGeomDrawPtr->GetOrAdd2DViewProjOverride(); + auxGeomDrawPtr->DrawLines( drawArgs ); } + } - void SingleColorDynamicSizeLineHelper::Draw( - AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, - const RenderState& rendState - ) const - { - if (auxGeomDrawPtr && !m_points.empty()) - { - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = m_points.data(); - drawArgs.m_vertCount = aznumeric_cast(m_points.size()); - drawArgs.m_colors = &rendState.m_color; - drawArgs.m_colorCount = 1; - drawArgs.m_size = rendState.m_lineWidth; - drawArgs.m_opacityType = rendState.m_opacityType; - drawArgs.m_depthTest = rendState.m_depthTest; - drawArgs.m_depthWrite = rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = rendState.m_viewProjOverrideIndex; - auxGeomDrawPtr->DrawLines( drawArgs ); - } - } + void SingleColorDynamicSizeLineHelper::Reset() + { + m_points.clear(); + } + //////////////////////////////////////////////////////////////////////// - void SingleColorDynamicSizeLineHelper::Reset() + // Partial implementation of the DebugDisplayRequestBus on Atom. + // Commented out function prototypes are waiting to be implemented. + // work tracked in [ATOM-3459] + AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(AZ::RPI::ViewportContextPtr viewportContextPtr) + { + ResetRenderState(); + m_viewportId = viewportContextPtr->GetId(); + m_defaultInstance = false; + auto setupScene = [this](RPI::ScenePtr scene) { - m_points.clear(); - } - //////////////////////////////////////////////////////////////////////// + auto viewportContextManager = AZ::Interface::Get(); + AZ::RPI::ViewportContextPtr viewportContextPtr = viewportContextManager->GetViewportContextById(m_viewportId); + InitInternal(scene.get(), viewportContextPtr); + }; + setupScene(viewportContextPtr->GetRenderScene()); + m_sceneChangeHandler = AZ::RPI::ViewportContext::SceneChangedEvent::Handler(setupScene); + viewportContextPtr->ConnectSceneChangedHandler(m_sceneChangeHandler); + } - // Partial implementation of the DebugDisplayRequestBus on Atom. - // Commented out function prototypes are waiting to be implemented. - // work tracked in [ATOM-3459] - AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(AZ::RPI::ViewportContextPtr viewportContextPtr) - { - ResetRenderState(); - m_viewportId = viewportContextPtr->GetId(); - m_defaultInstance = false; - auto setupScene = [this](RPI::ScenePtr scene) - { - auto viewportContextManager = AZ::Interface::Get(); - AZ::RPI::ViewportContextPtr viewportContextPtr = viewportContextManager->GetViewportContextById(m_viewportId); - InitInternal(scene.get(), viewportContextPtr); - }; - setupScene(viewportContextPtr->GetRenderScene()); - m_sceneChangeHandler = AZ::RPI::ViewportContext::SceneChangedEvent::Handler(setupScene); - viewportContextPtr->ConnectSceneChangedHandler(m_sceneChangeHandler); - } + AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress) + { + ResetRenderState(); + m_viewportId = defaultInstanceAddress; + m_defaultInstance = true; + RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get(); + InitInternal(scene, nullptr); + } - AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress) + void AtomDebugDisplayViewportInterface::InitInternal(RPI::Scene* scene, AZ::RPI::ViewportContextPtr viewportContextPtr) + { + AzFramework::DebugDisplayRequestBus::Handler::BusDisconnect(m_viewportId); + if (!scene) { - ResetRenderState(); - m_viewportId = defaultInstanceAddress; - m_defaultInstance = true; - RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get(); - InitInternal(scene, nullptr); - } - - void AtomDebugDisplayViewportInterface::InitInternal(RPI::Scene* scene, AZ::RPI::ViewportContextPtr viewportContextPtr) - { - AzFramework::DebugDisplayRequestBus::Handler::BusDisconnect(m_viewportId); - if (!scene) - { - m_auxGeomPtr = nullptr; - return; - } - auto auxGeomFP = scene->GetFeatureProcessor(); - if (!auxGeomFP) - { - m_auxGeomPtr = nullptr; - return; - } - if (m_defaultInstance) - { - m_auxGeomPtr = auxGeomFP->GetDrawQueue(); - } - else - { - m_auxGeomPtr = auxGeomFP->GetOrCreateDrawQueueForView(viewportContextPtr->GetDefaultView().get()); - } - AzFramework::DebugDisplayRequestBus::Handler::BusConnect(m_viewportId); - } - - AtomDebugDisplayViewportInterface::~AtomDebugDisplayViewportInterface() - { - AzFramework::DebugDisplayRequestBus::Handler::BusDisconnect(m_viewportId); - m_viewportId = AzFramework::InvalidViewportId; m_auxGeomPtr = nullptr; + return; + } + auto auxGeomFP = scene->GetFeatureProcessor(); + if (!auxGeomFP) + { + m_auxGeomPtr = nullptr; + return; + } + if (m_defaultInstance) + { + m_auxGeomPtr = auxGeomFP->GetDrawQueue(); + } + else + { + m_auxGeomPtr = auxGeomFP->GetOrCreateDrawQueueForView(viewportContextPtr->GetDefaultView().get()); + } + AzFramework::DebugDisplayRequestBus::Handler::BusConnect(m_viewportId); + } + + AtomDebugDisplayViewportInterface::~AtomDebugDisplayViewportInterface() + { + AzFramework::DebugDisplayRequestBus::Handler::BusDisconnect(m_viewportId); + m_viewportId = AzFramework::InvalidViewportId; + m_auxGeomPtr = nullptr; + } + + void AtomDebugDisplayViewportInterface::ResetRenderState() + { + m_rendState = RenderState(); + for (int index = 0; index < RenderState::TransformStackSize; ++index) + { + m_rendState.m_transformStack[index] = AZ::Matrix3x4::Identity(); + } + } + + void AtomDebugDisplayViewportInterface::SetColor(float r, float g, float b, float a) + { + m_rendState.m_color = AZ::Color(r, g, b, a); + } + + void AtomDebugDisplayViewportInterface::SetColor(const AZ::Color& color) + { + m_rendState.m_color = color; + } + + void AtomDebugDisplayViewportInterface::SetColor(const AZ::Vector4& color) + { + m_rendState.m_color = AZ::Color(color); + } + + void AtomDebugDisplayViewportInterface::SetAlpha(float a) + { + m_rendState.m_color.SetA(a); + if (a < 1.0f) + { + m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Opaque; + } + else + { + m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Translucent; + } + } + + void AtomDebugDisplayViewportInterface::DrawQuad( + const AZ::Vector3& p1, + const AZ::Vector3& p2, + const AZ::Vector3& p3, + const AZ::Vector3& p4) + { + if (m_auxGeomPtr) + { + AZ::Vector3 wsPoints[4] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3), ToWorldSpacePosition(p4) }; + AZ::Vector3 triangles[6]; + triangles[0] = wsPoints[0]; + triangles[1] = wsPoints[1]; + triangles[2] = wsPoints[2]; + triangles[3] = wsPoints[2]; + triangles[4] = wsPoints[3]; + triangles[5] = wsPoints[0]; + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = triangles; + drawArgs.m_vertCount = 6; + drawArgs.m_colors = &m_rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawTriangles(drawArgs); + } + } + + void AtomDebugDisplayViewportInterface::DrawQuad(float width, float height) + { + if (!m_auxGeomPtr || width <= 0.0f || height <= 0.0f) + { + return; } - void AtomDebugDisplayViewportInterface::ResetRenderState() + m_auxGeomPtr->DrawQuad( + width, + height, + GetCurrentTransform(), + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Shaded, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex); + } + + void AtomDebugDisplayViewportInterface::DrawWireQuad( + const AZ::Vector3& p1, + const AZ::Vector3& p2, + const AZ::Vector3& p3, + const AZ::Vector3& p4) + { + if (m_auxGeomPtr) { - m_rendState = RenderState(); - for (int index = 0; index < RenderState::TransformStackSize; ++index) + AZ::Vector3 wsPoints[4] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3), ToWorldSpacePosition(p4) }; + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = wsPoints; + drawArgs.m_vertCount = 4; + drawArgs.m_colors = &m_rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawPolylines(drawArgs, AZ::RPI::AuxGeomDraw::PolylineEnd::Closed); + } + } + + void AtomDebugDisplayViewportInterface::DrawWireQuad(float width, float height) + { + if (!m_auxGeomPtr || width <= 0.0f || height <= 0.0f) + { + return; + } + + m_auxGeomPtr->DrawQuad( + width, + height, + GetCurrentTransform(), + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Line, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex); + } + + void AtomDebugDisplayViewportInterface::DrawQuadGradient( + const AZ::Vector3& p1, + const AZ::Vector3& p2, + const AZ::Vector3& p3, + const AZ::Vector3& p4, + const AZ::Vector4& firstColor, + const AZ::Vector4& secondColor) + { + if (m_auxGeomPtr) + { + AZ::Vector3 wsPoints[4] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3), ToWorldSpacePosition(p4) }; + AZ::Vector3 triangles[6]; + AZ::Color colors[6]; + triangles[0] = wsPoints[0]; colors[0] = firstColor; + triangles[1] = wsPoints[1]; colors[1] = firstColor; + triangles[2] = wsPoints[2]; colors[2] = secondColor; + triangles[3] = wsPoints[2]; colors[3] = secondColor; + triangles[4] = wsPoints[3]; colors[4] = secondColor; + triangles[5] = wsPoints[0]; colors[5] = firstColor; + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = triangles; + drawArgs.m_vertCount = 6; + drawArgs.m_colors = colors; + drawArgs.m_colorCount = 6; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawTriangles(drawArgs); + } + } + + void AtomDebugDisplayViewportInterface::DrawTri(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3) + { + if (m_auxGeomPtr) + { + AZ::Vector3 verts[3] = {ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3)}; + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = verts; + drawArgs.m_vertCount = 3; + drawArgs.m_colors = &m_rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawTriangles(drawArgs); + } + } + + void AtomDebugDisplayViewportInterface::DrawTriangles(const AZStd::vector& vertices, const AZ::Color& color) + { + if (m_auxGeomPtr) + { + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = vertices.data(); + drawArgs.m_vertCount = aznumeric_cast(vertices.size()); + drawArgs.m_colors = &color; + drawArgs.m_colorCount = 1; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawTriangles(drawArgs); + } + } + + void AtomDebugDisplayViewportInterface::DrawTrianglesIndexed( + const AZStd::vector& vertices, + const AZStd::vector& indices, + const AZ::Color& color) + { + if (m_auxGeomPtr) + { + AZ::RPI::AuxGeomDraw::AuxGeomDynamicIndexedDrawArguments drawArgs; + drawArgs.m_verts = vertices.data(); + drawArgs.m_vertCount = aznumeric_cast(vertices.size()); + drawArgs.m_indices = indices.data(); + drawArgs.m_indexCount = aznumeric_cast(indices.size()); + drawArgs.m_colors = &color; + drawArgs.m_colorCount = 1; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawTriangles(drawArgs); + } + } + + void AtomDebugDisplayViewportInterface::DrawWireBox(const AZ::Vector3& min, const AZ::Vector3& max) + { + if (m_auxGeomPtr) + { + m_auxGeomPtr->DrawAabb( + AZ::Aabb::CreateFromMinMax(min, max), + GetCurrentTransform(), + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Line, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex + ); + } + } + + void AtomDebugDisplayViewportInterface::DrawSolidBox(const AZ::Vector3& min, const AZ::Vector3& max) + { + if (m_auxGeomPtr) + { + m_auxGeomPtr->DrawAabb( + AZ::Aabb::CreateFromMinMax(min, max), + GetCurrentTransform(), + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Solid, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex); + } + } + + void AtomDebugDisplayViewportInterface::DrawSolidOBB( + const AZ::Vector3& center, + const AZ::Vector3& axisX, + const AZ::Vector3& axisY, + const AZ::Vector3& axisZ, + const AZ::Vector3& halfExtents) + { + if (m_auxGeomPtr) + { + AZ::Quaternion rotation = AZ::Quaternion::CreateFromMatrix3x3(AZ::Matrix3x3::CreateFromColumns(axisX, axisY, axisZ)); + AZ::Obb obb = AZ::Obb::CreateFromPositionRotationAndHalfLengths(center, rotation, halfExtents); + m_auxGeomPtr->DrawObb( + obb, + AZ::Vector3::CreateZero(), + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Solid, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex); + } + } + + void AtomDebugDisplayViewportInterface::DrawPoint(const AZ::Vector3& p, int nSize) + { + if (m_auxGeomPtr) + { + AZ::Vector3 wsPoint = ToWorldSpacePosition(p); + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = &wsPoint; + drawArgs.m_vertCount = 1; + drawArgs.m_colors = &m_rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_size = aznumeric_cast(nSize); + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawPoints(drawArgs); + } + } + + void AtomDebugDisplayViewportInterface::DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2) + { + if (m_auxGeomPtr) + { + AZ::Vector3 verts[2] = {ToWorldSpacePosition(p1), ToWorldSpacePosition(p2)}; + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = verts; + drawArgs.m_vertCount = 2; + drawArgs.m_colors = &m_rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_size = m_rendState.m_lineWidth; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawLines(drawArgs); + } + } + + void AtomDebugDisplayViewportInterface::DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector4& col1, const AZ::Vector4& col2) + { + if (m_auxGeomPtr) + { + AZ::Vector3 verts[2] = {ToWorldSpacePosition(p1), ToWorldSpacePosition(p2)}; + AZ::Color colors[2] = {col1, col2}; + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = verts; + drawArgs.m_vertCount = 2; + drawArgs.m_colors = colors; + drawArgs.m_colorCount = 2; + drawArgs.m_size = m_rendState.m_lineWidth; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawLines(drawArgs); + } + } + + void AtomDebugDisplayViewportInterface::DrawLines(const AZStd::vector& lines, const AZ::Color& color) + { + if (m_auxGeomPtr) + { + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = lines.data(); + drawArgs.m_vertCount = aznumeric_cast(lines.size()); + drawArgs.m_colors = &color; + drawArgs.m_colorCount = 1; + drawArgs.m_size = m_rendState.m_lineWidth; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawLines(drawArgs); + } + } + + void AtomDebugDisplayViewportInterface::DrawPolyLine(const AZ::Vector3* pnts, int numPoints, bool cycled) + { + if (m_auxGeomPtr) + { + AZStd::vector wsPoints(static_cast(numPoints)); + for (int index = 0; index < numPoints; ++index) { - m_rendState.m_transformStack[index] = AZ::Matrix3x4::Identity(); + wsPoints[index] = ToWorldSpacePosition(pnts[index]); } + AZ::RPI::AuxGeomDraw::PolylineEnd polylineEnd = cycled ? AZ::RPI::AuxGeomDraw::PolylineEnd::Closed : AZ::RPI::AuxGeomDraw::PolylineEnd::Open; + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = wsPoints.data(); + drawArgs.m_vertCount = aznumeric_cast(numPoints); + drawArgs.m_colors = &m_rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_size = m_rendState.m_lineWidth; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + m_auxGeomPtr->DrawPolylines(drawArgs, polylineEnd); } + } - void AtomDebugDisplayViewportInterface::SetColor(float r, float g, float b, float a) + void AtomDebugDisplayViewportInterface::DrawWireQuad2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) + { + if (m_auxGeomPtr) { - m_rendState.m_color = AZ::Color(r, g, b, a); + AZ::Vector3 points[4]; + points[0] = AZ::Vector3(p1.GetX(), p1.GetY(), z); + points[1] = AZ::Vector3(p2.GetX(), p1.GetY(), z); + points[2] = AZ::Vector3(p2.GetX(), p2.GetY(), z); + points[3] = AZ::Vector3(p1.GetX(), p2.GetY(), z); + + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = points; + drawArgs.m_vertCount = 4; + drawArgs.m_colors = &m_rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_size = m_rendState.m_lineWidth; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_auxGeomPtr->GetOrAdd2DViewProjOverride(); + m_auxGeomPtr->DrawPolylines(drawArgs, AZ::RPI::AuxGeomDraw::PolylineEnd::Closed); } + } - void AtomDebugDisplayViewportInterface::SetColor(const AZ::Color& color) + void AtomDebugDisplayViewportInterface::DrawLine2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) + { + if (m_auxGeomPtr) { - m_rendState.m_color = color; + AZ::Vector3 points[2]; + points[0] = AZ::Vector3(p1.GetX(), p1.GetY(), z); + points[1] = AZ::Vector3(p2.GetX(), p2.GetY(), z); + + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = points; + drawArgs.m_vertCount = 2; + drawArgs.m_colors = &m_rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_size = m_rendState.m_lineWidth; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_auxGeomPtr->GetOrAdd2DViewProjOverride(); + m_auxGeomPtr->DrawLines(drawArgs); } + } - void AtomDebugDisplayViewportInterface::SetColor(const AZ::Vector4& color) + void AtomDebugDisplayViewportInterface::DrawLine2dGradient(const AZ::Vector2& p1, const AZ::Vector2& p2, float z, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor) + { + if (m_auxGeomPtr) { - m_rendState.m_color = AZ::Color(color); + AZ::Vector3 points[2]; + points[0] = AZ::Vector3(p1.GetX(), p1.GetY(), z); + points[1] = AZ::Vector3(p2.GetX(), p2.GetY(), z); + AZ::Color colors[2] = {firstColor, secondColor}; + + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = points; + drawArgs.m_vertCount = 2; + drawArgs.m_colors = colors; + drawArgs.m_colorCount = 2; + drawArgs.m_size = m_rendState.m_lineWidth; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_auxGeomPtr->GetOrAdd2DViewProjOverride(); + m_auxGeomPtr->DrawLines(drawArgs); } + } - void AtomDebugDisplayViewportInterface::SetAlpha(float a) + void AtomDebugDisplayViewportInterface::DrawWireCircle2d(const AZ::Vector2& center, float radius, float z) + { + if (m_auxGeomPtr) { - m_rendState.m_color.SetA(a); - if (a < 1.0f) + // Draw axis aligned arc + constexpr float angularStepDegrees = 10.0f; + constexpr float startAngleDegrees = 0.0f; + constexpr float sweepAngleDegrees = 360.0f; + const float stepAngle = DegToRad(angularStepDegrees); + const float startAngle = DegToRad(startAngleDegrees); + const float stopAngle = DegToRad(sweepAngleDegrees) + startAngle; + SingleColorDynamicSizeLineHelper lines(1+static_cast(sweepAngleDegrees/angularStepDegrees)); + AZ::Vector3 radiusV3 = AZ::Vector3(radius); + AZ::Vector3 pos = AZ::Vector3(center.GetX(), center.GetY(), z); + CreateAxisAlignedArc( + lines, + stepAngle, + startAngle, + stopAngle, + pos, + radiusV3, + CircleAxis::CircleAxisZ + ); + lines.Draw2d(m_auxGeomPtr, m_rendState); + } + } + + void AtomDebugDisplayViewportInterface::DrawArc( + const AZ::Vector3& pos, + float radius, + float startAngleDegrees, + float sweepAngleDegrees, + float angularStepDegrees, + int referenceAxis) + { + if (m_auxGeomPtr) + { + // Draw axis aligned arc + const float stepAngle = DegToRad(angularStepDegrees); + const float startAngle = DegToRad(startAngleDegrees); + const float stopAngle = DegToRad(sweepAngleDegrees) + startAngle; + SingleColorDynamicSizeLineHelper lines(1+static_cast(sweepAngleDegrees/angularStepDegrees)); + AZ::Vector3 radiusV3 = AZ::Vector3(radius); + CreateAxisAlignedArc( + lines, + stepAngle, + startAngle, + stopAngle, + pos, + radiusV3, + static_cast(referenceAxis) + ); + lines.Draw(m_auxGeomPtr, m_rendState); + } + } + + void AtomDebugDisplayViewportInterface::DrawArc( + const AZ::Vector3& pos, + float radius, + float startAngleDegrees, + float sweepAngleDegrees, + float angularStepDegrees, + const AZ::Vector3& fixedAxis) + { + if (m_auxGeomPtr) + { + // Draw arbitraty axis arc + const float stepAngle = DegToRad(angularStepDegrees); + const float startAngle = DegToRad(startAngleDegrees); + const float stopAngle = DegToRad(sweepAngleDegrees) + startAngle; + SingleColorDynamicSizeLineHelper lines(1+static_cast(sweepAngleDegrees/angularStepDegrees)); + AZ::Vector3 radiusV3 = AZ::Vector3(radius); + CreateArbitraryAxisArc( + lines, + stepAngle, + startAngle, + stopAngle, + pos, + radiusV3, + fixedAxis + ); + lines.Draw(m_auxGeomPtr, m_rendState); + } + } + + void AtomDebugDisplayViewportInterface::DrawCircle(const AZ::Vector3& pos, float radius, int nUnchangedAxis) + { + if (m_auxGeomPtr) + { + // Draw circle with default radius. + const float step = DegToRad(10.0f); + const float maxAngle = DegToRad(360.0f) + step; + SingleColorStaticSizeLineHelper<40> lines; // hard code 40 lines until DegToRad is constexpr. + AZ::Vector3 radiusV3 = AZ::Vector3(radius); + CreateAxisAlignedArc( + lines, + step, + 0.0f, + maxAngle, + pos, + radiusV3, + static_cast(nUnchangedAxis)); + lines.Draw(m_auxGeomPtr, m_rendState); + } + } + + void AtomDebugDisplayViewportInterface::DrawHalfDottedCircle(const AZ::Vector3& pos, float radius, const AZ::Vector3& viewPos, int nUnchangedAxis) + { + if (m_auxGeomPtr) + { + // Draw circle with single radius. + const float step = DegToRad(10.0f); + const float maxAngle = DegToRad(360.0f) + step; + SingleColorStaticSizeLineHelper<40> lines; // hard code 40 lines until DegToRad is constexpr. + + AZ::Vector3 radiusV3 = AZ::Vector3(radius); + const AZ::Vector3 worldPos = ToWorldSpacePosition(pos); + const AZ::Vector3 worldView = ToWorldSpacePosition(viewPos); + const AZ::Vector3 worldDir = worldView - worldPos; + + CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, radiusV3, static_cast(nUnchangedAxis%CircleAxisMax), + [&worldPos, &worldDir](const AZ::Vector3& lineStart, const AZ::Vector3& lineEnd, int segmentIndex) + { + AZ_UNUSED(lineEnd); + const float dot = (lineStart - worldPos).Dot(worldDir); + const bool facing = dot > 0.0f; + // if so skip every other line to produce a dotted effect + if (facing || segmentIndex % 2 == 0) + { + return true; + } + return false; + }); + lines.Draw(m_auxGeomPtr, m_rendState); + } + } + + void AtomDebugDisplayViewportInterface::DrawCone(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius, float height, bool drawShaded) + { + if (m_auxGeomPtr) + { + const AZ::Vector3 worldPos = ToWorldSpacePosition(pos); + const AZ::Vector3 worldDir = ToWorldSpaceVector(dir); + m_auxGeomPtr->DrawCone( + worldPos, + worldDir, + radius, + height, + m_rendState.m_color, + drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex + ); + } + } + + void AtomDebugDisplayViewportInterface::DrawWireCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height) + { + if (m_auxGeomPtr) + { + const AZ::Vector3 worldCenter = ToWorldSpacePosition(center); + const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis); + m_auxGeomPtr->DrawCylinder( + worldCenter, + worldAxis, + radius, + height, + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Line, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex + ); + } + } + + void AtomDebugDisplayViewportInterface::DrawSolidCylinder( + const AZ::Vector3& center, + const AZ::Vector3& axis, + float radius, + float height, + bool drawShaded) + { + if (m_auxGeomPtr) + { + const AZ::Vector3 worldCenter = ToWorldSpacePosition(center); + const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis); + m_auxGeomPtr->DrawCylinder( + worldCenter, + worldAxis, + radius, + height, + m_rendState.m_color, + drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex + ); + } + } + + void AtomDebugDisplayViewportInterface::DrawWireCapsule( + const AZ::Vector3& center, + const AZ::Vector3& axis, + float radius, + float heightStraightSection) + { + if (m_auxGeomPtr && radius > FLT_EPSILON && axis.GetLengthSq() > FLT_EPSILON) + { + AZ::Vector3 axisNormalized = axis.GetNormalizedEstimate(); + SingleColorStaticSizeLineHelper<(16+1) * 5> lines; // 360/22.5 = 16, 5 possible calls to CreateArbitraryAxisArc + AZ::Vector3 radiusV3 = AZ::Vector3(radius); + float stepAngle = DegToRad(22.5f); + float Deg0 = DegToRad(0.0f); + + + // Draw cylinder part (or just a circle around the middle) + if (heightStraightSection > FLT_EPSILON) { - m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Opaque; + DrawWireCylinder(center, axis, radius, heightStraightSection); } else { - m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Translucent; - } - } - - void AtomDebugDisplayViewportInterface::DrawQuad( - const AZ::Vector3& p1, - const AZ::Vector3& p2, - const AZ::Vector3& p3, - const AZ::Vector3& p4) - { - if (m_auxGeomPtr) - { - AZ::Vector3 wsPoints[4] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3), ToWorldSpacePosition(p4) }; - AZ::Vector3 triangles[6]; - triangles[0] = wsPoints[0]; - triangles[1] = wsPoints[1]; - triangles[2] = wsPoints[2]; - triangles[3] = wsPoints[2]; - triangles[4] = wsPoints[3]; - triangles[5] = wsPoints[0]; - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = triangles; - drawArgs.m_vertCount = 6; - drawArgs.m_colors = &m_rendState.m_color; - drawArgs.m_colorCount = 1; - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - m_auxGeomPtr->DrawTriangles(drawArgs); - } - } - - // void DrawQuad(float width, float height) override - // void DrawWireQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4) override; - // void DrawWireQuad(float width, float height) override; - - void AtomDebugDisplayViewportInterface::DrawQuadGradient( - const AZ::Vector3& p1, - const AZ::Vector3& p2, - const AZ::Vector3& p3, - const AZ::Vector3& p4, - const AZ::Vector4& firstColor, - const AZ::Vector4& secondColor) - { - if (m_auxGeomPtr) - { - AZ::Vector3 wsPoints[4] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3), ToWorldSpacePosition(p4) }; - AZ::Vector3 triangles[6]; - AZ::Color colors[6]; - triangles[0] = wsPoints[0]; colors[0] = firstColor; - triangles[1] = wsPoints[1]; colors[1] = firstColor; - triangles[2] = wsPoints[2]; colors[2] = secondColor; - triangles[3] = wsPoints[2]; colors[3] = secondColor; - triangles[4] = wsPoints[3]; colors[4] = secondColor; - triangles[5] = wsPoints[0]; colors[5] = firstColor; - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = triangles; - drawArgs.m_vertCount = 6; - drawArgs.m_colors = colors; - drawArgs.m_colorCount = 6; - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - m_auxGeomPtr->DrawTriangles(drawArgs); - } - } - - void AtomDebugDisplayViewportInterface::DrawTri(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3) - { - if (m_auxGeomPtr) - { - AZ::Vector3 verts[3] = {ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3)}; - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = verts; - drawArgs.m_vertCount = 3; - drawArgs.m_colors = &m_rendState.m_color; - drawArgs.m_colorCount = 1; - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - m_auxGeomPtr->DrawTriangles(drawArgs); - } - } - - void AtomDebugDisplayViewportInterface::DrawTriangles(const AZStd::vector& vertices, const AZ::Color& color) - { - if (m_auxGeomPtr) - { - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = vertices.data(); - drawArgs.m_vertCount = aznumeric_cast(vertices.size()); - drawArgs.m_colors = &color; - drawArgs.m_colorCount = 1; - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - m_auxGeomPtr->DrawTriangles(drawArgs); - } - } - - void AtomDebugDisplayViewportInterface::DrawTrianglesIndexed( - const AZStd::vector& vertices, - const AZStd::vector& indices, - const AZ::Color& color) - { - if (m_auxGeomPtr) - { - AZ::RPI::AuxGeomDraw::AuxGeomDynamicIndexedDrawArguments drawArgs; - drawArgs.m_verts = vertices.data(); - drawArgs.m_vertCount = aznumeric_cast(vertices.size()); - drawArgs.m_indices = indices.data(); - drawArgs.m_indexCount = aznumeric_cast(indices.size()); - drawArgs.m_colors = &color; - drawArgs.m_colorCount = 1; - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - m_auxGeomPtr->DrawTriangles(drawArgs); - } - } - - void AtomDebugDisplayViewportInterface::DrawWireBox(const AZ::Vector3& min, const AZ::Vector3& max) - { - if (m_auxGeomPtr) - { - m_auxGeomPtr->DrawAabb( - AZ::Aabb::CreateFromMinMax(min, max), - GetCurrentTransform(), - m_rendState.m_color, - AZ::RPI::AuxGeomDraw::DrawStyle::Line, - m_rendState.m_depthTest, - m_rendState.m_depthWrite, - m_rendState.m_faceCullMode, - m_rendState.m_viewProjOverrideIndex + float Deg360 = DegToRad(360.0f); + CreateArbitraryAxisArc( + lines, + stepAngle, + Deg0, + Deg360, + center, + radiusV3, + axisNormalized ); } - } - void AtomDebugDisplayViewportInterface::DrawSolidBox(const AZ::Vector3& min, const AZ::Vector3& max) - { - if (m_auxGeomPtr) - { - m_auxGeomPtr->DrawAabb( - AZ::Aabb::CreateFromMinMax(min, max), - GetCurrentTransform(), - m_rendState.m_color, - AZ::RPI::AuxGeomDraw::DrawStyle::Solid, - m_rendState.m_depthTest, - m_rendState.m_depthWrite, - m_rendState.m_faceCullMode, - m_rendState.m_viewProjOverrideIndex); - } - } + float Deg90 = DegToRad(90.0f); + float Deg180 = DegToRad(180.0f); - void AtomDebugDisplayViewportInterface::DrawSolidOBB( - const AZ::Vector3& center, - const AZ::Vector3& axisX, - const AZ::Vector3& axisY, - const AZ::Vector3& axisZ, - const AZ::Vector3& halfExtents) - { - if (m_auxGeomPtr) - { - AZ::Quaternion rotation = AZ::Quaternion::CreateFromMatrix3x3(AZ::Matrix3x3::CreateFromColumns(axisX, axisY, axisZ)); - AZ::Obb obb = AZ::Obb::CreateFromPositionRotationAndHalfLengths(center, rotation, halfExtents); - m_auxGeomPtr->DrawObb( - obb, - AZ::Vector3::CreateZero(), - m_rendState.m_color, - AZ::RPI::AuxGeomDraw::DrawStyle::Solid, - m_rendState.m_depthTest, - m_rendState.m_depthWrite, - m_rendState.m_faceCullMode, - m_rendState.m_viewProjOverrideIndex); - } - } + AZ::Vector3 ortho1Normalized, ortho2Normalized; + CalcBasisVectors(axisNormalized, ortho1Normalized, ortho2Normalized); + AZ::Vector3 centerToTopCircleCenter = axisNormalized * heightStraightSection * 0.5f; + AZ::Vector3 topCenter = center + centerToTopCircleCenter; + AZ::Vector3 bottomCenter = center - centerToTopCircleCenter; - void AtomDebugDisplayViewportInterface::DrawPoint(const AZ::Vector3& p, int nSize) - { - if (m_auxGeomPtr) - { - AZ::Vector3 wsPoint = ToWorldSpacePosition(p); - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = &wsPoint; - drawArgs.m_vertCount = 1; - drawArgs.m_colors = &m_rendState.m_color; - drawArgs.m_colorCount = 1; - drawArgs.m_size = aznumeric_cast(nSize); - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - m_auxGeomPtr->DrawPoints(drawArgs); - } - } - - void AtomDebugDisplayViewportInterface::DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2) - { - if (m_auxGeomPtr) - { - AZ::Vector3 verts[2] = {ToWorldSpacePosition(p1), ToWorldSpacePosition(p2)}; - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = verts; - drawArgs.m_vertCount = 2; - drawArgs.m_colors = &m_rendState.m_color; - drawArgs.m_colorCount = 1; - drawArgs.m_size = m_rendState.m_lineWidth; - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - m_auxGeomPtr->DrawLines(drawArgs); - } - } - - void AtomDebugDisplayViewportInterface::DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector4& col1, const AZ::Vector4& col2) - { - if (m_auxGeomPtr) - { - AZ::Vector3 verts[2] = {ToWorldSpacePosition(p1), ToWorldSpacePosition(p2)}; - AZ::Color colors[2] = {col1, col2}; - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = verts; - drawArgs.m_vertCount = 2; - drawArgs.m_colors = colors; - drawArgs.m_colorCount = 2; - drawArgs.m_size = m_rendState.m_lineWidth; - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - m_auxGeomPtr->DrawLines(drawArgs); - } - } - - void AtomDebugDisplayViewportInterface::DrawLines(const AZStd::vector& lines, const AZ::Color& color) - { - if (m_auxGeomPtr) - { - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = lines.data(); - drawArgs.m_vertCount = aznumeric_cast(lines.size()); - drawArgs.m_colors = &color; - drawArgs.m_colorCount = 1; - drawArgs.m_size = m_rendState.m_lineWidth; - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - m_auxGeomPtr->DrawLines(drawArgs); - } - } - - void AtomDebugDisplayViewportInterface::DrawPolyLine(const AZ::Vector3* pnts, int numPoints, bool cycled) - { - if (m_auxGeomPtr) - { - AZStd::vector wsPoints(static_cast(numPoints)); - for (int index = 0; index < numPoints; ++index) - { - wsPoints[index] = ToWorldSpacePosition(pnts[index]); - } - AZ::RPI::AuxGeomDraw::PolylineEnd polylineEnd = cycled ? AZ::RPI::AuxGeomDraw::PolylineEnd::Closed : AZ::RPI::AuxGeomDraw::PolylineEnd::Open; - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = wsPoints.data(); - drawArgs.m_vertCount = aznumeric_cast(numPoints); - drawArgs.m_colors = &m_rendState.m_color; - drawArgs.m_colorCount = 1; - drawArgs.m_size = m_rendState.m_lineWidth; - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - m_auxGeomPtr->DrawPolylines(drawArgs, polylineEnd); - } - } - - // void AtomDebugDisplayViewportInterface::DrawWireQuad2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override; - // void AtomDebugDisplayViewportInterface::DrawLine2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override; - // void AtomDebugDisplayViewportInterface::DrawLine2dGradient(const AZ::Vector2& p1, const AZ::Vector2& p2, float z, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor) override; - // void AtomDebugDisplayViewportInterface::DrawWireCircle2d(const AZ::Vector2& center, float radius, float z) override; - - void AtomDebugDisplayViewportInterface::DrawArc( - const AZ::Vector3& pos, - float radius, - float startAngleDegrees, - float sweepAngleDegrees, - float angularStepDegrees, - int referenceAxis) - { - if (m_auxGeomPtr) - { - // Draw axis aligned arc - const float stepAngle = DegToRad(angularStepDegrees); - const float startAngle = DegToRad(startAngleDegrees); - const float stopAngle = DegToRad(sweepAngleDegrees) + startAngle; - SingleColorDynamicSizeLineHelper lines(1+static_cast(sweepAngleDegrees/angularStepDegrees)); - AZ::Vector3 radiusV3 = AZ::Vector3(radius); - CreateAxisAlignedArc( - lines, - stepAngle, - startAngle, - stopAngle, - pos, - radiusV3, - static_cast(referenceAxis) - ); - lines.Draw(m_auxGeomPtr, m_rendState); - } - } - - void AtomDebugDisplayViewportInterface::DrawArc( - const AZ::Vector3& pos, - float radius, - float startAngleDegrees, - float sweepAngleDegrees, - float angularStepDegrees, - const AZ::Vector3& fixedAxis) - { - if (m_auxGeomPtr) - { - // Draw arbitraty axis arc - const float stepAngle = DegToRad(angularStepDegrees); - const float startAngle = DegToRad(startAngleDegrees); - const float stopAngle = DegToRad(sweepAngleDegrees) + startAngle; - SingleColorDynamicSizeLineHelper lines(1+static_cast(sweepAngleDegrees/angularStepDegrees)); - AZ::Vector3 radiusV3 = AZ::Vector3(radius); - CreateArbitraryAxisArc( - lines, - stepAngle, - startAngle, - stopAngle, - pos, + // Draw top cap as two criss-crossing 180deg arcs + CreateArbitraryAxisArc( + lines, + stepAngle, + Deg90, + Deg90 + Deg180, + topCenter, radiusV3, - fixedAxis + ortho1Normalized + ); + + CreateArbitraryAxisArc( + lines, + stepAngle, + Deg180, + Deg180 + Deg180, + topCenter, + radiusV3, + ortho2Normalized + ); + + // Draw bottom cap + CreateArbitraryAxisArc( + lines, + stepAngle, + -Deg90, + -Deg90 + Deg180, + bottomCenter, + radiusV3, + ortho1Normalized + ); + + CreateArbitraryAxisArc( + lines, + stepAngle, + Deg0, + Deg0 + Deg180, + bottomCenter, + radiusV3, + ortho2Normalized + ); + + lines.Draw(m_auxGeomPtr, m_rendState); + } + } + + void AtomDebugDisplayViewportInterface::DrawWireSphere(const AZ::Vector3& pos, float radius) + { + if (m_auxGeomPtr) + { + + m_auxGeomPtr->DrawSphere( + ToWorldSpacePosition(pos), + radius, + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Line, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex + ); + } + } + + void AtomDebugDisplayViewportInterface::DrawWireSphere(const AZ::Vector3& pos, const AZ::Vector3 radius) + { + if (m_auxGeomPtr) + { + // This matches Cry behavior, the DrawWireSphere above may need modifying to use the same approach. + // Draw 3 axis aligned circles + const float step = DegToRad(10.0f); + const float maxAngle = DegToRad(360.0f) + step; + SingleColorStaticSizeLineHelper<40*3> lines; // hard code to 40 lines * 3 circles until DegToRad is constexpr. + + // Z Axis + AZ::Vector3 axisRadius(radius.GetX(), radius.GetY(), 0.0f); + CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, axisRadius, CircleAxisZ); + + // X Axis + axisRadius = AZ::Vector3(0.0f, radius.GetY(), radius.GetZ()); + CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, axisRadius, CircleAxisX); + + // Y Axis + axisRadius = AZ::Vector3(radius.GetX(), 0.0f, radius.GetZ()); + CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, axisRadius, CircleAxisY); + lines.Draw(m_auxGeomPtr, m_rendState); + } + } + + void AtomDebugDisplayViewportInterface::DrawWireDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius) + { + if (m_auxGeomPtr) + { + + // Draw 3 axis aligned circles + const float stepAngle = DegToRad(11.25f); + const float startAngle = DegToRad(0.0f); + const float stopAngle = DegToRad(360.0f) + startAngle; + SingleColorDynamicSizeLineHelper lines(2+static_cast(360.0f/11.25f)); // num disk segments + 1 for azis line + 1 for spare + const AZ::Vector3 radiusV3 = AZ::Vector3(radius); + CreateArbitraryAxisArc( + lines, + stepAngle, + startAngle, + stopAngle, + pos, + radiusV3, + dir + ); + + lines.AddLineSegment(ToWorldSpacePosition(pos), ToWorldSpacePosition(pos + dir * (radius * 0.2f))); // 0.2f comes from Code\Sandbox\Editor\Objects\DisplayContextShared.inl DisplayContext::DrawWireDisk + lines.Draw(m_auxGeomPtr, m_rendState); + } + } + + void AtomDebugDisplayViewportInterface::DrawBall(const AZ::Vector3& pos, float radius, bool drawShaded) + { + if (m_auxGeomPtr) + { + // get the max scaled radius in case the transform on the stack is scaled non-uniformly + const float transformedRadiusX = ToWorldSpaceVector(AZ::Vector3(radius, 0.0f, 0.0f)).GetLengthEstimate(); + const float transformedRadiusY = ToWorldSpaceVector(AZ::Vector3(0.0f, radius, 0.0f)).GetLengthEstimate(); + const float transformedRadiusZ = ToWorldSpaceVector(AZ::Vector3(0.0f, 0.0f, radius)).GetLengthEstimate(); + const float maxTransformedRadius = + AZ::GetMax(transformedRadiusX, AZ::GetMax(transformedRadiusY, transformedRadiusZ)); + + AZ::RPI::AuxGeomDraw::DrawStyle drawStyle = drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid; + m_auxGeomPtr->DrawSphere( + ToWorldSpacePosition(pos), + maxTransformedRadius, + m_rendState.m_color, + drawStyle, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex ); - lines.Draw(m_auxGeomPtr, m_rendState); - } } - - void AtomDebugDisplayViewportInterface::DrawCircle(const AZ::Vector3& pos, float radius, int nUnchangedAxis) + } + + void AtomDebugDisplayViewportInterface::DrawDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius) + { + if (m_auxGeomPtr) { - if (m_auxGeomPtr) - { - // Draw circle with default radius. - const float step = DegToRad(10.0f); - const float maxAngle = DegToRad(360.0f) + step; - SingleColorStaticSizeLineHelper<40> lines; // hard code 40 lines until DegToRad is constexpr. - AZ::Vector3 radiusV3 = AZ::Vector3(radius); - CreateAxisAlignedArc( - lines, - step, - 0.0f, - maxAngle, - pos, - radiusV3, - static_cast(nUnchangedAxis)); - lines.Draw(m_auxGeomPtr, m_rendState); - } + const AZ::Vector3 worldPos = ToWorldSpacePosition(pos); + const AZ::Vector3 worldDir = ToWorldSpaceVector(dir); + m_auxGeomPtr->DrawDisk( + worldPos, + worldDir, + radius, + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Shaded, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex + ); } + } - void AtomDebugDisplayViewportInterface::DrawHalfDottedCircle(const AZ::Vector3& pos, float radius, const AZ::Vector3& viewPos, int nUnchangedAxis) + void AtomDebugDisplayViewportInterface::DrawArrow(const AZ::Vector3& src, const AZ::Vector3& trg, float headScale, bool dualEndedArrow) + { + if (m_auxGeomPtr) { - if (m_auxGeomPtr) + float f2dScale = 1.0f; + float arrowLen = 0.4f * headScale; + float arrowRadius = 0.1f * headScale; + // if (flags & DISPLAY_2D) + // { + // f2dScale = 1.2f * ToWorldSpaceVector(Vec3(1, 0, 0)).GetLength(); + // } + AZ::Vector3 dir = trg - src; + dir = ToWorldSpaceVector(dir.GetNormalized()); + AZ::Vector3 verts[2] = {ToWorldSpacePosition(src), ToWorldSpacePosition(trg)}; + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = verts; + drawArgs.m_vertCount = 2; + drawArgs.m_colors = &m_rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_size = m_rendState.m_lineWidth; + drawArgs.m_opacityType = m_rendState.m_opacityType; + drawArgs.m_depthTest = m_rendState.m_depthTest; + drawArgs.m_depthWrite = m_rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; + if (!dualEndedArrow) { - // Draw circle with single radius. - const float step = DegToRad(10.0f); - const float maxAngle = DegToRad(360.0f) + step; - SingleColorStaticSizeLineHelper<40> lines; // hard code 40 lines until DegToRad is constexpr. - - AZ::Vector3 radiusV3 = AZ::Vector3(radius); - const AZ::Vector3 worldPos = ToWorldSpacePosition(pos); - const AZ::Vector3 worldView = ToWorldSpacePosition(viewPos); - const AZ::Vector3 worldDir = worldView - worldPos; - - CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, radiusV3, static_cast(nUnchangedAxis%CircleAxisMax), - [&worldPos, &worldDir](const AZ::Vector3& lineStart, const AZ::Vector3& lineEnd, int segmentIndex) - { - AZ_UNUSED(lineEnd); - const float dot = (lineStart - worldPos).Dot(worldDir); - const bool facing = dot > 0.0f; - // if so skip every other line to produce a dotted effect - if (facing || segmentIndex % 2 == 0) - { - return true; - } - return false; - }); - lines.Draw(m_auxGeomPtr, m_rendState); - } - } - - void AtomDebugDisplayViewportInterface::DrawCone(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius, float height, bool drawShaded) - { - if (m_auxGeomPtr) - { - const AZ::Vector3 worldPos = ToWorldSpacePosition(pos); - const AZ::Vector3 worldDir = ToWorldSpaceVector(dir); + verts[1] -= dir * arrowLen; + m_auxGeomPtr->DrawLines(drawArgs); m_auxGeomPtr->DrawCone( - worldPos, - worldDir, - radius, - height, - m_rendState.m_color, - drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid, - m_rendState.m_depthTest, - m_rendState.m_depthWrite, - m_rendState.m_faceCullMode, - m_rendState.m_viewProjOverrideIndex - ); - } - } - - void AtomDebugDisplayViewportInterface::DrawWireCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height) - { - if (m_auxGeomPtr) - { - const AZ::Vector3 worldCenter = ToWorldSpacePosition(center); - const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis); - m_auxGeomPtr->DrawCylinder( - worldCenter, - worldAxis, - radius, - height, - m_rendState.m_color, - AZ::RPI::AuxGeomDraw::DrawStyle::Line, - m_rendState.m_depthTest, - m_rendState.m_depthWrite, - m_rendState.m_faceCullMode, - m_rendState.m_viewProjOverrideIndex - ); - } - } - - void AtomDebugDisplayViewportInterface::DrawSolidCylinder( - const AZ::Vector3& center, - const AZ::Vector3& axis, - float radius, - float height, - bool drawShaded) - { - if (m_auxGeomPtr) - { - const AZ::Vector3 worldCenter = ToWorldSpacePosition(center); - const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis); - m_auxGeomPtr->DrawCylinder( - worldCenter, - worldAxis, - radius, - height, - m_rendState.m_color, - drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid, - m_rendState.m_depthTest, - m_rendState.m_depthWrite, - m_rendState.m_faceCullMode, - m_rendState.m_viewProjOverrideIndex - ); - } - } - - void AtomDebugDisplayViewportInterface::DrawWireCapsule( - const AZ::Vector3& center, - const AZ::Vector3& axis, - float radius, - float heightStraightSection) - { - if (m_auxGeomPtr && radius > FLT_EPSILON && axis.GetLengthSq() > FLT_EPSILON) - { - AZ::Vector3 axisNormalized = axis.GetNormalizedEstimate(); - SingleColorStaticSizeLineHelper<(16+1) * 5> lines; // 360/22.5 = 16, 5 possible calls to CreateArbitraryAxisArc - AZ::Vector3 radiusV3 = AZ::Vector3(radius); - float stepAngle = DegToRad(22.5f); - float Deg0 = DegToRad(0.0f); - - - // Draw cylinder part (or just a circle around the middle) - if (heightStraightSection > FLT_EPSILON) - { - DrawWireCylinder(center, axis, radius, heightStraightSection); - } - else - { - float Deg360 = DegToRad(360.0f); - CreateArbitraryAxisArc( - lines, - stepAngle, - Deg0, - Deg360, - center, - radiusV3, - axisNormalized - ); - } - - float Deg90 = DegToRad(90.0f); - float Deg180 = DegToRad(180.0f); - - AZ::Vector3 ortho1Normalized, ortho2Normalized; - CalcBasisVectors(axisNormalized, ortho1Normalized, ortho2Normalized); - AZ::Vector3 centerToTopCircleCenter = axisNormalized * heightStraightSection * 0.5f; - AZ::Vector3 topCenter = center + centerToTopCircleCenter; - AZ::Vector3 bottomCenter = center - centerToTopCircleCenter; - - // Draw top cap as two criss-crossing 180deg arcs - CreateArbitraryAxisArc( - lines, - stepAngle, - Deg90, - Deg90 + Deg180, - topCenter, - radiusV3, - ortho1Normalized - ); - - CreateArbitraryAxisArc( - lines, - stepAngle, - Deg180, - Deg180 + Deg180, - topCenter, - radiusV3, - ortho2Normalized - ); - - // Draw bottom cap - CreateArbitraryAxisArc( - lines, - stepAngle, - -Deg90, - -Deg90 + Deg180, - bottomCenter, - radiusV3, - ortho1Normalized - ); - - CreateArbitraryAxisArc( - lines, - stepAngle, - Deg0, - Deg0 + Deg180, - bottomCenter, - radiusV3, - ortho2Normalized - ); - - lines.Draw(m_auxGeomPtr, m_rendState); - } - } - - void AtomDebugDisplayViewportInterface::DrawWireSphere(const AZ::Vector3& pos, float radius) - { - if (m_auxGeomPtr) - { - - m_auxGeomPtr->DrawSphere( - ToWorldSpacePosition(pos), - radius, - m_rendState.m_color, - AZ::RPI::AuxGeomDraw::DrawStyle::Line, - m_rendState.m_depthTest, - m_rendState.m_depthWrite, - m_rendState.m_faceCullMode, - m_rendState.m_viewProjOverrideIndex - ); - } - } - - void AtomDebugDisplayViewportInterface::DrawWireSphere(const AZ::Vector3& pos, const AZ::Vector3 radius) - { - if (m_auxGeomPtr) - { - // This matches Cry behavior, the DrawWireSphere above may need modifying to use the same approach. - // Draw 3 axis aligned circles - const float step = DegToRad(10.0f); - const float maxAngle = DegToRad(360.0f) + step; - SingleColorStaticSizeLineHelper<40*3> lines; // hard code to 40 lines * 3 circles until DegToRad is constexpr. - - // Z Axis - AZ::Vector3 axisRadius(radius.GetX(), radius.GetY(), 0.0f); - CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, axisRadius, CircleAxisZ); - - // X Axis - axisRadius = AZ::Vector3(0.0f, radius.GetY(), radius.GetZ()); - CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, axisRadius, CircleAxisX); - - // Y Axis - axisRadius = AZ::Vector3(radius.GetX(), 0.0f, radius.GetZ()); - CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, axisRadius, CircleAxisY); - lines.Draw(m_auxGeomPtr, m_rendState); - } - } - - void AtomDebugDisplayViewportInterface::DrawWireDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius) - { - if (m_auxGeomPtr) - { - - // Draw 3 axis aligned circles - const float stepAngle = DegToRad(11.25f); - const float startAngle = DegToRad(0.0f); - const float stopAngle = DegToRad(360.0f) + startAngle; - SingleColorDynamicSizeLineHelper lines(2+static_cast(360.0f/11.25f)); // num disk segments + 1 for azis line + 1 for spare - const AZ::Vector3 radiusV3 = AZ::Vector3(radius); - CreateArbitraryAxisArc( - lines, - stepAngle, - startAngle, - stopAngle, - pos, - radiusV3, - dir - ); - - lines.AddLineSegment(ToWorldSpacePosition(pos), ToWorldSpacePosition(pos + dir * (radius * 0.2f))); // 0.2f comes from Code\Sandbox\Editor\Objects\DisplayContextShared.inl DisplayContext::DrawWireDisk - lines.Draw(m_auxGeomPtr, m_rendState); - } - } - - void AtomDebugDisplayViewportInterface::DrawBall(const AZ::Vector3& pos, float radius, bool drawShaded) - { - if (m_auxGeomPtr) - { - // get the max scaled radius in case the transform on the stack is scaled non-uniformly - const float transformedRadiusX = ToWorldSpaceVector(AZ::Vector3(radius, 0.0f, 0.0f)).GetLengthEstimate(); - const float transformedRadiusY = ToWorldSpaceVector(AZ::Vector3(0.0f, radius, 0.0f)).GetLengthEstimate(); - const float transformedRadiusZ = ToWorldSpaceVector(AZ::Vector3(0.0f, 0.0f, radius)).GetLengthEstimate(); - const float maxTransformedRadius = - AZ::GetMax(transformedRadiusX, AZ::GetMax(transformedRadiusY, transformedRadiusZ)); - - AZ::RPI::AuxGeomDraw::DrawStyle drawStyle = drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid; - m_auxGeomPtr->DrawSphere( - ToWorldSpacePosition(pos), - maxTransformedRadius, - m_rendState.m_color, - drawStyle, + verts[1], + dir, + arrowRadius * f2dScale, + arrowLen * f2dScale, + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Shaded, m_rendState.m_depthTest, m_rendState.m_depthWrite, m_rendState.m_faceCullMode, m_rendState.m_viewProjOverrideIndex ); } - } - - void AtomDebugDisplayViewportInterface::DrawDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius) - { - if (m_auxGeomPtr) + else { - const AZ::Vector3 worldPos = ToWorldSpacePosition(pos); - const AZ::Vector3 worldDir = ToWorldSpaceVector(dir); - m_auxGeomPtr->DrawDisk( - worldPos, - worldDir, - radius, + verts[0] += dir * arrowLen; + verts[1] -= dir * arrowLen; + m_auxGeomPtr->DrawLines(drawArgs); + m_auxGeomPtr->DrawCone( + verts[0], + -dir, + arrowRadius * f2dScale, + arrowLen * f2dScale, + m_rendState.m_color, + AZ::RPI::AuxGeomDraw::DrawStyle::Shaded, + m_rendState.m_depthTest, + m_rendState.m_depthWrite, + m_rendState.m_faceCullMode, + m_rendState.m_viewProjOverrideIndex + ); + m_auxGeomPtr->DrawCone( + verts[1], + dir, + arrowRadius * f2dScale, + arrowLen * f2dScale, m_rendState.m_color, AZ::RPI::AuxGeomDraw::DrawStyle::Shaded, m_rendState.m_depthTest, @@ -829,179 +1224,297 @@ namespace AZ ); } } + } - void AtomDebugDisplayViewportInterface::DrawArrow(const AZ::Vector3& src, const AZ::Vector3& trg, float headScale, bool dualEndedArrow) + void AtomDebugDisplayViewportInterface::DrawTextLabel( + const AZ::Vector3& pos, + float size, + const char* text, + const bool center, + int srcOffsetX [[maybe_unused]], + int srcOffsetY [[maybe_unused]]) + { + AzFramework::FontDrawInterface* fontDrawInterface = AZ::Interface::Get()->GetDefaultFontDrawInterface(); + if (!fontDrawInterface || !text || size == 0.0f) { - if (m_auxGeomPtr) + return; + } + // if 2d draw need to project pos to screen first + AzFramework::TextDrawParameters params; + AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); + params.m_drawViewportId = viewportContext->GetId(); // get the viewport ID so default viewport works + params.m_position = pos; + params.m_color = m_rendState.m_color; + params.m_scale = AZ::Vector2(size); + params.m_hAlign = center ? AzFramework::TextHorizontalAlignment::Center : AzFramework::TextHorizontalAlignment::Left; //! Horizontal text alignment + params.m_monospace = false; //! disable character proportional spacing + params.m_depthTest = false; //! Test character against the depth buffer + params.m_virtual800x600ScreenSize = true; //! Text placement and size are scaled relative to a virtual 800x600 resolution + params.m_scaleWithWindow = false; //! Font gets bigger as the window gets bigger + params.m_multiline = true; //! text respects ascii newline characters + + fontDrawInterface->DrawScreenAlignedText3d(params, text); + } + + void AtomDebugDisplayViewportInterface::Draw2dTextLabel( + float x, + float y, + float size, + const char* text, + bool center) + { + AzFramework::FontDrawInterface* fontDrawInterface = AZ::Interface::Get()->GetDefaultFontDrawInterface(); + if (!fontDrawInterface || !text || size == 0.0f) + { + return; + } + // if 2d draw need to project pos to screen first + AzFramework::TextDrawParameters params; + AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); + params.m_drawViewportId = viewportContext->GetId(); // get the viewport ID so default viewport works + params.m_position = AZ::Vector3(x, y, 1.0f); + params.m_color = m_rendState.m_color; + params.m_scale = AZ::Vector2(size); + params.m_hAlign = center ? AzFramework::TextHorizontalAlignment::Center : AzFramework::TextHorizontalAlignment::Left; //! Horizontal text alignment + params.m_monospace = false; //! disable character proportional spacing + params.m_depthTest = false; //! Test character against the depth buffer + params.m_virtual800x600ScreenSize = true; //! Text placement and size are scaled relative to a virtual 800x600 resolution + params.m_scaleWithWindow = false; //! Font gets bigger as the window gets bigger + params.m_multiline = true; //! text respects ascii newline characters + + fontDrawInterface->DrawScreenAlignedText2d(params, text); + } + + void AtomDebugDisplayViewportInterface::DrawTextOn2DBox( + const AZ::Vector3& pos [[maybe_unused]], + const char* text [[maybe_unused]], + float textScale [[maybe_unused]], + const AZ::Vector4& TextColor [[maybe_unused]], + const AZ::Vector4& TextBackColor [[maybe_unused]]) + { + AZ_Assert(false, "Unexpected use of legacy api, please file a feature request with the rendering team to get this implemented!"); + } + // unhandledled on Atom - virtual void DrawTextureLabel(ITexture* texture, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override; + // void AtomDebugDisplayViewportInterface::DrawTextureLabel(int textureId, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override; + + void AtomDebugDisplayViewportInterface::SetLineWidth(float width) + { + AZ_Assert(width >= 0.0f && width <= 255.0f, "Width (%f) exceeds allowable range [0 - 255]", width); + m_rendState.m_lineWidth = static_cast(width); + } + + bool AtomDebugDisplayViewportInterface::IsVisible(const AZ::Aabb& bounds) + { + AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); + const AZ::Matrix4x4& worldToClip = viewportContext->GetDefaultView()->GetWorldToClipMatrix(); + AZ::Frustum frustum = AZ::Frustum::CreateFromMatrixColumnMajor(worldToClip, Frustum::ReverseDepth::True); + return frustum.IntersectAabb(bounds) != AZ::IntersectResult::Exterior; + } + // int AtomDebugDisplayViewportInterface::SetFillMode(int nFillMode) override; + float AtomDebugDisplayViewportInterface::GetLineWidth() + { + return m_rendState.m_lineWidth; + } + + float AtomDebugDisplayViewportInterface::GetAspectRatio() + { + AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); + auto windowSize = viewportContext->GetViewportSize(); + return aznumeric_cast(windowSize.m_width)/aznumeric_cast(windowSize.m_height); + } + + void AtomDebugDisplayViewportInterface::DepthTestOff() + { + m_rendState.m_depthTest = AZ::RPI::AuxGeomDraw::DepthTest::Off; + } + + void AtomDebugDisplayViewportInterface::DepthTestOn() + { + m_rendState.m_depthTest = AZ::RPI::AuxGeomDraw::DepthTest::On; + } + + void AtomDebugDisplayViewportInterface::DepthWriteOff() + { + m_rendState.m_depthWrite = AZ::RPI::AuxGeomDraw::DepthWrite::Off; + } + + void AtomDebugDisplayViewportInterface::DepthWriteOn() + { + m_rendState.m_depthWrite = AZ::RPI::AuxGeomDraw::DepthWrite::On; + } + + void AtomDebugDisplayViewportInterface::CullOff() + { + m_rendState.m_faceCullMode = AZ::RPI::AuxGeomDraw::FaceCullMode::None; + } + + void AtomDebugDisplayViewportInterface::CullOn() + { + m_rendState.m_faceCullMode = AZ::RPI::AuxGeomDraw::FaceCullMode::Back; + } + + bool AtomDebugDisplayViewportInterface::SetDrawInFrontMode(bool on) + { + AZ_UNUSED(on); + return false; + } + + AZ::u32 AtomDebugDisplayViewportInterface::GetState() + { + return ConvertRenderStateToCry(); + } + + AZ::u32 AtomDebugDisplayViewportInterface::SetState(AZ::u32 state) + { + uint32_t currentState = ConvertRenderStateToCry(); + uint32_t changedState = (state & e_PublicParamsMask) ^ currentState; + + if (changedState & e_Mode2D3DMask) + { + // this is the only way to turn on 2d Mode under Atom + if (state & e_Mode2D) { - float f2dScale = 1.0f; - float arrowLen = 0.4f * headScale; - float arrowRadius = 0.1f * headScale; - // if (flags & DISPLAY_2D) - // { - // f2dScale = 1.2f * ToWorldSpaceVector(Vec3(1, 0, 0)).GetLength(); - // } - AZ::Vector3 dir = trg - src; - dir = ToWorldSpaceVector(dir.GetNormalized()); - AZ::Vector3 verts[2] = {ToWorldSpacePosition(src), ToWorldSpacePosition(trg)}; - AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; - drawArgs.m_verts = verts; - drawArgs.m_vertCount = 2; - drawArgs.m_colors = &m_rendState.m_color; - drawArgs.m_colorCount = 1; - drawArgs.m_size = m_rendState.m_lineWidth; - drawArgs.m_opacityType = m_rendState.m_opacityType; - drawArgs.m_depthTest = m_rendState.m_depthTest; - drawArgs.m_depthWrite = m_rendState.m_depthWrite; - drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex; - if (!dualEndedArrow) - { - verts[1] -= dir * arrowLen; - m_auxGeomPtr->DrawLines(drawArgs); - m_auxGeomPtr->DrawCone( - verts[1], - dir, - arrowRadius * f2dScale, - arrowLen * f2dScale, - m_rendState.m_color, - AZ::RPI::AuxGeomDraw::DrawStyle::Shaded, - m_rendState.m_depthTest, - m_rendState.m_depthWrite, - m_rendState.m_faceCullMode, - m_rendState.m_viewProjOverrideIndex - ); - } - else - { - verts[0] += dir * arrowLen; - verts[1] -= dir * arrowLen; - m_auxGeomPtr->DrawLines(drawArgs); - m_auxGeomPtr->DrawCone( - verts[0], - -dir, - arrowRadius * f2dScale, - arrowLen * f2dScale, - m_rendState.m_color, - AZ::RPI::AuxGeomDraw::DrawStyle::Shaded, - m_rendState.m_depthTest, - m_rendState.m_depthWrite, - m_rendState.m_faceCullMode, - m_rendState.m_viewProjOverrideIndex - ); - m_auxGeomPtr->DrawCone( - verts[1], - dir, - arrowRadius * f2dScale, - arrowLen * f2dScale, - m_rendState.m_color, - AZ::RPI::AuxGeomDraw::DrawStyle::Shaded, - m_rendState.m_depthTest, - m_rendState.m_depthWrite, - m_rendState.m_faceCullMode, - m_rendState.m_viewProjOverrideIndex - ); - } + AZ_Assert((currentState & e_DrawInFrontOn) == 0 && (changedState & e_DrawInFrontOn) == 0, "Atom doesnt support Draw In Front and 2d at the same time"); + m_rendState.m_viewProjOverrideIndex = m_auxGeomPtr->GetOrAdd2DViewProjOverride(); + m_rendState.m_2dMode = true; + } + else // switch back to mode 3d + { + m_rendState.m_viewProjOverrideIndex = -1; + m_rendState.m_2dMode = false; } } - // void AtomDebugDisplayViewportInterface::DrawTextLabel(const AZ::Vector3& pos, float size, const char* text, const bool bCenter = false, int srcOffsetX = 0, int srcOffsetY = 0) override; - // void AtomDebugDisplayViewportInterface::Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter = false) override; - // void AtomDebugDisplayViewportInterface::DrawTextOn2DBox(const AZ::Vector3& pos, const char* text, float textScale, const AZ::Vector4& TextColor, const AZ::Vector4& TextBackColor) override; - // unhandledled on Atom - virtual void DrawTextureLabel(ITexture* texture, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override; - // void AtomDebugDisplayViewportInterface::DrawTextureLabel(int textureId, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override; - - void AtomDebugDisplayViewportInterface::SetLineWidth(float width) + if (changedState & e_AlphaBlendingMask) { - AZ_Assert(width >= 0.0f && width <= 255.0f, "Width (%f) exceeds allowable range [0 - 255]", width); - m_rendState.m_lineWidth = static_cast(width); - } - - // bool AtomDebugDisplayViewportInterface::IsVisible(const AZ::Aabb& bounds) override; - // int AtomDebugDisplayViewportInterface::SetFillMode(int nFillMode) override; - float AtomDebugDisplayViewportInterface::GetLineWidth() - { - return m_rendState.m_lineWidth; - } - - float AtomDebugDisplayViewportInterface::GetAspectRatio() - { - auto viewContextManager = AZ::Interface::Get(); - AZ::RPI::ViewportContextPtr viewportContext; - if (m_defaultInstance) + switch (state&e_AlphaBlendingMask) { - viewportContext = viewContextManager->GetViewportContextByName(viewContextManager->GetDefaultViewportContextName()); + case e_AlphaNone: + m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Opaque; + break; + case e_AlphaAdditive: + [[fallthrough]]; // Additive not currently supported in Atom AuxGeom implementation + case e_AlphaBlended: + m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Translucent; + break; + } + } + + if (changedState & e_DrawInFrontMask) + { + AZ_Assert( // either state is turning DrawInFront off or Mode 2D has to be off + (state & e_DrawInFrontOn) == 0 || + ((currentState & e_Mode2D) == 0 && (changedState & e_Mode2D) == 0), + "Atom doesnt support Draw In Front and 2d at the same time"); + SetDrawInFrontMode(changedState & e_DrawInFrontOn); + } + + if (changedState & e_CullModeMask) + { + switch (state & e_CullModeMask) + { + case e_CullModeNone: + CullOff(); + break; + case e_CullModeFront: + // Currently no other way to set front face culling in DebugDisplayRequestBus + m_rendState.m_faceCullMode = AZ::RPI::AuxGeomDraw::FaceCullMode::Front; + break; + case e_CullModeBack: + CullOn(); + break; + } + } + + if (changedState & e_DepthWriteMask) + { + if (state & e_DepthWriteOff) + { + DepthWriteOff(); } else { - viewportContext = viewContextManager->GetViewportContextById(m_viewportId); + DepthWriteOn(); } - auto windowSize = viewportContext->GetViewportSize(); - return aznumeric_cast(windowSize.m_width)/aznumeric_cast(windowSize.m_height); } - void AtomDebugDisplayViewportInterface::DepthTestOff() + if (changedState & e_DepthTestMask) { - m_rendState.m_depthTest = AZ::RPI::AuxGeomDraw::DepthTest::Off; - } - - void AtomDebugDisplayViewportInterface::DepthTestOn() - { - m_rendState.m_depthTest = AZ::RPI::AuxGeomDraw::DepthTest::On; - } - - void AtomDebugDisplayViewportInterface::DepthWriteOff() - { - m_rendState.m_depthWrite = AZ::RPI::AuxGeomDraw::DepthWrite::Off; - } - - void AtomDebugDisplayViewportInterface::DepthWriteOn() - { - m_rendState.m_depthWrite = AZ::RPI::AuxGeomDraw::DepthWrite::On; - } - - void AtomDebugDisplayViewportInterface::CullOff() - { - m_rendState.m_faceCullMode = AZ::RPI::AuxGeomDraw::FaceCullMode::None; - } - - void AtomDebugDisplayViewportInterface::CullOn() - { - m_rendState.m_faceCullMode = AZ::RPI::AuxGeomDraw::FaceCullMode::Back; - } - - bool AtomDebugDisplayViewportInterface::SetDrawInFrontMode(bool on) - { - AZ_UNUSED(on); - return false; - } - - // AZ::u32 AtomDebugDisplayViewportInterface::GetState() override; - // AZ::u32 AtomDebugDisplayViewportInterface::SetState(AZ::u32 state) override; - // AZ::u32 AtomDebugDisplayViewportInterface::SetStateFlag(AZ::u32 state) override; - // AZ::u32 AtomDebugDisplayViewportInterface::ClearStateFlag(AZ::u32 state) override; - - void AtomDebugDisplayViewportInterface::PushMatrix(const AZ::Transform& tm) - { - AZ_Assert(m_rendState.m_currentTransform < RenderState::TransformStackSize, "Exceeded AtomDebugDisplayViewportInterface matrix stack size"); - if (m_rendState.m_currentTransform < RenderState::TransformStackSize) + if (state & e_DepthTestOff) { - m_rendState.m_currentTransform++; - m_rendState.m_transformStack[m_rendState.m_currentTransform] = m_rendState.m_transformStack[m_rendState.m_currentTransform - 1] * AZ::Matrix3x4::CreateFromTransform(tm); + DepthTestOff(); } - } - - void AtomDebugDisplayViewportInterface::PopMatrix() - { - AZ_Assert(m_rendState.m_currentTransform > 0, "Underflowed AtomDebugDisplayViewportInterface matrix stack"); - if (m_rendState.m_currentTransform > 0) + else { - m_rendState.m_currentTransform--; + DepthTestOn(); } } - const AZ::Matrix3x4& AtomDebugDisplayViewportInterface::GetCurrentTransform() const + return currentState; + } + + void AtomDebugDisplayViewportInterface::PushMatrix(const AZ::Transform& tm) + { + AZ_Assert(m_rendState.m_currentTransform < RenderState::TransformStackSize, "Exceeded AtomDebugDisplayViewportInterface matrix stack size"); + if (m_rendState.m_currentTransform < RenderState::TransformStackSize) { - return m_rendState.m_transformStack[m_rendState.m_currentTransform]; + m_rendState.m_currentTransform++; + m_rendState.m_transformStack[m_rendState.m_currentTransform] = m_rendState.m_transformStack[m_rendState.m_currentTransform - 1] * AZ::Matrix3x4::CreateFromTransform(tm); } } + + void AtomDebugDisplayViewportInterface::PopMatrix() + { + AZ_Assert(m_rendState.m_currentTransform > 0, "Underflowed AtomDebugDisplayViewportInterface matrix stack"); + if (m_rendState.m_currentTransform > 0) + { + m_rendState.m_currentTransform--; + } + } + + const AZ::Matrix3x4& AtomDebugDisplayViewportInterface::GetCurrentTransform() const + { + return m_rendState.m_transformStack[m_rendState.m_currentTransform]; + } + + AZ::RPI::ViewportContextPtr AtomDebugDisplayViewportInterface::GetViewportContext() const + { + auto viewContextManager = AZ::Interface::Get(); + if (m_defaultInstance) + { + return viewContextManager->GetViewportContextByName(viewContextManager->GetDefaultViewportContextName()); + } + else + { + return viewContextManager->GetViewportContextById(m_viewportId); + } + } + + uint32_t AtomDebugDisplayViewportInterface::ConvertRenderStateToCry() const + { + uint32_t result = 0; + + result |= m_rendState.m_2dMode ? e_Mode2D : e_Mode3D; + result |= m_rendState.m_opacityType == AZ::RPI::AuxGeomDraw::OpacityType::Opaque ? e_AlphaNone : e_AlphaBlended; + result |= m_rendState.m_drawInFront ? e_DrawInFrontOn : e_DrawInFrontOff; + result |= m_rendState.m_depthTest == AZ::RPI::AuxGeomDraw::DepthTest::On ? e_DepthTestOn : e_DepthTestOff; + result |= m_rendState.m_depthWrite == AZ::RPI::AuxGeomDraw::DepthWrite::On ? e_DepthWriteOn : e_DepthWriteOff; + switch (m_rendState.m_faceCullMode) + { + case AZ::RPI::AuxGeomDraw::FaceCullMode::None: + result |= e_CullModeNone; + break; + case AZ::RPI::AuxGeomDraw::FaceCullMode::Front: + result |= e_CullModeFront; + break; + case AZ::RPI::AuxGeomDraw::FaceCullMode::Back: + result |= e_CullModeBack; + break; + default: + AZ_Assert(false, "Trying to convert an unknown culling mode to cry!"); + break; + } + + return result; + } } diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h index 48091ea8d8..021d816ca4 100644 --- a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h +++ b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h @@ -42,6 +42,10 @@ namespace AZ::AtomBridge AZ::RPI::AuxGeomDraw::DepthWrite m_depthWrite = AZ::RPI::AuxGeomDraw::DepthWrite::On; AZ::RPI::AuxGeomDraw::FaceCullMode m_faceCullMode = AZ::RPI::AuxGeomDraw::FaceCullMode::Back; int32_t m_viewProjOverrideIndex = -1; // will be used to implement SetDrawInFrontMode & 2D mode + + // separate tracking for Cry only state + bool m_drawInFront = false; + bool m_2dMode = false; }; //! Utility class to collect line segments when the number of segments is known at compile time. @@ -77,6 +81,24 @@ namespace AZ::AtomBridge } } + void Draw2d(AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, const RenderState& rendState) const + { + if (auxGeomDrawPtr && !m_points.empty()) + { + AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs; + drawArgs.m_verts = m_points.data(); + drawArgs.m_vertCount = aznumeric_cast(m_points.size()); + drawArgs.m_colors = &rendState.m_color; + drawArgs.m_colorCount = 1; + drawArgs.m_size = rendState.m_lineWidth; + drawArgs.m_opacityType = rendState.m_opacityType; + drawArgs.m_depthTest = rendState.m_depthTest; + drawArgs.m_depthWrite = rendState.m_depthWrite; + drawArgs.m_viewProjectionOverrideIndex = auxGeomDrawPtr->GetOrAdd2DViewProjOverride(); + auxGeomDrawPtr->DrawLines( drawArgs ); + } + } + void Reset() { m_points.clear(); @@ -91,6 +113,7 @@ namespace AZ::AtomBridge SingleColorDynamicSizeLineHelper(int estimatedNumLineSegments); void AddLineSegment(const AZ::Vector3& lineStart, const AZ::Vector3& lineEnd); void Draw(AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, const RenderState& rendState) const; + void Draw2d(AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, const RenderState& rendState) const; void Reset(); AZStd::vector m_points; @@ -119,9 +142,9 @@ namespace AZ::AtomBridge void SetColor(const AZ::Vector4& color) override; void SetAlpha(float a) override; void DrawQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4) override; - // void DrawQuad(float width, float height) overr - // void DrawWireQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4) override; - // void DrawWireQuad(float width, float height) override; + void DrawQuad(float width, float height) override; + void DrawWireQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4) override; + void DrawWireQuad(float width, float height) override; void DrawQuadGradient(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor) override; void DrawTri(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3) override; void DrawTriangles(const AZStd::vector& vertices, const AZ::Color& color) override; @@ -134,10 +157,10 @@ namespace AZ::AtomBridge void DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector4& col1, const AZ::Vector4& col2) override; void DrawLines(const AZStd::vector& lines, const AZ::Color& color) override; void DrawPolyLine(const AZ::Vector3* pnts, int numPoints, bool cycled = true) override; - // void DrawWireQuad2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override; - // void DrawLine2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override; - // void DrawLine2dGradient(const AZ::Vector2& p1, const AZ::Vector2& p2, float z, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor) override; - // void DrawWireCircle2d(const AZ::Vector2& center, float radius, float z) override; + void DrawWireQuad2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override; + void DrawLine2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override; + void DrawLine2dGradient(const AZ::Vector2& p1, const AZ::Vector2& p2, float z, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor) override; + void DrawWireCircle2d(const AZ::Vector2& center, float radius, float z) override; void DrawArc(const AZ::Vector3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, int referenceAxis = 2) override; void DrawArc(const AZ::Vector3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, const AZ::Vector3& fixedAxis) override; void DrawCircle(const AZ::Vector3& pos, float radius, int nUnchangedAxis = 2 /*z axis*/) override; @@ -152,13 +175,13 @@ namespace AZ::AtomBridge void DrawBall(const AZ::Vector3& pos, float radius, bool drawShaded) override; void DrawDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius) override; void DrawArrow(const AZ::Vector3& src, const AZ::Vector3& trg, float headScale = 1.0f, bool dualEndedArrow = false) override; - // void DrawTextLabel(const AZ::Vector3& pos, float size, const char* text, const bool bCenter = false, int srcOffsetX = 0, int srcOffsetY = 0) override; - // void Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter = false) override; - // void DrawTextOn2DBox(const AZ::Vector3& pos, const char* text, float textScale, const AZ::Vector4& TextColor, const AZ::Vector4& TextBackColor) override; + void DrawTextLabel(const AZ::Vector3& pos, float size, const char* text, const bool bCenter = false, int srcOffsetX = 0, int srcOffsetY = 0) override; + void Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter = false) override; + void DrawTextOn2DBox(const AZ::Vector3& pos, const char* text, float textScale, const AZ::Vector4& TextColor, const AZ::Vector4& TextBackColor) override; // unhandled on Atom - virtual void DrawTextureLabel(ITexture* texture, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override; // void DrawTextureLabel(int textureId, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override; void SetLineWidth(float width) override; - // bool IsVisible(const AZ::Aabb& bounds) override; + bool IsVisible(const AZ::Aabb& bounds) override; // int SetFillMode(int nFillMode) override; float GetLineWidth() override; float GetAspectRatio() override; @@ -169,10 +192,8 @@ namespace AZ::AtomBridge void CullOff() override; void CullOn() override; bool SetDrawInFrontMode(bool on) override; - // AZ::u32 GetState() override; - // AZ::u32 SetState(AZ::u32 state) override; - // AZ::u32 SetStateFlag(AZ::u32 state) override; - // AZ::u32 ClearStateFlag(AZ::u32 state) override; + AZ::u32 GetState() override; + AZ::u32 SetState(AZ::u32 state) override; void PushMatrix(const AZ::Transform& tm) override; void PopMatrix() override; @@ -226,6 +247,10 @@ namespace AZ::AtomBridge void InitInternal(RPI::Scene* scene, AZ::RPI::ViewportContextPtr viewportContextPtr); + AZ::RPI::ViewportContextPtr GetViewportContext() const; + + uint32_t ConvertRenderStateToCry() const; + RenderState m_rendState; AZ::RPI::AuxGeomDrawPtr m_auxGeomPtr; diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h index b1feaf1d87..2969e35a51 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/AtomFont.h @@ -20,8 +20,14 @@ #include #include #include +#include #include +#include +#include + +#include + namespace AZ { class FFont; @@ -33,6 +39,8 @@ namespace AZ //! and manages their loading & saving together. class AtomFont : public ICryFont + , public AzFramework::FontQueryInterface + , public AzFramework::SceneSystemNotificationBus::Handler { friend class FFont; @@ -79,16 +87,31 @@ namespace AZ void ReloadAllFonts() override; ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + // FontQueryInterface implementation + AzFramework::FontDrawInterface* GetFontDrawInterface(AzFramework::FontId fontId) const override; + AzFramework::FontDrawInterface* GetDefaultFontDrawInterface() const override; + + // SceneSystemNotificationBus handlers + void SceneAboutToBeRemoved(AzFramework::Scene& scene) override; + + + // Atom DynamicDraw interface management + AZ::RHI::Ptr GetOrCreateDynamicDrawForScene(AZ::RPI::Scene* scene); + + public: void UnregisterFont(const char* fontName); private: - typedef std::map FontMap; - typedef FontMap::iterator FontMapItor; - typedef FontMap::const_iterator FontMapConstItor; + using FontMap = std::unordered_map; + using FontMapItor = FontMap::iterator; + using FontMapConstItor = FontMap::const_iterator; - typedef AZStd::map> FontFamilyMap; - typedef AZStd::map FontFamilyReverseLookupMap; + using FontFamilyMap = AZStd::unordered_map>; + using FontFamilyReverseLookupMap = AZStd::unordered_map; + + using SceneToDynamicDrawMap = AZStd::unordered_map>; private: //! Convenience method for loading fonts @@ -119,9 +142,13 @@ namespace AZ FontFamilyReverseLookupMap m_fontFamilyReverseLookup; // m_persistedFontFamilies; //!< Stores persisted fonts (if "persist font families" is enabled) + SceneToDynamicDrawMap m_sceneToDynamicDrawMap; + AZStd::shared_mutex m_sceneToDynamicDrawMutex; }; } #endif diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h index 4f87334b46..96f5e09fc3 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h +++ b/Gems/AtomLyIntegration/AtomFont/Code/Include/AtomLyIntegration/AtomFont/FFont.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,8 @@ namespace AZ void operator () (const AZStd::intrusive_refcount* ptr) const; }; + using TextDrawContext = STextDrawContext; + //! FFont is the implementation of IFFont used to draw text with a particular font (e.g. Consolas Italic) //! FFont manages creation of a gpu texture to cache the font and generates draw commands that use that texture. //! FFont's are managed by AtomFont as either individual font instances or a font family @@ -64,12 +67,12 @@ namespace AZ class FFont : public IFFont , public AZStd::intrusive_refcount + , public AzFramework::FontDrawInterface , private AZ::Render::Bootstrap::NotificationBus::Handler { using ref_count = AZStd::intrusive_refcount; friend FontDeleter; public: - using TextDrawContext = STextDrawContext; //! Determines how characters of different sizes should be handled during render. enum class SizeBehavior { @@ -201,6 +204,14 @@ namespace AZ uint32_t GetFontTextureVersion() override; ///////////////////////////////////////////////////////////////////////////////////////////////////// + // AzFramework::FontDrawInterface implementation + void DrawScreenAlignedText2d( + const AzFramework::TextDrawParameters& params, + const AZStd::string_view& string) override; + + void DrawScreenAlignedText3d( + const AzFramework::TextDrawParameters& params, + const AZStd::string_view& string) override; public: FFont(AtomFont* atomFont, const char* fontName); @@ -220,8 +231,18 @@ namespace AZ bool InitCache(); void Prepare(const char* str, bool updateTexture, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize); - void DrawStringUInternal(float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx); - Vec2 GetTextSizeUInternal(const char* str, const bool asciiMultiLine, const TextDrawContext& ctx); + void DrawStringUInternal( + const RHI::Viewport& viewport, + RPI::ViewportContext* viewportContext, + float x, + float y, + float z, + const char* str, + const bool asciiMultiLine, + const TextDrawContext& ctx); + Vec2 GetTextSizeUInternal(const RHI::Viewport& viewport, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx); + Vec2 GetKerningInternal(const RHI::Viewport& viewport, uint32_t leftGlyph, uint32_t rightGlyph, const TextDrawContext& ctx) const; + float GetBaselineInternal(const RHI::Viewport& viewport, const TextDrawContext& ctx) const; // returns true if add operation was successful, false otherwise using AddFunction = AZStd::function; @@ -229,6 +250,7 @@ namespace AZ //! This function is used by both DrawStringUInternal and WriteTextQuadsToBuffers //! To do this is takes a function pointer that implement the appropriate AddQuad behavior int CreateQuadsForText( + const RHI::Viewport& viewport, float x, float y, float z, @@ -247,16 +269,16 @@ namespace AZ float rcpCellWidth; }; - TextScaleInfoInternal CalculateScaleInternal(const TextDrawContext& ctx) const; + TextScaleInfoInternal CalculateScaleInternal(const RHI::Viewport& viewport, const TextDrawContext& ctx) const; Vec2 GetRestoredFontSize(const TextDrawContext& ctx) const; bool UpdateTexture(); - void ScaleCoord(float& x, float& y) const; + void ScaleCoord(const RHI::Viewport& viewport, float& x, float& y) const; - void InitWindowContext(); - void InitViewportContext(); + void InitDefaultWindowContext(); + void InitDefaultViewportContext(); void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) override; @@ -272,8 +294,8 @@ namespace AZ size_t m_fontBufferSize = 0; unsigned char* m_fontBuffer = nullptr; - AZStd::shared_ptr m_windowContext; - AZStd::shared_ptr m_viewportContext; + AZStd::shared_ptr m_defaultWindowContext; + AZStd::shared_ptr m_defaultViewportContext; AZ::Data::Instance m_fontStreamingImage; AZ::RHI::Ptr m_fontImage; @@ -296,8 +318,6 @@ namespace AZ FontShaderData m_fontShaderData; - AZ::RHI::Ptr m_dynamicDraw; - bool m_monospacedFont = false; //!< True if this font is fixed/monospaced, false otherwise (obtained from FreeType) float m_sizeRatio = IFFontConstants::defaultSizeRatio; @@ -325,25 +345,25 @@ namespace AZ } } -inline void AZ::FFont::InitWindowContext() +inline void AZ::FFont::InitDefaultWindowContext() { - if (!m_windowContext) + if (!m_defaultWindowContext) { // font is created before window & viewport in the editor so need to do late init // TODO need to deal with multiple windows, such as the editor - AZ::Render::Bootstrap::DefaultWindowBus::BroadcastResult(m_windowContext, &AZ::Render::Bootstrap::DefaultWindowInterface::GetDefaultWindowContext); - AZ_Assert(m_windowContext, "Unable to get the main window context"); + AZ::Render::Bootstrap::DefaultWindowBus::BroadcastResult(m_defaultWindowContext, &AZ::Render::Bootstrap::DefaultWindowInterface::GetDefaultWindowContext); + AZ_Assert(m_defaultWindowContext, "Unable to get the main window context"); } } -inline void AZ::FFont::InitViewportContext() +inline void AZ::FFont::InitDefaultViewportContext() { - if (!m_viewportContext) + if (!m_defaultViewportContext) { // font is created before window & viewport in the editor so need to do late init auto viewContextManager = AZ::Interface::Get(); - m_viewportContext = viewContextManager->GetViewportContextByName(viewContextManager->GetDefaultViewportContextName()); - AZ_Assert(m_viewportContext, "Unable to get the viewport context"); + m_defaultViewportContext = viewContextManager->GetViewportContextByName(viewContextManager->GetDefaultViewportContextName()); + AZ_Assert(m_defaultViewportContext, "Unable to get the viewport context"); } } diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp b/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp index 0a081d01f1..636583fe98 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp +++ b/Gems/AtomLyIntegration/AtomFont/Code/Source/AtomFont.cpp @@ -28,8 +28,12 @@ #include #include +#include +#include #include +#include +#include // Static member definitions const AZ::AtomFont::GlyphSize AZ::AtomFont::defaultGlyphSize = AZ::AtomFont::GlyphSize(ICryFont::defaultGlyphSizeX, ICryFont::defaultGlyphSizeY); @@ -348,10 +352,14 @@ AZ::AtomFont::AtomFont(ISystem* system) REGISTER_COMMAND("r_ReloadFonts", ReloadFonts, VF_NULL, "Reload all fonts"); #endif + AZ::Interface::Register(this); } AZ::AtomFont::~AtomFont() { + AZ::Interface::Unregister(this); + m_defaultFontDrawInterface = nullptr; + // Persist fonts for application lifetime to prevent unnecessary work m_persistedFontFamilies.clear(); @@ -372,24 +380,41 @@ IFFont* AZ::AtomFont::NewFont(const char* fontName) { string name = fontName; name.MakeLower(); + AzFramework::FontId fontId = GetFontId(name.c_str()); - FontMapItor it = m_fonts.find(CONST_TEMP_STRING(name.c_str())); + FontMapItor it = m_fonts.find(fontId); if (it != m_fonts.end()) { return it->second; } FFont* font = new FFont(this, name.c_str()); - m_fonts.insert(FontMapItor::value_type(name, font)); + m_fonts.insert(FontMapItor::value_type(fontId, font)); + if(!m_defaultFontDrawInterface) + { + m_defaultFontDrawInterface = static_cast(font); + } return font; } IFFont* AZ::AtomFont::GetFont(const char* fontName) const { - FontMapConstItor it = m_fonts.find(CONST_TEMP_STRING(string(fontName).MakeLower())); + AzFramework::FontId fontId = GetFontId(string(fontName).MakeLower().c_str()); + FontMapConstItor it = m_fonts.find(fontId); return it != m_fonts.end() ? it->second : 0; } +AzFramework::FontDrawInterface* AZ::AtomFont::GetFontDrawInterface(AzFramework::FontId fontId) const +{ + FontMapConstItor it = m_fonts.find(fontId); + return (it != m_fonts.end()) ? it->second : nullptr; +} + +AzFramework::FontDrawInterface* AZ::AtomFont::GetDefaultFontDrawInterface() const +{ + return m_defaultFontDrawInterface; +} + FontFamilyPtr AZ::AtomFont::LoadFontFamily(const char* fontFamilyName) { FontFamilyPtr fontFamily(nullptr); @@ -648,7 +673,8 @@ void AZ::AtomFont::ReloadAllFonts() void AZ::AtomFont::UnregisterFont(const char* fontName) { - FontMapItor it = m_fonts.find(CONST_TEMP_STRING(fontName)); + AzFramework::FontId fontId = GetFontId(string(fontName).MakeLower().c_str()); + FontMapItor it = m_fonts.find(fontId); #if defined(AZ_ENABLE_TRACING) IFFont* fontPtr = it->second; @@ -823,5 +849,49 @@ XmlNodeRef AZ::AtomFont::LoadFontFamilyXml(const char* fontFamilyName, string& o return root; } +void AZ::AtomFont::SceneAboutToBeRemoved(AzFramework::Scene& scene) +{ + AZ::RPI::Scene* rpiScene = scene.GetSubsystem(); + + AZStd::lock_guard lock(m_sceneToDynamicDrawMutex); + if ( auto it = m_sceneToDynamicDrawMap.find(rpiScene); it != m_sceneToDynamicDrawMap.end()) + { + m_sceneToDynamicDrawMap.erase(it); + } +} + +AZ::RHI::Ptr AZ::AtomFont::GetOrCreateDynamicDrawForScene(AZ::RPI::Scene* scene) +{ + static const char* shaderFilepath = "Shaders/SimpleTextured.azshader"; + + { + // shared lock while reading + AZStd::shared_lock lock(m_sceneToDynamicDrawMutex); + + if (auto it = m_sceneToDynamicDrawMap.find(scene); it != m_sceneToDynamicDrawMap.end()) + { + return it->second; + } + } + + // Create and initialize DynamicDrawContext for font draw + AZ::RHI::Ptr dynamicDraw = RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext(scene); + + Data::Instance shader = AZ::RPI::LoadShader(shaderFilepath); + AZ::RPI::ShaderOptionList shaderOptions; + shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("false"))); + shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_clamp"), AZ::Name("true"))); + dynamicDraw->InitShaderWithVariant(shader, &shaderOptions); + dynamicDraw->InitVertexFormat({{"POSITION", RHI::Format::R32G32B32_FLOAT}, {"COLOR", RHI::Format::R8G8B8A8_UNORM}, {"TEXCOORD0", RHI::Format::R32G32_FLOAT}}); + dynamicDraw->EndInit(); + + // exclusive lock while writing + AZStd::lock_guard lock(m_sceneToDynamicDrawMutex); + m_sceneToDynamicDrawMap.insert(AZStd::make_pair(scene, dynamicDraw)); + + return dynamicDraw; +} + + #endif diff --git a/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp b/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp index bb4eb23d8f..d32302a07b 100644 --- a/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp +++ b/Gems/AtomLyIntegration/AtomFont/Code/Source/FFont.cpp @@ -23,6 +23,9 @@ #include #include +#include +#include + #include #include @@ -42,6 +45,8 @@ #include #include #include +#include +#include #include #include @@ -49,6 +54,7 @@ #include +static const AZ::Vector2 UiDraw_TextSizeFactor = AZ::Vector2(12.0f, 12.0f); static const int TabCharCount = 4; // set buffer sizes to hold max characters that can be drawn in 1 DrawString call static const size_t MaxVerts = 8 * 1024; // 2048 quads @@ -78,6 +84,7 @@ AZ::FFont::FFont(AtomFont* atomFont, const char* fontName) AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect(); } + bool AZ::FFont::InitFont() { if (m_fontInitialized) @@ -85,24 +92,14 @@ bool AZ::FFont::InitFont() return true; } - InitWindowContext(); - InitViewportContext(); - - const char* shaderFilepath = "Shaders/SimpleTextured.azshader"; + InitDefaultWindowContext(); + InitDefaultViewportContext(); // Create and initialize DynamicDrawContext for font draw - m_dynamicDraw = RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext(m_viewportContext->GetRenderScene().get()); - - Data::Instance shader = AZ::RPI::LoadShader(shaderFilepath); - AZ::RPI::ShaderOptionList shaderOptions; - shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("false"))); - shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_clamp"), AZ::Name("true"))); - m_dynamicDraw->InitShaderWithVariant(shader, &shaderOptions); - m_dynamicDraw->InitVertexFormat({{"POSITION", RHI::Format::R32G32B32_FLOAT}, {"COLOR", RHI::Format::R8G8B8A8_UNORM}, {"TEXCOORD0", RHI::Format::R32G32_FLOAT}}); - m_dynamicDraw->EndInit(); + AZ::RPI::Ptr dynamicDraw = m_atomFont->GetOrCreateDynamicDrawForScene(m_defaultViewportContext->GetRenderScene().get()); // Save draw srg input indices for later use - Data::Instance drawSrg = m_dynamicDraw->NewDrawSrg(); + Data::Instance drawSrg = dynamicDraw->NewDrawSrg(); const RHI::ShaderResourceGroupLayout* layout = drawSrg->GetAsset()->GetLayout(); m_fontShaderData.m_imageInputIndex = layout->FindShaderInputImageIndex(AZ::Name(ShaderInputs::TextureIndexName)); @@ -257,27 +254,39 @@ void AZ::FFont::Free() void AZ::FFont::DrawString(float x, float y, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) { - if (!str || !m_vertexBuffer) + if (!str) { return; } - DrawStringUInternal(x, y, 1.0f, str, asciiMultiLine, ctx); + DrawStringUInternal(m_defaultWindowContext->GetViewport(), m_defaultViewportContext.get(), x, y, 1.0f, str, asciiMultiLine, ctx); } void AZ::FFont::DrawString(float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) { - if (!str || !m_vertexBuffer) + if (!str) { return; } - DrawStringUInternal(x, y, z, str, asciiMultiLine, ctx); + DrawStringUInternal(m_defaultWindowContext->GetViewport(), m_defaultViewportContext.get(), x, y, z, str, asciiMultiLine, ctx); } -void AZ::FFont::DrawStringUInternal(float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) +void AZ::FFont::DrawStringUInternal( + const RHI::Viewport& viewport, + RPI::ViewportContext* viewportContext, + float x, + float y, + float z, + const char* str, + const bool asciiMultiLine, + const TextDrawContext& ctx) { - if (!str || !m_fontTexture || ctx.m_fxIdx >= m_effects.size() || m_effects[ctx.m_fxIdx].m_passes.empty()) + if (!str + || !m_vertexBuffer // vertex buffer isn't created until BootstrapScene is ready, Editor tries to render text before that. + || !m_fontTexture + || ctx.m_fxIdx >= m_effects.size() + || m_effects[ctx.m_fxIdx].m_passes.empty()) { return; } @@ -296,7 +305,6 @@ void AZ::FFont::DrawStringUInternal(float x, float y, float z, const char* str, const bool orthoMode = ctx.m_overrideViewProjMatrices; - const RHI::Viewport& viewport = m_windowContext->GetViewport(); const float viewX = viewport.m_minX; const float viewY = viewport.m_minY; const float viewWidth = viewport.m_maxX - viewport.m_minX; @@ -307,7 +315,7 @@ void AZ::FFont::DrawStringUInternal(float x, float y, float z, const char* str, Matrix4x4 modelViewProjMat; if (!orthoMode) { - AZ::RPI::ViewPtr view = m_viewportContext->GetDefaultView(); + AZ::RPI::ViewPtr view = viewportContext->GetDefaultView(); modelViewProjMat = view->GetWorldToClipMatrix(); } else @@ -322,7 +330,7 @@ void AZ::FFont::DrawStringUInternal(float x, float y, float z, const char* str, size_t startingVertexCount = m_vertexCount; // Local function that is passed into CreateQuadsForText as the AddQuad function - AddFunction AddQuad = [this, startingVertexCount] + AZ::FFont::AddFunction AddQuad = [this, startingVertexCount] (const Vec3& v0, const Vec3& v1, const Vec3& v2, const Vec3& v3, const Vec2& tc0, const Vec2& tc1, const Vec2& tc2, const Vec2& tc3, uint32_t packedColor) { const bool vertexSpaceLeft = m_vertexCount + 4 < MaxVerts; @@ -367,18 +375,19 @@ void AZ::FFont::DrawStringUInternal(float x, float y, float z, const char* str, int numQuads = 0; { AZStd::lock_guard lock(m_vertexDataMutex); - numQuads = CreateQuadsForText(x, y, z, str, asciiMultiLine, ctx, AddQuad); + numQuads = CreateQuadsForText(viewport, x, y, z, str, asciiMultiLine, ctx, AddQuad); } if (numQuads) { + auto dynamicDraw = m_atomFont->GetOrCreateDynamicDrawForScene(viewportContext->GetRenderScene().get()); //setup per draw srg - auto drawSrg = m_dynamicDraw->NewDrawSrg(); + auto drawSrg = dynamicDraw->NewDrawSrg(); drawSrg->SetConstant(m_fontShaderData.m_viewProjInputIndex, modelViewProjMat); drawSrg->SetImageView(m_fontShaderData.m_imageInputIndex, m_fontStreamingImage->GetImageView()); drawSrg->Compile(); - m_dynamicDraw->DrawIndexed(m_vertexBuffer, m_vertexCount, m_indexBuffer, m_indexCount, RHI::IndexFormat::Uint16, drawSrg); + dynamicDraw->DrawIndexed(m_vertexBuffer, m_vertexCount, m_indexBuffer, m_indexCount, RHI::IndexFormat::Uint16, drawSrg); m_indexCount = 0; m_vertexCount = 0; } @@ -391,10 +400,14 @@ Vec2 AZ::FFont::GetTextSize(const char* str, const bool asciiMultiLine, const Te return Vec2(0.0f, 0.0f); } - return GetTextSizeUInternal(str, asciiMultiLine, ctx); + return GetTextSizeUInternal(m_defaultWindowContext->GetViewport(), str, asciiMultiLine, ctx); } -Vec2 AZ::FFont::GetTextSizeUInternal(const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) +Vec2 AZ::FFont::GetTextSizeUInternal( + const RHI::Viewport& viewport, + const char* str, + const bool asciiMultiLine, + const TextDrawContext& ctx) { const size_t fxSize = m_effects.size(); @@ -411,12 +424,12 @@ Vec2 AZ::FFont::GetTextSizeUInternal(const char* str, const bool asciiMultiLine, Vec2 size = ctx.m_size; if (ctx.m_sizeIn800x600) { - ScaleCoord(size.x, size.y); + ScaleCoord(viewport, size.x, size.y); } // This scaling takes into account the logical size of the font relative // to any additional scaling applied (such as from "size ratio"). - const TextScaleInfoInternal scaleInfo(CalculateScaleInternal(ctx)); + const TextScaleInfoInternal scaleInfo(CalculateScaleInternal(viewport, ctx)); float maxW = 0; float maxH = 0; @@ -733,7 +746,7 @@ uint32_t AZ::FFont::WriteTextQuadsToBuffers(SVF_P2F_C4B_T2F_F4B* verts, uint16_t return true; }; - CreateQuadsForText(x, y, z, str, asciiMultiLine, ctx, AddQuad); + CreateQuadsForText(m_defaultWindowContext->GetViewport(), x, y, z, str, asciiMultiLine, ctx, AddQuad); return numQuadsWritten; } @@ -743,7 +756,7 @@ uint32_t AZ::FFont::GetFontTextureVersion() return m_fontImageVersion; } -int AZ::FFont::CreateQuadsForText(float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx, +int AZ::FFont::CreateQuadsForText(const RHI::Viewport& viewport, float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx, AddFunction AddQuad) { int numQuads = 0; @@ -768,17 +781,17 @@ int AZ::FFont::CreateQuadsForText(float x, float y, float z, const char* str, co Vec2 size = ctx.m_size; if (ctx.m_sizeIn800x600) { - ScaleCoord(size.x, size.y); + ScaleCoord(viewport, size.x, size.y); } // This scaling takes into account the logical size of the font relative // to any additional scaling applied (such as from "size ratio"). - const TextScaleInfoInternal scaleInfo(CalculateScaleInternal(ctx)); + const TextScaleInfoInternal scaleInfo(CalculateScaleInternal(viewport, ctx)); Vec2 baseXY = Vec2(x, y); // in pixels if (ctx.m_sizeIn800x600) { - ScaleCoord(baseXY.x, baseXY.y); + ScaleCoord(viewport, baseXY.x, baseXY.y); } // snap for pixel perfect rendering (better quality for text) @@ -826,7 +839,7 @@ int AZ::FFont::CreateQuadsForText(float x, float y, float z, const char* str, co ColorB tempColor(255, 255, 255, 255); uint32_t frameColor = tempColor.pack_abgr8888(); //note: this ends up in r,g,b,a order on little-endian machines - Vec2 textSize = GetTextSizeUInternal(str, asciiMultiLine, ctx); + Vec2 textSize = GetTextSizeUInternal(viewport, str, asciiMultiLine, ctx); float x0 = baseXY.x - 12; float y0 = baseXY.y - 6; @@ -1107,13 +1120,13 @@ int AZ::FFont::CreateQuadsForText(float x, float y, float z, const char* str, co return numQuads; } -AZ::FFont::TextScaleInfoInternal AZ::FFont::CalculateScaleInternal(const TextDrawContext& ctx) const +AZ::FFont::TextScaleInfoInternal AZ::FFont::CalculateScaleInternal(const RHI::Viewport& viewport, const TextDrawContext& ctx) const { Vec2 size = GetRestoredFontSize(ctx); // in pixel if (ctx.m_sizeIn800x600) { - ScaleCoord(size.x, size.y); + ScaleCoord(viewport, size.x, size.y); } float rcpCellWidth; @@ -1196,7 +1209,7 @@ void AZ::FFont::WrapText(string& result, float maxWidth, const char* str, const maxWidth = gEnv->pRenderer->ScaleCoordX(maxWidth); } - Vec2 strSize = GetTextSizeUInternal(result.c_str(), true, ctx); + Vec2 strSize = GetTextSize(result.c_str(), true, ctx); if (strSize.x <= maxWidth) { @@ -1245,7 +1258,7 @@ void AZ::FFont::WrapText(string& result, float maxWidth, const char* str, const // Note: This is not unicode compatible, since char-width depends on surrounding context (ie, combining diacritics etc) char codepoint[5]; Unicode::Convert(codepoint, ch); - curCharWidth = GetTextSizeUInternal(codepoint, true, ctx).x; + curCharWidth = GetTextSize(codepoint, true, ctx).x; // keep track of spaces // they are good for splitting the string @@ -1425,7 +1438,12 @@ void AZ::FFont::AddCharsToFontTexture(const char* chars, int glyphSizeX, int gly Vec2 AZ::FFont::GetKerning(uint32_t leftGlyph, uint32_t rightGlyph, const TextDrawContext& ctx) const { - const TextScaleInfoInternal scaleInfo(CalculateScaleInternal(ctx)); + return GetKerningInternal(m_defaultWindowContext->GetViewport(), leftGlyph, rightGlyph, ctx); +} + +Vec2 AZ::FFont::GetKerningInternal(const RHI::Viewport& viewport, uint32_t leftGlyph, uint32_t rightGlyph, const TextDrawContext& ctx) const +{ + const TextScaleInfoInternal scaleInfo(CalculateScaleInternal(viewport, ctx)); return m_fontTexture->GetKerning(leftGlyph, rightGlyph) * scaleInfo.scale.x; } @@ -1436,12 +1454,18 @@ float AZ::FFont::GetAscender(const TextDrawContext& ctx) const float AZ::FFont::GetBaseline(const TextDrawContext& ctx) const { - const TextScaleInfoInternal scaleInfo(CalculateScaleInternal(ctx)); + return GetBaselineInternal(m_defaultWindowContext->GetViewport(), ctx); +} + +float AZ::FFont::GetBaselineInternal(const RHI::Viewport& viewport, const TextDrawContext& ctx) const +{ + const TextScaleInfoInternal scaleInfo(CalculateScaleInternal(viewport, ctx)); // Calculate baseline the same way as the font renderer which uses the glyph height * size ratio. // Adding 1 because FontTexture always adds 1 to the char height in GetTextureCoord return (round(m_fontTexture->GetCellHeight() * GetSizeRatio()) + 1.0f) * scaleInfo.scale.y; } + bool AZ::FFont::InitTexture() { using namespace AZ; @@ -1565,14 +1589,8 @@ Vec2 AZ::FFont::GetRestoredFontSize(const TextDrawContext& ctx) const return Vec2(ctx.m_size.x * restoringScale, ctx.m_size.y * restoringScale); } -void AZ::FFont::ScaleCoord(float& x, float& y) const +void AZ::FFont::ScaleCoord(const RHI::Viewport& viewport, float& x, float& y) const { - if (!m_windowContext) - { - return; - } - - const RHI::Viewport& viewport = m_windowContext->GetViewport(); float width = viewport.m_maxX - viewport.m_minX; float height = viewport.m_maxY - viewport.m_minY; @@ -1580,11 +1598,161 @@ void AZ::FFont::ScaleCoord(float& x, float& y) const y *= height / WindowScaleHeight; } + void AZ::FFont::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene) { InitFont(); } +static void SetCommonContextFlags(AZ::TextDrawContext& ctx, const AzFramework::TextDrawParameters& params) +{ + if (params.m_hAlign == AzFramework::TextHorizontalAlignment::Center) + { + ctx.m_drawTextFlags |= eDrawText_Center; + } -#endif + if (params.m_hAlign == AzFramework::TextHorizontalAlignment::Right) + { + ctx.m_drawTextFlags |= eDrawText_Right; + } + + if (params.m_vAlign == AzFramework::TextVerticalAlignment::Center) + { + ctx.m_drawTextFlags |= eDrawText_CenterV; + } + + if (params.m_vAlign == AzFramework::TextVerticalAlignment::Bottom) + { + ctx.m_drawTextFlags |= eDrawText_Bottom; + } + + if (params.m_monospace) + { + ctx.m_drawTextFlags |= eDrawText_Monospace; + } + + if (params.m_depthTest) + { + ctx.m_drawTextFlags |= eDrawText_DepthTest; + } + + if (params.m_virtual800x600ScreenSize) + { + ctx.m_drawTextFlags |= eDrawText_800x600; + } + + if (!params.m_scaleWithWindow) + { + ctx.m_drawTextFlags |= eDrawText_FixedSize; + } +} + +void AZ::FFont::DrawScreenAlignedText2d( + const AzFramework::TextDrawParameters& params, + const AZStd::string_view& string) +{ + if (params.m_drawViewportId == AzFramework::InvalidViewportId || + string.empty()) + { + return; + } + + //Code mostly duplicated from CRenderer::Draw2dTextWithDepth + float posX = params.m_position.GetX(); + float posY = params.m_position.GetY(); + AZ::RPI::ViewportContext* viewportContext = AZ::Interface::Get()->GetViewportContextById(params.m_drawViewportId).get(); + const AZ::RHI::Viewport& viewport = viewportContext->GetWindowContext()->GetViewport(); + if (params.m_virtual800x600ScreenSize) + { + posX *= WindowScaleWidth / (viewport.m_maxX - viewport.m_minX); + posY *= WindowScaleHeight / (viewport.m_maxY - viewport.m_minY); + } + TextDrawContext ctx; + ctx.SetBaseState(GS_NODEPTHTEST); + ctx.SetColor(AZColorToLYColorF(params.m_color)); + ctx.SetCharWidthScale((params.m_monospace || params.m_scaleWithWindow) ? 0.5f : 1.0f); + ctx.EnableFrame(false); + ctx.SetProportional(!params.m_monospace && params.m_scaleWithWindow); + ctx.SetSizeIn800x600(params.m_scaleWithWindow && params.m_virtual800x600ScreenSize); + ctx.SetSize(AZVec2ToLYVec2(UiDraw_TextSizeFactor * params.m_scale)); + if (params.m_monospace || !params.m_scaleWithWindow) + { + ScaleCoord(viewport, posX, posY); + } + + if (params.m_hAlign != AzFramework::TextHorizontalAlignment::Left || + params.m_vAlign != AzFramework::TextVerticalAlignment::Top) + { + Vec2 textSize = GetTextSizeUInternal(viewport, string.data(), params.m_multiline, ctx); + + // If we're using virtual 800x600 coordinates, convert the text size from + // pixels to that before using it as an offset. + if (ctx.m_sizeIn800x600) + { + float width = 1.0f; + float height = 1.0f; + ScaleCoord(viewport, width, height); + textSize.x /= width; + textSize.y /= height; + } + + if (params.m_hAlign == AzFramework::TextHorizontalAlignment::Center) + { + posX -= textSize.x * 0.5f; + } + else if (params.m_hAlign == AzFramework::TextHorizontalAlignment::Right) + { + posX -= textSize.x; + } + + if (params.m_vAlign == AzFramework::TextVerticalAlignment::Center) + { + posY -= textSize.y * 0.5f; + } + else if (params.m_vAlign == AzFramework::TextVerticalAlignment::Bottom) + { + posY -= textSize.y; + } + } + SetCommonContextFlags(ctx, params); + ctx.m_drawTextFlags |= eDrawText_2D; + + DrawStringUInternal( + viewport, + viewportContext, + posX, + posY, + params.m_position.GetZ(), // Z + string.data(), + params.m_multiline, + ctx + ); +} + +void AZ::FFont::DrawScreenAlignedText3d( + const AzFramework::TextDrawParameters& params, + const AZStd::string_view& string) +{ + if (params.m_drawViewportId == AzFramework::InvalidViewportId || + string.empty()) + { + return; + } + AZ::RPI::ViewportContext* viewportContext = AZ::Interface::Get()->GetViewportContextById(params.m_drawViewportId).get(); + AZ::RPI::ViewPtr currentView = viewportContext->GetDefaultView(); + if (!currentView) + { + return; + } + AZ::Vector3 positionNDC = AzFramework::WorldToScreenNDC( + params.m_position, + currentView->GetViewToWorldMatrix(), + currentView->GetViewToClipMatrix() + ); + AzFramework::TextDrawParameters param2d = params; + param2d.m_position = positionNDC; + DrawScreenAlignedText2d(param2d, string); +} + +#endif //USE_NULLFONT_ALWAYS diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h index 857e795257..fe40cabc12 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h @@ -73,6 +73,9 @@ namespace AZ bool RequiresShapeComponent() const; + //! Returns true if the light type is anything other than unknown. + bool LightTypeIsSelected() const; + //! Returns true if m_attenuationRadiusMode is set to LightAttenuationRadiusMode::Automatic bool IsAttenuationRadiusModeAutomatic() const; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp index 2afa6514cd..2dc439b846 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp @@ -73,6 +73,11 @@ namespace AZ || m_lightType == LightType::Polygon; } + bool AreaLightComponentConfig::LightTypeIsSelected() const + { + return m_lightType != LightType::Unknown; + } + bool AreaLightComponentConfig::IsAttenuationRadiusModeAutomatic() const { return m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp index 1bbc2a411e..c1c957ed4c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp @@ -234,6 +234,11 @@ namespace AZ::Render !(m_configuration.m_lightType == AreaLightComponentConfig::LightType::Polygon && m_configuration.m_shapeType != PoylgonShapeTypeId), "The light type is a polygon, but the shape component is not."); } + + if (m_configuration.m_lightType == AreaLightComponentConfig::LightType::SimpleSpot) + { + m_configuration.m_enableShutters = true; // Simple spot always has shutters. + } } void AreaLightComponentController::ConfigurationChanged() @@ -620,6 +625,10 @@ namespace AZ::Render break; } } + if (m_lightShapeDelegate) + { + m_lightShapeDelegate->SetConfig(&m_configuration); + } } } // namespace AZ::Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp index 32b6a9f0b7..2758da2b38 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp @@ -51,14 +51,52 @@ namespace AZ::Render return m_shapeBus->GetRadius() * GetTransform().GetScale().GetMaxElement(); } - void DiskLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const + void DiskLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& /*color*/, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const { if (isSelected) { - debugDisplay.SetColor(color); + debugDisplay.PushMatrix(transform); + float radius = GetConfig()->m_attenuationRadius; - // Draw a disk for the attenuation radius - debugDisplay.DrawWireSphere(transform.GetTranslation(), CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity)); + if (GetConfig()->m_enableShutters) + { + + float innerRadians = DegToRad(GetConfig()->m_innerShutterAngleDegrees); + float outerRadians = DegToRad(GetConfig()->m_outerShutterAngleDegrees); + + // Draw a cone using the cone angle and attenuation radius + innerRadians = GetMin(innerRadians, outerRadians); + float coneRadiusInner = sin(innerRadians) * radius; + float coneHeightInner = cos(innerRadians) * radius; + float coneRadiusOuter = sin(outerRadians) * radius; + float coneHeightOuter = cos(outerRadians) * radius; + + auto DrawConicalFrustum = [&debugDisplay](uint32_t numRadiusLines, float topRadius, float bottomRadius, float height, float brightness) + { + debugDisplay.SetColor(Color(brightness, brightness, brightness, 1.0f)); + debugDisplay.DrawWireDisk(Vector3(0.0, 0.0, height), Vector3::CreateAxisZ(), bottomRadius); + + for (uint32_t i = 0; i < numRadiusLines; ++i) + { + float radiusLineAngle = float(i) / numRadiusLines * Constants::TwoPi; + debugDisplay.DrawLine( + Vector3(cos(radiusLineAngle) * topRadius, sin(radiusLineAngle) * topRadius, 0), + Vector3(cos(radiusLineAngle) * bottomRadius, sin(radiusLineAngle) * bottomRadius, height) + ); + } + }; + + DrawConicalFrustum(16, m_shapeBus->GetRadius(), m_shapeBus->GetRadius() + coneRadiusInner, coneHeightInner, 1.0f); + DrawConicalFrustum(16, m_shapeBus->GetRadius(), m_shapeBus->GetRadius() + coneRadiusOuter, coneHeightOuter, 0.65f); + + } + else + { + debugDisplay.DrawWireDisk(Vector3::CreateZero(), Vector3::CreateAxisZ(), radius); + debugDisplay.DrawArc(Vector3::CreateZero(), radius, 90.0f, 180.0f, -3.0f, 0); + debugDisplay.DrawArc(Vector3::CreateZero(), radius, 0.0f, 180.0f, 3.0f, 1); + } + debugDisplay.PopMatrix(); } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index bdff97b48e..6a07a8a737 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -67,50 +67,56 @@ namespace AZ editContext->Class( "AreaLightComponentConfig", "") ->ClassElement(Edit::ClassElements::EditorData, "") - ->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_lightType, "Light Type", "Which type of light this component represents.") - ->EnumAttribute(AreaLightComponentConfig::LightType::Unknown, "Choose a Light Type") - ->EnumAttribute(AreaLightComponentConfig::LightType::Sphere, "Point (Sphere)") - ->EnumAttribute(AreaLightComponentConfig::LightType::SimplePoint, "Point (Simple)") - ->EnumAttribute(AreaLightComponentConfig::LightType::SpotDisk, "Spot (Disk)") - ->EnumAttribute(AreaLightComponentConfig::LightType::SimpleSpot, "Spot (Simple)") + ->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_lightType, "Light type", "Which type of light this component represents.") + ->EnumAttribute(AreaLightComponentConfig::LightType::Unknown, "Choose a light type") + ->EnumAttribute(AreaLightComponentConfig::LightType::Sphere, "Point (sphere)") + ->EnumAttribute(AreaLightComponentConfig::LightType::SimplePoint, "Point (simple punctual)") + ->EnumAttribute(AreaLightComponentConfig::LightType::SpotDisk, "Spot (disk)") + ->EnumAttribute(AreaLightComponentConfig::LightType::SimpleSpot, "Spot (simple punctual)") ->EnumAttribute(AreaLightComponentConfig::LightType::Capsule, "Capsule") ->EnumAttribute(AreaLightComponentConfig::LightType::Quad, "Quad") ->EnumAttribute(AreaLightComponentConfig::LightType::Polygon, "Polygon") ->DataElement(Edit::UIHandlers::Color, &AreaLightComponentConfig::m_color, "Color", "Color of the light") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::LightTypeIsSelected) ->Attribute("ColorEditorConfiguration", RPI::ColorUtils::GetLinearRgbEditorConfig()) - ->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_intensityMode, "Intensity Mode", "Allows specifying which photometric unit to work in.") + ->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_intensityMode, "Intensity mode", "Allows specifying which photometric unit to work in.") ->Attribute(AZ::Edit::Attributes::EnumValues, &AreaLightComponentConfig::GetValidPhotometricUnits) + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::LightTypeIsSelected) ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_intensity, "Intensity", "Intensity of the light in the set photometric unit.") ->Attribute(Edit::Attributes::Min, &AreaLightComponentConfig::GetIntensityMin) ->Attribute(Edit::Attributes::Max, &AreaLightComponentConfig::GetIntensityMax) ->Attribute(Edit::Attributes::SoftMin, &AreaLightComponentConfig::GetIntensitySoftMin) ->Attribute(Edit::Attributes::SoftMax, &AreaLightComponentConfig::GetIntensitySoftMax) ->Attribute(Edit::Attributes::Suffix, &AreaLightComponentConfig::GetIntensitySuffix) - ->DataElement(Edit::UIHandlers::CheckBox, &AreaLightComponentConfig::m_lightEmitsBothDirections, "Both Directions", "Whether light should emit from both sides of the surface or just the front") + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::LightTypeIsSelected) + ->DataElement(Edit::UIHandlers::CheckBox, &AreaLightComponentConfig::m_lightEmitsBothDirections, "Both directions", "Whether light should emit from both sides of the surface or just the front") ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsBothDirections) - ->DataElement(Edit::UIHandlers::CheckBox, &AreaLightComponentConfig::m_useFastApproximation, "Fast Approximation", "Whether the light should use the default high quality linear transformed cosine technique or a faster approximation.") + ->DataElement(Edit::UIHandlers::CheckBox, &AreaLightComponentConfig::m_useFastApproximation, "Fast approximation", "Whether the light should use the default high quality linear transformed cosine technique or a faster approximation.") ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsFastApproximation) - ->ClassElement(Edit::ClassElements::Group, "Attenuation Radius") + ->ClassElement(Edit::ClassElements::Group, "Attenuation radius") ->Attribute(Edit::Attributes::AutoExpand, true) + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::LightTypeIsSelected) ->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_attenuationRadiusMode, "Mode", "Controls whether the attenation radius is calculated automatically or set explicitly.") ->EnumAttribute(LightAttenuationRadiusMode::Automatic, "Automatic") ->EnumAttribute(LightAttenuationRadiusMode::Explicit, "Explicit") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::LightTypeIsSelected) ->DataElement(Edit::UIHandlers::Default, &AreaLightComponentConfig::m_attenuationRadius, "Radius", "The distance at which this light no longer has an affect.") ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsAttenuationRadiusModeAutomatic) + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::LightTypeIsSelected) ->ClassElement(Edit::ClassElements::Group, "Shutters") ->Attribute(Edit::Attributes::AutoExpand, true) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters) - ->DataElement(Edit::UIHandlers::Default, &AreaLightComponentConfig::m_enableShutters, "Enable Shutters", "Restrict the light to a specific beam angle depending on shape.") + ->DataElement(Edit::UIHandlers::Default, &AreaLightComponentConfig::m_enableShutters, "Enable shutters", "Restrict the light to a specific beam angle depending on shape.") ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::ShuttersMustBeEnabled) - ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_innerShutterAngleDegrees, "Inner Angle", "The inner angle of the shutters where the light beam begins to be occluded.") + ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_innerShutterAngleDegrees, "Inner angle", "The inner angle of the shutters where the light beam begins to be occluded.") ->Attribute(Edit::Attributes::Min, 0.0f) ->Attribute(Edit::Attributes::Max, 180.0f) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShuttersDisabled) - ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_outerShutterAngleDegrees, "Outer Angle", "The outer angle of the shutters where the light beam is completely occluded.") + ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_outerShutterAngleDegrees, "Outer angle", "The outer angle of the shutters where the light beam is completely occluded.") ->Attribute(Edit::Attributes::Min, 0.0f) ->Attribute(Edit::Attributes::Max, 180.0f) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters) @@ -119,9 +125,9 @@ namespace AZ ->ClassElement(Edit::ClassElements::Group, "Shadows") ->Attribute(Edit::Attributes::AutoExpand, true) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) - ->DataElement(Edit::UIHandlers::Default, &AreaLightComponentConfig::m_enableShadow, "Enable Shadow", "Enable shadow for the light") + ->DataElement(Edit::UIHandlers::Default, &AreaLightComponentConfig::m_enableShadow, "Enable shadow", "Enable shadow for the light") ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) - ->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_shadowmapMaxSize, "Shadowmap Size", "Width/Height of shadowmap") + ->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_shadowmapMaxSize, "Shadowmap size", "Width and height of shadowmap") ->EnumAttribute(ShadowmapSize::Size256, " 256") ->EnumAttribute(ShadowmapSize::Size512, " 512") ->EnumAttribute(ShadowmapSize::Size1024, "1024") @@ -129,13 +135,13 @@ namespace AZ ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled) - ->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_shadowFilterMethod, "Shadow Filter Method", + ->DataElement(Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_shadowFilterMethod, "Shadow filter method", "Filtering method of edge-softening of shadows.\n" " None: no filtering\n" - " PCF: Percentage-Closer Filtering\n" - " ESM: Exponential Shadow Maps\n" + " PCF: Percentage-closer Filtering\n" + " ESM: Exponential shadow maps\n" " ESM+PCF: ESM with a PCF fallback\n" - "For BehaviorContext (or TrackView), None=0, PCF=1, ESM=2, ESM+PCF=3") + "For BehaviorContext (or track view), None=0, PCF=1, ESM=2, ESM+PCF=3") ->EnumAttribute(ShadowFilterMethod::None, "None") ->EnumAttribute(ShadowFilterMethod::Pcf, "PCF") ->EnumAttribute(ShadowFilterMethod::Esm, "ESM") @@ -143,7 +149,7 @@ namespace AZ ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled) - ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_boundaryWidthInDegrees, "Softening Boundary Width", + ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_boundaryWidthInDegrees, "Softening boundary width", "Width of the boundary between shadowed area and lit one. " "Units are in degrees. " "If this is 0, softening edge is disabled.") @@ -152,26 +158,27 @@ namespace AZ ->Attribute(Edit::Attributes::Suffix, " deg") ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsPcfBoundarySearchDisabled) - ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_predictionSampleCount, "Prediction Sample Count", + ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_predictionSampleCount, "Prediction sample count", "Sample Count for prediction of whether the pixel is on the boundary. Specific to PCF and ESM+PCF.") ->Attribute(Edit::Attributes::Min, 4) ->Attribute(Edit::Attributes::Max, 16) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsPcfBoundarySearchDisabled) - ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_filteringSampleCount, "Filtering Sample Count", + ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_filteringSampleCount, "Filtering sample count", "It is used only when the pixel is predicted to be on the boundary. Specific to PCF and ESM+PCF.") ->Attribute(Edit::Attributes::Min, 4) ->Attribute(Edit::Attributes::Max, 64) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled) ->DataElement( - Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_pcfMethod, "Pcf Method", - "Type of Pcf to use.\n" + Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_pcfMethod, "Pcf method", + "Type of PCF to use.\n" " Boundary search: do several taps to first determine if we are on a shadow boundary\n" " Bicubic: a smooth, fixed-size kernel \n") - ->EnumAttribute(PcfMethod::BoundarySearch, "Boundary Search") + ->EnumAttribute(PcfMethod::BoundarySearch, "Boundary search") ->EnumAttribute(PcfMethod::Bicubic, "Bicubic") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled); ; } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h index 4cf94c1a58..da221341c3 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -40,6 +41,8 @@ namespace AZ LightDelegateBase(EntityId entityId, bool isVisible); virtual ~LightDelegateBase(); + void SetConfig(const AreaLightComponentConfig* config) override; + // LightDelegateInterface overrides... void SetChroma(const AZ::Color& chroma) override; void SetIntensity(float intensity) override; @@ -66,6 +69,7 @@ namespace AZ // Trivial getters FeatureProcessorType* GetFeatureProcessor() const { return m_featureProcessor; }; + const AreaLightComponentConfig* GetConfig() const { return m_componentConfig; }; typename FeatureProcessorType::LightHandle GetLightHandle() const { return m_lightHandle; }; const AZ::Transform& GetTransform() const { return m_transform; }; bool GetShuttersEnabled() { return m_shuttersEnabled; }; @@ -81,6 +85,7 @@ namespace AZ private: FeatureProcessorType* m_featureProcessor = nullptr; typename FeatureProcessorType::LightHandle m_lightHandle; + const AreaLightComponentConfig* m_componentConfig = nullptr; LmbrCentral::ShapeComponentRequests* m_shapeBus; AZ::Transform m_transform; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.inl b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.inl index ee4a29f1b0..406df42547 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.inl +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.inl @@ -59,6 +59,12 @@ namespace AZ m_featureProcessor->SetRgbIntensity(m_lightHandle, m_photometricValue.GetCombinedRgb()); } } + + template + void LightDelegateBase::SetConfig(const AreaLightComponentConfig* config) + { + m_componentConfig = config; + } template void LightDelegateBase::SetChroma(const AZ::Color& color) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h index 110a7d73ad..b3f5fb6014 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h @@ -33,6 +33,9 @@ namespace AZ { public: virtual ~LightDelegateInterface() {}; + + //! Sets the area light component config so delegates don't have to cache the same data locally. + virtual void SetConfig(const AreaLightComponentConfig* config) = 0; //! Sets the color of the light independent of light intensity. The color is a mask on the total light intensity. virtual void SetChroma(const AZ::Color& chroma) = 0; //! Sets the light intensity diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SimpleSpotLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SimpleSpotLightDelegate.cpp index 255f527557..705a71571a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SimpleSpotLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SimpleSpotLightDelegate.cpp @@ -44,15 +44,40 @@ namespace AZ::Render { GetFeatureProcessor()->SetConeAngles(GetLightHandle(), DegToRad(innerAngleDegrees), DegToRad(outerAngleDegrees)); } - - void SimpleSpotLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& color, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const + + void SimpleSpotLightDelegate::DrawDebugDisplay(const Transform& transform, const Color& /*color*/, AzFramework::DebugDisplayRequests& debugDisplay, bool isSelected) const { if (isSelected) { - debugDisplay.SetColor(color); + float innerRadians = DegToRad(GetConfig()->m_innerShutterAngleDegrees); + float outerRadians = DegToRad(GetConfig()->m_outerShutterAngleDegrees); + float radius = GetConfig()->m_attenuationRadius; - // Draw a cone for the cone angle and attenuation radius - debugDisplay.DrawCone(transform.GetTranslation(), transform.GetBasisX(), CalculateAttenuationRadius(AreaLightComponentConfig::CutoffIntensity), false); + // Draw a cone using the cone angle and attenuation radius + innerRadians = GetMin(innerRadians, outerRadians); + float coneRadiusInner = sin(innerRadians) * radius; + float coneHeightInner = cos(innerRadians) * radius; + float coneRadiusOuter = sin(outerRadians) * radius; + float coneHeightOuter = cos(outerRadians) * radius; + + debugDisplay.PushMatrix(transform); + + auto DrawCone = [&debugDisplay](uint32_t numRadiusLines, float radius, float height, float brightness) + { + debugDisplay.SetColor(Color(brightness, brightness, brightness, 1.0f)); + debugDisplay.DrawWireDisk(Vector3(0.0, 0.0, height), Vector3::CreateAxisZ(), radius); + + for (uint32_t i = 0; i < numRadiusLines; ++i) + { + float radiusLineAngle = float(i) / numRadiusLines * Constants::TwoPi; + debugDisplay.DrawLine(Vector3::CreateZero(), Vector3(cos(radiusLineAngle) * radius, sin(radiusLineAngle) * radius, height)); + } + }; + + DrawCone(16, coneRadiusInner, coneHeightInner, 1.0f); + DrawCone(16, coneRadiusOuter, coneHeightOuter, 0.65f); + + debugDisplay.PopMatrix(); } } } // namespace AZ::Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SimpleSpotLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SimpleSpotLightDelegate.h index 66569fc27c..28359daaef 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SimpleSpotLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SimpleSpotLightDelegate.h @@ -25,6 +25,8 @@ namespace AZ class SimpleSpotLightDelegate final : public LightDelegateBase { + using Base = LightDelegateBase; + public: SimpleSpotLightDelegate(EntityId entityId, bool isVisible); @@ -34,9 +36,9 @@ namespace AZ float GetSurfaceArea() const override; float GetEffectiveSolidAngle() const override { return PhotometricValue::DirectionalEffectiveSteradians; } void SetShutterAngles(float innerAngleDegrees, float outerAngleDegrees) override; + private: virtual void HandleShapeChanged(); - }; } // namespace Render diff --git a/Gems/AtomLyIntegration/CryRenderAtomShim/AtomShim_RenderAuxGeom.cpp b/Gems/AtomLyIntegration/CryRenderAtomShim/AtomShim_RenderAuxGeom.cpp index 093e068e2a..955b240514 100644 --- a/Gems/AtomLyIntegration/CryRenderAtomShim/AtomShim_RenderAuxGeom.cpp +++ b/Gems/AtomLyIntegration/CryRenderAtomShim/AtomShim_RenderAuxGeom.cpp @@ -519,8 +519,8 @@ void CAtomShimRenderAuxGeom::DrawQuad(float width, float height, const Matrix34& if (auto auxGeom = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(defaultScene)) { AZ::RPI::AuxGeomDraw::DrawStyle drawStyle = drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid; - AZ::Transform transform = LYTransformToAZTransform(matWorld); - auxGeom->DrawQuad(width, height, transform, LYColorBToAZColor(col), drawStyle, m_drawArgs.m_depthTest); + AZ::Matrix3x4 local2World = LYTransformToAZMatrix3x4(matWorld); + auxGeom->DrawQuad(width, height, local2World, LYColorBToAZColor(col), drawStyle, m_drawArgs.m_depthTest); } } diff --git a/cmake/FindTarget.cmake.in b/cmake/FindTarget.cmake.in new file mode 100644 index 0000000000..7d0129d05a --- /dev/null +++ b/cmake/FindTarget.cmake.in @@ -0,0 +1,45 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +# Generated by O3DE + +include(FindPackageHandleStandardArgs) + +ly_add_target( + +NAME @NAME_PLACEHOLDER@ UNKNOWN IMPORTED + +@NAMESPACE_PLACEHOLDER@ + +@INCLUDE_DIRECTORIES_PLACEHOLDER@ + +@BUILD_DEPENDENCIES_PLACEHOLDER@ + +@RUNTIME_DEPENDENCIES_PLACEHOLDER@ + +@COMPILE_DEFINITIONS_PLACEHOLDER@ +) + +# The below if was generated from if (NOT HEADER_ONLY_PLACEHOLDER) +# HEADER_ONLY_PLACEHOLDER evaluates to TRUE or FALSE +if (NOT @HEADER_ONLY_PLACEHOLDER@) + # Load information for each installed configuration. + foreach(config @ALL_CONFIGS@) + set(@NAME_PLACEHOLDER@_${config}_FOUND FALSE) + include("${LY_ROOT_FOLDER}/cmake_autogen/@NAME_PLACEHOLDER@/@NAME_PLACEHOLDER@_${config}.cmake") + endforeach() + + find_package_handle_standard_args(@NAME_PLACEHOLDER@ + "Could not find package @NAME_PLACEHOLDER@" + @TARGET_CONFIG_FOUND_VARS_PLACEHOLDER@) +else() + set(@NAME_PLACEHOLDER@_FOUND TRUE) +endif() \ No newline at end of file diff --git a/cmake/Findo3de.cmake b/cmake/Findo3de.cmake index 30246ebd4b..0b4d0b75e7 100644 --- a/cmake/Findo3de.cmake +++ b/cmake/Findo3de.cmake @@ -27,24 +27,19 @@ if(json_error) message(FATAL_ERROR "Unable to read key 'engine_name' from '${current_path}/../engine.json', error: ${json_error}") endif() -if(NOT this_engine_name STREQUAL LY_ENGINE_NAME_TO_USE) - set(o3de_FOUND FALSE) - set(o3de_NOT_FOUND_MESSAGE) - find_package_handle_standard_args(o3de - "Could not find an engine with matching ${LY_ENGINE_NAME_TO_USE}" - o3de_FOUND - ) - return() +set(found_matching_engine FALSE) +if(this_engine_name STREQUAL LY_ENGINE_NAME_TO_USE) + set(found_matching_engine TRUE) endif() +find_package_handle_standard_args(o3de + "Could not find an engine with matching ${LY_ENGINE_NAME_TO_USE}" + found_matching_engine +) + macro(o3de_initialize) + set(INSTALLED_ENGINE FALSE) set(LY_PROJECTS ${CMAKE_CURRENT_LIST_DIR}) o3de_current_file_path(current_path) add_subdirectory(${current_path}/.. o3de) -endmacro() - -message(STATUS "Found ${this_engine_name} in ${current_path}") -set(o3de_FOUND FALSE) -find_package_handle_standard_args(o3de - o3de_FOUND -) \ No newline at end of file +endmacro() \ No newline at end of file diff --git a/cmake/Findo3de.cmake.in b/cmake/Findo3de.cmake.in new file mode 100644 index 0000000000..7ecb73e874 --- /dev/null +++ b/cmake/Findo3de.cmake.in @@ -0,0 +1,36 @@ +# +# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +# its licensors. +# +# For complete copyright and license terms please see the LICENSE at the root of this +# distribution (the "License"). All use of this software is governed by the License, +# or, if provided, by the license below or the license accompanying this file. Do not +# remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# + +# Generated by O3DE + +include(FindPackageHandleStandardArgs) + +# This will be called from within the installed engine's CMakeLists.txt +macro(ly_find_o3de_packages) + @FIND_PACKAGES_PLACEHOLDER@ + find_package(LauncherGenerator) +endmacro() + + +function(o3de_current_file_path path) + set(${path} ${CMAKE_CURRENT_FUNCTION_LIST_DIR} PARENT_SCOPE) +endfunction() + + +# We are using the engine's CMakeLists.txt to handle initialization/importing targets +# Since this is external to the project's source, we need to specify an output directory +# even though we don't build +macro(o3de_initialize) + set(INSTALLED_ENGINE TRUE) + set(LY_PROJECTS ${CMAKE_SOURCE_DIR}) + o3de_current_file_path(current_path) + add_subdirectory(${current_path}/.. o3de) +endmacro() \ No newline at end of file diff --git a/cmake/Platform/Common/Install_common.cmake b/cmake/Platform/Common/Install_common.cmake index 9164105f3a..7ac9a3afa8 100644 --- a/cmake/Platform/Common/Install_common.cmake +++ b/cmake/Platform/Common/Install_common.cmake @@ -13,13 +13,6 @@ #! ly_install_target: registers the target to be installed by cmake install. # # \arg:NAME name of the target -# \arg:NAMESPACE namespace declaration for this target. It will be used for IDE and dependencies -# \arg:INCLUDE_DIRECTORIES paths to the include directories -# \arg:BUILD_DEPENDENCIES list of interfaces this target depends on (could be a compilation dependency -# if the dependency is only exposing an include path, or could be a linking -# dependency is exposing a lib) -# \arg:RUNTIME_DEPENDENCIES list of dependencies this target depends on at runtime -# \arg:COMPILE_DEFINITIONS list of compilation definitions this target will use to compile function(ly_install_target ly_install_target_NAME) # All include directories marked PUBLIC or INTERFACE will be installed @@ -143,7 +136,7 @@ function(ly_generate_target_find_file) set(HEADER_ONLY_PLACEHOLDER TRUE) endif() - configure_file(${LY_ROOT_FOLDER}/cmake/FindTargetTemplate.cmake ${CMAKE_CURRENT_BINARY_DIR}/Find${ly_generate_target_find_file_NAME}.cmake @ONLY) + configure_file(${LY_ROOT_FOLDER}/cmake/FindTarget.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/Find${ly_generate_target_find_file_NAME}.cmake @ONLY) endfunction() @@ -214,7 +207,7 @@ function(ly_setup_o3de_install) string(REPLACE ";" "\n" FIND_PACKAGES_PLACEHOLDER "${find_package_list}") - configure_file(${LY_ROOT_FOLDER}/cmake/Findo3deTemplate.cmake ${CMAKE_CURRENT_BINARY_DIR}/Findo3de.cmake @ONLY) + configure_file(${LY_ROOT_FOLDER}/cmake/Findo3de.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/Findo3de.cmake @ONLY) ly_install_launcher_target_generator()