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/CryCommon/IMovieSystem.h b/Code/CryEngine/CryCommon/IMovieSystem.h index 654ccfd240..7a1125ae2b 100644 --- a/Code/CryEngine/CryCommon/IMovieSystem.h +++ b/Code/CryEngine/CryCommon/IMovieSystem.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -914,9 +915,18 @@ struct IAnimStringTable */ struct IAnimSequence { - AZ_RTTI(IAnimSequence, "{A60F95F5-5A4A-47DB-B3BB-525BBC0BC8DB}") + AZ_RTTI(IAnimSequence, "{A60F95F5-5A4A-47DB-B3BB-525BBC0BC8DB}"); + AZ_CLASS_ALLOCATOR(IAnimSequence, AZ::SystemAllocator, 0); - static const int kSequenceVersion = 4; + static const int kSequenceVersion = 5; + + static void Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context); serializeContext != nullptr) + { + serializeContext->Class(); + } + } //! Flags used for SetFlags(),GetFlags(),SetParentFlags(),GetParentFlags() methods. enum EAnimSequenceFlags 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/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index de97842cee..a3af2648cf 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -926,6 +926,8 @@ namespace AZ SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif + // Update the Runtime file paths in case the "{BootstrapSettingsRootKey}/assets" key was overriden by a setting registry + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); } void ComponentApplication::SetSettingsRegistrySpecializations(SettingsRegistryInterface::Specializations& specializations) 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/AzCore/AzCore/PlatformId/PlatformDefaults.cpp b/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.cpp new file mode 100644 index 0000000000..63aad1ecf4 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.cpp @@ -0,0 +1,340 @@ +/* +* 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 + +namespace AZ +{ + inline namespace PlatformDefaults + { + static const char* PlatformNames[PlatformId::NumPlatformIds] = { PlatformPC, PlatformES3, PlatformIOS, PlatformOSX, PlatformProvo, PlatformSalem, PlatformJasper, PlatformServer, PlatformAll, PlatformAllClient }; + + const char* PlatformIdToPalFolder(AZ::PlatformId platform) + { +#ifdef IOS +#define AZ_REDEFINE_IOS_AT_END IOS +#undef IOS +#endif + switch (platform) + { + case AZ::PC: + return "PC"; + case AZ::ES3: + return "Android"; + case AZ::IOS: + return "iOS"; + case AZ::OSX: + return "Mac"; + case AZ::PROVO: + return "Provo"; + case AZ::SALEM: + return "Salem"; + case AZ::JASPER: + return "Jasper"; + case AZ::SERVER: + return "Server"; + case AZ::ALL: + case AZ::ALL_CLIENT: + case AZ::NumPlatformIds: + case AZ::Invalid: + default: + return ""; + } + +#ifdef AZ_REDEFINE_IOS_AT_END +#define IOS AZ_REDEFINE_IOS_AT_END +#endif + } + + const char* OSPlatformToDefaultAssetPlatform(AZStd::string_view osPlatform) + { + if (osPlatform == PlatformCodeNameWindows || osPlatform == PlatformCodeNameLinux) + { + return PlatformPC; + } + else if (osPlatform == PlatformCodeNameMac) + { + return PlatformOSX; + } + else if (osPlatform == PlatformCodeNameAndroid) + { + return PlatformES3; + } + else if (osPlatform == PlatformCodeNameiOS) + { + return PlatformIOS; + } + else if (osPlatform == PlatformCodeNameProvo) + { + return PlatformProvo; + } + else if (osPlatform == PlatformCodeNameSalem) + { + return PlatformSalem; + } + else if (osPlatform == PlatformCodeNameJasper) + { + return PlatformJasper; + } + + AZ_Error("PlatformDefault", false, R"(Supplied OS platform "%.*s" does not have a corresponding default asset platform)", + aznumeric_cast(osPlatform.size()), osPlatform.data()); + return ""; + } + + PlatformFlags PlatformHelper::GetPlatformFlagFromPlatformIndex(PlatformId platformIndex) + { + if (platformIndex < 0 || platformIndex > PlatformId::NumPlatformIds) + { + return PlatformFlags::Platform_NONE; + } + if (platformIndex == PlatformId::ALL) + { + return PlatformFlags::Platform_ALL; + } + if (platformIndex == PlatformId::ALL_CLIENT) + { + return PlatformFlags::Platform_ALL_CLIENT; + } + return static_cast(1 << platformIndex); + } + + AZStd::fixed_vector PlatformHelper::GetPlatforms(PlatformFlags platformFlags) + { + AZStd::fixed_vector platforms; + for (int platformNum = 0; platformNum < PlatformId::NumPlatformIds; ++platformNum) + { + const bool isAllPlatforms = PlatformId::ALL == static_cast(platformNum) + && ((platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE); + + const bool isAllClientPlatforms = PlatformId::ALL_CLIENT == static_cast(platformNum) + && ((platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE); + + if (isAllPlatforms || isAllClientPlatforms + || (platformFlags & static_cast(1 << platformNum)) != PlatformFlags::Platform_NONE) + { + platforms.push_back(PlatformNames[platformNum]); + } + } + + return platforms; + } + + AZStd::fixed_vector PlatformHelper::GetPlatformsInterpreted(PlatformFlags platformFlags) + { + return GetPlatforms(GetPlatformFlagsInterpreted(platformFlags)); + } + + AZStd::fixed_vector PlatformHelper::GetPlatformIndices(PlatformFlags platformFlags) + { + AZStd::fixed_vector platformIndices; + for (int i = 0; i < PlatformId::NumPlatformIds; i++) + { + PlatformId index = static_cast(i); + if ((GetPlatformFlagFromPlatformIndex(index) & platformFlags) != PlatformFlags::Platform_NONE) + { + platformIndices.emplace_back(index); + } + } + return platformIndices; + } + + AZStd::fixed_vector PlatformHelper::GetPlatformIndicesInterpreted(PlatformFlags platformFlags) + { + return GetPlatformIndices(GetPlatformFlagsInterpreted(platformFlags)); + } + + PlatformFlags PlatformHelper::GetPlatformFlag(AZStd::string_view platform) + { + int platformIndex = GetPlatformIndexFromName(platform); + if (platformIndex == PlatformId::Invalid) + { + AZ_Error("PlatformDefault", false, "Invalid Platform ( %.*s ).\n", static_cast(platform.length()), platform.data()); + return PlatformFlags::Platform_NONE; + } + + if (platformIndex == PlatformId::ALL) + { + return PlatformFlags::Platform_ALL; + } + + if (platformIndex == PlatformId::ALL_CLIENT) + { + return PlatformFlags::Platform_ALL_CLIENT; + } + + return static_cast(1 << platformIndex); + } + + const char* PlatformHelper::GetPlatformName(PlatformId platform) + { + if (platform < 0 || platform > PlatformId::NumPlatformIds) + { + return "invalid"; + } + return PlatformNames[platform]; + } + + void PlatformHelper::AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, AZStd::string_view platformId) + { + PlatformId platform = GetPlatformIdFromName(platformId); + AZ_Assert(platform != PlatformId::Invalid, "Unsupported Platform ID: %.*s", static_cast(platformId.length()), platformId.data()); + AppendPlatformCodeNames(platformCodes, platform); + } + + void PlatformHelper::AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, PlatformId platformId) + { + // The IOS SDK has a macro that defines IOS as 1 which causes the enum below to be incorrectly converted to "PlatformId::1". +#pragma push_macro("IOS") +#undef IOS + // To reduce work the Asset Processor groups assets that can be shared between hardware platforms together. For this + // reason "PC" can for instance cover both the Windows and Linux platforms and "IOS" can cover AppleTV and iOS. + switch (platformId) + { + case PlatformId::PC: + platformCodes.emplace_back(PlatformCodeNameWindows); + platformCodes.emplace_back(PlatformCodeNameLinux); + break; + case PlatformId::ES3: + platformCodes.emplace_back(PlatformCodeNameAndroid); + break; + case PlatformId::IOS: + platformCodes.emplace_back(PlatformCodeNameiOS); + break; + case PlatformId::OSX: + platformCodes.emplace_back(PlatformCodeNameMac); + break; + case PlatformId::PROVO: + platformCodes.emplace_back(PlatformCodeNameProvo); + break; + case PlatformId::SALEM: + platformCodes.emplace_back(PlatformCodeNameSalem); + break; + case PlatformId::JASPER: + platformCodes.emplace_back(PlatformCodeNameJasper); + break; + case PlatformId::SERVER: + // Server is not a hardware platform + break; + default: + AZ_Assert(false, "Unsupported Platform ID: %i", platformId); + break; + } +#pragma pop_macro("IOS") + } + + int PlatformHelper::GetPlatformIndexFromName(AZStd::string_view platformName) + { + for (int idx = 0; idx < PlatformId::NumPlatformIds; idx++) + { + if (platformName == PlatformNames[idx]) + { + return idx; + } + } + + return PlatformId::Invalid; + } + + PlatformId PlatformHelper::GetPlatformIdFromName(AZStd::string_view platformName) + { + return aznumeric_caster(GetPlatformIndexFromName(platformName)); + } + + AssetPlatformCombinedString PlatformHelper::GetCommaSeparatedPlatformList(PlatformFlags platformFlags) + { + AZStd::fixed_vector platformNames = GetPlatforms(platformFlags); + AssetPlatformCombinedString platformsString; + AZ::StringFunc::Join(platformsString, platformNames.begin(), platformNames.end(), ", "); + return platformsString; + } + + PlatformFlags PlatformHelper::GetPlatformFlagsInterpreted(PlatformFlags platformFlags) + { + PlatformFlags returnFlags = PlatformFlags::Platform_NONE; + + if ((platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE) + { + for (int i = 0; i < NumPlatforms; ++i) + { + auto platformId = static_cast(i); + + if (platformId != PlatformId::ALL && platformId != PlatformId::ALL_CLIENT) + { + returnFlags |= GetPlatformFlagFromPlatformIndex(platformId); + } + } + } + else if ((platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE) + { + for (int i = 0; i < NumPlatforms; ++i) + { + auto platformId = static_cast(i); + + if (platformId != PlatformId::ALL && platformId != PlatformId::ALL_CLIENT && platformId != PlatformId::SERVER) + { + returnFlags |= GetPlatformFlagFromPlatformIndex(platformId); + } + } + } + else + { + returnFlags = platformFlags; + } + + return returnFlags; + } + + bool PlatformHelper::IsSpecialPlatform(PlatformFlags platformFlags) + { + return (platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE + || (platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE; + } + + bool HasFlagHelper(PlatformFlags flags, PlatformFlags checkPlatform) + { + return (flags & checkPlatform) == checkPlatform; + } + + + bool PlatformHelper::HasPlatformFlag(PlatformFlags flags, PlatformId checkPlatform) + { + // If checkPlatform contains any kind of invalid id, just exit out here + if (checkPlatform == PlatformId::Invalid || checkPlatform == NumPlatforms) + { + return false; + } + + // ALL_CLIENT + SERVER = ALL + if (HasFlagHelper(flags, PlatformFlags::Platform_ALL_CLIENT | PlatformFlags::Platform_SERVER)) + { + flags = PlatformFlags::Platform_ALL; + } + + if (HasFlagHelper(flags, PlatformFlags::Platform_ALL)) + { + // It doesn't matter what checkPlatform is set to in this case, just return true + return true; + } + + if (HasFlagHelper(flags, PlatformFlags::Platform_ALL_CLIENT)) + { + return checkPlatform != PlatformId::SERVER; + } + + return HasFlagHelper(flags, GetPlatformFlagFromPlatformIndex(checkPlatform)); + } + } +} diff --git a/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.h b/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.h new file mode 100644 index 0000000000..2d67c860cd --- /dev/null +++ b/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.h @@ -0,0 +1,157 @@ +/* +* 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 + +// On IOS builds IOS will be defined and interfere with the below enums +#pragma push_macro("IOS") +#undef IOS + +namespace AZ +{ + inline namespace PlatformDefaults + { + constexpr char PlatformPC[] = "pc"; + constexpr char PlatformES3[] = "es3"; + constexpr char PlatformIOS[] = "ios"; + constexpr char PlatformOSX[] = "osx_gl"; + constexpr char PlatformProvo[] = "provo"; + constexpr char PlatformSalem[] = "salem"; + constexpr char PlatformJasper[] = "jasper"; + constexpr char PlatformServer[] = "server"; + + constexpr char PlatformCodeNameWindows[] = "Windows"; + constexpr char PlatformCodeNameLinux[] = "Linux"; + constexpr char PlatformCodeNameAndroid[] = "Android"; + constexpr char PlatformCodeNameiOS[] = "iOS"; + constexpr char PlatformCodeNameMac[] = "Mac"; + constexpr char PlatformCodeNameProvo[] = "Provo"; + constexpr char PlatformCodeNameSalem[] = "Salem"; + constexpr char PlatformCodeNameJasper[] = "Jasper"; + constexpr char PlatformAll[] = "all"; + constexpr char PlatformAllClient[] = "all_client"; + + // Used for the capacity of a fixed vector to store the code names of platforms + // The value needs to be higher than the number of unique OS platforms that are supported(at this time 8) + constexpr size_t MaxPlatformCodeNames = 16; + + //! This platform enum have platform values in sequence and can also be used to get the platform count. + AZ_ENUM_WITH_UNDERLYING_TYPE(PlatformId, int, + (Invalid, -1), + PC, + ES3, + IOS, + OSX, + PROVO, + SALEM, + JASPER, + SERVER, // Corresponds to the customer's flavor of "server" which could be windows, ubuntu, etc + ALL, + ALL_CLIENT, + + // Add new platforms above this + NumPlatformIds + ); + constexpr int NumClientPlatforms = 7; + constexpr int NumPlatforms = NumClientPlatforms + 1; // 1 "Server" platform currently + enum class PlatformFlags : AZ::u32 + { + Platform_NONE = 0x00, + Platform_PC = 1 << PlatformId::PC, + Platform_ES3 = 1 << PlatformId::ES3, + Platform_IOS = 1 << PlatformId::IOS, + Platform_OSX = 1 << PlatformId::OSX, + Platform_PROVO = 1 << PlatformId::PROVO, + Platform_SALEM = 1 << PlatformId::SALEM, + Platform_JASPER = 1 << PlatformId::JASPER, + Platform_SERVER = 1 << PlatformId::SERVER, + + // A special platform that will always correspond to all platforms, even if new ones are added + Platform_ALL = 1ULL << 30, + + // A special platform that will always correspond to all non-server platforms, even if new ones are added + Platform_ALL_CLIENT = 1ULL << 31, + + AllNamedPlatforms = Platform_PC | Platform_ES3 | Platform_IOS | Platform_OSX | Platform_PROVO | Platform_SALEM | Platform_JASPER | Platform_SERVER, + }; + + AZ_DEFINE_ENUM_BITWISE_OPERATORS(PlatformFlags); + + // 32 characters should be more than enough to store a platform name + using AssetPlatformFixedString = AZStd::fixed_string<32>; + // Fixed string which can store a comma separated list of platforms names + // Additional byte is added to take into account the comma + using AssetPlatformCombinedString = AZStd::fixed_string < (AssetPlatformFixedString{}.max_size() + 1)* PlatformId::NumPlatformIds > ; + + const char* PlatformIdToPalFolder(PlatformId platform); + + const char* OSPlatformToDefaultAssetPlatform(AZStd::string_view osPlatform); + + //! Platform Helper is an utility class that can be used to retrieve platform related information + class PlatformHelper + { + public: + + //! Given a platformIndex returns the platform name + static const char* GetPlatformName(PlatformId platform); + + //! Converts the platform name to the platform code names as defined in AZ_TRAIT_OS_PLATFORM_CODENAME. + static void AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, AZStd::string_view platformName); + + //! Converts the platform name to the platform code names as defined in AZ_TRAIT_OS_PLATFORM_CODENAME. + static void AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, PlatformId platformId); + + //! Given a platform name returns a platform index. + //! If the platform is not found, the method returns -1. + static int GetPlatformIndexFromName(AZStd::string_view platformName); + + //! Given a platform name returns a platform id. + //! If the platform is not found, the method returns -1. + static PlatformId GetPlatformIdFromName(AZStd::string_view platformName); + + //! Given a platformIndex returns the platformFlags + static PlatformFlags GetPlatformFlagFromPlatformIndex(PlatformId platform); + + //! Given a platformFlags returns all the platform identifiers that are set. + static AZStd::fixed_vector GetPlatforms(PlatformFlags platformFlags); + //! Given a platformFlags returns all the platform identifiers that are set, with special flags interpreted. Do not use the result for saving + static AZStd::fixed_vector GetPlatformsInterpreted(PlatformFlags platformFlags); + + //! Given a platformFlags return a list of PlatformId indices + static AZStd::fixed_vector GetPlatformIndices(PlatformFlags platformFlags); + //! Given a platformFlags return a list of PlatformId indices, with special flags interpreted. Do not use the result for saving + static AZStd::fixed_vector GetPlatformIndicesInterpreted(PlatformFlags platformFlags); + + //! Given a platform identifier returns its corresponding platform flag. + static PlatformFlags GetPlatformFlag(AZStd::string_view platform); + + //! Given any platformFlags returns a string listing the input platforms + static AssetPlatformCombinedString GetCommaSeparatedPlatformList(PlatformFlags platformFlags); + + //! If platformFlags contains any special flags, they are removed and replaced with the normal flags they represent + static PlatformFlags GetPlatformFlagsInterpreted(PlatformFlags platformFlags); + + //! Returns true if platformFlags contains any special flags + static bool IsSpecialPlatform(PlatformFlags platformFlags); + + //! Returns true if platformFlags has checkPlatform flag set. + static bool HasPlatformFlag(PlatformFlags platformFlags, PlatformId checkPlatform); + }; + } +} +#pragma pop_macro("IOS") diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index f84ff354b2..52085757fe 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -525,9 +526,10 @@ namespace AZ::SettingsRegistryMergeUtils // and if that's missing just get "assets". constexpr char platformName[] = AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER; - SettingsRegistryInterface::FixedValueString assetPlatform; buffer = AZStd::fixed_string::format("%s/%s_assets", BootstrapSettingsRootKey, platformName); AZStd::string_view assetPlatformKey(buffer); + // Use the platform codename to retrieve the default asset platform value + SettingsRegistryInterface::FixedValueString assetPlatform = AZ::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); if (!registry.Get(assetPlatform, assetPlatformKey)) { buffer = AZStd::fixed_string::format("%s/assets", BootstrapSettingsRootKey); diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index e100b240c2..5357ed66a6 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -607,6 +607,8 @@ set(FILES Utils/Utils.h Script/lua/lua.h Memory/HeapSchema.cpp + PlatformId/PlatformDefaults.h + PlatformId/PlatformDefaults.cpp PlatformId/PlatformId.h PlatformId/PlatformId.cpp Socket/AzSocket_fwd.h 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/Platform/PlatformDefaults.cpp b/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.cpp deleted file mode 100644 index 81154bae35..0000000000 --- a/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/* -* 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 - -namespace AzFramework -{ - static const char* PlatformNames[PlatformId::NumPlatformIds] = { PlatformPC, PlatformES3, PlatformIOS, PlatformOSX, PlatformProvo, PlatformSalem, PlatformJasper, PlatformServer, PlatformAll, PlatformAllClient }; - - const char* PlatformIdToPalFolder(AzFramework::PlatformId platform) - { -#ifdef IOS -#define AZ_REDEFINE_IOS_AT_END IOS -#undef IOS -#endif - switch (platform) - { - case AzFramework::PC: - return "PC"; - case AzFramework::ES3: - return "Android"; - case AzFramework::IOS: - return "iOS"; - case AzFramework::OSX: - return "Mac"; - case AzFramework::PROVO: - return "Provo"; - case AzFramework::SALEM: - return "Salem"; - case AzFramework::JASPER: - return "Jasper"; - case AzFramework::SERVER: - return "Server"; - case AzFramework::ALL: - case AzFramework::ALL_CLIENT: - case AzFramework::NumPlatformIds: - case AzFramework::Invalid: - default: - return ""; - } - -#ifdef AZ_REDEFINE_IOS_AT_END -#define IOS AZ_REDEFINE_IOS_AT_END -#endif - } - - const char* OSPlatformToDefaultAssetPlatform(AZStd::string_view osPlatform) - { - if (osPlatform == PlatformCodeNameWindows || osPlatform == PlatformCodeNameLinux) - { - return PlatformPC; - } - else if (osPlatform == PlatformCodeNameMac) - { - return PlatformOSX; - } - else if (osPlatform == PlatformCodeNameAndroid) - { - return PlatformES3; - } - else if (osPlatform == PlatformCodeNameiOS) - { - return PlatformIOS; - } - else if (osPlatform == PlatformCodeNameProvo) - { - return PlatformProvo; - } - else if (osPlatform == PlatformCodeNameSalem) - { - return PlatformSalem; - } - else if (osPlatform == PlatformCodeNameJasper) - { - return PlatformJasper; - } - - AZ_Error("PlatformDefault", false, R"(Supplied OS platform "%.*s" does not have a corresponding default asset platform)", - aznumeric_cast(osPlatform.size()), osPlatform.data()); - return ""; - } - - PlatformFlags PlatformHelper::GetPlatformFlagFromPlatformIndex(PlatformId platformIndex) - { - if (platformIndex < 0 || platformIndex > PlatformId::NumPlatformIds) - { - return PlatformFlags::Platform_NONE; - } - if (platformIndex == PlatformId::ALL) - { - return PlatformFlags::Platform_ALL; - } - if (platformIndex == PlatformId::ALL_CLIENT) - { - return PlatformFlags::Platform_ALL_CLIENT; - } - return static_cast(1 << platformIndex); - } - - AZStd::fixed_vector PlatformHelper::GetPlatforms(PlatformFlags platformFlags) - { - AZStd::fixed_vector platforms; - for (int platformNum = 0; platformNum < PlatformId::NumPlatformIds; ++platformNum) - { - const bool isAllPlatforms = PlatformId::ALL == static_cast(platformNum) - && ((platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE); - - const bool isAllClientPlatforms = PlatformId::ALL_CLIENT == static_cast(platformNum) - && ((platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE); - - if (isAllPlatforms || isAllClientPlatforms - || (platformFlags & static_cast(1 << platformNum)) != PlatformFlags::Platform_NONE) - { - platforms.push_back(PlatformNames[platformNum]); - } - } - - return platforms; - } - - AZStd::fixed_vector PlatformHelper::GetPlatformsInterpreted(PlatformFlags platformFlags) - { - return GetPlatforms(GetPlatformFlagsInterpreted(platformFlags)); - } - - AZStd::fixed_vector PlatformHelper::GetPlatformIndices(PlatformFlags platformFlags) - { - AZStd::fixed_vector platformIndices; - for (int i = 0; i < PlatformId::NumPlatformIds; i++) - { - PlatformId index = static_cast(i); - if ((GetPlatformFlagFromPlatformIndex(index) & platformFlags) != PlatformFlags::Platform_NONE) - { - platformIndices.emplace_back(index); - } - } - return platformIndices; - } - - AZStd::fixed_vector PlatformHelper::GetPlatformIndicesInterpreted(PlatformFlags platformFlags) - { - return GetPlatformIndices(GetPlatformFlagsInterpreted(platformFlags)); - } - - PlatformFlags PlatformHelper::GetPlatformFlag(AZStd::string_view platform) - { - int platformIndex = GetPlatformIndexFromName(platform); - if (platformIndex == PlatformId::Invalid) - { - AZ_Error("PlatformDefault", false, "Invalid Platform ( %.*s ).\n", static_cast(platform.length()), platform.data()); - return PlatformFlags::Platform_NONE; - } - - if(platformIndex == PlatformId::ALL) - { - return PlatformFlags::Platform_ALL; - } - - if (platformIndex == PlatformId::ALL_CLIENT) - { - return PlatformFlags::Platform_ALL_CLIENT; - } - - return static_cast(1 << platformIndex); - } - - const char* PlatformHelper::GetPlatformName(PlatformId platform) - { - if (platform < 0 || platform > PlatformId::NumPlatformIds) - { - return "invalid"; - } - return PlatformNames[platform]; - } - - void PlatformHelper::AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, AZStd::string_view platformId) - { - PlatformId platform = GetPlatformIdFromName(platformId); - AZ_Assert(platform != PlatformId::Invalid, "Unsupported Platform ID: %.*s", static_cast(platformId.length()), platformId.data()); - AppendPlatformCodeNames(platformCodes, platform); - } - - void PlatformHelper::AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, PlatformId platformId) - { -// The IOS SDK has a macro that defines IOS as 1 which causes the enum below to be incorrectly converted to "PlatformId::1". -#pragma push_macro("IOS") -#undef IOS - // To reduce work the Asset Processor groups assets that can be shared between hardware platforms together. For this - // reason "PC" can for instance cover both the Windows and Linux platforms and "IOS" can cover AppleTV and iOS. - switch (platformId) - { - case PlatformId::PC: - platformCodes.emplace_back(PlatformCodeNameWindows); - platformCodes.emplace_back(PlatformCodeNameLinux); - break; - case PlatformId::ES3: - platformCodes.emplace_back(PlatformCodeNameAndroid); - break; - case PlatformId::IOS: - platformCodes.emplace_back(PlatformCodeNameiOS); - break; - case PlatformId::OSX: - platformCodes.emplace_back(PlatformCodeNameMac); - break; - case PlatformId::PROVO: - platformCodes.emplace_back(PlatformCodeNameProvo); - break; - case PlatformId::SALEM: - platformCodes.emplace_back(PlatformCodeNameSalem); - break; - case PlatformId::JASPER: - platformCodes.emplace_back(PlatformCodeNameJasper); - break; - case PlatformId::SERVER: - // Server is not a hardware platform - break; - default: - AZ_Assert(false, "Unsupported Platform ID: %i", platformId); - break; - } -#pragma pop_macro("IOS") - } - - int PlatformHelper::GetPlatformIndexFromName(AZStd::string_view platformName) - { - for (int idx = 0; idx < PlatformId::NumPlatformIds; idx++) - { - if (platformName == PlatformNames[idx]) - { - return idx; - } - } - - return PlatformId::Invalid; - } - - PlatformId PlatformHelper::GetPlatformIdFromName(AZStd::string_view platformName) - { - return aznumeric_caster(GetPlatformIndexFromName(platformName)); - } - - AssetPlatformCombinedString PlatformHelper::GetCommaSeparatedPlatformList(PlatformFlags platformFlags) - { - AZStd::fixed_vector platformNames = GetPlatforms(platformFlags); - AssetPlatformCombinedString platformsString; - AZ::StringFunc::Join(platformsString, platformNames.begin(), platformNames.end(), ", "); - return platformsString; - } - - PlatformFlags PlatformHelper::GetPlatformFlagsInterpreted(PlatformFlags platformFlags) - { - PlatformFlags returnFlags = PlatformFlags::Platform_NONE; - - if((platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE) - { - for (int i = 0; i < NumPlatforms; ++i) - { - auto platformId = static_cast(i); - - if (platformId != PlatformId::ALL && platformId != PlatformId::ALL_CLIENT) - { - returnFlags |= GetPlatformFlagFromPlatformIndex(platformId); - } - } - } - else if((platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE) - { - for (int i = 0; i < NumPlatforms; ++i) - { - auto platformId = static_cast(i); - - if (platformId != PlatformId::ALL && platformId != PlatformId::ALL_CLIENT && platformId != PlatformId::SERVER) - { - returnFlags |= GetPlatformFlagFromPlatformIndex(platformId); - } - } - } - else - { - returnFlags = platformFlags; - } - - return returnFlags; - } - - bool PlatformHelper::IsSpecialPlatform(PlatformFlags platformFlags) - { - return (platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE - || (platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE; - } - - bool HasFlagHelper(PlatformFlags flags, PlatformFlags checkPlatform) - { - return (flags & checkPlatform) == checkPlatform; - } - - - bool PlatformHelper::HasPlatformFlag(PlatformFlags flags, PlatformId checkPlatform) - { - // If checkPlatform contains any kind of invalid id, just exit out here - if(checkPlatform == PlatformId::Invalid || checkPlatform == NumPlatforms) - { - return false; - } - - // ALL_CLIENT + SERVER = ALL - if(HasFlagHelper(flags, PlatformFlags::Platform_ALL_CLIENT | PlatformFlags::Platform_SERVER)) - { - flags = PlatformFlags::Platform_ALL; - } - - if(HasFlagHelper(flags, PlatformFlags::Platform_ALL)) - { - // It doesn't matter what checkPlatform is set to in this case, just return true - return true; - } - - if(HasFlagHelper(flags, PlatformFlags::Platform_ALL_CLIENT)) - { - return checkPlatform != PlatformId::SERVER; - } - - return HasFlagHelper(flags, GetPlatformFlagFromPlatformIndex(checkPlatform)); - } - -} diff --git a/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.h b/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.h index d7f467ec0f..13f7fa20e5 100644 --- a/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.h +++ b/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.h @@ -12,144 +12,12 @@ #pragma once -#include -#include -#include -#include -#include - -// On IOS builds IOS will be defined and interfere with the below enums -#pragma push_macro("IOS") -#undef IOS +#include +// As the Platform defaults is needed within AzCore, +// those structures have been moved to AzCore and brought into +// The AzFramework namespace for backwards compatibility namespace AzFramework { - constexpr char PlatformPC[] = "pc"; - constexpr char PlatformES3[] = "es3"; - constexpr char PlatformIOS[] = "ios"; - constexpr char PlatformOSX[] = "osx_gl"; - constexpr char PlatformProvo[] = "provo"; - constexpr char PlatformSalem[] = "salem"; - constexpr char PlatformJasper[] = "jasper"; - constexpr char PlatformServer[] = "server"; - - constexpr char PlatformCodeNameWindows[] = "Windows"; - constexpr char PlatformCodeNameLinux[] = "Linux"; - constexpr char PlatformCodeNameAndroid[] = "Android"; - constexpr char PlatformCodeNameiOS[] = "iOS"; - constexpr char PlatformCodeNameMac[] = "Mac"; - constexpr char PlatformCodeNameProvo[] = "Provo"; - constexpr char PlatformCodeNameSalem[] = "Salem"; - constexpr char PlatformCodeNameJasper[] = "Jasper"; - constexpr char PlatformAll[] = "all"; - constexpr char PlatformAllClient[] = "all_client"; - - // Used for the capacity of a fixed vector to store the code names of platforms - // The value needs to be higher than the number of unique OS platforms that are supported(at this time 8) - constexpr size_t MaxPlatformCodeNames = 16; - - //! This platform enum have platform values in sequence and can also be used to get the platform count. - AZ_ENUM_WITH_UNDERLYING_TYPE(PlatformId, int, - (Invalid, -1), - PC, - ES3, - IOS, - OSX, - PROVO, - SALEM, - JASPER, - SERVER, // Corresponds to the customer's flavor of "server" which could be windows, ubuntu, etc - ALL, - ALL_CLIENT, - - // Add new platforms above this - NumPlatformIds - ); - constexpr int NumClientPlatforms = 7; - constexpr int NumPlatforms = NumClientPlatforms + 1; // 1 "Server" platform currently - enum class PlatformFlags : AZ::u32 - { - Platform_NONE = 0x00, - Platform_PC = 1 << PlatformId::PC, - Platform_ES3 = 1 << PlatformId::ES3, - Platform_IOS = 1 << PlatformId::IOS, - Platform_OSX = 1 << PlatformId::OSX, - Platform_PROVO = 1 << PlatformId::PROVO, - Platform_SALEM = 1 << PlatformId::SALEM, - Platform_JASPER = 1 << PlatformId::JASPER, - Platform_SERVER = 1 << PlatformId::SERVER, - - // A special platform that will always correspond to all platforms, even if new ones are added - Platform_ALL = 1ULL << 30, - - // A special platform that will always correspond to all non-server platforms, even if new ones are added - Platform_ALL_CLIENT = 1ULL << 31, - - AllNamedPlatforms = Platform_PC | Platform_ES3 | Platform_IOS | Platform_OSX | Platform_PROVO | Platform_SALEM | Platform_JASPER | Platform_SERVER, - }; - - AZ_DEFINE_ENUM_BITWISE_OPERATORS(PlatformFlags); - - // 32 characters should be more than enough to store a platform name - using AssetPlatformFixedString = AZStd::fixed_string<32>; - // Fixed string which can store a comma separated list of platforms names - // Additional byte is added to take into account the comma - using AssetPlatformCombinedString = AZStd::fixed_string<(AssetPlatformFixedString{}.max_size() + 1) * PlatformId::NumPlatformIds>; - - const char* PlatformIdToPalFolder(AzFramework::PlatformId platform); - - const char* OSPlatformToDefaultAssetPlatform(AZStd::string_view osPlatform); - - //! Platform Helper is an utility class that can be used to retrieve platform related information - class PlatformHelper - { - public: - - //! Given a platformIndex returns the platform name - static const char* GetPlatformName(PlatformId platform); - - //! Converts the platform name to the platform code names as defined in AZ_TRAIT_OS_PLATFORM_CODENAME. - static void AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, AZStd::string_view platformName); - - //! Converts the platform name to the platform code names as defined in AZ_TRAIT_OS_PLATFORM_CODENAME. - static void AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, PlatformId platformId); - - //! Given a platform name returns a platform index. - //! If the platform is not found, the method returns -1. - static int GetPlatformIndexFromName(AZStd::string_view platformName); - - //! Given a platform name returns a platform id. - //! If the platform is not found, the method returns -1. - static PlatformId GetPlatformIdFromName(AZStd::string_view platformName); - - //! Given a platformIndex returns the platformFlags - static PlatformFlags GetPlatformFlagFromPlatformIndex(PlatformId platform); - - //! Given a platformFlags returns all the platform identifiers that are set. - static AZStd::fixed_vector GetPlatforms(PlatformFlags platformFlags); - //! Given a platformFlags returns all the platform identifiers that are set, with special flags interpreted. Do not use the result for saving - static AZStd::fixed_vector GetPlatformsInterpreted(PlatformFlags platformFlags); - - //! Given a platformFlags return a list of PlatformId indices - static AZStd::fixed_vector GetPlatformIndices(PlatformFlags platformFlags); - //! Given a platformFlags return a list of PlatformId indices, with special flags interpreted. Do not use the result for saving - static AZStd::fixed_vector GetPlatformIndicesInterpreted(PlatformFlags platformFlags); - - //! Given a platform identifier returns its corresponding platform flag. - static PlatformFlags GetPlatformFlag(AZStd::string_view platform); - - //! Given any platformFlags returns a string listing the input platforms - static AssetPlatformCombinedString GetCommaSeparatedPlatformList(PlatformFlags platformFlags); - - //! If platformFlags contains any special flags, they are removed and replaced with the normal flags they represent - static PlatformFlags GetPlatformFlagsInterpreted(PlatformFlags platformFlags); - - //! Returns true if platformFlags contains any special flags - static bool IsSpecialPlatform(PlatformFlags platformFlags); - - //! Returns true if platformFlags has checkPlatform flag set. - static bool HasPlatformFlag(PlatformFlags platformFlags, PlatformId checkPlatform); - }; + using namespace AZ::PlatformDefaults; } - -#pragma pop_macro("IOS") 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..312a3766ac 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 @@ -316,7 +317,6 @@ set(FILES Terrain/TerrainDataRequestBus.h Terrain/TerrainDataRequestBus.cpp Platform/PlatformDefaults.h - Platform/PlatformDefaults.cpp Windowing/WindowBus.h Windowing/NativeWindow.cpp Windowing/NativeWindow.h diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index f4fc9364f7..edd4af293d 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -80,6 +80,8 @@ namespace AzGameFramework AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif + // Update the Runtime file paths in case the "{BootstrapSettingsRootKey}/assets" key was overriden by a setting registry + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); } AZ::ComponentTypeList GameApplication::GetRequiredSystemComponents() const 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/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp index 2003f8eafd..5ccbd95f09 100644 --- a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp +++ b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp @@ -68,7 +68,7 @@ namespace UnitTest { assets[idx] = AssetId(AZ::Uuid::CreateRandom(), 0); AZ::Data::AssetInfo info; - info.m_relativePath = AZStd::string::format("Asset%d.txt", idx); + info.m_relativePath = AZStd::string::format("asset%d.txt", idx); m_assetsPath[idx] = info.m_relativePath; info.m_assetId = assets[idx]; m_assetRegistry->RegisterAsset(assets[idx], info); @@ -623,7 +623,7 @@ namespace UnitTest EXPECT_TRUE(Search(assetList1, assets[fileIndex])); if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { - AZStd::string fileContent = AZStd::string::format("Asset%d.txt", fileIndex); + AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex); m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str()); m_fileStreams[0][fileIndex].Close(); } @@ -654,7 +654,7 @@ namespace UnitTest EXPECT_TRUE(Search(assetList1, assets[fileIndex])); if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { - AZStd::string fileContent = AZStd::string::format("Asset%d.txt", fileIndex + 1);// changing file content + AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex + 1);// changing file content m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str()); m_fileStreams[0][fileIndex].Close(); } @@ -987,7 +987,7 @@ namespace UnitTest m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); - m_assetSeedManager->RemoveSeedAsset("Asset0.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); + m_assetSeedManager->RemoveSeedAsset("asset0.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList(); EXPECT_EQ(secondSeedList.size(), 0); } @@ -1003,7 +1003,7 @@ namespace UnitTest m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); - m_assetSeedManager->RemoveSeedAsset("Asset0.txt", AzFramework::PlatformFlags::Platform_PC); + m_assetSeedManager->RemoveSeedAsset("asset0.txt", AzFramework::PlatformFlags::Platform_PC); const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList(); EXPECT_EQ(secondSeedList.size(), 1); } @@ -1017,7 +1017,7 @@ namespace UnitTest EXPECT_EQ(seedList.size(), 1); - m_assetSeedManager->RemoveSeedAsset("Asset1.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); + m_assetSeedManager->RemoveSeedAsset("asset1.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList(); EXPECT_EQ(secondSeedList.size(), 1); } diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index a3b2542418..695a0fa5f1 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -1617,11 +1617,6 @@ void EditorViewportWidget::keyPressEvent(QKeyEvent* event) // because we want the movement to be butter smooth. if (!event->isAutoRepeat()) { - if (m_keyDown.isEmpty()) - { - grabKeyboard(); - } - m_keyDown.insert(event->key()); } 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/Tools/MaterialEditor/Assets/MaterialEditor/Materials/basic_grey.material b/Gems/Atom/Feature/Common/Assets/Materials/basic_grey.material similarity index 100% rename from Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/Materials/basic_grey.material rename to Gems/Atom/Feature/Common/Assets/Materials/basic_grey.material 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/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp index 206e58d5e6..e0ff253301 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp @@ -131,8 +131,13 @@ namespace AZ AZ_Assert(m_blendedLut.m_lutImage != nullptr, "BlendColorGradingLutsPass unable to acquire LUT image"); AZ::RHI::AttachmentId imageAttachmentId = AZ::RHI::AttachmentId("BlendColorGradingLutImageAttachmentId"); - [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportImage(imageAttachmentId, m_blendedLut.m_lutImage); - AZ_Error("BlendColorGradingLutsPass", result == RHI::ResultCode::Success, "Failed to import compute buffer with error %d", result); + + // import this attachment if it wasn't imported + if (!frameGraph.GetAttachmentDatabase().IsAttachmentValid(imageAttachmentId)) + { + [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportImage(imageAttachmentId, m_blendedLut.m_lutImage); + AZ_Error("BlendColorGradingLutsPass", result == RHI::ResultCode::Success, "Failed to import BlendColorGradingLutImageAttachmentId with error %d", result); + } RHI::ImageScopeAttachmentDescriptor desc; desc.m_attachmentId = imageAttachmentId; diff --git a/Gems/Atom/RHI/Code/Source/RHI.Reflect/Base.cpp b/Gems/Atom/RHI/Code/Source/RHI.Reflect/Base.cpp index 4d35411e09..21eb634159 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Reflect/Base.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Reflect/Base.cpp @@ -16,6 +16,6 @@ namespace AZ { namespace RHI { - bool Validation::s_isEnabled = BuildOptions::IsDebugBuild; + bool Validation::s_isEnabled = BuildOptions::IsDebugBuild || BuildOptions::IsProfileBuild; } } diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp index 1ae8a4ae96..7fc1db179a 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp @@ -404,6 +404,12 @@ namespace AZ Buffer& buffer = static_cast(*bufferFrameAttachment.GetBuffer()); RHI::BufferScopeAttachment* scopeAttachment = bufferFrameAttachment.GetFirstScopeAttachment(); + if (scopeAttachment == nullptr) + { + AZ_WarningOnce("RHI", false, "Imported BufferFrameAttachment isn't used in any Scope"); + return; + } + D3D12_RESOURCE_TRANSITION_BARRIER transition; transition.pResource = buffer.GetMemoryView().GetMemory(); transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; @@ -471,6 +477,12 @@ namespace AZ Image& image = static_cast(*imageFrameAttachment.GetImage()); RHI::ImageScopeAttachment* scopeAttachment = imageFrameAttachment.GetFirstScopeAttachment(); + if (scopeAttachment == nullptr) + { + AZ_WarningOnce("RHI", false, "Imported ImageFrameAttachment isn't used in any Scope"); + return; + } + D3D12_RESOURCE_TRANSITION_BARRIER transition; transition.pResource = image.GetMemoryView().GetMemory(); 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/Atom/RPI/Code/Source/RPI.Reflect/Base.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Base.cpp index 7012a7cf88..8addb16a23 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Base.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Base.cpp @@ -16,6 +16,6 @@ namespace AZ { namespace RPI { - bool Validation::s_isEnabled = RHI::BuildOptions::IsDebugBuild; + bool Validation::s_isEnabled = RHI::BuildOptions::IsDebugBuild || RHI::BuildOptions::IsProfileBuild; } } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/InputController/MaterialEditorViewportInputControllerBus.h b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/InputController/MaterialEditorViewportInputControllerBus.h index 04250c4efd..2acdc79286 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/InputController/MaterialEditorViewportInputControllerBus.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/InputController/MaterialEditorViewportInputControllerBus.h @@ -53,6 +53,9 @@ namespace MaterialEditor //! Modify camera's field of view //! @param value field of view in degrees virtual void SetFieldOfView(float value) = 0; + + //! Check if camera is looking directly at a model + virtual bool IsCameraCentered() const = 0; }; using MaterialEditorViewportInputControllerRequestBus = AZ::EBus; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.cpp index 8355b390ef..159d3339be 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.cpp @@ -76,11 +76,35 @@ namespace MaterialEditor void Behavior::TickInternal([[maybe_unused]] float x, [[maybe_unused]] float y, float z) { m_distanceToTarget = m_distanceToTarget - z; + + bool isCameraCentered = false; + MaterialEditorViewportInputControllerRequestBus::BroadcastResult( + isCameraCentered, + &MaterialEditorViewportInputControllerRequestBus::Handler::IsCameraCentered); + + // if camera is looking at the model (locked to the model) we don't want to zoom past the model's center + if (isCameraCentered) + { + m_distanceToTarget = AZ::GetMax(m_distanceToTarget, 0.0f); + } + AZ::Transform transform = AZ::Transform::CreateIdentity(); AZ::TransformBus::EventResult(transform, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTM); AZ::Vector3 position = m_targetPosition - transform.GetRotation().TransformVector(AZ::Vector3::CreateAxisY(m_distanceToTarget)); AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetLocalTranslation, position); + + // if camera is not locked to the model, move its focal point so we can free look + if (!isCameraCentered) + { + m_targetPosition += transform.GetRotation().TransformVector(AZ::Vector3::CreateAxisY(z)); + MaterialEditorViewportInputControllerRequestBus::Broadcast( + &MaterialEditorViewportInputControllerRequestBus::Handler::SetTargetPosition, + m_targetPosition); + MaterialEditorViewportInputControllerRequestBus::BroadcastResult( + m_distanceToTarget, + &MaterialEditorViewportInputControllerRequestBus::Handler::GetDistanceToTarget); + } } float Behavior::GetSensitivityX() diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp index e180a5d979..83ec5a41c5 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp @@ -96,6 +96,7 @@ namespace MaterialEditor void MaterialEditorViewportInputController::SetTargetPosition(const AZ::Vector3& targetPosition) { m_targetPosition = targetPosition; + m_isCameraCentered = false; } float MaterialEditorViewportInputController::GetDistanceToTarget() const @@ -246,6 +247,7 @@ namespace MaterialEditor cameraPosition = cameraRotation.TransformVector(cameraPosition); AZ::Transform cameraTransform = AZ::Transform::CreateFromQuaternionAndTranslation(cameraRotation, cameraPosition); AZ::TransformBus::Event(m_cameraEntityId, &AZ::TransformBus::Events::SetLocalTM, cameraTransform); + m_isCameraCentered = true; // reset model AZ::Transform modelTransform = AZ::Transform::CreateIdentity(); @@ -258,6 +260,12 @@ namespace MaterialEditor AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene(); auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor(); skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix); + + if (m_behavior) + { + m_behavior->End(); + m_behavior->Start(); + } } void MaterialEditorViewportInputController::SetFieldOfView(float value) @@ -265,6 +273,11 @@ namespace MaterialEditor Camera::CameraRequestBus::Event(m_cameraEntityId, &Camera::CameraRequestBus::Events::SetFovDegrees, value); } + bool MaterialEditorViewportInputController::IsCameraCentered() const + { + return m_isCameraCentered; + } + void MaterialEditorViewportInputController::CalculateExtents() { AZ::TransformBus::EventResult(m_modelCenter, m_targetEntityId, &AZ::TransformBus::Events::GetLocalTranslation); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.h index aa3dd836d6..ee40b5c259 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.h @@ -45,6 +45,7 @@ namespace MaterialEditor void GetExtents(float& distanceMin, float& distanceMax) const override; void Reset() override; void SetFieldOfView(float value) override; + bool IsCameraCentered() const override; // AzFramework::ViewportControllerInstance interface overrides... bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override; @@ -95,6 +96,8 @@ namespace MaterialEditor float m_distanceMin = 1.0f; //! Maximum distance from camera to target float m_distanceMax = 10.0f; + //! True if camera is centered on a model + bool m_isCameraCentered = true; static constexpr float MaxDistanceMultiplier = 2.5f; static constexpr float StartingDistanceMultiplier = 2.0f; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/PanCameraBehavior.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/PanCameraBehavior.cpp index 087591e6ea..e36a335129 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/PanCameraBehavior.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/PanCameraBehavior.cpp @@ -34,10 +34,8 @@ namespace MaterialEditor targetPosition); } - void PanCameraBehavior::TickInternal(float x, float y, float z) + void PanCameraBehavior::TickInternal(float x, float y, [[maybe_unused]] float z) { - Behavior::TickInternal(x, y, z); - AZ::Transform transform = AZ::Transform::CreateIdentity(); AZ::TransformBus::EventResult(transform, m_cameraEntityId, &AZ::TransformBus::Events::GetLocalTM); AZ::Quaternion rotation = transform.GetRotation(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp index 20d1b587b5..76aee99e52 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp @@ -60,13 +60,17 @@ namespace MaterialEditor AZ::Data::AssetCatalogRequestBus::Broadcast(&AZ::Data::AssetCatalogRequestBus::Events::EnumerateAssets, nullptr, enumerateCB, nullptr); //Update the material type file info whenever the combo box selection changes - QObject::connect(m_ui->m_materialTypeComboBox, static_cast(&QComboBox::currentIndexChanged), m_ui->m_materialTypeComboBox, [this](int index) { - QVariant data = m_ui->m_materialTypeComboBox->itemData(index); - m_materialTypeFileInfo = QFileInfo(data.toString()); - }); + QObject::connect(m_ui->m_materialTypeComboBox, static_cast(&QComboBox::currentIndexChanged), this, [this]() { UpdateMaterialTypeSelection(); }); + QObject::connect(m_ui->m_materialTypeComboBox, &QComboBox::currentTextChanged, this, [this]() { UpdateMaterialTypeSelection(); }); - //Select StandardPBR by default but we will later data drive this with editor settings - m_ui->m_materialTypeComboBox->setCurrentText("StandardPBR"); + // Select StandardPBR by default but we will later data drive this with editor settings + const int index = m_ui->m_materialTypeComboBox->findText("StandardPBR"); + if (index >= 0) + { + m_ui->m_materialTypeComboBox->setCurrentIndex(index); + } + + UpdateMaterialTypeSelection(); } void CreateMaterialDialog::InitMaterialFileSelection() @@ -88,15 +92,24 @@ namespace MaterialEditor m_materialFileInfo.absoluteFilePath(), QString("Material (*.material)")); - //Reject empty or invalid filenames which indicate user cancellation + // Reject empty or invalid filenames which indicate user cancellation if (!fileInfo.absoluteFilePath().isEmpty()) { m_materialFileInfo = fileInfo; m_ui->m_materialFilePicker->setText(m_materialFileInfo.fileName()); } - }); + }); } + void CreateMaterialDialog::UpdateMaterialTypeSelection() + { + const int index = m_ui->m_materialTypeComboBox->currentIndex(); + if (index >= 0) + { + const QVariant itemData = m_ui->m_materialTypeComboBox->itemData(index); + m_materialTypeFileInfo = QFileInfo(itemData.toString()); + } + } } // namespace MaterialEditor #include diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.h index bf39671343..54d7c2175d 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.h @@ -36,5 +36,6 @@ namespace MaterialEditor QScopedPointer m_ui; void InitMaterialTypeSelection(); void InitMaterialFileSelection(); + void UpdateMaterialTypeSelection(); }; } // namespace MaterialEditor diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h index 6520844edd..ce6915699b 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.h @@ -249,7 +249,7 @@ namespace AZ bool m_showTimeline = false; // Controls how often the timestamp data is refreshed - RefreshType m_refreshType = RefreshType::OncePerSecond; + RefreshType m_refreshType = RefreshType::Realtime; AZStd::sys_time_t m_lastUpdateTimeMicroSecond; }; diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl index eb0e295129..fa9395dffc 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiGpuProfiler.inl @@ -16,6 +16,8 @@ #include #include +#include + namespace AZ { namespace Render @@ -725,7 +727,7 @@ namespace AZ ImGui::BeginTooltip(); ImGui::Text("Name: %s", passEntry->m_name.GetCStr()); ImGui::Text("Path: %s", passEntry->m_path.GetCStr()); - ImGui::Text("Duration in ticks: %lu", passEntry->m_timestampResult.GetDurationInTicks()); + ImGui::Text("Duration in ticks: %" PRIu64, passEntry->m_timestampResult.GetDurationInTicks()); ImGui::Text("Duration in microsecond: %.3f us", passEntry->m_timestampResult.GetDurationInNanoseconds()/1000.f); ImGui::EndTooltip(); } diff --git a/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp b/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.cpp index ec7aa17151..77f15284f1 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 #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/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h index 9c8ea57cea..8a7bace6aa 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Thumbnails/Rendering/ThumbnailRendererData.h @@ -36,7 +36,7 @@ namespace AZ struct ThumbnailRendererData final { static constexpr const char* LightingPresetPath = "lightingpresets/thumbnail.lightingpreset.azasset"; - static constexpr const char* DefaultModelPath = "materialeditor/viewportmodels/quadsphere.azmodel"; + static constexpr const char* DefaultModelPath = "models/sphere.azmodel"; static constexpr const char* DefaultMaterialPath = "materials/basic_grey.azmaterial"; RPI::ScenePtr m_scene; 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/Gems/EMotionFX/Code/CMakeLists.txt b/Gems/EMotionFX/Code/CMakeLists.txt index d46c67fafb..b90902a948 100644 --- a/Gems/EMotionFX/Code/CMakeLists.txt +++ b/Gems/EMotionFX/Code/CMakeLists.txt @@ -68,12 +68,6 @@ ly_add_target( ) if (PAL_TRAIT_BUILD_HOST_TOOLS) - - find_package(OpenGL QUIET REQUIRED) - # Imported targets (like OpenGL::GL) are scoped to a directory. Add a - # a global scope - add_library(3rdParty::OpenGLInterface INTERFACE IMPORTED GLOBAL) - target_link_libraries(3rdParty::OpenGLInterface INTERFACE OpenGL::GL) ly_add_target( NAME EMotionFX.Editor.Static STATIC diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLRenderUtil.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLRenderUtil.cpp index 3ef3908271..b8b4843555 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLRenderUtil.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLRenderUtil.cpp @@ -131,8 +131,14 @@ namespace RenderGL void GLRenderUtil::Validate() { - mLineShader->Validate(); - mMeshShader->Validate(); + if (mLineShader) + { + mLineShader->Validate(); + } + if (mMeshShader) + { + mMeshShader->Validate(); + } } // destroy the allocated memory diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.cpp index 54b926c4fa..b11c3cb955 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.cpp @@ -116,12 +116,12 @@ namespace RenderGL } - bool GLSLShader::CompileShader(const GLenum type, unsigned int* outShader, const char* filename) + bool GLSLShader::CompileShader(const GLenum type, unsigned int* outShader, AZ::IO::PathView filename) { - QFile file(filename); + QFile file(QString::fromUtf8(filename.Native().data(), aznumeric_caster(filename.Native().size()))); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - AZ_Error("EMotionFX", false, "[GLSL] Failed to open shader file '%s'.", filename); + AZ_Error("EMotionFX", false, "[GLSL] Failed to open shader file '%.*s'.", AZ_STRING_ARG(filename.Native())); return false; } @@ -156,7 +156,7 @@ namespace RenderGL if (success == false) { - MCore::LogError("[GLSL] Failed to compile shader '%s'.", filename); + MCore::LogError("[GLSL] Failed to compile shader '%.*s'.", AZ_STRING_ARG(filename.Native())); return false; } @@ -212,7 +212,7 @@ namespace RenderGL // Init - bool GLSLShader::Init(const char* vFile, const char* pFile, MCore::Array& defines) + bool GLSLShader::Init(AZ::IO::PathView vertexFileName, AZ::IO::PathView pixelFileName, MCore::Array& defines) { initializeOpenGLFunctions(); /*const char* args[] = { "unroll all", @@ -225,24 +225,24 @@ namespace RenderGL glUseProgram(0); // compile shaders - if (vFile && CompileShader(GL_VERTEX_SHADER, &mVertexShader, vFile) == false) + if (!vertexFileName.empty() && CompileShader(GL_VERTEX_SHADER, &mVertexShader, vertexFileName) == false) { return false; } - if (pFile && CompileShader(GL_FRAGMENT_SHADER, &mPixelShader, pFile) == false) + if (!pixelFileName.empty() && CompileShader(GL_FRAGMENT_SHADER, &mPixelShader, pixelFileName) == false) { return false; } // create program mProgram = glCreateProgram(); - if (vFile) + if (!vertexFileName.empty()) { glAttachShader(mProgram, mVertexShader); } - if (pFile) + if (!pixelFileName.empty()) { glAttachShader(mProgram, mPixelShader); } @@ -256,7 +256,7 @@ namespace RenderGL if (!success) { - MCore::LogInfo("[OpenGL] Failed to link shaders '%s' and '%s' ", vFile, pFile); + MCore::LogInfo("[OpenGL] Failed to link shaders '%.*s' and '%.*s' ", AZ_STRING_ARG(vertexFileName.Native()), AZ_STRING_ARG(pixelFileName.Native())); InfoLog(mProgram, &QOpenGLExtraFunctions::glGetProgramInfoLog); return false; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.h b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.h index b9251dd718..73aee4313f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.h +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GLSLShader.h @@ -14,6 +14,7 @@ #define __RENDERGL_GLSLSHADER_H #include +#include #include "Shader.h" // include OpenGL @@ -45,7 +46,7 @@ namespace RenderGL MCORE_INLINE unsigned int GetProgram() const { return mProgram; } bool CheckIfIsDefined(const char* attributeName); - bool Init(const char* vertexFileName, const char* pixelFileName, MCore::Array& defines); + bool Init(AZ::IO::PathView vertexFileName, AZ::IO::PathView pixelFileName, MCore::Array& defines); void SetAttribute(const char* name, uint32 dim, uint32 type, uint32 stride, size_t offset) override; void SetUniform(const char* name, float value) override; @@ -81,11 +82,11 @@ namespace RenderGL ShaderParameter* FindAttribute(const char* name); ShaderParameter* FindUniform(const char* name); - bool CompileShader(const GLenum type, unsigned int* outShader, const char* filename); + bool CompileShader(const GLenum type, unsigned int* outShader, AZ::IO::PathView filename); template void InfoLog(GLuint object, T func); - AZStd::string mFileName; + AZ::IO::Path mFileName; MCore::Array mActivatedAttribs; MCore::Array mActivatedTextures; diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GraphicsManager.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GraphicsManager.cpp index 127f18ba67..5512028ad5 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GraphicsManager.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GraphicsManager.cpp @@ -203,7 +203,7 @@ namespace RenderGL // try to initialize the graphics system - bool GraphicsManager::Init(const char* shaderPath) + bool GraphicsManager::Init(AZ::IO::PathView shaderPath) { initializeOpenGLFunctions(); @@ -364,7 +364,7 @@ namespace RenderGL // try to load a texture - Texture* GraphicsManager::LoadTexture([[maybe_unused]] const char* filename, [[maybe_unused]] bool createMipMaps) + Texture* GraphicsManager::LoadTexture([[maybe_unused]] AZ::IO::PathView filename, [[maybe_unused]] bool createMipMaps) { //Texture Library is no longer used //temporarily blank @@ -373,19 +373,19 @@ namespace RenderGL // try to load a texture - Texture* GraphicsManager::LoadTexture(const char* filename) + Texture* GraphicsManager::LoadTexture(AZ::IO::PathView filename) { return LoadTexture(filename, mCreateMipMaps); } // LoadPostProcessShader - PostProcessShader* GraphicsManager::LoadPostProcessShader(const char* cFileName) + PostProcessShader* GraphicsManager::LoadPostProcessShader(AZ::IO::PathView cFileName) { - AZStd::string filename = mShaderPath + AZStd::string(cFileName); + AZ::IO::PathView filename = mShaderPath / cFileName; // check if the shader is already in the cache - Shader* s = mShaderCache.FindShader(filename.c_str()); + Shader* s = mShaderCache.FindShader(filename.Native()); if (s) { return (PostProcessShader*)s; @@ -393,19 +393,19 @@ namespace RenderGL // load the shader from disk PostProcessShader* shader = new PostProcessShader(); - if (!shader->Init(filename.c_str())) + if (!shader->Init(filename)) { delete shader; return nullptr; } - mShaderCache.AddShader(filename.c_str(), shader); + mShaderCache.AddShader(filename.Native(), shader); return shader; } // LoadShader - GLSLShader* GraphicsManager::LoadShader(const char* vertexFileName, const char* pixelFileName) + GLSLShader* GraphicsManager::LoadShader(AZ::IO::PathView vertexFileName, AZ::IO::PathView pixelFileName) { MCore::Array defines; return LoadShader(vertexFileName, pixelFileName, defines); @@ -413,34 +413,21 @@ namespace RenderGL // LoadShader - GLSLShader* GraphicsManager::LoadShader(const char* vFile, const char* pFile, MCore::Array& defines) + GLSLShader* GraphicsManager::LoadShader(AZ::IO::PathView vertexFileName, AZ::IO::PathView pixelFileName, MCore::Array& defines) { - AZStd::string vStr; - AZStd::string pStr; - - if (vFile) - { - vStr = AZStd::string::format("%s%s", mShaderPath.c_str(), vFile); - } - - if (pFile) - { - pStr = AZStd::string::format("%s%s", mShaderPath.c_str(), pFile); - } + const AZ::IO::Path vertexPath {vertexFileName.empty() ? AZ::IO::Path{} : mShaderPath / vertexFileName}; + const AZ::IO::Path pixelPath {pixelFileName.empty() ? AZ::IO::Path{} : mShaderPath / pixelFileName}; // construct the lookup string for the shader cache - AZStd::string dStr; + AZStd::string cacheLookupStr = vertexPath.Native() + pixelPath.Native(); const uint32 numDefines = defines.GetLength(); for (uint32 n = 0; n < numDefines; n++) { - dStr += AZStd::string::format("#%s", defines[n].c_str()); + cacheLookupStr += AZStd::string::format("#%s", defines[n].c_str()); } - AZStd::string cStr; - cStr = AZStd::string::format("%s%s%s", vStr.c_str(), pStr.c_str(), dStr.c_str()); - // check if the shader is already in the cache - Shader* cShader = mShaderCache.FindShader(cStr.c_str()); + Shader* cShader = mShaderCache.FindShader(cacheLookupStr); if (cShader) { return (GLSLShader*)cShader; @@ -448,13 +435,13 @@ namespace RenderGL // load the shader from disk GLSLShader* shader = new GLSLShader(); - if (!shader->Init(vFile ? vStr.c_str() : nullptr, pFile ? pStr.c_str() : nullptr, defines)) + if (!shader->Init(vertexPath, pixelPath, defines)) { delete shader; return nullptr; } - mShaderCache.AddShader(cStr.c_str(), shader); + mShaderCache.AddShader(cacheLookupStr, shader); return shader; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GraphicsManager.h b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GraphicsManager.h index 811fe2998b..4aaf6a16d1 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GraphicsManager.h +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/GraphicsManager.h @@ -13,6 +13,7 @@ #ifndef __RENDERGL_GRAPHICSMANAGER__H #define __RENDERGL_GRAPHICSMANAGER__H +#include #include #include #include @@ -57,21 +58,21 @@ namespace RenderGL const char* GetDeviceName(); const char* GetDeviceVendor(); MCORE_INLINE RenderTexture* GetRenderTexture() { return mRenderTexture; } - MCORE_INLINE const char* GetShaderPath() const { return mShaderPath.c_str(); } + MCORE_INLINE AZ::IO::PathView GetShaderPath() const { return mShaderPath; } MCORE_INLINE TextureCache* GetTextureCache() { return &mTextureCache; } - bool Init(const char* shaderPath = "Shaders/"); + bool Init(AZ::IO::PathView shaderPath = "Shaders"); bool GetIsPostProcessingEnabled() const { return mPostProcessing; } - PostProcessShader* LoadPostProcessShader(const char* filename); - GLSLShader* LoadShader(const char* vertexFileName, const char* pixelFileName); - GLSLShader* LoadShader(const char* vertexFileName, const char* pixelFileName, MCore::Array& defines); + PostProcessShader* LoadPostProcessShader(AZ::IO::PathView filename); + GLSLShader* LoadShader(AZ::IO::PathView vertexFileName, AZ::IO::PathView pixelFileName); + GLSLShader* LoadShader(AZ::IO::PathView vertexFileName, AZ::IO::PathView pixelFileName, MCore::Array& defines); MCORE_INLINE void SetGBuffer(GBuffer* gBuffer) { mGBuffer = gBuffer; } MCORE_INLINE GBuffer* GetGBuffer() { return mGBuffer; } - Texture* LoadTexture(const char* filename, bool createMipMaps); - Texture* LoadTexture(const char* filename); + Texture* LoadTexture(AZ::IO::PathView filename, bool createMipMaps); + Texture* LoadTexture(AZ::IO::PathView filename); void SetCreateMipMaps(bool createMipMaps) { mCreateMipMaps = createMipMaps; } MCORE_INLINE bool GetCreateMipMaps() const { return mCreateMipMaps; } @@ -96,7 +97,7 @@ namespace RenderGL void SetShader(Shader* shader); MCORE_INLINE void SetRenderTexture(RenderTexture* texture) { mRenderTexture = texture; } - MCORE_INLINE void SetShaderPath(const char* shaderPath) { mShaderPath = shaderPath; } + MCORE_INLINE void SetShaderPath(AZ::IO::PathView shaderPath) { mShaderPath = shaderPath; } MCORE_INLINE void SetBloomEnabled(bool enabled) { mBloomEnabled = enabled; } MCORE_INLINE void SetBloomThreshold(float threshold) { mBloomThreshold = threshold; } @@ -154,7 +155,7 @@ namespace RenderGL MCommon::Camera* mCamera; /**< The camera used for rendering. */ ShaderCache mShaderCache; /**< The shader manager used to load and manage vertex and pixel shaders. */ - AZStd::string mShaderPath; /**< The absolute path to the directory where the shaders are located. This string will be added as prefix to each shader file the user tries to load. */ + AZ::IO::Path mShaderPath; /**< The absolute path to the directory where the shaders are located. This string will be added as prefix to each shader file the user tries to load. */ MCore::RGBAColor mClearColor; /**< The scene background color. */ MCore::RGBAColor mGradientSourceColor; /**< The background gradient source color. */ MCore::RGBAColor mGradientTargetColor; /**< The background gradient target color. */ diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/PostProcessShader.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/PostProcessShader.cpp index 11f46d2d13..8c5c79391f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/PostProcessShader.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/PostProcessShader.cpp @@ -11,6 +11,7 @@ */ #include +#include #include "PostProcessShader.h" #include "GraphicsManager.h" @@ -82,7 +83,7 @@ namespace RenderGL // Init - bool PostProcessShader::Init(const char* filename) + bool PostProcessShader::Init(AZ::IO::PathView filename) { MCore::Array defines; return GLSLShader::Init(nullptr, filename, defines); diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/PostProcessShader.h b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/PostProcessShader.h index c16554faa7..b3068a9b8a 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/PostProcessShader.h +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/PostProcessShader.h @@ -13,6 +13,7 @@ #ifndef __RENDERGL_POSTPROCESS_SHADER_H #define __RENDERGL_POSTPROCESS_SHADER_H +#include #include "GLSLShader.h" #include "RenderTexture.h" @@ -34,7 +35,7 @@ namespace RenderGL void Deactivate() override; - bool Init(const char* filename); + bool Init(AZ::IO::PathView filename); void Render(); private: diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/ShaderCache.cpp b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/ShaderCache.cpp index cef9c93388..b3f2accb66 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/ShaderCache.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/ShaderCache.cpp @@ -48,7 +48,7 @@ namespace RenderGL // add the shader to the cache (assume there are no duplicate names) - void ShaderCache::AddShader(const char* filename, Shader* shader) + void ShaderCache::AddShader(AZStd::string_view filename, Shader* shader) { mEntries.AddEmpty(); mEntries.GetLast().mName = filename; @@ -57,12 +57,12 @@ namespace RenderGL // try to locate a shader based on its name - Shader* ShaderCache::FindShader(const char* filename) const + Shader* ShaderCache::FindShader(AZStd::string_view filename) const { const uint32 numEntries = mEntries.GetLength(); for (uint32 i = 0; i < numEntries; ++i) { - if (AzFramework::StringFunc::Equal(mEntries[i].mName.c_str(), filename, false /* no case */)) // non-case-sensitive name compare + if (AzFramework::StringFunc::Equal(mEntries[i].mName, filename, false /* no case */)) // non-case-sensitive name compare { return mEntries[i].mShader; } diff --git a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/shadercache.h b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/shadercache.h index d7ec884e6a..98bb87d373 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/shadercache.h +++ b/Gems/EMotionFX/Code/EMotionFX/Rendering/OpenGL2/Source/shadercache.h @@ -33,8 +33,8 @@ namespace RenderGL ~ShaderCache(); // automatically calls Release void Release(); - void AddShader(const char* filename, Shader* shader); - Shader* FindShader(const char* filename) const; + void AddShader(AZStd::string_view filename, Shader* shader); + Shader* FindShader(AZStd::string_view filename) const; bool CheckIfHasShader(Shader* shader) const; private: diff --git a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/OpenGLRenderPlugin.cpp b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/OpenGLRenderPlugin.cpp index 99f203d6e7..bfd6a3921f 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/OpenGLRenderPlugin.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/OpenGLRenderPlugin.cpp @@ -64,7 +64,7 @@ namespace EMStudio // create graphics manager and initialize it mGraphicsManager = new RenderGL::GraphicsManager(); - if (mGraphicsManager->Init(shaderPath.c_str()) == false) + if (mGraphicsManager->Init(shaderPath) == false) { MCore::LogError("Could not initialize OpenGL graphics manager."); return false; diff --git a/Gems/EMotionFX/Code/Editor/Platform/Mac/platform_mac.cmake b/Gems/EMotionFX/Code/Editor/Platform/Mac/platform_mac.cmake index 821e7d1f25..95df062a93 100644 --- a/Gems/EMotionFX/Code/Editor/Platform/Mac/platform_mac.cmake +++ b/Gems/EMotionFX/Code/Editor/Platform/Mac/platform_mac.cmake @@ -13,10 +13,4 @@ # based on the active platform # NOTE: functions in cmake are global, therefore adding functions to this file # is being avoided to prevent overriding functions declared in other targets platfrom -# specific cmake files - -target_compile_definitions(3rdParty::OpenGLInterface - INTERFACE - # MacOS 10.14 deprecates OpenGL. This silences the warnings for now. - GL_SILENCE_DEPRECATION -) \ No newline at end of file +# specific cmake files \ No newline at end of file diff --git a/Gems/Maestro/Code/Source/Cinematics/AnimSequence.cpp b/Gems/Maestro/Code/Source/Cinematics/AnimSequence.cpp index 8d6c547c0e..ffbdce8ed6 100644 --- a/Gems/Maestro/Code/Source/Cinematics/AnimSequence.cpp +++ b/Gems/Maestro/Code/Source/Cinematics/AnimSequence.cpp @@ -823,20 +823,37 @@ void CAnimSequence::SetId(uint32 newId) } ////////////////////////////////////////////////////////////////////////// -void CAnimSequence::Reflect(AZ::SerializeContext* serializeContext) +static bool AnimSequenceVersionConverter( + AZ::SerializeContext& serializeContext, + AZ::SerializeContext::DataElementNode& rootElement) { - serializeContext->Class() - ->Version(4) - ->Field("Name", &CAnimSequence::m_name) - ->Field("SequenceEntityId", &CAnimSequence::m_sequenceEntityId) - ->Field("Flags", &CAnimSequence::m_flags) - ->Field("TimeRange", &CAnimSequence::m_timeRange) - ->Field("ID", &CAnimSequence::m_id) - ->Field("Nodes", &CAnimSequence::m_nodes) - ->Field("SequenceType", &CAnimSequence::m_sequenceType) - ->Field("Events", &CAnimSequence::m_events) - ->Field("Expanded", &CAnimSequence::m_expanded) - ->Field("ActiveDirectorNodeId", &CAnimSequence::m_activeDirectorNodeId); + if (rootElement.GetVersion() < 5) + { + rootElement.AddElement(serializeContext, "BaseClass1", azrtti_typeid()); + } + + return true; +} + +void CAnimSequence::Reflect(AZ::ReflectContext* context) +{ + IAnimSequence::Reflect(context); + + if (auto serializeContext = azrtti_cast(context); serializeContext != nullptr) + { + serializeContext->Class() + ->Version(IAnimSequence::kSequenceVersion, &AnimSequenceVersionConverter) + ->Field("Name", &CAnimSequence::m_name) + ->Field("SequenceEntityId", &CAnimSequence::m_sequenceEntityId) + ->Field("Flags", &CAnimSequence::m_flags) + ->Field("TimeRange", &CAnimSequence::m_timeRange) + ->Field("ID", &CAnimSequence::m_id) + ->Field("Nodes", &CAnimSequence::m_nodes) + ->Field("SequenceType", &CAnimSequence::m_sequenceType) + ->Field("Events", &CAnimSequence::m_events) + ->Field("Expanded", &CAnimSequence::m_expanded) + ->Field("ActiveDirectorNodeId", &CAnimSequence::m_activeDirectorNodeId); + } } ////////////////////////////////////////////////////////////////////////// diff --git a/Gems/Maestro/Code/Source/Cinematics/AnimSequence.h b/Gems/Maestro/Code/Source/Cinematics/AnimSequence.h index 3069896f50..d54b48c9eb 100644 --- a/Gems/Maestro/Code/Source/Cinematics/AnimSequence.h +++ b/Gems/Maestro/Code/Source/Cinematics/AnimSequence.h @@ -154,7 +154,7 @@ public: return m_nextTrackId++; } - static void Reflect(AZ::SerializeContext* serializeContext); + static void Reflect(AZ::ReflectContext* context); private: void ComputeTimeRange(); diff --git a/bootstrap.cfg b/bootstrap.cfg index cbe6ed025e..aa7af07645 100644 --- a/bootstrap.cfg +++ b/bootstrap.cfg @@ -1,84 +1,12 @@ --- When you see an option that does not have a platform preceeding it, that is the default --- value for anything not specificly set per platform. So if remote_filesystem=0 and you have --- ios_remote_file_system=1 then remote filesystem will be off for all platforms except ios --- Any of the settings in this file can be prefixed with a platform name: --- android, ios, mac, linux, windows, etc... --- or left unprefixed, to set all platforms not specified. The rules apply in the order they're declared +; This file is deprecated and is only use currently for setting the path when running O3DE in an engine-centric manner +; By engine-centric, what is meant is using CMake to configure from the directory and passing in the LY_PROJECTS value project_path=AutomatedTesting --- remote_filesystem - enable Virtual File System (VFS) --- This feature allows a remote instance of the game to run off assets --- on the asset processor computers cache instead of deploying them the remote device --- By default it is off and can be overridden for any platform -remote_filesystem=0 -provo_remote_filesystem=0 -android_remote_filesystem=0 -ios_remote_filesystem=0 -mac_remote_filesystem=0 - --- What type of assets are we going to load? --- We need to know this before we establish VFS because different platform assets --- are stored in different root folders in the cache. These correspond to the names --- In the asset processor config file. This value also controls what config file is read --- when you read system_xxxx_xxxx.cfg (for example, system_windows_pc.cfg or system_android_es3.cfg) --- by default, pc assets (in the 'pc' folder) are used, with RC being fed 'pc' as the platform --- by default on console we use the default assets=pc for better iteration times --- we should turn on console specific assets only when in release and/or testing assets and/or loading performance --- that way most people will not need to have 3 different caches taking up disk space -assets = pc --- provo_assets = provo --- salem_assets = salem --- jasper_assets = jasper -android_assets = es3 -ios_assets = ios -mac_assets = osx_gl - --- Add the IP address of your console to the allowed list that will connect to the asset processor here --- You can list addresses or CIDR's. CIDR's are helpful if you are using DHCP. A CIDR looks like an ip address with --- a /n on the end means how many bits are significant. 8bits.8bits.8bits.8bits = /32 --- Example: 192.168.1.3 --- Example: 192.168.1.3, 192.168.1.15 --- Example: 192.168.1.0/24 will allow any address starting with 192.168.1. --- Example: 192.168.0.0/16 will allow any address starting with 192.168. --- Example: 192.168.0.0/8 will allow any address starting with 192. --- allowed_list = - --- IP address and optionally port of the asset processor. --- Set your PC IP here: (and uncomment the next line) --- If you are running your asset processor on a windows machine you --- can find out your ip address by opening a cmd prompt and typing in ipconfig --- remote_ip = 127.0.0.1 --- remote_port = 45643 - --- Which way do you want to connect the asset processor to the game: 1=game connects to AP "connect", 0=AP connects to game "listen" --- Note: android and IOS over USB port forwarding may need to listen instead of connect -connect_to_remote=0 -windows_connect_to_remote=1 -provo_connect_to_remote=1 -salem_connect_to_remote=0 -jasper_connect_to_remote=0 -android_connect_to_remote=0 -ios_connect_to_remote=0 -mac_connect_to_remote=0 - --- Should we tell the game to wait and not proceed unless we have a connection to the AP or --- do we allow it to continue to try to connect in the background without waiting --- Note: Certain options REQUIRE that we do not proceed unless we have a connection, and will override this option to 1 when set --- Since remote_filesystem=1 requires a connection to proceed it will override our option to 1 -wait_for_connect=0 -provo_wait_for_connect=0 -salem_wait_for_connect=0 -jasper_wait_for_connect=0 -windows_wait_for_connect=1 -android_wait_for_connect=0 -ios_wait_for_connect=0 -mac_wait_for_connect=0 - --- How long applications should wait while attempting to connect to an already launched AP(in seconds) --- connect_ap_timeout=3 - --- How long application should wait when launching the AP and wait for the AP to connect back to it(in seconds) --- This time is dependent on Machine load as well as how long it takes for the new AP instance to initialize --- A debug AP takes longer to start up than a profile AP --- launch_ap_timeout=15 +; The Asset Processor Specific settings are now the /Engine/Registry/bootstrap.setreg settings +; The Engine specific settings can be overridden in order of least precedence to most +; 1. Override the settings in a "/Registry/*.setreg(patch)" file (Shared per Gem Settings) +; 2. Override the settings in a "/Registry/*.setreg(patch)" file (Shared per Project Settings) +; 3. Override the settings in a "/Registry/*.setreg(patch)" file (User per Project Settings) +; 4. Override the settings in a "~/.o3de/Registry/*.setreg(patch)" file (User Global Settings) +; Where "~" is %USERPROFILE% on Windows and $HOME on Unix like platforms diff --git a/cmake/3rdParty.cmake b/cmake/3rdParty.cmake index 4cd3ab2917..8d0c030302 100644 --- a/cmake/3rdParty.cmake +++ b/cmake/3rdParty.cmake @@ -116,10 +116,6 @@ function(ly_add_external_target) # Setting BASE_PATH variable in the parent scope to allow for the Find<3rdParty>.cmake scripts to use them set(BASE_PATH ${BASE_PATH} PARENT_SCOPE) - if(NOT EXISTS ${BASE_PATH}) - message(FATAL_ERROR "Cannot find 3rdParty library ${ly_add_external_target_NAME} on path ${BASE_PATH}") - endif() - add_library(3rdParty::${NAME_WITH_NAMESPACE} INTERFACE IMPORTED GLOBAL) if(ly_add_external_target_INCLUDE_DIRECTORIES) diff --git a/cmake/3rdParty/FindOpenGLInterface.cmake b/cmake/3rdParty/FindOpenGLInterface.cmake new file mode 100644 index 0000000000..1e4992290f --- /dev/null +++ b/cmake/3rdParty/FindOpenGLInterface.cmake @@ -0,0 +1,19 @@ +# +# 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. +# + +find_package(OpenGL) + +ly_add_external_target( + NAME OpenGLInterface + VERSION "" + BUILD_DEPENDENCIES + OpenGL::GL +) \ No newline at end of file diff --git a/cmake/3rdParty/Platform/Mac/OpenGLInterface_mac.cmake b/cmake/3rdParty/Platform/Mac/OpenGLInterface_mac.cmake new file mode 100644 index 0000000000..7d0d47740f --- /dev/null +++ b/cmake/3rdParty/Platform/Mac/OpenGLInterface_mac.cmake @@ -0,0 +1,13 @@ +# +# 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. +# + +# MacOS 10.14 deprecates OpenGL. This silences the warnings for now. +set(OPENGLINTERFACE_COMPILE_DEFINITIONS GL_SILENCE_DEPRECATION) \ No newline at end of file diff --git a/cmake/3rdParty/Platform/Mac/cmake_mac_files.cmake b/cmake/3rdParty/Platform/Mac/cmake_mac_files.cmake index f786f80cf7..0e3cc53262 100644 --- a/cmake/3rdParty/Platform/Mac/cmake_mac_files.cmake +++ b/cmake/3rdParty/Platform/Mac/cmake_mac_files.cmake @@ -15,6 +15,7 @@ set(FILES Clang_mac.cmake DirectXShaderCompiler_mac.cmake FbxSdk_mac.cmake + OpenGLInterface_mac.cmake OpenSSL_mac.cmake Wwise_mac.cmake ) diff --git a/cmake/3rdParty/cmake_files.cmake b/cmake/3rdParty/cmake_files.cmake index 3fe15bc0ce..46b612df42 100644 --- a/cmake/3rdParty/cmake_files.cmake +++ b/cmake/3rdParty/cmake_files.cmake @@ -18,6 +18,7 @@ set(FILES Finddyad.cmake FindFbxSdk.cmake Findlibav.cmake + FindOpenGLInterface.cmake FindOpenSSL.cmake FindRadTelemetry.cmake FindVkValidation.cmake 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() diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 3d9ddd0411..297c406b7b 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -26,8 +26,7 @@ def pipelineParameters = [ booleanParam(defaultValue: false, description: 'Deletes the contents of the output directory before building. This will cause a \"clean\" build. NOTE: does not imply CLEAN_ASSETS', name: 'CLEAN_OUTPUT_DIRECTORY'), booleanParam(defaultValue: false, description: 'Deletes the contents of the output directories of the AssetProcessor before building.', name: 'CLEAN_ASSETS'), booleanParam(defaultValue: false, description: 'Deletes the contents of the workspace and forces a complete pull.', name: 'CLEAN_WORKSPACE'), - booleanParam(defaultValue: false, description: 'Recreates the volume used for the workspace. The volume will be created out of a snapshot taken from main.', name: 'RECREATE_VOLUME'), - string(defaultValue: '', description: 'Filters and overrides the list of jobs to run for each of the below platforms (comma-separated). Can\'t be used during a pull request.', name: 'JOB_LIST_OVERRIDE') + booleanParam(defaultValue: false, description: 'Recreates the volume used for the workspace. The volume will be created out of a snapshot taken from main.', name: 'RECREATE_VOLUME') ] def palSh(cmd, lbl = '', winSlashReplacement = true) { @@ -76,18 +75,22 @@ def palRmDir(path) { } } -def IsJobEnabled(buildTypeMap, pipelineName, platformName) { - def job_list_override = params.JOB_LIST_OVERRIDE.tokenize(',') +def IsPullRequest(branchName) { + // temporarily using the name to detect if we are in a PR + // In the future we will check with github + return branchName.startsWith('PR-') +} + +def IsJobEnabled(branchName, buildTypeMap, pipelineName, platformName) { + if (IsPullRequest(branchName)) { + return buildTypeMap.value.TAGS && buildTypeMap.value.TAGS.contains(pipelineName) + } + def job_list_override = params.JOB_LIST_OVERRIDE ? params.JOB_LIST_OVERRIDE.tokenize(',') : '' if (!job_list_override.isEmpty()) { return params[platformName] && job_list_override.contains(buildTypeMap.key); } else { - if (params[platformName]) { - if(buildTypeMap.value.TAGS) { - return buildTypeMap.value.TAGS.contains(pipelineName) - } - } + return params[platformName] && buildTypeMap.value.TAGS && buildTypeMap.value.TAGS.contains(pipelineName) } - return false } def GetRunningPipelineName(JENKINS_JOB_NAME) { @@ -448,8 +451,12 @@ try { pipelineConfig = LoadPipelineConfig(pipelineName, branchName) // Add each platform as a parameter that the user can disable if needed - pipelineConfig.platforms.each { platform -> - pipelineParameters.add(booleanParam(defaultValue: true, description: '', name: platform.key)) + if (!IsPullRequest(branchName)) { + pipelineParameters.add(stringParam(defaultValue: '', description: 'Filters and overrides the list of jobs to run for each of the below platforms (comma-separated). Can\'t be used during a pull request.', name: 'JOB_LIST_OVERRIDE')) + + pipelineConfig.platforms.each { platform -> + pipelineParameters.add(booleanParam(defaultValue: true, description: '', name: platform.key)) + } } pipelineProperties.add(parameters(pipelineParameters)) properties(pipelineProperties) @@ -462,23 +469,26 @@ try { } } - if(env.BUILD_NUMBER == '1' && !branchName.startsWith('PR-')) { + if(env.BUILD_NUMBER == '1' && !IsPullRequest(branchName)) { // Exit pipeline early on the intial build. This allows Jenkins to load the pipeline for the branch and enables users // to select build parameters on their first actual build. See https://issues.jenkins.io/browse/JENKINS-41929 currentBuild.result = 'SUCCESS' return } + def someBuildHappened = false + // Build and Post-Build Testing Stage def buildConfigs = [:] // Platform Builds run on EC2 pipelineConfig.platforms.each { platform -> platform.value.build_types.each { build_job -> - if (IsJobEnabled(build_job, pipelineName, platform.key)) { // User can filter jobs, jobs are tagged by pipeline + if (IsJobEnabled(branchName, build_job, pipelineName, platform.key)) { // User can filter jobs, jobs are tagged by pipeline def envVars = GetBuildEnvVars(platform.value.PIPELINE_ENV ?: EMPTY_JSON, build_job.value.PIPELINE_ENV ?: EMPTY_JSON, pipelineName) envVars['JOB_NAME'] = "${branchName}_${platform.key}_${build_job.key}" // backwards compatibility, some scripts rely on this def nodeLabel = envVars['NODE_LABEL'] + someBuildHappened = true buildConfigs["${platform.key} [${build_job.key}]"] = { node("${nodeLabel}") { @@ -538,6 +548,9 @@ try { echo 'All builds successful' } + if (!someBuildHappened) { + currentBuild.result = 'NOT_BUILT' + } } catch(Exception e) { error "Exception: ${e}" diff --git a/scripts/build/Platform/Linux/build_config.json b/scripts/build/Platform/Linux/build_config.json index d7f5ddc9d0..426bf1d7ce 100644 --- a/scripts/build/Platform/Linux/build_config.json +++ b/scripts/build/Platform/Linux/build_config.json @@ -7,14 +7,14 @@ "CMAKE_LY_PROJECTS": "AutomatedTesting" } }, - "profile_pipe": { + "profile_nounity_pipe": { "TAGS": [ "default" ], "steps": [ "profile_nounity", - "asset_profile", - "test_profile" + "asset_profile_nounity", + "test_profile_nounity" ] }, "metrics": { @@ -84,6 +84,18 @@ "CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSClientAuth.Tests|Gem::AWSCore.Editor.Tests) -L FRAMEWORK_googletest" } }, + "test_profile_nounity": { + "TAGS": [], + "COMMAND": "build_test_linux.sh", + "PARAMETERS": { + "CONFIGURATION": "profile", + "OUTPUT_DIRECTORY": "build/linux", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_LY_PROJECTS": "AutomatedTesting", + "CMAKE_TARGET": "all", + "CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSClientAuth.Tests|Gem::AWSCore.Editor.Tests) -L FRAMEWORK_googletest" + } + }, "asset_profile": { "TAGS": [ "weekly-build-metrics" @@ -100,6 +112,20 @@ "ASSET_PROCESSOR_PLATFORMS": "pc,server" } }, + "asset_profile_nounity": { + "TAGS": [], + "COMMAND": "build_asset_linux.sh", + "PARAMETERS": { + "CONFIGURATION": "profile", + "OUTPUT_DIRECTORY": "build/linux", + "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=FALSE -DLY_PARALLEL_LINK_JOBS=4", + "CMAKE_LY_PROJECTS": "AutomatedTesting", + "CMAKE_TARGET": "AssetProcessorBatch", + "ASSET_PROCESSOR_BINARY": "bin/profile/AssetProcessorBatch", + "ASSET_PROCESSOR_OPTIONS": "/zeroAnalysisMode", + "ASSET_PROCESSOR_PLATFORMS": "pc,server" + } + }, "asset_clean_profile": { "TAGS": [ "nightly" diff --git a/scripts/commit_validation/commit_validation/pal_allowedlist.txt b/scripts/commit_validation/commit_validation/pal_allowedlist.txt index 3b1dfdb3b9..278262d59c 100644 --- a/scripts/commit_validation/commit_validation/pal_allowedlist.txt +++ b/scripts/commit_validation/commit_validation/pal_allowedlist.txt @@ -17,6 +17,7 @@ */Code/Framework/AzCore/AzCore/Math/VectorFloat.h */Code/Framework/AzCore/AzCore/Memory/dlmalloc.inl */Code/Framework/AzCore/AzCore/Memory/nedmalloc.inl +*/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.* */Code/Framework/AzCore/AzCore/PlatformDef.h */Code/Framework/AzCore/AzCore/std/containers/compressed_pair.h */Code/Framework/AzCore/AzCore/std/containers/variant.h