From 00a529ad74d139419ea2e4f331b21509a01dcf85 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Fri, 28 May 2021 14:56:52 -0500 Subject: [PATCH 01/15] Fix AssImpTransformImporter logic for bone nodes For bone nodes, the Transform is computed by multiplying the parent offsetMatrix by the inverse of the node's offsetMatrix Note that this currently disables the LimitBoneWeights option since that results in the removal of bone nodes that are not attached to a mesh. Without the bones there is no way to retrieve the offsetMatrix, so the Transform cannot be computed correctly Fixes LYN-3755 --- .../Importers/AssImpTransformImporter.cpp | 59 ++++++++++++++++--- .../SDKWrapper/AssImpSceneWrapper.cpp | 5 +- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp index 5357c32fa9..bcc007e3a7 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.cpp @@ -46,22 +46,69 @@ namespace AZ serializeContext->Class()->Version(1); } } - + + void GetAllBones(const aiScene* scene, AZStd::unordered_map& boneLookup) + { + for (unsigned meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) + { + const aiMesh* mesh = scene->mMeshes[meshIndex]; + + for (unsigned boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) + { + const aiBone* bone = mesh->mBones[boneIndex]; + + boneLookup[bone->mName.C_Str()] = bone; + } + } + } + Events::ProcessingResult AssImpTransformImporter::ImportTransform(AssImpSceneNodeAppendedContext& context) { AZ_TraceContext("Importer", "transform"); const aiNode* currentNode = context.m_sourceNode.GetAssImpNode(); const aiScene* scene = context.m_sourceScene.GetAssImpScene(); - + if (currentNode == scene->mRootNode || IsPivotNode(currentNode->mName)) { return Events::ProcessingResult::Ignored; } - aiMatrix4x4 combinedTransform = GetConcatenatedLocalTransform(currentNode); + AZStd::unordered_map boneLookup; + GetAllBones(scene, boneLookup); + + auto boneIterator = boneLookup.find(currentNode->mName.C_Str()); + const bool isBone = boneIterator != boneLookup.end(); + + aiMatrix4x4 combinedTransform; + + if (isBone) + { + auto parentNode = currentNode->mParent; + + aiMatrix4x4 offsetMatrix = boneIterator->second->mOffsetMatrix; + aiMatrix4x4 parentOffset {}; + + auto parentBoneIterator = boneLookup.find(parentNode->mName.C_Str()); + + if (parentNode && parentBoneIterator != boneLookup.end()) + { + const auto& parentBone = parentBoneIterator->second; + + parentOffset = parentBone->mOffsetMatrix; + } + + auto inverseOffset = offsetMatrix; + inverseOffset.Inverse(); + + combinedTransform = parentOffset * inverseOffset; + } + else + { + combinedTransform = GetConcatenatedLocalTransform(currentNode); + } DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform); - + context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform); context.m_sourceSceneSystem.ConvertUnit(localTransform); @@ -105,9 +152,7 @@ namespace AZ } else { - bool addedData = context.m_scene.GetGraph().SetContent( - context.m_currentGraphPosition, - transformData); + bool addedData = context.m_scene.GetGraph().SetContent(context.m_currentGraphPosition, transformData); AZ_Error(SceneAPI::Utilities::ErrorWindow, addedData, "Failed to add node data"); return addedData ? Events::ProcessingResult::Success : Events::ProcessingResult::Failure; diff --git a/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp b/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp index 791af4bf68..9186a2fb7a 100644 --- a/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp +++ b/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp @@ -69,13 +69,14 @@ namespace AZ // aiProcess_JoinIdenticalVertices is not enabled because O3DE has a mesh optimizer that also does this, // this flag is disabled to keep AssImp output similar to FBX SDK to reduce downstream bugs for the initial AssImp release. // There's currently a minimum of properties and flags set to maximize compatibility with the existing node graph. + + // aiProcess_LimitBoneWeights is not enabled because it will remove bones which are not associated with a mesh. + // This results in the loss of the offset matrix data for nodes without a mesh which is required for the Transform Importer. m_importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, false); m_importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, false); m_sceneFileName = fileName; m_assImpScene = m_importer.ReadFile(fileName, aiProcess_Triangulate //Triangulates all faces of all meshes - | aiProcess_LimitBoneWeights //Limits the number of bones that can affect a vertex to a maximum value - //dropping the least important and re-normalizing | aiProcess_GenNormals); //Generate normals for meshes #if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL From dda6fee2276f5e2418159a40dc6f978ddf789ab6 Mon Sep 17 00:00:00 2001 From: gallowj Date: Wed, 9 Jun 2021 09:58:38 -0500 Subject: [PATCH 02/15] fixed a type-o --- Gems/AtomContent/gem.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/AtomContent/gem.json b/Gems/AtomContent/gem.json index 941e7dea20..b043cbbaca 100644 --- a/Gems/AtomContent/gem.json +++ b/Gems/AtomContent/gem.json @@ -8,7 +8,7 @@ "Gem" ], "user_tags": [ - "AtomConent" + "AtomContent" ], "icon_path": "preview.png" } From d5916630b88fc19bd017c9fff6591a3db2a7818a Mon Sep 17 00:00:00 2001 From: gallowj Date: Wed, 9 Jun 2021 14:27:59 -0500 Subject: [PATCH 03/15] Changes related to ATOM-15021, this allows maya on py2.7 to work with .o3de\boostrap changes --- .../Solutions/.wing/DCCsi_7x.wpr | 6 ++++++ .../DccScriptingInterface/azpy/config_utils.py | 8 +++++--- .../DccScriptingInterface/azpy/constants.py | 13 ++++++++++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Solutions/.wing/DCCsi_7x.wpr b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Solutions/.wing/DCCsi_7x.wpr index d57e91f35d..aa7a8c4bd9 100644 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Solutions/.wing/DCCsi_7x.wpr +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/Solutions/.wing/DCCsi_7x.wpr @@ -69,10 +69,16 @@ proj.launch-config = {loc('../../SDK/Atom/Scripts/Python/DCC_Materials/maya_mate loc('../../azpy/__init__.py'): ('custom', (u'', 'launch-oobMrvXFf1SwtYBg')), + loc('../../azpy/constants.py'): ('custom', + (u'', + 'launch-GeaM41WYMGA1sEfm')), loc('../../azpy/env_base.py'): ('project', (u'', 'launch-GeaM41WYMGA1sEfm')), loc('../../azpy/maya/callbacks/node_message_callback_handler.py'): ('c'\ 'ustom', + (u'', + 'launch-GeaM41WYMGA1sEfm')), + loc('../../config.py'): ('custom', (u'', 'launch-GeaM41WYMGA1sEfm'))} diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/config_utils.py b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/config_utils.py index 0a0c6b8337..5b5c5aa079 100755 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/config_utils.py +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/config_utils.py @@ -165,12 +165,14 @@ def get_current_project(): bootstrap_box = None try: - bootstrap_box = Box.from_json(filename=PATH_USER_O3DE_BOOTSTRAP, + bootstrap_box = Box.from_json(filename=str(Path(PATH_USER_O3DE_BOOTSTRAP).resolve()), encoding="utf-8", errors="strict", object_pairs_hook=OrderedDict) - except FileExistsError as e: - _LOGGER.error('File does not exist: {}'.format(PATH_USER_O3DE_BOOTSTRAP)) + except Exception as e: + # this file runs in py2.7 for Maya 2020, FileExistsError is not defined + _LOGGER.error('FileExistsError: {}'.format(PATH_USER_O3DE_BOOTSTRAP)) + _LOGGER.error('exception is: {}'.format(e)) if bootstrap_box: # this seems fairly hard coded - what if the data changes? diff --git a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/constants.py b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/constants.py index e10221d324..7f6b0e4523 100755 --- a/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/constants.py +++ b/Gems/AtomLyIntegration/TechnicalArt/DccScriptingInterface/azpy/constants.py @@ -226,7 +226,18 @@ TAG_DEFAULT_PY = str('Launch_pyBASE.bat') FILENAME_DEFAULT_CONFIG = str('DCCSI_config.json') # new o3de related paths -PATH_USER_O3DE = str('{home}\\{o3de}').format(home=expanduser("~"), +# os.path.expanduser("~") returns different values in py2.7 vs 3 +PATH_USER_HOME = expanduser("~") +_LOGGER.debug('user home: {}'.format(PATH_USER_HOME)) + +# special case, make sure didn't return \documents +parts = os.path.split(PATH_USER_HOME) + +if str(parts[1].lower()) == 'documents': + PATH_USER_HOME = parts[0] + _LOGGER.debug('user home CORRECTED: {}'.format(PATH_USER_HOME)) + +PATH_USER_O3DE = str('{home}\\{o3de}').format(home=PATH_USER_HOME, o3de=TAG_O3DE_FOLDER) PATH_USER_O3DE_REGISTRY = str('{0}\\Registry').format(PATH_USER_O3DE) PATH_USER_O3DE_BOOTSTRAP = str('{reg}\\{file}').format(reg=PATH_USER_O3DE_REGISTRY, From 886601ad947142cfeff23c6cb810c1798aeb43dc Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Sat, 12 Jun 2021 03:20:31 -0700 Subject: [PATCH 04/15] Created a new ReflectionScreenSpaceCompositePass to set the maximum roughness mip in the pass Srg. Changed the ReflectionScreenSpaceBlurPass to auto-generate the mip chain, which will compute the appropriate number of mips. --- .../Passes/ReflectionScreenSpaceBlur.pass | 4 +- .../ReflectionScreenSpaceComposite.pass | 2 +- .../ReflectionScreenSpaceComposite.azsl | 10 ++-- .../Code/Source/CommonSystemComponent.cpp | 2 + .../ReflectionScreenSpaceBlurPass.h | 3 + .../ReflectionScreenSpaceCompositePass.cpp | 55 +++++++++++++++++++ .../ReflectionScreenSpaceCompositePass.h | 43 +++++++++++++++ .../Code/atom_feature_common_files.cmake | 2 + 8 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp create mode 100644 Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h diff --git a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlur.pass b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlur.pass index 1d20382408..e2fde2d4ef 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlur.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceBlur.pass @@ -24,9 +24,9 @@ }, "ImageDescriptor": { "Format": "R16G16B16A16_FLOAT", - "MipLevels": "8", "SharedQueueMask": "Graphics" - } + }, + "GenerateFullMipChain": true } ], "Connections": [ diff --git a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceComposite.pass b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceComposite.pass index 80c4e8987b..5443c32406 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceComposite.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/ReflectionScreenSpaceComposite.pass @@ -5,7 +5,7 @@ "ClassData": { "PassTemplate": { "Name": "ReflectionScreenSpaceCompositePassTemplate", - "PassClass": "FullScreenTriangle", + "PassClass": "ReflectionScreenSpaceCompositePass", "Slots": [ { "Name": "TraceInput", diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceComposite.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceComposite.azsl index fa3885f180..c5c724e106 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceComposite.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/Reflections/ReflectionScreenSpaceComposite.azsl @@ -37,6 +37,9 @@ ShaderResourceGroup PassSrg : SRG_PerPass AddressV = Clamp; AddressW = Clamp; }; + + // the max roughness mip level for sampling the previous frame image + uint m_maxMipLevel; } #include @@ -69,10 +72,6 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) float4 positionWS = mul(ViewSrg::m_viewProjectionInverseMatrix, projectedPos); positionWS /= positionWS.w; - //float4 positionVS = mul(ViewSrg::m_projectionMatrixInverse, projectedPos); - //positionVS /= positionVS.w; - //float4 positionWS = mul(ViewSrg::m_viewMatrixInverse, positionVS); - // compute ray from camera to surface position float3 cameraToPositionWS = normalize(positionWS.xyz - ViewSrg::m_worldPosition); @@ -103,8 +102,7 @@ PSOutput MainPS(VSOutput IN, in uint sampleIndex : SV_SampleIndex) // compute the roughness mip to use in the previous frame image // remap the roughness mip into a lower range to more closely match the material roughness values const float MaxRoughness = 0.5f; - const float MaxRoughnessMip = 7; - float mip = saturate(roughness / MaxRoughness) * MaxRoughnessMip; + float mip = saturate(roughness / MaxRoughness) * PassSrg::m_maxMipLevel; // sample reflection value from the roughness mip float4 reflectionColor = float4(PassSrg::m_previousFrame.SampleLevel(PassSrg::LinearSampler, tracePrevUV, mip).rgb, 1.0f); diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index af28624357..1866da63e5 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -103,6 +103,7 @@ #include #include #include +#include #include #include @@ -283,6 +284,7 @@ namespace AZ // Add Reflection passes passSystem->AddPassCreator(Name("ReflectionScreenSpaceBlurPass"), &Render::ReflectionScreenSpaceBlurPass::Create); passSystem->AddPassCreator(Name("ReflectionScreenSpaceBlurChildPass"), &Render::ReflectionScreenSpaceBlurChildPass::Create); + passSystem->AddPassCreator(Name("ReflectionScreenSpaceCompositePass"), &Render::ReflectionScreenSpaceCompositePass::Create); passSystem->AddPassCreator(Name("ReflectionCopyFrameBufferPass"), &Render::ReflectionCopyFrameBufferPass::Create); // Add RayTracing pas diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h index 4a2ccce1d4..be8dc6d596 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h @@ -37,6 +37,9 @@ namespace AZ //! to store the previous frame image Data::Instance& GetFrameBufferImageAttachment() { return m_frameBufferImageAttachment; } + //! Returns the number of mip levels in the blur + uint32_t GetNumBlurMips() const { return m_numBlurMips; } + private: explicit ReflectionScreenSpaceBlurPass(const RPI::PassDescriptor& descriptor); diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp new file mode 100644 index 0000000000..fe2030ca7e --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp @@ -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. +* +*/ + +#include "ReflectionScreenSpaceCompositePass.h" +#include "ReflectionScreenSpaceBlurPass.h" +#include +#include + +namespace AZ +{ + namespace Render + { + RPI::Ptr ReflectionScreenSpaceCompositePass::Create(const RPI::PassDescriptor& descriptor) + { + RPI::Ptr pass = aznew ReflectionScreenSpaceCompositePass(descriptor); + return AZStd::move(pass); + } + + ReflectionScreenSpaceCompositePass::ReflectionScreenSpaceCompositePass(const RPI::PassDescriptor& descriptor) + : RPI::FullscreenTrianglePass(descriptor) + { + } + + void ReflectionScreenSpaceCompositePass::CompileResources([[maybe_unused]] const RHI::FrameGraphCompileContext& context) + { + if (!m_shaderResourceGroup) + { + return; + } + + RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass")); + const AZStd::vector& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter); + if (!passes.empty()) + { + Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(passes.front()); + const uint32_t MaxNumRoughnessMips = 8; + uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1; + + auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); + m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel); + } + + FullscreenTrianglePass::CompileResources(context); + } + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h new file mode 100644 index 0000000000..110673541e --- /dev/null +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h @@ -0,0 +1,43 @@ +/* +* 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 + +namespace AZ +{ + namespace Render + { + //! This pass composites the screenspace reflection trace onto the reflection buffer. + class ReflectionScreenSpaceCompositePass + : public RPI::FullscreenTrianglePass + { + AZ_RPI_PASS(ReflectionScreenSpaceCompositePass); + + public: + AZ_RTTI(Render::ReflectionScreenSpaceCompositePass, "{88739CC9-C3F1-413A-A527-9916C697D93A}", FullscreenTrianglePass); + AZ_CLASS_ALLOCATOR(Render::ReflectionScreenSpaceCompositePass, SystemAllocator, 0); + + //! Creates a new pass without a PassTemplate + static RPI::Ptr Create(const RPI::PassDescriptor& descriptor); + + private: + explicit ReflectionScreenSpaceCompositePass(const RPI::PassDescriptor& descriptor); + + // Pass Overrides... + void CompileResources(const RHI::FrameGraphCompileContext& context) override; + }; + } // namespace RPI +} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index a759de77fa..a656558abf 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -267,6 +267,8 @@ set(FILES Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurPass.h Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.cpp Source/ReflectionScreenSpace/ReflectionScreenSpaceBlurChildPass.h + Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp + Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.h Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.cpp Source/ReflectionScreenSpace/ReflectionCopyFrameBufferPass.h Source/ScreenSpace/DeferredFogSettings.cpp From bb083fde3c3e58458a94e1ffed1315b835fb6746 Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Sat, 12 Jun 2021 17:28:50 -0700 Subject: [PATCH 05/15] Added ReflectiveCubeMap usage flag if the shadow is rendering in an EnvironmentCubeMap pipeline --- .../DirectionalLightFeatureProcessor.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index c4f4bc54b3..08bc443586 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -1070,7 +1072,18 @@ namespace AZ segment.m_pipelineViewTag = viewTag; if (!segment.m_view || segment.m_view->GetName() != viewName) { - segment.m_view = RPI::View::CreateView(viewName, RPI::View::UsageShadow); + RPI::View::UsageFlags usageFlags = RPI::View::UsageShadow; + + // if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view, + // to filter out shadows from objects that are excluded from the cubemap + RPI::PassClassFilter passFilter; + AZStd::vector cubeMapPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); + if (!cubeMapPasses.empty()) + { + usageFlags |= RPI::View::UsageReflectiveCubeMap; + } + + segment.m_view = RPI::View::CreateView(viewName, usageFlags); } } } From 7ef292d2102a3212d0150d8ed1e9aaaa7b2bf60b Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Mon, 14 Jun 2021 10:27:03 -0700 Subject: [PATCH 06/15] Removed VK_KHR_ray_query extension requirement for enabling ray tracing --- .../RHI/Vulkan/External/glad/2.0.0-beta/include/glad/vulkan.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gems/Atom/RHI/Vulkan/External/glad/2.0.0-beta/include/glad/vulkan.h b/Gems/Atom/RHI/Vulkan/External/glad/2.0.0-beta/include/glad/vulkan.h index a6ee9e8634..33d4b64082 100644 --- a/Gems/Atom/RHI/Vulkan/External/glad/2.0.0-beta/include/glad/vulkan.h +++ b/Gems/Atom/RHI/Vulkan/External/glad/2.0.0-beta/include/glad/vulkan.h @@ -12691,8 +12691,7 @@ static int glad_vk_find_extensions_vulkan( VkPhysicalDevice physical_device) { #endif GLAD_VK_KHR_push_descriptor = glad_vk_has_extension("VK_KHR_push_descriptor", extension_count, extensions); GLAD_VK_KHR_ray_tracing = (glad_vk_has_extension("VK_KHR_acceleration_structure", extension_count, extensions) - && glad_vk_has_extension("VK_KHR_ray_tracing_pipeline", extension_count, extensions) - && glad_vk_has_extension("VK_KHR_ray_query", extension_count, extensions)); + && glad_vk_has_extension("VK_KHR_ray_tracing_pipeline", extension_count, extensions)); GLAD_VK_KHR_relaxed_block_layout = glad_vk_has_extension("VK_KHR_relaxed_block_layout", extension_count, extensions); GLAD_VK_KHR_sampler_mirror_clamp_to_edge = glad_vk_has_extension("VK_KHR_sampler_mirror_clamp_to_edge", extension_count, extensions); GLAD_VK_KHR_sampler_ycbcr_conversion = glad_vk_has_extension("VK_KHR_sampler_ycbcr_conversion", extension_count, extensions); From 6c05adddec4a1c056fd7e52a28aeccd7f289cec1 Mon Sep 17 00:00:00 2001 From: gallowj Date: Mon, 14 Jun 2021 15:41:50 -0500 Subject: [PATCH 07/15] This material did not look correct, sneaking it in --- .../Objects/PlayfulTeapot_playfulteapot.material | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/PlayfulTeapot_playfulteapot.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/PlayfulTeapot_playfulteapot.material index 27540c587e..da35fda141 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/PlayfulTeapot_playfulteapot.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Objects/PlayfulTeapot_playfulteapot.material @@ -14,13 +14,14 @@ }, "clearCoat": { "enable": true, - "normalMap": "EngineAssets/Textures/perlinNoiseNormal_ddn.tif" + "normalMap": "EngineAssets/Textures/perlinNoiseNormal_ddn.tif", + "normalStrength": 0.10000000149011612 }, "general": { "applySpecularAA": true }, "metallic": { - "factor": 0.5 + "factor": 0.10000000149011612 }, "normal": { "factor": 0.05000000074505806, @@ -31,6 +32,9 @@ }, "roughness": { "factor": 0.0 + }, + "specularF0": { + "enableMultiScatterCompensation": true } } -} +} \ No newline at end of file From 11c3a7532198708ff3fb5821aabd289ec8ea4676 Mon Sep 17 00:00:00 2001 From: amzn-hdoke <61443753+hdoke@users.noreply.github.com> Date: Mon, 14 Jun 2021 13:54:04 -0700 Subject: [PATCH 08/15] Enable Client Auth unit test on Linux (#1312) --- scripts/build/Platform/Linux/build_config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build/Platform/Linux/build_config.json b/scripts/build/Platform/Linux/build_config.json index ee6da77b29..903ac52568 100644 --- a/scripts/build/Platform/Linux/build_config.json +++ b/scripts/build/Platform/Linux/build_config.json @@ -83,7 +83,7 @@ "CMAKE_OPTIONS": "-G 'Ninja Multi-Config' -DCMAKE_C_COMPILER=clang-6.0 -DCMAKE_CXX_COMPILER=clang++-6.0 -DLY_UNITY_BUILD=TRUE -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) -LE SUITE_sandbox -L FRAMEWORK_googletest" + "CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSCore.Editor.Tests) -LE SUITE_sandbox -L FRAMEWORK_googletest" } }, "test_profile_nounity": { @@ -95,7 +95,7 @@ "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) -LE SUITE_sandbox -L FRAMEWORK_googletest" + "CTEST_OPTIONS": "-E (Gem::EMotionFX.Editor.Tests|Gem::AWSCore.Editor.Tests) -LE SUITE_sandbox -L FRAMEWORK_googletest" } }, "asset_profile": { From 86d0acf76c18b373f81a48f6725605f2489be3c0 Mon Sep 17 00:00:00 2001 From: sharmajs-amzn <82233357+sharmajs-amzn@users.noreply.github.com> Date: Mon, 14 Jun 2021 13:55:37 -0700 Subject: [PATCH 09/15] fixes for invalid drive letter casing for scanfolder (#1281) --- .../assetprocessor_static_files.cmake | 1 + .../AssetManager/assetScanFolderInfo.cpp | 42 +++++++++++++++++++ .../native/AssetManager/assetScanFolderInfo.h | 14 +------ 3 files changed, 44 insertions(+), 13 deletions(-) create mode 100644 Code/Tools/AssetProcessor/native/AssetManager/assetScanFolderInfo.cpp diff --git a/Code/Tools/AssetProcessor/assetprocessor_static_files.cmake b/Code/Tools/AssetProcessor/assetprocessor_static_files.cmake index 194e99b247..1e78d1dc6c 100644 --- a/Code/Tools/AssetProcessor/assetprocessor_static_files.cmake +++ b/Code/Tools/AssetProcessor/assetprocessor_static_files.cmake @@ -19,6 +19,7 @@ set(FILES native/AssetManager/AssetRequestHandler.cpp native/AssetManager/AssetRequestHandler.h native/AssetManager/assetScanFolderInfo.h + native/AssetManager/assetScanFolderInfo.cpp native/AssetManager/assetScanner.cpp native/AssetManager/assetScanner.h native/AssetManager/assetScannerWorker.cpp diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetScanFolderInfo.cpp b/Code/Tools/AssetProcessor/native/AssetManager/assetScanFolderInfo.cpp new file mode 100644 index 0000000000..f849b4ee49 --- /dev/null +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetScanFolderInfo.cpp @@ -0,0 +1,42 @@ +/* +* 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 + +namespace AssetProcessor +{ + ScanFolderInfo::ScanFolderInfo( + QString path, + QString displayName, + QString portableKey, + bool isRoot, + bool recurseSubFolders, + AZStd::vector platforms, + int order, + AZ::s64 scanFolderID, + bool canSaveNewAssets) + : m_scanPath(path) + , m_displayName(displayName) + , m_portableKey (portableKey) + , m_isRoot(isRoot) + , m_recurseSubFolders(recurseSubFolders) + , m_order(order) + , m_scanFolderID(scanFolderID) + , m_platforms(platforms) + , m_canSaveNewAssets(canSaveNewAssets) + { + m_scanPath = AssetUtilities::NormalizeFilePath(m_scanPath); + // note that m_scanFolderID is 0 unless its filled in from the DB. + } + +} // end namespace AssetProcessor diff --git a/Code/Tools/AssetProcessor/native/AssetManager/assetScanFolderInfo.h b/Code/Tools/AssetProcessor/native/AssetManager/assetScanFolderInfo.h index 5767822451..5fbda237d7 100644 --- a/Code/Tools/AssetProcessor/native/AssetManager/assetScanFolderInfo.h +++ b/Code/Tools/AssetProcessor/native/AssetManager/assetScanFolderInfo.h @@ -33,19 +33,7 @@ namespace AssetProcessor AZStd::vector platforms = AZStd::vector{}, int order = 0, AZ::s64 scanFolderID = 0, - bool canSaveNewAssets = false) - : m_scanPath(path) - , m_displayName(displayName) - , m_portableKey (portableKey) - , m_isRoot(isRoot) - , m_recurseSubFolders(recurseSubFolders) - , m_order(order) - , m_scanFolderID(scanFolderID) - , m_platforms(platforms) - , m_canSaveNewAssets(canSaveNewAssets) - { - // note that m_scanFolderID is 0 unless its filled in from the DB. - } + bool canSaveNewAssets = false); ScanFolderInfo() = default; ScanFolderInfo(const ScanFolderInfo& other) = default; From 948075fa61a9a08f1ef36b059602eeaabce69a94 Mon Sep 17 00:00:00 2001 From: AMZN-nggieber <52797929+AMZN-nggieber@users.noreply.github.com> Date: Mon, 14 Jun 2021 15:56:54 -0700 Subject: [PATCH 10/15] Gem Catalog Allows Filtering by Gem Selected Status Live (#1274) --- .../Source/GemCatalog/GemCatalogScreen.cpp | 2 + .../Source/GemCatalog/GemFilterWidget.cpp | 111 ++++++++++++++++-- .../Source/GemCatalog/GemFilterWidget.h | 9 +- .../Source/GemCatalog/GemItemDelegate.cpp | 20 ---- .../Source/GemCatalog/GemListHeaderWidget.cpp | 10 ++ .../Source/GemCatalog/GemModel.cpp | 15 +++ .../Source/GemCatalog/GemModel.h | 2 + .../GemCatalog/GemSortFilterProxyModel.cpp | 23 ++++ .../GemCatalog/GemSortFilterProxyModel.h | 13 ++ .../Source/UpdateProjectCtrl.cpp | 6 +- 10 files changed, 179 insertions(+), 32 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 4424767c0b..2c92af4e51 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -82,6 +82,8 @@ namespace O3DE::ProjectManager m_headerWidget->ReinitForProject(); + connect(m_gemModel, &GemModel::dataChanged, m_filterWidget, &GemFilterWidget::ResetGemStatusFilter); + // Select the first entry after everything got correctly sized QTimer::singleShot(200, [=]{ QModelIndex firstModelIndex = m_gemListView->model()->index(0,0); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp index a6a4e95ff9..7c6150ff99 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp @@ -26,6 +26,7 @@ namespace O3DE::ProjectManager const QVector& elementNames, const QVector& elementCounts, bool showAllLessButton, + bool collapsed, int defaultShowCount, QWidget* parent) : QWidget(parent) @@ -40,6 +41,7 @@ namespace O3DE::ProjectManager QHBoxLayout* collapseLayout = new QHBoxLayout(); m_collapseButton = new QPushButton(); m_collapseButton->setCheckable(true); + m_collapseButton->setChecked(collapsed); m_collapseButton->setFlat(true); m_collapseButton->setFocusPolicy(Qt::NoFocus); m_collapseButton->setFixedWidth(s_collapseButtonSize); @@ -178,6 +180,11 @@ namespace O3DE::ProjectManager return m_buttonGroup; } + bool FilterCategoryWidget::IsCollapsed() + { + return m_collapseButton->isChecked(); + } + GemFilterWidget::GemFilterWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent) : QScrollArea(parent) , m_filterProxyModel(filterProxyModel) @@ -193,20 +200,106 @@ namespace O3DE::ProjectManager QWidget* mainWidget = new QWidget(); setWidget(mainWidget); - m_mainLayout = new QVBoxLayout(); - m_mainLayout->setAlignment(Qt::AlignTop); - mainWidget->setLayout(m_mainLayout); + QVBoxLayout* mainLayout = new QVBoxLayout(); + mainLayout->setAlignment(Qt::AlignTop); + mainWidget->setLayout(mainLayout); QLabel* filterByLabel = new QLabel("Filter by"); filterByLabel->setStyleSheet("font-size: 16px;"); - m_mainLayout->addWidget(filterByLabel); + mainLayout->addWidget(filterByLabel); + QWidget* filterSection = new QWidget(this); + mainLayout->addWidget(filterSection); + + m_filterLayout = new QVBoxLayout(); + m_filterLayout->setAlignment(Qt::AlignTop); + m_filterLayout->setContentsMargins(0, 0, 0, 0); + filterSection->setLayout(m_filterLayout); + + ResetGemStatusFilter(); AddGemOriginFilter(); AddTypeFilter(); AddPlatformFilter(); AddFeatureFilter(); } + void GemFilterWidget::ResetGemStatusFilter() + { + QVector elementNames; + QVector elementCounts; + const int totalGems = m_gemModel->rowCount(); + const int selectedGemTotal = m_gemModel->TotalAddedGems(); + + elementNames.push_back(GemSortFilterProxyModel::GetGemStatusString(GemSortFilterProxyModel::GemStatus::Unselected)); + elementCounts.push_back(totalGems - selectedGemTotal); + + elementNames.push_back(GemSortFilterProxyModel::GetGemStatusString(GemSortFilterProxyModel::GemStatus::Selected)); + elementCounts.push_back(selectedGemTotal); + + bool wasCollapsed = false; + if (m_statusFilter) + { + wasCollapsed = m_statusFilter->IsCollapsed(); + } + + FilterCategoryWidget* filterWidget = + new FilterCategoryWidget("Status", elementNames, elementCounts, /*showAllLessButton=*/false, /*collapsed*/wasCollapsed); + if (m_statusFilter) + { + m_filterLayout->replaceWidget(m_statusFilter, filterWidget); + } + else + { + m_filterLayout->addWidget(filterWidget); + } + + m_statusFilter->deleteLater(); + m_statusFilter = filterWidget; + + const GemSortFilterProxyModel::GemStatus currentFilterState = m_filterProxyModel->GetGemStatus(); + const QList buttons = m_statusFilter->GetButtonGroup()->buttons(); + for (int statusFilterIndex = 0; statusFilterIndex < buttons.size(); ++statusFilterIndex) + { + const GemSortFilterProxyModel::GemStatus gemStatus = static_cast(statusFilterIndex); + QAbstractButton* button = buttons[statusFilterIndex]; + + if (static_cast(statusFilterIndex) == currentFilterState) + { + button->setChecked(true); + } + + connect( + button, &QAbstractButton::toggled, this, + [=](bool checked) + { + GemSortFilterProxyModel::GemStatus filterStatus = m_filterProxyModel->GetGemStatus(); + if (checked) + { + if (filterStatus == GemSortFilterProxyModel::GemStatus::NoFilter) + { + filterStatus = gemStatus; + } + else + { + filterStatus = GemSortFilterProxyModel::GemStatus::NoFilter; + } + } + else + { + if (filterStatus != gemStatus) + { + filterStatus = static_cast(!gemStatus); + } + else + { + filterStatus = GemSortFilterProxyModel::GemStatus::NoFilter; + } + } + m_filterProxyModel->SetGemStatus(filterStatus); + }); + } + } + void GemFilterWidget::AddGemOriginFilter() { QVector elementNames; @@ -233,7 +326,7 @@ namespace O3DE::ProjectManager } FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Provider", elementNames, elementCounts, /*showAllLessButton=*/false); - m_mainLayout->addWidget(filterWidget); + m_filterLayout->addWidget(filterWidget); const QList buttons = filterWidget->GetButtonGroup()->buttons(); for (int i = 0; i < buttons.size(); ++i) @@ -283,7 +376,7 @@ namespace O3DE::ProjectManager } FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Type", elementNames, elementCounts, /*showAllLessButton=*/false); - m_mainLayout->addWidget(filterWidget); + m_filterLayout->addWidget(filterWidget); const QList buttons = filterWidget->GetButtonGroup()->buttons(); for (int i = 0; i < buttons.size(); ++i) @@ -333,7 +426,7 @@ namespace O3DE::ProjectManager } FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Supported Platforms", elementNames, elementCounts, /*showAllLessButton=*/false); - m_mainLayout->addWidget(filterWidget); + m_filterLayout->addWidget(filterWidget); const QList buttons = filterWidget->GetButtonGroup()->buttons(); for (int i = 0; i < buttons.size(); ++i) @@ -388,8 +481,8 @@ namespace O3DE::ProjectManager } FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Features", elementNames, elementCounts, - /*showAllLessButton=*/true, /*defaultShowCount=*/5); - m_mainLayout->addWidget(filterWidget); + /*showAllLessButton=*/true, false, /*defaultShowCount=*/5); + m_filterLayout->addWidget(filterWidget); const QList buttons = filterWidget->GetButtonGroup()->buttons(); for (int i = 0; i < buttons.size(); ++i) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.h index 017eadc020..520370eb44 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.h @@ -37,11 +37,14 @@ namespace O3DE::ProjectManager const QVector& elementNames, const QVector& elementCounts, bool showAllLessButton = true, + bool collapsed = false, int defaultShowCount = 4, QWidget* parent = nullptr); QButtonGroup* GetButtonGroup(); + bool IsCollapsed(); + private: void UpdateCollapseState(); void UpdateSeeMoreLess(); @@ -66,14 +69,18 @@ namespace O3DE::ProjectManager explicit GemFilterWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent = nullptr); ~GemFilterWidget() = default; + public slots: + void ResetGemStatusFilter(); + private: void AddGemOriginFilter(); void AddTypeFilter(); void AddPlatformFilter(); void AddFeatureFilter(); - QVBoxLayout* m_mainLayout = nullptr; + QVBoxLayout* m_filterLayout = nullptr; GemModel* m_gemModel = nullptr; GemSortFilterProxyModel* m_filterProxyModel = nullptr; + FilterCategoryWidget* m_statusFilter = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index 8aa68fb7a2..03787de7e8 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -204,7 +204,6 @@ namespace O3DE::ProjectManager painter->save(); const QRect buttonRect = CalcButtonRect(contentRect); QPoint circleCenter; - QString buttonText; const bool isAdded = GemModel::IsAdded(modelIndex); if (isAdded) @@ -213,34 +212,15 @@ namespace O3DE::ProjectManager painter->setPen(m_buttonEnabledColor); circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1); - buttonText = "Added"; } else { circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius, 1); - buttonText = "Get"; } // Rounded rect painter->drawRoundedRect(buttonRect, s_buttonBorderRadius, s_buttonBorderRadius); - // Text - QFont font; - QRect textRect = GetTextRect(font, buttonText, s_buttonFontSize); - if (isAdded) - { - textRect = QRect(buttonRect.left(), buttonRect.top(), buttonRect.width() - s_buttonCircleRadius * 2.0, buttonRect.height()); - } - else - { - textRect = QRect(buttonRect.left() + s_buttonCircleRadius * 2.0, buttonRect.top(), buttonRect.width() - s_buttonCircleRadius * 2.0, buttonRect.height()); - } - - font.setPixelSize(s_buttonFontSize); - painter->setFont(font); - painter->setPen(m_textColor); - painter->drawText(textRect, Qt::AlignCenter, buttonText); - // Circle painter->setBrush(m_textColor); painter->drawEllipse(circleCenter, s_buttonCircleRadius, s_buttonCircleRadius); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp index bc287e3c61..ad1b57a27c 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp @@ -15,6 +15,7 @@ #include #include #include +#include namespace O3DE::ProjectManager { @@ -74,6 +75,15 @@ namespace O3DE::ProjectManager gemSummaryLabel->setStyleSheet("font-size: 12px;"); columnHeaderLayout->addWidget(gemSummaryLabel); + QSpacerItem* horizontalSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); + columnHeaderLayout->addSpacerItem(horizontalSpacer); + + QLabel* gemSelectedLabel = new QLabel(tr("Selected")); + gemSelectedLabel->setStyleSheet("font-size: 12px;"); + columnHeaderLayout->addWidget(gemSelectedLabel); + + columnHeaderLayout->addSpacing(60); + vLayout->addLayout(columnHeaderLayout); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 6c09c95572..5dc40723c9 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -235,4 +235,19 @@ namespace O3DE::ProjectManager } return result; } + + int GemModel::TotalAddedGems() const + { + int result = 0; + for (int row = 0; row < rowCount(); ++row) + { + const QModelIndex modelIndex = index(row, 0); + if (IsAdded(modelIndex)) + { + ++result; + } + } + return result; + } + } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 77f973a91c..2e05472cdf 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -63,6 +63,8 @@ namespace O3DE::ProjectManager QVector GatherGemsToBeAdded() const; QVector GatherGemsToBeRemoved() const; + int TotalAddedGems() const; + private: enum UserRole { diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp index d8f41c077e..c1360cabc6 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp @@ -37,6 +37,16 @@ namespace O3DE::ProjectManager return false; } + // Gem status + if (m_gemStatusFilter != GemStatus::NoFilter) + { + const GemStatus sourceGemStatus = static_cast(GemModel::IsAdded(sourceIndex)); + if (m_gemStatusFilter != sourceGemStatus) + { + return false; + } + } + // Gem origins if (m_gemOriginFilter) { @@ -125,6 +135,19 @@ namespace O3DE::ProjectManager return true; } + QString GemSortFilterProxyModel::GetGemStatusString(GemStatus status) + { + switch (status) + { + case Unselected: + return "Unselected"; + case Selected: + return "Selected"; + default: + return ""; + } + } + void GemSortFilterProxyModel::InvalidateFilter() { invalidate(); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h index f24a724ecf..fcde226f40 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h @@ -29,8 +29,17 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: + enum GemStatus + { + NoFilter = -1, + Unselected, + Selected + }; + GemSortFilterProxyModel(GemModel* sourceModel, QObject* parent = nullptr); + static QString GetGemStatusString(GemStatus status); + bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override; GemModel* GetSourceModel() const { return m_sourceModel; } @@ -38,6 +47,9 @@ namespace O3DE::ProjectManager void SetSearchString(const QString& searchString) { m_searchString = searchString; InvalidateFilter(); } + GemStatus GetGemStatus() const { return m_gemStatusFilter; } + void SetGemStatus(GemStatus gemStatus) { m_gemStatusFilter = gemStatus; InvalidateFilter(); } + GemInfo::GemOrigins GetGemOrigins() const { return m_gemOriginFilter; } void SetGemOrigins(const GemInfo::GemOrigins& gemOrigins) { m_gemOriginFilter = gemOrigins; InvalidateFilter(); } @@ -61,6 +73,7 @@ namespace O3DE::ProjectManager AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr; QString m_searchString; + GemStatus m_gemStatusFilter = GemStatus::NoFilter; GemInfo::GemOrigins m_gemOriginFilter = {}; GemInfo::Platforms m_platformFilter = {}; GemInfo::Types m_typeFilter = {}; diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index be1f0e5529..65f73accd1 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -189,11 +189,13 @@ namespace O3DE::ProjectManager { if (m_stack->currentIndex() == ScreenOrder::Gems) { - m_header->setSubTitle(QString(tr("Configure Gems for \"%1\"")).arg(m_projectInfo.m_projectName)); - m_nextButton->setText(tr("Confirm")); + m_header->setTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.m_projectName)); + m_header->setSubTitle(QString(tr("Configure Gems"))); + m_nextButton->setText(tr("Finalize")); } else { + m_header->setTitle(""); m_header->setSubTitle(QString(tr("Edit Project Settings: \"%1\"")).arg(m_projectInfo.m_projectName)); m_nextButton->setText(tr("Save")); } From ecded991b57be2db905ce4c15d7af9d2fb9c297f Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Mon, 14 Jun 2021 17:02:22 -0700 Subject: [PATCH 11/15] Display error when unable to start Python Added AzFramework Application, logging, unit tests --- Code/Framework/AzCore/AzCore/Utils/Utils.cpp | 7 + Code/Framework/AzCore/AzCore/Utils/Utils.h | 3 + Code/Sandbox/Editor/CryEdit.cpp | 2 +- Code/Tools/ProjectManager/CMakeLists.txt | 63 +++++- .../Linux/PAL_linux_tests_files.cmake | 15 ++ .../Linux/ProjectManager_Test_Traits_Linux.h | 15 ++ .../ProjectManager_Test_Traits_Platform.h | 15 ++ .../Platform/Mac/PAL_mac_tests_files.cmake | 15 ++ .../Mac/ProjectManager_Test_Traits_Mac.h | 15 ++ .../Mac/ProjectManager_Test_Traits_Platform.h | 15 ++ .../Windows/PAL_windows_tests_files.cmake | 15 ++ .../ProjectManager_Test_Traits_Platform.h | 15 ++ .../ProjectManager_Test_Traits_Windows.h | 15 ++ .../Resources/ProjectManager.qss | 5 + .../ProjectManager/Source/Application.cpp | 186 ++++++++++++++++++ .../Tools/ProjectManager/Source/Application.h | 48 +++++ .../Source/EngineSettingsScreen.cpp | 2 +- .../Source/ProjectButtonWidget.cpp | 2 +- .../Source/ProjectManagerWindow.cpp | 27 +-- .../Source/ProjectManagerWindow.h | 8 +- .../Source/ProjectSettingsScreen.cpp | 2 +- .../ProjectManager/Source/ProjectsScreen.cpp | 4 +- .../ProjectManager/Source/PythonBindings.cpp | 14 +- .../ProjectManager/Source/PythonBindings.h | 4 + .../Source/PythonBindingsInterface.h | 6 + Code/Tools/ProjectManager/Source/main.cpp | 87 ++------ .../project_manager_app_files.cmake | 17 ++ .../project_manager_files.cmake | 7 +- .../project_manager_tests_files.cmake | 17 ++ .../ProjectManager/tests/ApplicationTests.cpp | 47 +++++ Code/Tools/ProjectManager/tests/main.cpp | 35 ++++ 31 files changed, 606 insertions(+), 122 deletions(-) create mode 100644 Code/Tools/ProjectManager/Platform/Linux/PAL_linux_tests_files.cmake create mode 100644 Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Test_Traits_Linux.h create mode 100644 Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Test_Traits_Platform.h create mode 100644 Code/Tools/ProjectManager/Platform/Mac/PAL_mac_tests_files.cmake create mode 100644 Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Test_Traits_Mac.h create mode 100644 Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Test_Traits_Platform.h create mode 100644 Code/Tools/ProjectManager/Platform/Windows/PAL_windows_tests_files.cmake create mode 100644 Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Test_Traits_Platform.h create mode 100644 Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Test_Traits_Windows.h create mode 100644 Code/Tools/ProjectManager/Source/Application.cpp create mode 100644 Code/Tools/ProjectManager/Source/Application.h create mode 100644 Code/Tools/ProjectManager/project_manager_app_files.cmake create mode 100644 Code/Tools/ProjectManager/project_manager_tests_files.cmake create mode 100644 Code/Tools/ProjectManager/tests/ApplicationTests.cpp create mode 100644 Code/Tools/ProjectManager/tests/main.cpp diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp index 7025b3977e..e3647ec2cb 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.cpp +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.cpp @@ -175,4 +175,11 @@ namespace AZ::Utils path /= ".o3de"; return path.Native(); } + + AZ::IO::FixedMaxPathString GetO3deLogsDirectory() + { + AZ::IO::FixedMaxPath path = GetO3deManifestDirectory(); + path /= "Logs"; + return path.Native(); + } } diff --git a/Code/Framework/AzCore/AzCore/Utils/Utils.h b/Code/Framework/AzCore/AzCore/Utils/Utils.h index d082a3ebe0..8fb6f05742 100644 --- a/Code/Framework/AzCore/AzCore/Utils/Utils.h +++ b/Code/Framework/AzCore/AzCore/Utils/Utils.h @@ -97,6 +97,9 @@ namespace AZ //! Retrieves the full path where the manifest file lives, i.e. "/.o3de/o3de_manifest.json" AZ::IO::FixedMaxPathString GetEngineManifestPath(); + //! Retrieves the full directory to the O3DE logs directory, i.e. "/.o3de/Logs" + AZ::IO::FixedMaxPathString GetO3deLogsDirectory(); + //! Retrieves the App root path to use on the current platform //! If the optional is not engaged the AppRootPath should be calculated based //! on the location of the bootstrap.cfg file diff --git a/Code/Sandbox/Editor/CryEdit.cpp b/Code/Sandbox/Editor/CryEdit.cpp index a972a4bd9b..67e228a3ce 100644 --- a/Code/Sandbox/Editor/CryEdit.cpp +++ b/Code/Sandbox/Editor/CryEdit.cpp @@ -2891,7 +2891,7 @@ void CCryEditApp::OpenProjectManager(const AZStd::string& screen) { // provide the current project path for in case we want to update the project AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath(); - const AZStd::string commandLineOptions = AZStd::string::format(" --screen %s --project_path %s", screen.c_str(), projectPath.c_str()); + const AZStd::string commandLineOptions = AZStd::string::format(" --screen %s --project-path %s", screen.c_str(), projectPath.c_str()); bool launchSuccess = AzFramework::ProjectManager::LaunchProjectManager(commandLineOptions); if (!launchSuccess) { diff --git a/Code/Tools/ProjectManager/CMakeLists.txt b/Code/Tools/ProjectManager/CMakeLists.txt index aeb7be9793..434ce1424e 100644 --- a/Code/Tools/ProjectManager/CMakeLists.txt +++ b/Code/Tools/ProjectManager/CMakeLists.txt @@ -20,12 +20,11 @@ if (NOT python_package_name) message(WARNING "Python was not found in the package assocation list. Did someone call ly_associate_package(xxxxxxx Python) ?") endif() + ly_add_target( - NAME ProjectManager APPLICATION - OUTPUT_NAME o3de + NAME ProjectManager.Static STATIC NAMESPACE AZ AUTOMOC - AUTORCC FILES_CMAKE project_manager_files.cmake Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake @@ -47,6 +46,60 @@ ly_add_target( 3rdParty::pybind11 AZ::AzCore AZ::AzFramework - AZ::AzToolsFramework AZ::AzQtComponents -) \ No newline at end of file +) + +ly_add_target( + NAME ProjectManager APPLICATION + OUTPUT_NAME o3de + NAMESPACE AZ + AUTORCC + FILES_CMAKE + project_manager_app_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + BUILD_DEPENDENCIES + PRIVATE + 3rdParty::Qt::Core + 3rdParty::Qt::Concurrent + 3rdParty::Qt::Widgets + 3rdParty::Python + 3rdParty::pybind11 + AZ::AzCore + AZ::AzFramework + AZ::AzQtComponents + AZ::ProjectManager.Static +) + +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + ly_add_target( + NAME ProjectManager.Tests EXECUTABLE + NAMESPACE AZ + AUTORCC + FILES_CMAKE + project_manager_tests_files.cmake + Platform/${PAL_PLATFORM_NAME}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + Platform/${PAL_PLATFORM_NAME} + BUILD_DEPENDENCIES + PRIVATE + 3rdParty::Qt::Core + 3rdParty::Qt::Concurrent + 3rdParty::Qt::Widgets + 3rdParty::Python + 3rdParty::pybind11 + AZ::AzTest + AZ::AzFramework + AZ::AzFrameworkTestShared + AZ::ProjectManager.Static + ) + + ly_add_googletest( + NAME AZ::ProjectManager.Tests + TEST_COMMAND $ --unittest + ) + +endif() diff --git a/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_tests_files.cmake b/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_tests_files.cmake new file mode 100644 index 0000000000..e79da7183d --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Linux/PAL_linux_tests_files.cmake @@ -0,0 +1,15 @@ +# +# 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. +# + +set(FILES + ProjectManager_Test_Traits_Platform.h + ProjectManager_Test_Traits_Linux.h +) diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Test_Traits_Linux.h b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Test_Traits_Linux.h new file mode 100644 index 0000000000..c8b428a1c2 --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Test_Traits_Linux.h @@ -0,0 +1,15 @@ +/* + * 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 + +#define AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS true diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Test_Traits_Platform.h b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Test_Traits_Platform.h new file mode 100644 index 0000000000..639ef8a387 --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Test_Traits_Platform.h @@ -0,0 +1,15 @@ +/* + * 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 diff --git a/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_tests_files.cmake b/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_tests_files.cmake new file mode 100644 index 0000000000..a2d480de40 --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Mac/PAL_mac_tests_files.cmake @@ -0,0 +1,15 @@ +# +# 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. +# + +set(FILES + ProjectManager_Test_Traits_Platform.h + ProjectManager_Test_Traits_Mac.h +) diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Test_Traits_Mac.h b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Test_Traits_Mac.h new file mode 100644 index 0000000000..053db745ea --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Test_Traits_Mac.h @@ -0,0 +1,15 @@ +/* + * 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 + +#define AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS false diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Test_Traits_Platform.h b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Test_Traits_Platform.h new file mode 100644 index 0000000000..af8817998f --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Test_Traits_Platform.h @@ -0,0 +1,15 @@ +/* + * 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 diff --git a/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_tests_files.cmake b/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_tests_files.cmake new file mode 100644 index 0000000000..00d9da3db3 --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Windows/PAL_windows_tests_files.cmake @@ -0,0 +1,15 @@ +# +# 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. +# + +set(FILES + ProjectManager_Test_Traits_Platform.h + ProjectManager_Test_Traits_Windows.h +) diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Test_Traits_Platform.h b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Test_Traits_Platform.h new file mode 100644 index 0000000000..915a86644a --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Test_Traits_Platform.h @@ -0,0 +1,15 @@ +/* + * 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 diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Test_Traits_Windows.h b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Test_Traits_Windows.h new file mode 100644 index 0000000000..053db745ea --- /dev/null +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Test_Traits_Windows.h @@ -0,0 +1,15 @@ +/* + * 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 + +#define AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS false diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 80470591a8..efc01802b7 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -7,6 +7,11 @@ QMainWindow { margin:0; } +#ScreensCtrl { + min-width:1200px; + min-height:800px; +} + QPushButton:focus { outline: none; border:1px solid #1e70eb; diff --git a/Code/Tools/ProjectManager/Source/Application.cpp b/Code/Tools/ProjectManager/Source/Application.cpp new file mode 100644 index 0000000000..c566e76ef1 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/Application.cpp @@ -0,0 +1,186 @@ +/* + * 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 +#include +#include + +namespace O3DE::ProjectManager +{ + Application::~Application() + { + TearDown(); + } + + bool Application::Init(bool interactive) + { + constexpr const char* applicationName { "O3DE" }; + + QApplication::setOrganizationName(applicationName); + QApplication::setOrganizationDomain("o3de.org"); + + QCoreApplication::setApplicationName(applicationName); + QCoreApplication::setApplicationVersion("1.0"); + + // Use the LogComponent for non-dev logging log + RegisterComponentDescriptor(AzFramework::LogComponent::CreateDescriptor()); + + // set the log alias to .o3de/Logs instead of the default user/logs + AZ::IO::FixedMaxPath path = AZ::Utils::GetO3deLogsDirectory(); + + // DevWriteStorage is where the event log is written during development + m_settingsRegistry->Set(AZ::SettingsRegistryMergeUtils::FilePathKey_DevWriteStorage, path.LexicallyNormal().Native()); + + // Save event logs to .o3de/Logs/eventlogger/EventLogO3DE.azsl + m_settingsRegistry->Set(AZ::SettingsRegistryMergeUtils::BuildTargetNameKey, applicationName); + + Start(AzFramework::Application::Descriptor()); + + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); + + QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates)); + + QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); + AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::SystemDpiAware); + + // Create the actual Qt Application - this needs to happen before using QMessageBox + m_app.reset(new QApplication(*GetArgC(), *GetArgV())); + + if(!InitLog(applicationName)) + { + AZ_Warning("ProjectManager", false, "Failed to init logging"); + } + + m_pythonBindings = AZStd::make_unique(GetEngineRoot()); + if (!m_pythonBindings || !m_pythonBindings->PythonStarted()) + { + if (interactive) + { + QMessageBox::critical(nullptr, QObject::tr("Failed to start Python"), + QObject::tr("This tool requires an O3DE engine with a Python runtime, " + "but either Python is missing or mis-configured. Please rename " + "your python/runtime folder to python/runtime_bak, then run " + "python/get_python.bat to restore the Python runtime folder.")); + } + return false; + } + + const AZ::CommandLine* commandLine = GetCommandLine(); + AZ_Assert(commandLine, "Failed to get command line"); + + ProjectManagerScreen startScreen = ProjectManagerScreen::Projects; + if (size_t screenSwitchCount = commandLine->GetNumSwitchValues("screen"); screenSwitchCount > 0) + { + QString screenOption = commandLine->GetSwitchValue("screen", screenSwitchCount - 1).c_str(); + ProjectManagerScreen screen = ProjectUtils::GetProjectManagerScreen(screenOption); + if (screen != ProjectManagerScreen::Invalid) + { + startScreen = screen; + } + } + + AZ::IO::FixedMaxPath projectPath; + if (size_t projectSwitchCount = commandLine->GetNumSwitchValues("project-path"); projectSwitchCount > 0) + { + projectPath = commandLine->GetSwitchValue("project-path", projectSwitchCount - 1).c_str(); + } + + m_mainWindow.reset(new ProjectManagerWindow(nullptr, projectPath, startScreen)); + + return true; + } + + bool Application::InitLog(const char* logName) + { + if (!m_entity) + { + // override the log alias to the O3de Logs directory instead of the default project user/Logs folder + AZ::IO::FixedMaxPath path = AZ::Utils::GetO3deLogsDirectory(); + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "Failed to get FileIOBase instance"); + + fileIO->SetAlias("@log@", path.LexicallyNormal().Native().c_str()); + + // this entity exists because we need a home for LogComponent + // and cannot use the system entity because we need to be able to call SetLogFileBaseName + // so the log will be named O3DE.log + m_entity = aznew AZ::Entity("Application Entity"); + if (m_entity) + { + AzFramework::LogComponent* logger = aznew AzFramework::LogComponent(); + AZ_Assert(logger, "Failed to create LogComponent"); + logger->SetLogFileBaseName(logName); + m_entity->AddComponent(logger); + m_entity->Init(); + m_entity->Activate(); + } + } + + return m_entity != nullptr; + } + + void Application::TearDown() + { + if (m_entity) + { + m_entity->Deactivate(); + delete m_entity; + m_entity = nullptr; + } + + m_pythonBindings.reset(); + m_mainWindow.reset(); + m_app.reset(); + } + + bool Application::Run() + { + // Set up the Style Manager + AzQtComponents::StyleManager styleManager(qApp); + styleManager.initialize(qApp, GetEngineRoot()); + + // setup stylesheets and hot reloading + AZ::IO::FixedMaxPath engineRoot(GetEngineRoot()); + QDir rootDir(engineRoot.c_str()); + const auto pathOnDisk = rootDir.absoluteFilePath("Code/Tools/ProjectManager/Resources"); + const auto qrcPath = QStringLiteral(":/ProjectManager/style"); + AzQtComponents::StyleManager::addSearchPaths("style", pathOnDisk, qrcPath, engineRoot); + + // set stylesheet after creating the main window or their styles won't get updated + AzQtComponents::StyleManager::setStyleSheet(m_mainWindow.data(), QStringLiteral("style:ProjectManager.qss")); + + // the decoration wrapper is intended to remember window positioning and sizing + auto wrapper = new AzQtComponents::WindowDecorationWrapper(); + wrapper->setGuest(m_mainWindow.data()); + wrapper->show(); + m_mainWindow->show(); + + qApp->setQuitOnLastWindowClosed(true); + + // Run the application + return qApp->exec(); + } + +} diff --git a/Code/Tools/ProjectManager/Source/Application.h b/Code/Tools/ProjectManager/Source/Application.h new file mode 100644 index 0000000000..d4e94e8dd4 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/Application.h @@ -0,0 +1,48 @@ +/* + * 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 + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#include +#endif + +namespace AZ +{ + class Entity; +} + +namespace O3DE::ProjectManager +{ + class Application + : public AzFramework::Application + { + public: + using AzFramework::Application::Application; + virtual ~Application(); + + bool Init(bool interactive = true); + bool Run(); + void TearDown(); + + private: + bool InitLog(const char* logName); + + AZStd::unique_ptr m_pythonBindings; + QSharedPointer m_app; + QSharedPointer m_mainWindow; + + AZ::Entity* m_entity = nullptr; + }; +} diff --git a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp index 6342041da4..cf597745ea 100644 --- a/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/EngineSettingsScreen.cpp @@ -25,7 +25,7 @@ namespace O3DE::ProjectManager EngineSettingsScreen::EngineSettingsScreen(QWidget* parent) : ScreenWidget(parent) { - auto* layout = new QVBoxLayout(this); + auto* layout = new QVBoxLayout(); layout->setAlignment(Qt::AlignTop); setObjectName("engineSettingsScreen"); diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp index 761572ffa5..3bde0a310d 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp @@ -33,7 +33,7 @@ namespace O3DE::ProjectManager { setObjectName("labelButton"); - QVBoxLayout* vLayout = new QVBoxLayout(this); + QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setContentsMargins(0, 0, 0, 0); vLayout->setSpacing(5); diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp index cb1398cc61..59be0aaa35 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp @@ -13,21 +13,11 @@ #include #include -#include -#include -#include -#include -#include - -#include - namespace O3DE::ProjectManager { - ProjectManagerWindow::ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath, const AZ::IO::PathView& projectPath, ProjectManagerScreen startScreen) + ProjectManagerWindow::ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& projectPath, ProjectManagerScreen startScreen) : QMainWindow(parent) { - m_pythonBindings = AZStd::make_unique(engineRootPath); - setWindowTitle(tr("O3DE Project Manager")); ScreensCtrl* screensCtrl = new ScreensCtrl(); @@ -44,15 +34,6 @@ namespace O3DE::ProjectManager setCentralWidget(screensCtrl); - // setup stylesheets and hot reloading - QDir rootDir = QString::fromUtf8(engineRootPath.Native().data(), aznumeric_cast(engineRootPath.Native().size())); - const auto pathOnDisk = rootDir.absoluteFilePath("Code/Tools/ProjectManager/Resources"); - const auto qrcPath = QStringLiteral(":/ProjectManager/style"); - AzQtComponents::StyleManager::addSearchPaths("style", pathOnDisk, qrcPath, engineRootPath); - - // set stylesheet after creating the screens or their styles won't get updated - AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("style:ProjectManager.qss")); - // always push the projects screen first so we have something to come back to if (startScreen != ProjectManagerScreen::Projects) { @@ -66,10 +47,4 @@ namespace O3DE::ProjectManager emit screensCtrl->NotifyCurrentProject(path); } } - - ProjectManagerWindow::~ProjectManagerWindow() - { - m_pythonBindings.reset(); - } - } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h index 758af8fc00..db2b1fd304 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h +++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.h @@ -13,7 +13,7 @@ #if !defined(Q_MOC_RUN) #include -#include +#include #include #endif @@ -25,12 +25,8 @@ namespace O3DE::ProjectManager Q_OBJECT public: - explicit ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& engineRootPath, const AZ::IO::PathView& projectPath, + explicit ProjectManagerWindow(QWidget* parent, const AZ::IO::PathView& projectPath, ProjectManagerScreen startScreen = ProjectManagerScreen::Projects); - ~ProjectManagerWindow(); - - private: - AZStd::unique_ptr m_pythonBindings; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp index 26711753d4..b198724353 100644 --- a/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectSettingsScreen.cpp @@ -37,7 +37,7 @@ namespace O3DE::ProjectManager // if we don't set this in a frame (just use a sub-layout) all the content will align incorrectly horizontally QFrame* projectSettingsFrame = new QFrame(this); projectSettingsFrame->setObjectName("projectSettings"); - m_verticalLayout = new QVBoxLayout(this); + m_verticalLayout = new QVBoxLayout(); // you cannot remove content margins in qss m_verticalLayout->setContentsMargins(0, 0, 0, 0); diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp index 8e41e52643..6633558406 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp @@ -85,7 +85,7 @@ namespace O3DE::ProjectManager QFrame* frame = new QFrame(this); frame->setObjectName("firstTimeContent"); { - QVBoxLayout* layout = new QVBoxLayout(this); + QVBoxLayout* layout = new QVBoxLayout(); layout->setContentsMargins(0, 0, 0, 0); layout->setAlignment(Qt::AlignTop); frame->setLayout(layout); @@ -100,7 +100,7 @@ namespace O3DE::ProjectManager "available by downloading our sample project.")); layout->addWidget(introLabel); - QHBoxLayout* buttonLayout = new QHBoxLayout(this); + QHBoxLayout* buttonLayout = new QHBoxLayout(); buttonLayout->setAlignment(Qt::AlignLeft); buttonLayout->setSpacing(s_spacerSize); diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index bb6c05a472..0e00319b6b 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -226,7 +226,7 @@ namespace O3DE::ProjectManager PythonBindings::PythonBindings(const AZ::IO::PathView& enginePath) : m_enginePath(enginePath) { - StartPython(); + m_pythonStarted = StartPython(); } PythonBindings::~PythonBindings() @@ -234,6 +234,11 @@ namespace O3DE::ProjectManager StopPython(); } + bool PythonBindings::PythonStarted() + { + return m_pythonStarted && Py_IsInitialized(); + } + bool PythonBindings::StartPython() { if (Py_IsInitialized()) @@ -246,7 +251,7 @@ namespace O3DE::ProjectManager AZStd::string pyBasePath = Platform::GetPythonHomePath(PY_PACKAGE, m_enginePath.c_str()); if (!AZ::IO::SystemFile::Exists(pyBasePath.c_str())) { - AZ_Assert(false, "Python home path must exist. path:%s", pyBasePath.c_str()); + AZ_Error("python", false, "Python home path does not exist: %s", pyBasePath.c_str()); return false; } @@ -351,6 +356,11 @@ namespace O3DE::ProjectManager AZ::Outcome PythonBindings::ExecuteWithLockErrorHandling(AZStd::function executionCallback) { + if (!Py_IsInitialized()) + { + return AZ::Failure("Python is not initialized"); + } + AZStd::lock_guard lock(m_lock); pybind11::gil_scoped_release release; pybind11::gil_scoped_acquire acquire; diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 5700ede850..065867a130 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -34,6 +34,8 @@ namespace O3DE::ProjectManager ~PythonBindings() override; // PythonBindings overrides + bool PythonStarted() override; + // Engine AZ::Outcome GetEngineInfo() override; bool SetEngineInfo(const EngineInfo& engineInfo) override; @@ -70,6 +72,8 @@ namespace O3DE::ProjectManager bool StopPython(); + bool m_pythonStarted = false; + AZ::IO::FixedMaxPath m_enginePath; pybind11::handle m_engineTemplate; AZStd::recursive_mutex m_lock; diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index bc20d8e3f0..6d72bfee0c 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -34,6 +34,12 @@ namespace O3DE::ProjectManager IPythonBindings() = default; virtual ~IPythonBindings() = default; + /** + * Get whether Python was started or not. All Python functionality will fail if Python + * failed to start. + * @return true if Python was started successfully, false on failure + */ + virtual bool PythonStarted() = 0; // Engine diff --git a/Code/Tools/ProjectManager/Source/main.cpp b/Code/Tools/ProjectManager/Source/main.cpp index c597b8a729..1f4cadfb14 100644 --- a/Code/Tools/ProjectManager/Source/main.cpp +++ b/Code/Tools/ProjectManager/Source/main.cpp @@ -10,85 +10,26 @@ * */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -using namespace O3DE::ProjectManager; +#include +#include int main(int argc, char* argv[]) { - QApplication::setOrganizationName("O3DE"); - QApplication::setOrganizationDomain("o3de.org"); - QCoreApplication::setApplicationName("ProjectManager"); - QCoreApplication::setApplicationVersion("1.0"); - - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); - QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); - QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); - AzQtComponents::Utilities::HandleDpiAwareness(AzQtComponents::Utilities::SystemDpiAware); - - AZ::AllocatorInstance::Create(); int runSuccess = 0; + + // Call before using any Qt, or the app may not be able to locate Qt libs + AzQtComponents::PrepareQtPaths(); + + O3DE::ProjectManager::Application application(&argc, &argv); + if (!application.Init()) { - QApplication app(argc, argv); - - // Need to use settings registry to get EngineRootFolder - AZ::IO::FixedMaxPath engineRootPath; - { - AZ::ComponentApplication componentApplication; - auto settingsRegistry = AZ::SettingsRegistry::Get(); - settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); - } - - AzQtComponents::StyleManager styleManager(&app); - styleManager.initialize(&app, engineRootPath); - - // Get the initial start screen if one is provided via command line - constexpr char optionPrefix[] = "--"; - AZ::CommandLine commandLine(optionPrefix); - commandLine.Parse(argc, argv); - - ProjectManagerScreen startScreen = ProjectManagerScreen::Projects; - if(commandLine.HasSwitch("screen")) - { - QString screenOption = commandLine.GetSwitchValue("screen", 0).c_str(); - ProjectManagerScreen screen = ProjectUtils::GetProjectManagerScreen(screenOption); - if (screen != ProjectManagerScreen::Invalid) - { - startScreen = screen; - } - } - - AZ::IO::FixedMaxPath projectPath; - if (commandLine.HasSwitch("project-path")) - { - projectPath = commandLine.GetSwitchValue("project-path", 0).c_str(); - } - - ProjectManagerWindow window(nullptr, engineRootPath, projectPath, startScreen); - window.show(); - - // somethings is preventing us from moving the window to the center of the - // primary screen - likely an Az style or component helper - constexpr int width = 1200; - constexpr int height = 800; - window.resize(width, height); - - runSuccess = app.exec(); + AZ_Error("ProjectManager", false, "Failed to initialize"); + runSuccess = 1; + } + else + { + runSuccess = application.Run() ? 0 : 1; } - AZ::AllocatorInstance::Destroy(); return runSuccess; } diff --git a/Code/Tools/ProjectManager/project_manager_app_files.cmake b/Code/Tools/ProjectManager/project_manager_app_files.cmake new file mode 100644 index 0000000000..223683ddd9 --- /dev/null +++ b/Code/Tools/ProjectManager/project_manager_app_files.cmake @@ -0,0 +1,17 @@ +# +# 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. +# + +set(FILES + Resources/ProjectManager.rc + Resources/ProjectManager.qrc + Resources/ProjectManager.qss + Source/main.cpp +) diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 633824f995..587b5907bb 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -1,4 +1,5 @@ # +# # All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or # its licensors. # @@ -10,10 +11,8 @@ # set(FILES - Resources/ProjectManager.rc - Resources/ProjectManager.qrc - Resources/ProjectManager.qss - Source/main.cpp + Source/Application.h + Source/Application.cpp Source/ScreenDefs.h Source/ScreenFactory.h Source/ScreenFactory.cpp diff --git a/Code/Tools/ProjectManager/project_manager_tests_files.cmake b/Code/Tools/ProjectManager/project_manager_tests_files.cmake new file mode 100644 index 0000000000..e1e84a43a7 --- /dev/null +++ b/Code/Tools/ProjectManager/project_manager_tests_files.cmake @@ -0,0 +1,17 @@ +# +# 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. +# + +set(FILES + Resources/ProjectManager.qrc + Resources/ProjectManager.qss + tests/ApplicationTests.cpp + tests/main.cpp +) diff --git a/Code/Tools/ProjectManager/tests/ApplicationTests.cpp b/Code/Tools/ProjectManager/tests/ApplicationTests.cpp new file mode 100644 index 0000000000..c98b1a3a6f --- /dev/null +++ b/Code/Tools/ProjectManager/tests/ApplicationTests.cpp @@ -0,0 +1,47 @@ +/* +* 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 + +namespace O3DE::ProjectManager +{ + class ProjectManagerApplicationTests + : public ::UnitTest::ScopedAllocatorSetupFixture + { + public: + + ProjectManagerApplicationTests() + { + m_application = AZStd::make_unique(); + } + + ~ProjectManagerApplicationTests() + { + m_application.reset(); + } + + AZStd::unique_ptr m_application; + }; + +#if AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS + TEST_F(ProjectManagerApplicationTests, DISABLED_Application_Init_Succeeds) +#else + TEST_F(ProjectManagerApplicationTests, Application_Init_Succeeds) +#endif // !AZ_TRAIT_DISABLE_FAILED_PROJECT_MANAGER_TESTS + { + // we don't want to interact with actual GUI or display it + EXPECT_TRUE(m_application->Init(/*interactive=*/false)); + } +} diff --git a/Code/Tools/ProjectManager/tests/main.cpp b/Code/Tools/ProjectManager/tests/main.cpp new file mode 100644 index 0000000000..191bef846a --- /dev/null +++ b/Code/Tools/ProjectManager/tests/main.cpp @@ -0,0 +1,35 @@ +/* +* 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 + +DECLARE_AZ_UNIT_TEST_MAIN(); + +int runDefaultRunner(int argc, char* argv[]) +{ + INVOKE_AZ_UNIT_TEST_MAIN(nullptr) + return 0; +} + +int main(int argc, char* argv[]) +{ + if (argc == 1) + { + // if no parameters are provided, add the --unittests parameter + constexpr int defaultArgc = 2; + char unittest_arg[] = "--unittests"; // Conversion from string literal to char* is not allowed per ISO C++11 + char* defaultArgv[defaultArgc] = { argv[0], unittest_arg }; + return runDefaultRunner(defaultArgc, defaultArgv); + } + INVOKE_AZ_UNIT_TEST_MAIN(nullptr); + return 0; +} From 5165f6ad0495cbc310f64c6294a2fe797f84f578 Mon Sep 17 00:00:00 2001 From: Ken Pruiksma Date: Mon, 14 Jun 2021 19:09:27 -0500 Subject: [PATCH 12/15] [ATOM-15769] Setting minimum angle to 0.5 degrees on disk lights to avoid visual artifacts that occur at values closer to 0. Also updating the outer cone angle max to be 90 degrees since it's measured from the center point, not all the way across. (#1260) --- .../Code/Source/CoreLights/EditorAreaLightComponent.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index 69bec21a6c..992b6319d8 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -112,13 +112,13 @@ namespace AZ ->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.") - ->Attribute(Edit::Attributes::Min, 0.0f) - ->Attribute(Edit::Attributes::Max, 180.0f) + ->Attribute(Edit::Attributes::Min, 0.5f) + ->Attribute(Edit::Attributes::Max, 90.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.") - ->Attribute(Edit::Attributes::Min, 0.0f) - ->Attribute(Edit::Attributes::Max, 180.0f) + ->Attribute(Edit::Attributes::Min, 0.5f) + ->Attribute(Edit::Attributes::Max, 90.0f) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShutters) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShuttersDisabled) From 0198f6121ba871022667cfb31e00ca6a1fef864b Mon Sep 17 00:00:00 2001 From: rgba16f <82187279+rgba16f@users.noreply.github.com> Date: Mon, 14 Jun 2021 20:29:37 -0500 Subject: [PATCH 13/15] Rebind the DebugDisplayRequestBus Instance to handle drawing in GameMode. (#1275) --- Code/Sandbox/Editor/EditorViewportWidget.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index 7e087d452b..e627d7d7c0 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -514,18 +514,28 @@ void EditorViewportWidget::Update() // Disable rendering to avoid recursion into Update() PushDisableRendering(); + + //get debug display interface for the viewport + AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus; + AzFramework::DebugDisplayRequestBus::Bind(debugDisplayBus, GetViewportId()); + AZ_Assert(debugDisplayBus, "Invalid DebugDisplayRequestBus."); + + AzFramework::DebugDisplayRequests* debugDisplay = + AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus); + + // draw debug visualizations - if (m_debugDisplay) + if (debugDisplay) { - const AZ::u32 prevState = m_debugDisplay->GetState(); - m_debugDisplay->SetState( + const AZ::u32 prevState = debugDisplay->GetState(); + debugDisplay->SetState( e_Mode3D | e_AlphaBlended | e_FillModeSolid | e_CullModeBack | e_DepthWriteOn | e_DepthTestOn); AzFramework::EntityDebugDisplayEventBus::Broadcast( &AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport, - AzFramework::ViewportInfo{ GetViewportId() }, *m_debugDisplay); + AzFramework::ViewportInfo{ GetViewportId() }, *debugDisplay); - m_debugDisplay->SetState(prevState); + debugDisplay->SetState(prevState); } QtViewport::Update(); From de4605d6b72cd3729ae5dfab9880f70c89657c7b Mon Sep 17 00:00:00 2001 From: Doug McDiarmid Date: Mon, 14 Jun 2021 18:31:43 -0700 Subject: [PATCH 14/15] Added comment. --- .../ReflectionScreenSpaceCompositePass.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp index fe2030ca7e..ab09d7175a 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionScreenSpace/ReflectionScreenSpaceCompositePass.cpp @@ -42,6 +42,9 @@ namespace AZ if (!passes.empty()) { Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast(passes.front()); + + // compute the max mip level based on the available mips in the previous frame image, and capping it + // to stay within a range that has reasonable data const uint32_t MaxNumRoughnessMips = 8; uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1; From 1f6bb14ed3680cb721ec7c276b754073cc1a7498 Mon Sep 17 00:00:00 2001 From: Roman <69218254+amzn-rhhong@users.noreply.github.com> Date: Mon, 14 Jun 2021 20:38:37 -0700 Subject: [PATCH 15/15] [EMFX][ATOM] crash during mesh reload (#1301) * Fixed a crash when entering game mode, removing a mesh and re-adding mesh. --- .../Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp | 5 +++++ .../EMotionFXAtom/Code/Source/ActorAsset.cpp | 3 ++- .../EMotionFXAtom/Code/Source/AtomActorInstance.cpp | 3 +-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp index 343370ae35..a87d272448 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp @@ -629,6 +629,11 @@ namespace AZ Data::Asset lodAsset; modelLodCreator.End(lodAsset); + if (!lodAsset.IsReady()) + { + // [GFX TODO] During mesh reload the modelLodCreator could report errors and result in the lodAsset not ready. + return nullptr; + } modelCreator.AddLodAsset(AZStd::move(lodAsset)); lodIndex++; diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp index 9f68a7d12c..1c4657d8df 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/ActorAsset.cpp @@ -311,7 +311,8 @@ namespace AZ Data::Asset modelAsset = actor->GetMeshAsset(); if (!modelAsset.IsReady()) { - AZ_Error("CreateSkinnedMeshInputFromActor", false, "Attempting to create skinned mesh input buffers for an actor that doesn't have a loaded model."); + AZ_Warning("CreateSkinnedMeshInputFromActor", false, "Check if the actor has a mesh added. Right click the source file in the asset browser, click edit settings, " + "and navigate to the Meshes tab. Add a mesh if it's missing."); return nullptr; } diff --git a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp index 532c8720b5..18a21c93a6 100644 --- a/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp +++ b/Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorInstance.cpp @@ -456,9 +456,8 @@ namespace AZ void AtomActorInstance::Create() { Destroy(); - m_skinnedMeshInputBuffers = GetRenderActor()->FindOrCreateSkinnedMeshInputBuffers(); - AZ_Error("AtomActorInstance", m_skinnedMeshInputBuffers, "Failed to get SkinnedMeshInputBuffers from Actor."); + AZ_Warning("AtomActorInstance", m_skinnedMeshInputBuffers, "Failed to create SkinnedMeshInputBuffers from Actor. It is likely that this actor doesn't have any meshes"); if (m_skinnedMeshInputBuffers) { m_boneTransforms = CreateBoneTransformBufferFromActorInstance(m_actorInstance, GetSkinningMethod());