From 2cd732de6cb55a5dd0f2441acfcef12e954bad58 Mon Sep 17 00:00:00 2001 From: Gene Walters Date: Thu, 11 Nov 2021 16:43:49 -0800 Subject: [PATCH 01/36] Fixing RPC autogen so that RPCs without parameters compile (and function). Signed-off-by: Gene Walters --- .../AutoGen/AutoComponent_Source.jinja | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja index e9bc21875b..d0b77159f8 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja @@ -308,13 +308,21 @@ void {{ ClassName }}::Set{{ UpperFirst(Property.attrib['Name']) }}(const {{ Prop {% endmacro %} {# +#} +{% macro PrintRpcParameters(printPrefix, paramDefines) %} +{% if paramDefines|count > 0 %} +{{ printPrefix }}{{ ', '.join(paramDefines) }} +{% endif %} +{% endmacro %} +{# + #} {% macro DefineRpcInvocation(Component, ClassName, Property, InvokeFrom, HandleOn) %} {% set paramNames = [] %} {% set paramTypes = [] %} {% set paramDefines = [] %} {{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} -void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramDefines) }}) +void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ PrintRpcParameters('', paramDefines) }}) { constexpr Multiplayer::RpcIndex rpcId = static_cast({{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ UpperFirst(Property.attrib['Name']) }}); {% if Property.attrib['IsReliable']|booleanTrue %} @@ -358,7 +366,7 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par {% set paramTypes = [] %} {% set paramDefines = [] %} {{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} - ->Method("{{ UpperFirst(Property.attrib['Name']) }}", []({{ ClassName }}* self, {{ ', '.join(paramDefines) }}) { + ->Method("{{ UpperFirst(Property.attrib['Name']) }}", []({{ ClassName }}* self{{ PrintRpcParameters(', ', paramDefines) }}) { {% if (InvokeFrom == 'Server') %} self->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }}); {% elif (InvokeFrom == 'Authority') or (InvokeFrom == 'Autonomous') %} @@ -372,7 +380,7 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par } {% endif %} }) - ->Method("{{ UpperFirst(Property.attrib['Name']) }}ByEntityId", [](AZ::EntityId id, {{ ', '.join(paramDefines) }}) { + ->Method("{{ UpperFirst(Property.attrib['Name']) }}ByEntityId", [](AZ::EntityId id{{ PrintRpcParameters(', ', paramDefines) }}) { AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id); if (!entity) @@ -497,9 +505,9 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp if (m_controller) { AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Authority, "Entity proxy does not have authority"); - m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); + m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection{{ PrintRpcParameters(', ', rpcParamList) }}); {% if (Property.attrib['GenerateEventBindings']|booleanTrue == true) %} - m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ ', '.join(rpcParamList) }}); + m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ PrintRpcParameters('', rpcParamList) }}); {% endif %} } else // Note that this rpc is marked reliable, trigger the appropriate rpc event so it can be forwarded @@ -513,15 +521,15 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp if (m_controller) { AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Autonomous, "Entity proxy does not have autonomy"); - m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); + m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection{{ PrintRpcParameters(', ', rpcParamList) }}); {% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} - m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ ', '.join(rpcParamList) }}); + m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ PrintRpcParameters('', rpcParamList) }}); {% endif %} } {% elif HandleOn == 'Client' %} - Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); + Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection{{ PrintRpcParameters(', ', rpcParamList) }}); {% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} - m_{{ UpperFirst(Property.attrib['Name']) }}Event.Signal({{ ', '.join(rpcParamList) }}); + m_{{ UpperFirst(Property.attrib['Name']) }}Event.Signal({{ PrintRpcParameters('', rpcParamList) }}); {% endif %} {% endif %} } From 92c0e598d576a755389b5d681c9c9b3408f78d4e Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 8 Nov 2021 10:54:32 -0600 Subject: [PATCH 02/36] Starting to remove MTL asset references Signed-off-by: Guthrie Adams --- .../AzAssetBrowserRequestHandler.cpp | 35 ------------------- Code/Editor/Include/IEditorMaterialManager.h | 4 --- .../AssetBrowser/AssetBrowserComponent.cpp | 5 --- .../PropertyEditor/EntityPropertyEditor.cpp | 19 +--------- .../AssetBuilderSDK/AssetBuilderSDK.cpp | 6 ---- Gems/LmbrCentral/Code/Source/LmbrCentral.cpp | 2 -- 6 files changed, 1 insertion(+), 70 deletions(-) diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp index 1c2be16a3d..6fc10e379a 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp @@ -199,41 +199,6 @@ namespace AzAssetBrowserRequestHandlerPrivate } } } - - // Helper utility - determines if the thing being dragged is a FBX from the scene import pipeline - // This is important to differentiate. - // when someone drags a MTL file directly into the viewport, even from a FBX, we want to spawn it as a decal - // but when someone drags a FBX that contains MTL files, we want only to spawn the meshes. - // so we have to specifically differentiate here between the mimeData type that contains the source as the root - // (dragging the fbx file itself) - // and one which contains the actual product at its root. - - bool IsDragOfFBX(const QMimeData* mimeData) - { - AZStd::vector entries; - if (!AssetBrowserEntry::FromMimeData(mimeData, entries)) - { - // if mimedata does not even contain entries, no point in proceeding. - return false; - } - - for (auto entry : entries) - { - if (entry->GetEntryType() != AssetBrowserEntry::AssetEntryType::Source) - { - continue; - } - // this is a source file. Is it the filetype we're looking for? - if (SourceAssetBrowserEntry* source = azrtti_cast(entry)) - { - if (AzFramework::StringFunc::Equal(source->GetExtension().c_str(), ".fbx", false)) - { - return true; - } - } - } - return false; - } } AzAssetBrowserRequestHandler::AzAssetBrowserRequestHandler() diff --git a/Code/Editor/Include/IEditorMaterialManager.h b/Code/Editor/Include/IEditorMaterialManager.h index d76ec32829..6f71c5ddd1 100644 --- a/Code/Editor/Include/IEditorMaterialManager.h +++ b/Code/Editor/Include/IEditorMaterialManager.h @@ -9,10 +9,6 @@ #define CRYINCLUDE_EDITOR_MATERIAL_IEDITORMATERIALMANAGER_H #pragma once -#define MATERIAL_FILE_EXT ".mtl" -#define DCC_MATERIAL_FILE_EXT ".dccmtl" -#define MATERIALS_PATH "materials/" - #include #include diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp index 7da6f794d6..172bd3a29c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp @@ -234,11 +234,6 @@ namespace AzToolsFramework return SourceFileDetails("Icons/AssetBrowser/Lua_16.svg"); } - if (AzFramework::StringFunc::Equal(extension.c_str(), ".mtl")) - { - return SourceFileDetails("Icons/AssetBrowser/Material_16.svg"); - } - if (AzFramework::StringFunc::Equal(extension.c_str(), AzToolsFramework::SliceUtilities::GetSliceFileExtension().c_str())) { return SourceFileDetails("Icons/AssetBrowser/Slice_16.svg"); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index 29bc106eed..9ecbdf5ffc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -4705,13 +4705,6 @@ namespace AzToolsFramework { if (mimeData->hasFormat(AssetBrowser::AssetBrowserEntry::GetMimeType())) { - // extra special case: MTLs from FBX drags are ignored. are we dragging a FBX file? - bool isDraggingFBXFile = false; - AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData(mimeData, [&](const AssetBrowser::SourceAssetBrowserEntry* source) - { - isDraggingFBXFile = isDraggingFBXFile || AzFramework::StringFunc::Equal(source->GetExtension().c_str(), ".fbx", false); - }); - // the usual case - we only allow asset browser drops of assets that have actually been associated with a kind of component. AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData(mimeData, [&](const AssetBrowser::ProductAssetBrowserEntry* product) { @@ -4723,17 +4716,7 @@ namespace AzToolsFramework if (canCreateComponent && !componentTypeId.IsNull()) { - // we have a component type that handles this asset. - // but we disallow it if its a MTL file from a FBX and the FBX itself is being dragged. Its still allowed - // to drag the actual MTL. - EBusFindAssetTypeByName materialAssetTypeResult("Material"); - AZ::AssetTypeInfoBus::BroadcastResult(materialAssetTypeResult, &AZ::AssetTypeInfo::GetAssetType); - AZ::Data::AssetType materialAssetType = materialAssetTypeResult.GetAssetType(); - - if ((!isDraggingFBXFile) || (product->GetAssetType() != materialAssetType)) - { - callbackFunction(product); - } + callbackFunction(product); } }); } diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp index a02eef8b75..f9b5d6aef7 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp @@ -690,7 +690,6 @@ namespace AssetBuilderSDK static const char* textureExtensions = ".dds"; static const char* staticMeshExtensions = ".cgf"; static const char* skinnedMeshExtensions = ".skin"; - static const char* materialExtensions = ".mtl"; // MIPS static const int c_MaxMipsCount = 11; // 11 is for 8k textures non-compressed. When not compressed it is using one file per mip. @@ -805,11 +804,6 @@ namespace AssetBuilderSDK return textureAssetType; } - if (AzFramework::StringFunc::Find(materialExtensions, extension.c_str()) != AZStd::string::npos) - { - return materialAssetType; - } - if (AzFramework::StringFunc::Find(staticMeshExtensions, extension.c_str()) != AZStd::string::npos) { return meshAssetType; diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp index 027d19fdef..ab187a6eed 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp @@ -364,8 +364,6 @@ namespace LmbrCentral assetCatalog->AddExtension("dds"); assetCatalog->AddExtension("caf"); assetCatalog->AddExtension("xml"); - assetCatalog->AddExtension("mtl"); - assetCatalog->AddExtension("dccmtl"); assetCatalog->AddExtension("sprite"); assetCatalog->AddExtension("cax"); } From 44f2cbae47f57c259f87f457f310d894b46a9aa6 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 11 Nov 2021 12:58:20 -0600 Subject: [PATCH 03/36] Removing material builder and related tests Signed-off-by: Guthrie Adams --- .../MaterialBuilderComponent.cpp | 612 ------------------ .../MaterialBuilderComponent.h | 65 -- .../Code/Source/LmbrCentralEditor.cpp | 2 - .../Tests/Builders/MaterialBuilderTests.cpp | 261 -------- .../Code/lmbrcentral_editor_files.cmake | 2 - .../Code/lmbrcentral_editor_tests_files.cmake | 1 - 6 files changed, 943 deletions(-) delete mode 100644 Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp delete mode 100644 Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.h delete mode 100644 Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp diff --git a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp b/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp deleted file mode 100644 index 48973b2779..0000000000 --- a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp +++ /dev/null @@ -1,612 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "MaterialBuilderComponent.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace MaterialBuilder -{ - [[maybe_unused]] const char s_materialBuilder[] = "MaterialBuilder"; - - namespace Internal - { - const char g_nodeNameMaterial[] = "Material"; - const char g_nodeNameSubmaterial[] = "SubMaterials"; - const char g_nodeNameTexture[] = "Texture"; - const char g_nodeNameTextures[] = "Textures"; - const char g_attributeFileName[] = "File"; - - const int g_numSourceImageFormats = 9; - const char* g_sourceImageFormats[g_numSourceImageFormats] = { ".tif", ".tiff", ".bmp", ".gif", ".jpg", ".jpeg", ".tga", ".png", ".dds" }; - bool IsSupportedImageExtension(const AZStd::string& extension) - { - for (const char* format : g_sourceImageFormats) - { - if (extension == format) - { - return true; - } - } - return false; - } - - // Cleans up legacy pathing from older materials - const char* CleanLegacyPathingFromTexturePath(const char* texturePath) - { - // Copied from MaterialHelpers::SetTexturesFromXml, line 459 - // legacy. Some textures used to be referenced using "engine\\" or "engine/" - this is no longer valid - if ( - (strlen(texturePath) > 7) && - (azstrnicmp(texturePath, "engine", 6) == 0) && - ((texturePath[6] == '\\') || (texturePath[6] == '/')) - ) - { - texturePath = texturePath + 7; - } - - // legacy: Files were saved into a mtl with many leading forward or back slashes, we eat them all here. We want it to start with a relative path. - const char* actualFileName = texturePath; - while ((actualFileName[0]) && ((actualFileName[0] == '\\') || (actualFileName[0] == '/'))) - { - ++actualFileName; - } - return actualFileName; - } - - // Parses the material XML for all texture paths - AZ::Outcome GetTexturePathsFromMaterial(AZ::rapidxml::xml_node* materialNode, AZStd::vector& paths) - { - AZ::Outcome resultOutcome = AZ::Failure(AZStd::string("")); - AZStd::string success_with_warning_message; - - // check if this material has a set of textures defined, and if so, grab all the paths from the textures - AZ::rapidxml::xml_node* texturesNode = materialNode->first_node(g_nodeNameTextures); - if (texturesNode) - { - AZ::rapidxml::xml_node* textureNode = texturesNode->first_node(g_nodeNameTexture); - // it is possible for an empty node to exist for things like collision materials, so check - // to make sure that there is at least one child node before starting to iterate. - if (textureNode) - { - do - { - AZ::rapidxml::xml_attribute* fileAttribute = textureNode->first_attribute(g_attributeFileName); - if (!fileAttribute) - { - success_with_warning_message = "Texture node exists but does not have a file attribute defined"; - } - else - { - const char* rawTexturePath = fileAttribute->value(); - // do an initial clean-up of the path taken from the file, similar to MaterialHelpers::SetTexturesFromXml - AZStd::string texturePath = CleanLegacyPathingFromTexturePath(rawTexturePath); - paths.emplace_back(AZStd::move(texturePath)); - } - - textureNode = textureNode->next_sibling(g_nodeNameTexture); - } while (textureNode); - } - } - - // check to see if this material has sub materials defined. If so, recurse into this function for each sub material - AZ::rapidxml::xml_node* subMaterialsNode = materialNode->first_node(g_nodeNameSubmaterial); - if (subMaterialsNode) - { - AZ::rapidxml::xml_node* subMaterialNode = subMaterialsNode->first_node(g_nodeNameMaterial); - if (subMaterialNode == nullptr) - { - // this is a malformed material as there is no material node child in the SubMaterials node, so error out - return AZ::Failure(AZStd::string("SubMaterials node exists but does not have any child Material nodes.")); - } - - do - { - // grab the texture paths from the submaterial, or error out if necessary - AZ::Outcome subMaterialTexturePathsResult = GetTexturePathsFromMaterial(subMaterialNode, paths); - if (!subMaterialTexturePathsResult.IsSuccess()) - { - return subMaterialTexturePathsResult; - } - else if (!subMaterialTexturePathsResult.GetValue().empty()) - { - success_with_warning_message = subMaterialTexturePathsResult.GetValue(); - } - - subMaterialNode = subMaterialNode->next_sibling(g_nodeNameMaterial); - } while (subMaterialNode); - } - - if (texturesNode == nullptr && subMaterialsNode == nullptr) - { - return AZ::Failure(AZStd::string("Failed to find a Textures node or SubMaterials node in this material. At least one of these must exist to be able to gather texture dependencies.")); - } - - if (!success_with_warning_message.empty()) - { - return AZ::Success(success_with_warning_message); - } - return AZ::Success(AZStd::string()); - } - - // find a sequence of digits with a string starting from lastDigitIndex, and try to parse that sequence to and int - // and store it in outAnimIndex. - bool ParseFilePathForCompleteNumber(const AZStd::string& filePath, int& lastDigitIndex, int& outAnimIndex) - { - int firstAnimIndexDigit = lastDigitIndex; - while (isdigit(static_cast(filePath[lastDigitIndex]))) - { - ++lastDigitIndex; - } - if (!AzFramework::StringFunc::LooksLikeInt(filePath.substr(firstAnimIndexDigit, lastDigitIndex - firstAnimIndexDigit).c_str(), &outAnimIndex)) - { - return false; - } - return true; - } - - // Parse the texture path for a texture animation to determine the actual names of the textures to resolve that - // make up the entire sequence. - AZ::Outcome GetAllTexturesInTextureSequence(const AZStd::string& path, AZStd::vector& texturesInSequence) - { - // Taken from CShaderMan::mfReadTexSequence - // All comments next to variable declarations in this function are the original variable names in - // CShaderMan::mfReadTexSequence, to help keep track of how these variables relate to the original function - AZStd::string prefix; - AZStd::string postfix; - - AZStd::string filePath = path; // name - AZStd::string extension; // ext - AzFramework::StringFunc::Path::GetExtension(filePath.c_str(), extension); - AzFramework::StringFunc::Path::StripExtension(filePath); - - // unsure if it is actually possible to enter here or the original version with '$' as the indicator - // for texture sequences, but they check for both just in case, so this will match the behavior. - char separator = '#'; // chSep - int firstSeparatorIndex = static_cast(filePath.find(separator)); - if (firstSeparatorIndex == AZStd::string::npos) - { - firstSeparatorIndex = static_cast(filePath.find('$')); - if (firstSeparatorIndex == AZStd::string::npos) - { - return AZ::Failure(AZStd::string("Failed to find separator '#' or '$' in texture path.")); - } - separator = '$'; - } - - // we don't actually care about getting the speed of the animation, so just remove everything from the - // end of the string starting with the last open parenthesis - size_t speedStartIndex = filePath.find_last_of('('); - if (speedStartIndex != AZStd::string::npos) - { - AzFramework::StringFunc::LKeep(filePath, speedStartIndex); - AzFramework::StringFunc::Append(filePath, '\0'); - } - - // try to find where the digits start after the separator (there can be any number of separators - // between the texture name prefix and where the digit range starts) - int firstAnimIndexDigit = -1; // m - int numSeparators = 0; // j - for (int stringIndex = firstSeparatorIndex; stringIndex < filePath.length(); ++stringIndex) - { - if (filePath[stringIndex] == separator) - { - ++numSeparators; - if (firstSeparatorIndex == -1) - { - firstSeparatorIndex = stringIndex; - } - } - else if (firstSeparatorIndex > 0 && firstAnimIndexDigit < 0) - { - firstAnimIndexDigit = stringIndex; - break; - } - } - if (numSeparators == 0) - { - return AZ::Failure(AZStd::string("Failed to find separator '#' or '$' in texture path.")); - } - - // store off everything before the separator - prefix = AZStd::move(filePath.substr(0, firstSeparatorIndex)); - - int startAnimIndex = 0; // startn - int endAnimIndex = 0; // endn - // we only found the separator, but no indexes, so just assume its 0 - 999 - if (firstAnimIndexDigit < 0) - { - startAnimIndex = 0; - endAnimIndex = 999; - } - else - { - // find the length of the first index, then parse that to an int - int lastDigitIndex = firstAnimIndexDigit; - if (!ParseFilePathForCompleteNumber(filePath, lastDigitIndex, startAnimIndex)) - { - return AZ::Failure(AZStd::string("Failed to determine first index of the sequence after the separators in texture path.")); - } - - // reset to the start of the next index - ++lastDigitIndex; - - // find the length of the end index, then parse that to an int - if (!ParseFilePathForCompleteNumber(filePath, lastDigitIndex, endAnimIndex)) - { - return AZ::Failure(AZStd::string("Failed to determine last index of the sequence after the first index of the sequence in texture path.")); - } - - // save off the rest of the string - postfix = AZStd::move(filePath.substr(lastDigitIndex)); - } - - int numTextures = endAnimIndex - startAnimIndex + 1; - const char* textureNameFormat = "%s%.*d%s%s"; // prefix, num separators (number of digits), sequence index, postfix, extension) - for (int sequenceIndex = 0; sequenceIndex < numTextures; ++sequenceIndex) - { - texturesInSequence.emplace_back(AZStd::move(AZStd::string::format(textureNameFormat, prefix.c_str(), numSeparators, startAnimIndex + sequenceIndex, postfix.c_str(), extension.c_str()))); - } - - return AZ::Success(); - } - - // Determine which product path to use based on the path stored in the texture, and make it relative to - // the cache. - bool ResolveMaterialTexturePath(const AZStd::string& path, AZStd::string& outPath) - { - AZStd::string aliasedPath = path; - - //if its a source image format try to load the dds - AZStd::string extension; - bool hasExtension = AzFramework::StringFunc::Path::GetExtension(path.c_str(), extension); - - // Replace all supported extensions with DDS if it has an extension. If the extension exists but is not supported, fail out. - if (hasExtension && IsSupportedImageExtension(extension)) - { - AzFramework::StringFunc::Path::ReplaceExtension(aliasedPath, ".dds"); - } - else if (hasExtension) - { - AZ_Warning(s_materialBuilder, false, "Failed to resolve texture path %s as the path is not to a supported texture format. Please make sure that textures in materials are formats supported by Open 3D Engine.", aliasedPath.c_str()); - return false; - } - - AZStd::to_lower(aliasedPath.begin(), aliasedPath.end()); - AzFramework::StringFunc::Path::Normalize(aliasedPath); - - AZStd::string currentFolderSpecifier = AZStd::string::format(".%c", AZ_CORRECT_FILESYSTEM_SEPARATOR); - if (AzFramework::StringFunc::StartsWith(aliasedPath, currentFolderSpecifier)) - { - AzFramework::StringFunc::Strip(aliasedPath, currentFolderSpecifier.c_str(), false, true); - } - - AZStd::string resolvedPath; - char fullPathBuffer[AZ_MAX_PATH_LEN] = {}; - // if there is an alias already at the front of the path, resolve it, and try to make it relative to the - // cache (@products@). If it can't, then error out. - // This case handles the possibility of aliases existing in texture paths in materials that is still supported - // by the legacy loading code, however it is not currently used, so the else path is always taken. - if (aliasedPath[0] == '@') - { - if (!AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(aliasedPath.c_str(), fullPathBuffer, AZ_MAX_PATH_LEN)) - { - AZ_Warning(s_materialBuilder, false, "Failed to resolve the alias in texture path %s. Please make sure all aliases are registered with the engine.", aliasedPath.c_str()); - return false; - } - resolvedPath = fullPathBuffer; - AzFramework::StringFunc::Path::Normalize(resolvedPath); - if (!AzFramework::StringFunc::Replace(resolvedPath, AZ::IO::FileIOBase::GetDirectInstance()->GetAlias("@products@"), "")) - { - AZ_Warning(s_materialBuilder, false, "Failed to resolve aliased texture path %s to be relative to the asset cache. Please make sure this alias resolves to a path within the asset cache.", aliasedPath.c_str()); - return false; - } - } - else - { - resolvedPath = AZStd::move(aliasedPath); - } - - // AP deferred path resolution requires UNIX separators and no leading separators, so clean up and convert here - if (AzFramework::StringFunc::StartsWith(resolvedPath, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING)) - { - AzFramework::StringFunc::Strip(resolvedPath, AZ_CORRECT_FILESYSTEM_SEPARATOR, false, true); - } - AzFramework::StringFunc::Replace(resolvedPath, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING, "/"); - - outPath = AZStd::move(resolvedPath); - return true; - } - - } - - BuilderPluginComponent::BuilderPluginComponent() - { - } - - BuilderPluginComponent::~BuilderPluginComponent() - { - } - - void BuilderPluginComponent::Init() - { - } - - void BuilderPluginComponent::Activate() - { - // Register material builder - AssetBuilderSDK::AssetBuilderDesc builderDescriptor; - builderDescriptor.m_name = "MaterialBuilderWorker"; - builderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.mtl", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); - builderDescriptor.m_busId = MaterialBuilderWorker::GetUUID(); - builderDescriptor.m_version = 5; - builderDescriptor.m_createJobFunction = AZStd::bind(&MaterialBuilderWorker::CreateJobs, &m_materialBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - builderDescriptor.m_processJobFunction = AZStd::bind(&MaterialBuilderWorker::ProcessJob, &m_materialBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - - // (optimization) this builder does not emit source dependencies: - builderDescriptor.m_flags |= AssetBuilderSDK::AssetBuilderDesc::BF_EmitsNoDependencies; - - m_materialBuilder.BusConnect(builderDescriptor.m_busId); - - EBUS_EVENT(AssetBuilderSDK::AssetBuilderBus, RegisterBuilderInformation, builderDescriptor); - } - - void BuilderPluginComponent::Deactivate() - { - m_materialBuilder.BusDisconnect(); - } - - void BuilderPluginComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Version(1) - ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector({ AssetBuilderSDK::ComponentTags::AssetBuilder })); - } - } - - MaterialBuilderWorker::MaterialBuilderWorker() - { - } - MaterialBuilderWorker::~MaterialBuilderWorker() - { - } - - void MaterialBuilderWorker::ShutDown() - { - // This will be called on a different thread than the process job thread - m_isShuttingDown = true; - } - - // This happens early on in the file scanning pass. - // This function should always create the same jobs and not do any checking whether the job is up to date. - void MaterialBuilderWorker::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) - { - if (m_isShuttingDown) - { - response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown; - return; - } - - for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms) - { - AssetBuilderSDK::JobDescriptor descriptor; - descriptor.m_jobKey = "Material Builder Job"; - descriptor.SetPlatformIdentifier(info.m_identifier.c_str()); - descriptor.m_priority = 8; // meshes are more important (at 10) but mats are still pretty important. - response.m_createJobOutputs.push_back(descriptor); - } - - response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; - } - - // The request will contain the CreateJobResponse you constructed earlier, including any keys and - // values you placed into the hash table - void MaterialBuilderWorker::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response) - { - AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Starting Job.\n"); - AZStd::string fileName; - AzFramework::StringFunc::Path::GetFullFileName(request.m_fullPath.c_str(), fileName); - AZStd::string destPath; - - // Do all work inside the tempDirPath. - AzFramework::StringFunc::Path::ConstructFull(request.m_tempDirPath.c_str(), fileName.c_str(), destPath, true); - - AZ::IO::LocalFileIO fileIO; - if (!m_isShuttingDown && fileIO.Copy(request.m_fullPath.c_str(), destPath.c_str()) == AZ::IO::ResultCode::Success) - { - // Push assets back into the response's product list - // Assets you created in your temp path can be specified using paths relative to the temp path - // since that is assumed where you're writing stuff. - AZStd::string relPath = destPath; - AssetBuilderSDK::ProductPathDependencySet dependencyPaths; - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; - AssetBuilderSDK::JobProduct jobProduct(fileName); - - bool dependencyResult = GatherProductDependencies(request.m_fullPath, dependencyPaths); - if (dependencyResult) - { - jobProduct.m_pathDependencies = AZStd::move(dependencyPaths); - jobProduct.m_dependenciesHandled = true; // We've output the dependencies immediately above so it's OK to tell the AP we've handled dependencies - } - else - { - AZ_Error(s_materialBuilder, false, "Dependency gathering for %s failed.", request.m_fullPath.c_str()); - } - response.m_outputProducts.push_back(jobProduct); - } - else - { - if (m_isShuttingDown) - { - AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Cancelled job %s because shutdown was requested.\n", request.m_fullPath.c_str()); - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled; - } - else - { - AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Error during processing job %s.\n", request.m_fullPath.c_str()); - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; - } - } - } - - bool MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial(const AZStd::string& path, AZStd::vector& resolvedPaths) - { - if (!AZ::IO::SystemFile::Exists(path.c_str())) - { - AZ_Error(s_materialBuilder, false, "Failed to find material at path %s. Please make sure this material exists on disk.", path.c_str()); - return false; - } - - uint64_t fileSize = AZ::IO::SystemFile::Length(path.c_str()); - if (fileSize == 0) - { - AZ_Error(s_materialBuilder, false, "Material at path %s is an empty file. Please make sure this material was properly saved to disk.", path.c_str()); - return false; - } - - AZStd::vector buffer(fileSize + 1); - buffer[fileSize] = 0; - if (!AZ::IO::SystemFile::Read(path.c_str(), buffer.data())) - { - AZ_Error(s_materialBuilder, false, "Failed to read material at path %s. Please make sure the file is not open or being edited by another program.", path.c_str()); - return false; - } - - AZ::rapidxml::xml_document* xmlDoc = azcreate(AZ::rapidxml::xml_document, (), AZ::SystemAllocator, "Mtl builder temp XML Reader"); - if (!xmlDoc->parse(buffer.data())) - { - azdestroy(xmlDoc, AZ::SystemAllocator, AZ::rapidxml::xml_document); - AZ_Error(s_materialBuilder, false, "Failed to parse material at path %s into XML. Please make sure that the material was properly saved to disk.", path.c_str()); - return false; - } - - // if the first node in this file isn't a material, this must not actually be a material so it can't have deps - AZ::rapidxml::xml_node* rootNode = xmlDoc->first_node(Internal::g_nodeNameMaterial); - if (!rootNode) - { - azdestroy(xmlDoc, AZ::SystemAllocator, AZ::rapidxml::xml_document); - AZ_Error(s_materialBuilder, false, "Failed to find root material node for material at path %s. Please make sure that the material was properly saved to disk.", path.c_str()); - return false; - } - - AZStd::vector texturePaths; - // gather all textures in the material file - AZ::Outcome texturePathsResult = Internal::GetTexturePathsFromMaterial(rootNode, texturePaths); - if (!texturePathsResult.IsSuccess()) - { - azdestroy(xmlDoc, AZ::SystemAllocator, AZ::rapidxml::xml_document); - AZ_Error(s_materialBuilder, false, "Failed to gather dependencies for %s as the material file is malformed. %s", path.c_str(), texturePathsResult.GetError().c_str()); - return false; - } - else if (!texturePathsResult.GetValue().empty()) - { - AZ_Warning(s_materialBuilder, false, "Some nodes in material %s could not be read as the material is malformed. %s. Some dependencies might not be reported correctly. Please make sure that the material was properly saved to disk.", path.c_str(), texturePathsResult.GetValue().c_str()); - } - azdestroy(xmlDoc, AZ::SystemAllocator, AZ::rapidxml::xml_document); - - // fail this if there are absolute paths. - for (const AZStd::string& texPath : texturePaths) - { - if (AZ::IO::PathView(texPath).IsAbsolute()) - { - AZ_Warning(s_materialBuilder, false, "Skipping resolving of texture path %s in material %s as the texture path is an absolute path. Please update the texture path to be relative to the asset cache.", texPath.c_str(), path.c_str()); - texturePaths.erase(AZStd::find(texturePaths.begin(), texturePaths.end(), texPath)); - } - } - - // for each path in the array, split any texture animation entry up into the individual files and add each to the list. - for (const AZStd::string& texPath : texturePaths) - { - if (texPath.find('#') != AZStd::string::npos) - { - AZStd::vector actualTexturePaths; - AZ::Outcome parseTextureSequenceResult = Internal::GetAllTexturesInTextureSequence(texPath, actualTexturePaths); - if (parseTextureSequenceResult.IsSuccess()) - { - texturePaths.erase(AZStd::find(texturePaths.begin(), texturePaths.end(), texPath)); - texturePaths.insert(texturePaths.end(), actualTexturePaths.begin(), actualTexturePaths.end()); - } - else - { - texturePaths.erase(AZStd::find(texturePaths.begin(), texturePaths.end(), texPath)); - AZ_Warning(s_materialBuilder, false, "Failed to parse texture sequence %s when trying to gather dependencies for %s. %s Please make sure the texture sequence path is formatted correctly. Registering dependencies for the texture sequence will be skipped.", texPath.c_str(), path.c_str(), parseTextureSequenceResult.GetError().c_str()); - } - } - } - - // for each texture in the file - for (const AZStd::string& texPath : texturePaths) - { - // if the texture path starts with a '$' then it is a special runtime defined texture, so it it doesn't have - // an actual asset on disk to depend on. If the texture path doesn't have an extension, then it is a texture - // that is determined at runtime (such as 'nearest_cubemap'), so also ignore those, as other things pull in - // those dependencies. - if (AzFramework::StringFunc::StartsWith(texPath, "$") || !AzFramework::StringFunc::Path::HasExtension(texPath.c_str())) - { - continue; - } - - // resolve the path in the file. - AZStd::string resolvedPath; - if (!Internal::ResolveMaterialTexturePath(texPath, resolvedPath)) - { - AZ_Warning(s_materialBuilder, false, "Failed to resolve texture path %s to a product path when gathering dependencies for %s. Registering dependencies on this texture path will be skipped.", texPath.c_str(), path.c_str()); - continue; - } - - resolvedPaths.emplace_back(AZStd::move(resolvedPath)); - } - - return true; - } - - bool MaterialBuilderWorker::PopulateProductDependencyList(AZStd::vector& resolvedPaths, AssetBuilderSDK::ProductPathDependencySet& dependencies) - { - for (const AZStd::string& texturePath : resolvedPaths) - { - if (texturePath.empty()) - { - AZ_Warning(s_materialBuilder, false, "Resolved path is empty.\n"); - return false; - } - - dependencies.emplace(texturePath, AssetBuilderSDK::ProductPathDependencyType::ProductFile); - } - return true; - } - - bool MaterialBuilderWorker::GatherProductDependencies(const AZStd::string& path, AssetBuilderSDK::ProductPathDependencySet& dependencies) - { - AZStd::vector resolvedTexturePaths; - if (!GetResolvedTexturePathsFromMaterial(path, resolvedTexturePaths)) - { - return false; - } - - if (!PopulateProductDependencyList(resolvedTexturePaths, dependencies)) - { - AZ_Warning(s_materialBuilder, false, "Failed to populate dependency list for material %s with possible variants for textures.", path.c_str()); - } - - return true; - } - - AZ::Uuid MaterialBuilderWorker::GetUUID() - { - return AZ::Uuid::CreateString("{258D34AC-12F8-4196-B535-3206D8E7287B}"); - } -} diff --git a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.h b/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.h deleted file mode 100644 index a7813cf0bd..0000000000 --- a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include - -namespace MaterialBuilder -{ - //! Material builder is responsible for building material files - class MaterialBuilderWorker - : public AssetBuilderSDK::AssetBuilderCommandBus::Handler - { - public: - MaterialBuilderWorker(); - ~MaterialBuilderWorker(); - - //! Asset Builder Callback Functions - void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response); - void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response); - - //!AssetBuilderSDK::AssetBuilderCommandBus interface - void ShutDown() override; - - //! Returns the UUID for this builder - static AZ::Uuid GetUUID(); - - bool GetResolvedTexturePathsFromMaterial(const AZStd::string& path, AZStd::vector& resolvedPaths); - bool PopulateProductDependencyList(AZStd::vector& resolvedPaths, AssetBuilderSDK::ProductPathDependencySet& dependencies); - - private: - bool GatherProductDependencies(const AZStd::string& path, AssetBuilderSDK::ProductPathDependencySet& dependencies); - - bool m_isShuttingDown = false; - }; - - class BuilderPluginComponent - : public AZ::Component - { - public: - AZ_COMPONENT(BuilderPluginComponent, "{4D1A4B0C-54CE-4397-B8AE-ADD08898C2CD}") - static void Reflect(AZ::ReflectContext* context); - - BuilderPluginComponent(); - - ////////////////////////////////////////////////////////////////////////// - // AZ::Component - virtual void Init(); // create objects, allocate memory and initialize yourself without reaching out to the outside world - virtual void Activate(); // reach out to the outside world and connect up to what you need to, register things, etc. - virtual void Deactivate(); // unregister things, disconnect from the outside world - ////////////////////////////////////////////////////////////////////////// - - virtual ~BuilderPluginComponent(); // free memory an uninitialize yourself. - - private: - MaterialBuilderWorker m_materialBuilder; - }; -} diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp index 511bf98582..61b8c8f73d 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include "Builders/CopyDependencyBuilder/CopyDependencyBuilderComponent.h" @@ -84,7 +83,6 @@ namespace LmbrCentral CopyDependencyBuilder::CopyDependencyBuilderComponent::CreateDescriptor(), DependencyBuilder::DependencyBuilderComponent::CreateDescriptor(), LevelBuilder::LevelBuilderComponent::CreateDescriptor(), - MaterialBuilder::BuilderPluginComponent::CreateDescriptor(), SliceBuilder::BuilderPluginComponent::CreateDescriptor(), TranslationBuilder::BuilderPluginComponent::CreateDescriptor(), LuaBuilder::BuilderPluginComponent::CreateDescriptor(), diff --git a/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp deleted file mode 100644 index 3786ef7565..0000000000 --- a/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace UnitTest -{ - using namespace MaterialBuilder; - using namespace AZ; - - class MaterialBuilderTests - : public UnitTest::AllocatorsTestFixture - , public UnitTest::TraceBusRedirector - { - protected: - void SetUp() override - { - UnitTest::AllocatorsTestFixture::SetUp(); - - m_app.reset(aznew AzToolsFramework::ToolsApplication); - m_app->Start(AZ::ComponentApplication::Descriptor()); - // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash - // in the unit tests. - AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - - const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); - - AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); - assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); - } - - void TearDown() override - { - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - m_app->Stop(); - m_app.reset(); - - UnitTest::AllocatorsTestFixture::TearDown(); - } - - AZStd::string GetTestFileAliasedPath(AZStd::string_view fileName) - { - constexpr char testFileFolder[] = "@engroot@/Gems/LmbrCentral/Code/Tests/Materials/"; - return AZStd::string::format("%s%.*s", testFileFolder, aznumeric_cast(fileName.size()), fileName.data()); - } - - AZStd::string GetTestFileFullPath(AZStd::string_view fileName) - { - AZStd::string aliasedPath = GetTestFileAliasedPath(fileName); - char resolvedPath[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(aliasedPath.c_str(), resolvedPath, AZ_MAX_PATH_LEN); - return AZStd::string(resolvedPath); - } - - void TestFailureCase(AZStd::string_view fileName, [[maybe_unused]] int expectedErrorCount) - { - MaterialBuilderWorker worker; - AZStd::vector resolvedPaths; - - AZStd::string absoluteMatPath = GetTestFileFullPath(fileName); - - AZ_TEST_START_ASSERTTEST; - ASSERT_FALSE(worker.GetResolvedTexturePathsFromMaterial(absoluteMatPath, resolvedPaths)); - AZ_TEST_STOP_ASSERTTEST(expectedErrorCount * 2); // The assert tests double count AZ errors, so just multiply expected count by 2 - ASSERT_EQ(resolvedPaths.size(), 0); - } - - void TestSuccessCase(AZStd::string_view fileName, AZStd::vector& expectedTextures) - { - MaterialBuilderWorker worker; - AZStd::vector resolvedPaths; - size_t texturesInMaterialFile = expectedTextures.size(); - - AZStd::string absoluteMatPath = GetTestFileFullPath(fileName); - ASSERT_TRUE(worker.GetResolvedTexturePathsFromMaterial(absoluteMatPath, resolvedPaths)); - ASSERT_EQ(resolvedPaths.size(), texturesInMaterialFile); - if (texturesInMaterialFile > 0) - { - ASSERT_THAT(resolvedPaths, testing::ElementsAreArray(expectedTextures)); - - AssetBuilderSDK::ProductPathDependencySet dependencies; - ASSERT_TRUE(worker.PopulateProductDependencyList(resolvedPaths, dependencies)); - ASSERT_EQ(dependencies.size(), texturesInMaterialFile); - } - } - - void TestSuccessCase(AZStd::string_view fileName, const char* expectedTexture) - { - AZStd::vector expectedTextures; - expectedTextures.push_back(expectedTexture); - TestSuccessCase(fileName, expectedTextures); - } - - void TestSuccessCaseNoDependencies(AZStd::string_view fileName) - { - AZStd::vector expectedTextures; - TestSuccessCase(fileName, expectedTextures); - } - - AZStd::unique_ptr m_app; - }; - - TEST_F(MaterialBuilderTests, MaterialBuilder_EmptyFile_ExpectFailure) - { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial, when checking for the size of the file. - TestFailureCase("test_mat1.mtl", 1); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_NoChildren_ExpectFailure) - { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling - // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when both a Textures node and a - // SubMaterials node are not found. No other AZ_Errors should be generated. - TestFailureCase("test_mat2.mtl", 1); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptyTexturesNode_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat3.mtl"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptySubMaterialNode_ExpectFailure) - { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling - // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when a SubMaterials node is present, - // but has no children Material node. No other AZ_Errors should be generated. - TestFailureCase("test_mat4.mtl", 1); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptyTextureNode_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat5.mtl"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptyMaterialInSubMaterial_ExpectFailure) - { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling - // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when a SubMaterials node is present, - // but a child Material node has no child Textures node and no child SubMaterials node. No other AZ_Errors should - // be generated. - TestFailureCase("test_mat6.mtl", 1); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptyTextureNodeInSubMaterial_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat7.mtl"); - } - -#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS // The following test file 'test_mat8.mtl' has a windows-specific absolute path, so this test is only valid on windows - TEST_F(MaterialBuilderTests, MaterialBuilder_TextureAbsolutePath_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat8.mtl"); - } -#endif - - TEST_F(MaterialBuilderTests, MaterialBuilder_TextureRuntimeAlias_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat9.mtl"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_TextureRuntimeTexture_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat10.mtl"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SingleMaterialSingleTexture_ValidSourceFormat) - { - // texture referenced is textures/natural/terrain/am_floor_tile_ddn.png - const char* expectedPath = "textures/natural/terrain/am_floor_tile_ddn.dds"; - TestSuccessCase("test_mat11.mtl", expectedPath); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SingleMaterialSingleTexture_ValidProductFormat) - { - // texture referenced is textures/natural/terrain/am_floor_tile_ddn.dds - const char* expectedPath = "textures/natural/terrain/am_floor_tile_ddn.dds"; - TestSuccessCase("test_mat12.mtl", expectedPath); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SingleMaterialSingleTexture_InvalidSourceFormat_NoDependenices) - { - // texture referenced is textures/natural/terrain/am_floor_tile_ddn.txt - TestSuccessCaseNoDependencies("test_mat13.mtl"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_TextureAnimSequence) - { - AZStd::vector expectedPaths = { - "path/to/my/textures/test_anim_sequence_01_texture000.dds", - "path/to/my/textures/test_anim_sequence_01_texture001.dds", - "path/to/my/textures/test_anim_sequence_01_texture002.dds", - "path/to/my/textures/test_anim_sequence_01_texture003.dds", - "path/to/my/textures/test_anim_sequence_01_texture004.dds", - "path/to/my/textures/test_anim_sequence_01_texture005.dds" - }; - TestSuccessCase("test_mat14.mtl", expectedPaths); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SingleMaterialMultipleTexture) - { - AZStd::vector expectedPaths = { - "engineassets/textures/hex.dds", - "engineassets/textures/hex_ddn.dds" - }; - TestSuccessCase("test_mat15.mtl", expectedPaths); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_MultipleTextures_OneEmptyTexture) - { - TestSuccessCase("test_mat16.mtl", "engineassets/textures/hex_ddn.dds"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SingleMaterialMultipleTexture_ResolveLeadingSeparatorsAndAliases) - { - AZStd::vector expectedPaths = { - "engineassets/textures/hex.dds", // resolved from "/engineassets/textures/hex.dds" - "engineassets/textures/hex_ddn.dds", // resolved from "./engineassets/textures/hex_ddn.dds" - "engineassets/textures/hex_spec.dds" // resolved from "@products@/engineassets/textures/hex_spec.dds" - }; - TestSuccessCase("test_mat17.mtl", expectedPaths); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SubMaterialSingleTexture) - { - AZStd::vector expectedPaths = { - "engineassets/textures/scratch.dds", - "engineassets/textures/perlinnoise2d.dds" - }; - TestSuccessCase("test_mat18.mtl", expectedPaths); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SubMaterialMultipleTexture) - { - AZStd::vector expectedPaths = { - "engineassets/textures/scratch.dds", - "engineassets/textures/scratch_ddn.dds", - "engineassets/textures/perlinnoise2d.dds", - "engineassets/textures/perlinnoisenormal_ddn.dds" - }; - TestSuccessCase("test_mat19.mtl", expectedPaths); - } -} diff --git a/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake b/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake index 5c77888922..aea2f493c7 100644 --- a/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake +++ b/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake @@ -116,8 +116,6 @@ set(FILES Source/Builders/LevelBuilder/LevelBuilderComponent.h Source/Builders/LevelBuilder/LevelBuilderWorker.cpp Source/Builders/LevelBuilder/LevelBuilderWorker.h - Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp - Source/Builders/MaterialBuilder/MaterialBuilderComponent.h Source/Builders/SliceBuilder/SliceBuilderComponent.cpp Source/Builders/SliceBuilder/SliceBuilderComponent.h Source/Builders/SliceBuilder/SliceBuilderWorker.cpp diff --git a/Gems/LmbrCentral/Code/lmbrcentral_editor_tests_files.cmake b/Gems/LmbrCentral/Code/lmbrcentral_editor_tests_files.cmake index 0f0cf484d1..afba79e566 100644 --- a/Gems/LmbrCentral/Code/lmbrcentral_editor_tests_files.cmake +++ b/Gems/LmbrCentral/Code/lmbrcentral_editor_tests_files.cmake @@ -21,7 +21,6 @@ set(FILES Tests/Builders/CopyDependencyBuilderTest.cpp Tests/Builders/SliceBuilderTests.cpp Tests/Builders/LevelBuilderTest.cpp - Tests/Builders/MaterialBuilderTests.cpp Tests/Builders/LuaBuilderTests.cpp Tests/Builders/SeedBuilderTests.cpp Source/LmbrCentral.cpp From 320ae45989a3e569f43f9808907349ef111662c6 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Thu, 11 Nov 2021 19:16:18 -0600 Subject: [PATCH 04/36] Removing material type asset info Signed-off-by: Guthrie Adams --- .../UI/AssetCatalogModel.cpp | 9 -- Gems/LmbrCentral/Code/Source/LmbrCentral.cpp | 15 ---- .../Material/MaterialAssetTypeInfo.cpp | 88 ------------------- .../Material/MaterialAssetTypeInfo.h | 55 ------------ Gems/LmbrCentral/Code/lmbrcentral_files.cmake | 2 - .../Code/Source/InstanceSystemComponent.cpp | 3 - 6 files changed, 172 deletions(-) delete mode 100644 Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp delete mode 100644 Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp index d0091f968e..2073d0dd5a 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -136,14 +135,6 @@ AssetCatalogModel::AssetCatalogModel(QObject* parent) } } - // Special cases for SimpleAssets. If these get full-fledged AssetData types, these cases can be removed. - QString textureExtensions = LmbrCentral::TextureAsset::GetFileFilter(); - m_extensionToAssetType.insert(AZStd::make_pair(textureExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector { AZ::AzTypeInfo::Uuid() })); - QString materialExtensions = LmbrCentral::MaterialAsset::GetFileFilter(); - m_extensionToAssetType.insert(AZStd::make_pair(materialExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector { AZ::AzTypeInfo::Uuid() })); - QString dccMaterialExtensions = LmbrCentral::DccMaterialAsset::GetFileFilter(); - m_extensionToAssetType.insert(AZStd::make_pair(dccMaterialExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector { AZ::AzTypeInfo::Uuid() })); - AZ::SerializeContext* serializeContext = nullptr; EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext); AZ_Assert(serializeContext, "Failed to acquire application serialize context."); diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp index ab187a6eed..ad90c16f43 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp @@ -38,9 +38,6 @@ #include "Geometry/GeometrySystemComponent.h" #include -// Unhandled asset types -// Material -#include "Unhandled/Material/MaterialAssetTypeInfo.h" // Other #include "Unhandled/Other/AudioAssetTypeInfo.h" #include "Unhandled/Other/CharacterPhysicsAssetTypeInfo.h" @@ -353,8 +350,6 @@ namespace LmbrCentral // Add asset types and extensions to AssetCatalog. Uses "AssetCatalogService". if (auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); assetCatalog) { - assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); - assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); @@ -370,16 +365,6 @@ namespace LmbrCentral AZ::Data::AssetManagerNotificationBus::Handler::BusConnect(); - - // Register unhandled asset type info - // Material - auto materialAssetTypeInfo = aznew MaterialAssetTypeInfo(); - materialAssetTypeInfo->Register(); - m_unhandledAssetInfo.emplace_back(materialAssetTypeInfo); - // DCC Material - auto dccMaterialAssetTypeInfo = aznew DccMaterialAssetTypeInfo(); - dccMaterialAssetTypeInfo->Register(); - m_unhandledAssetInfo.emplace_back(dccMaterialAssetTypeInfo); // Other auto audioAssetTypeInfo = aznew AudioAssetTypeInfo(); audioAssetTypeInfo->Register(); diff --git a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp b/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp deleted file mode 100644 index 24bc43740d..0000000000 --- a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "MaterialAssetTypeInfo.h" - -#include - -namespace LmbrCentral -{ - // MaterialAssetTypeInfo - - MaterialAssetTypeInfo::~MaterialAssetTypeInfo() - { - Unregister(); - } - - void MaterialAssetTypeInfo::Register() - { - AZ::AssetTypeInfoBus::Handler::BusConnect(AZ::AzTypeInfo::Uuid()); - } - - void MaterialAssetTypeInfo::Unregister() - { - AZ::AssetTypeInfoBus::Handler::BusDisconnect(AZ::AzTypeInfo::Uuid()); - } - - AZ::Data::AssetType MaterialAssetTypeInfo::GetAssetType() const - { - return AZ::AzTypeInfo::Uuid(); - } - - const char* MaterialAssetTypeInfo::GetAssetTypeDisplayName() const - { - return "Material"; - } - - const char* MaterialAssetTypeInfo::GetGroup() const - { - return "Material"; - } - - const char* MaterialAssetTypeInfo::GetBrowserIcon() const - { - return "Icons/Components/Decal.svg"; - } - - // DccMaterialAssetTypeInfo - - DccMaterialAssetTypeInfo::~DccMaterialAssetTypeInfo() - { - Unregister(); - } - - void DccMaterialAssetTypeInfo::Register() - { - AZ::AssetTypeInfoBus::Handler::BusConnect(AZ::AzTypeInfo::Uuid()); - } - - void DccMaterialAssetTypeInfo::Unregister() - { - AZ::AssetTypeInfoBus::Handler::BusDisconnect(AZ::AzTypeInfo::Uuid()); - } - - AZ::Data::AssetType DccMaterialAssetTypeInfo::GetAssetType() const - { - return AZ::AzTypeInfo::Uuid(); - } - - const char* DccMaterialAssetTypeInfo::GetAssetTypeDisplayName() const - { - return "DccMaterial"; - } - - const char* DccMaterialAssetTypeInfo::GetGroup() const - { - return "DccMaterial"; - } - - const char* DccMaterialAssetTypeInfo::GetBrowserIcon() const - { - return "Icons/Components/Decal.svg"; - } -} // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h b/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h deleted file mode 100644 index 2eafa31b41..0000000000 --- a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ -#pragma once - -#include - -namespace LmbrCentral -{ - class MaterialAssetTypeInfo - : public AZ::AssetTypeInfoBus::Handler - { - public: - - AZ_CLASS_ALLOCATOR(MaterialAssetTypeInfo, AZ::SystemAllocator, 0); - - ~MaterialAssetTypeInfo() override; - - ////////////////////////////////////////////////////////////////////////////////////////////// - // AZ::AssetTypeInfoBus::Handler - AZ::Data::AssetType GetAssetType() const override; - const char* GetAssetTypeDisplayName() const override; - const char* GetGroup() const override; - const char* GetBrowserIcon() const override; - ////////////////////////////////////////////////////////////////////////////////////////////// - - void Register(); - void Unregister(); - }; - - class DccMaterialAssetTypeInfo - : public AZ::AssetTypeInfoBus::Handler - { - public: - - AZ_CLASS_ALLOCATOR(DccMaterialAssetTypeInfo, AZ::SystemAllocator, 0); - - ~DccMaterialAssetTypeInfo() override; - - ////////////////////////////////////////////////////////////////////////////////////////////// - // AZ::AssetTypeInfoBus::Handler - AZ::Data::AssetType GetAssetType() const override; - const char* GetAssetTypeDisplayName() const override; - const char* GetGroup() const override; - const char* GetBrowserIcon() const override; - ////////////////////////////////////////////////////////////////////////////////////////////// - - void Register(); - void Unregister(); - }; -} // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/lmbrcentral_files.cmake b/Gems/LmbrCentral/Code/lmbrcentral_files.cmake index 18412e2a38..20a366b5f7 100644 --- a/Gems/LmbrCentral/Code/lmbrcentral_files.cmake +++ b/Gems/LmbrCentral/Code/lmbrcentral_files.cmake @@ -145,8 +145,6 @@ set(FILES Source/Shape/ShapeComponentConverters.inl Source/Shape/ShapeGeometryUtil.h Source/Shape/ShapeGeometryUtil.cpp - Source/Unhandled/Material/MaterialAssetTypeInfo.cpp - Source/Unhandled/Material/MaterialAssetTypeInfo.h Source/Unhandled/Other/AudioAssetTypeInfo.cpp Source/Unhandled/Other/AudioAssetTypeInfo.h Source/Unhandled/Other/CharacterPhysicsAssetTypeInfo.cpp diff --git a/Gems/Vegetation/Code/Source/InstanceSystemComponent.cpp b/Gems/Vegetation/Code/Source/InstanceSystemComponent.cpp index dd38daa633..85ba4bda61 100644 --- a/Gems/Vegetation/Code/Source/InstanceSystemComponent.cpp +++ b/Gems/Vegetation/Code/Source/InstanceSystemComponent.cpp @@ -15,9 +15,6 @@ #include #include -#include -#include - #include #include #include From f18f838da6561bd0419c0dc2af9bb125fd262f64 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 20 Oct 2021 10:25:05 -0500 Subject: [PATCH 05/36] material editor and exporter save source materials with relative paths Signed-off-by: Guthrie Adams --- .../Material/MaterialTypeSourceData.h | 4 - .../Material/MaterialTypeSourceData.cpp | 42 ------- .../Util/MaterialPropertyUtil.h | 12 +- .../Code/Source/Util/MaterialPropertyUtil.cpp | 48 +++++++- .../Code/Source/Document/MaterialDocument.cpp | 110 ++++++++++-------- .../Code/Source/Document/MaterialDocument.h | 5 +- .../Material/EditorMaterialComponentUtil.cpp | 52 +++++---- 7 files changed, 151 insertions(+), 122 deletions(-) diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 1234b15f95..f5336807c7 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -209,10 +209,6 @@ namespace AZ //! Traversal will stop once all properties have been enumerated or the callback function returns false void EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const; - //! Convert the property value into the format that will be stored in the source data - //! This is primarily needed to support conversions of special types like enums and images - bool ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const; - Outcome> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const; //! Possibly renames @propertyId based on the material version update steps. diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 396ba71e14..d5551e89ae 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -300,48 +300,6 @@ namespace AZ } } - bool MaterialTypeSourceData::ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const - { - if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) - { - const uint32_t index = propertyValue.GetValue(); - if (index >= propertyDefinition.m_enumValues.size()) - { - AZ_Error("Material source data", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str()); - return false; - } - - propertyValue = propertyDefinition.m_enumValues[index]; - return true; - } - - // Image asset references must be converted from asset IDs to a relative source file path - if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image && propertyValue.Is>()) - { - const Data::Asset& imageAsset = propertyValue.GetValue>(); - - Data::AssetInfo imageAssetInfo; - if (imageAsset.GetId().IsValid()) - { - bool result = false; - AZStd::string rootFilePath; - const AZStd::string platformName = ""; // Empty for default - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAssetInfoById, - imageAsset.GetId(), imageAsset.GetType(), platformName, imageAssetInfo, rootFilePath); - if (!result) - { - AZ_Error("Material source data", false, "Image asset could not be found for property: '%s'.", propertyDefinition.m_name.c_str()); - return false; - } - } - - propertyValue = imageAssetInfo.m_relativePath; - return true; - } - - return true; - } - Outcome> MaterialTypeSourceData::CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath, bool elevateWarnings) const { MaterialTypeAssetCreator materialTypeAssetCreator; diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h index 333796493d..d888c76553 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h @@ -7,11 +7,12 @@ */ #pragma once -#include -#include #include #include #include +#include +#include +#include namespace AzToolsFramework { @@ -41,6 +42,13 @@ namespace AtomToolsFramework //! Compare equality of data types and values of editor property stored in AZStd::any bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB); + //! Convert the property value into the format that will be stored in the source data + //! This is primarily needed to support conversions of special types like enums and images + bool ConvertToExportFormat( + const AZ::IO::BasicPath& exportFolder, + const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, + AZ::RPI::MaterialPropertyValue& propertyValue); + //! Traverse up the instance data node hierarchy to find the containing dynamic property object const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode); } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index 3f8a173918..b142977049 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -6,9 +6,10 @@ * */ -#include #include +#include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include namespace AtomToolsFramework @@ -163,6 +165,47 @@ namespace AtomToolsFramework return false; } + bool ConvertToExportFormat( + const AZ::IO::BasicPath& exportFolder, + const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, + AZ::RPI::MaterialPropertyValue& propertyValue) + { + if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) + { + const uint32_t index = propertyValue.GetValue(); + if (index >= propertyDefinition.m_enumValues.size()) + { + AZ_Error("AtomToolsFramework", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str()); + return false; + } + + propertyValue = propertyDefinition.m_enumValues[index]; + return true; + } + + // Image asset references must be converted from asset IDs to a relative source file path + if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image) + { + if (propertyValue.Is>()) + { + const auto& imageAsset = propertyValue.GetValue>(); + const auto& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAsset.GetId()); + propertyValue = AZ::IO::PathView(sourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + return true; + } + + if (propertyValue.Is>()) + { + const auto& image = propertyValue.GetValue>(); + const auto& sourcePath = image ? AZ::RPI::AssetUtils::GetSourcePathByAssetId(image->GetAssetId()) : ""; + propertyValue = AZ::IO::PathView(sourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + return true; + } + } + + return true; + } + const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode) { // Traverse up the hierarchy from the input node to search for an instance corresponding to material inspector property @@ -172,7 +215,8 @@ namespace AtomToolsFramework const AZ::SerializeContext::ClassData* classData = currentNode->GetClassMetadata(); if (context && classData) { - if (context->CanDowncast(classData->m_typeId, azrtti_typeid(), classData->m_azRtti, nullptr)) + if (context->CanDowncast( + classData->m_typeId, azrtti_typeid(), classData->m_azRtti, nullptr)) { return static_cast(currentNode->FirstInstance()); } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index ee58cbea3e..1d3ada6457 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -228,22 +228,22 @@ namespace MaterialEditor return false; } + AZ::IO::BasicPath exportFolder(m_absolutePath); + exportFolder.RemoveFilename(); + // create source data from properties MaterialSourceData sourceData; - sourceData.m_materialType = m_materialSourceData.m_materialType; - sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial; - - AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null."); - sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); - - // Force save data to store forward slashes - AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/"); - AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); + sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; + sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_parentMaterial = AZ::IO::PathView(m_materialSourceData.m_parentMaterial).LexicallyRelative(exportFolder).StringAsPosix(); // populate sourceData with modified or overwritten properties - const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); - }); + const bool savedProperties = SavePropertiesToSourceData( + exportFolder, sourceData, + [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); + }); if (!savedProperties) { @@ -302,22 +302,22 @@ namespace MaterialEditor return false; } + AZ::IO::BasicPath exportFolder(normalizedSavePath); + exportFolder.RemoveFilename(); + // create source data from properties MaterialSourceData sourceData; - sourceData.m_materialType = m_materialSourceData.m_materialType; - sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial; - - AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null."); - sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); - - // Force save data to store forward slashes - AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/"); - AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); + sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; + sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_parentMaterial = AZ::IO::PathView(m_materialSourceData.m_parentMaterial).LexicallyRelative(exportFolder).StringAsPosix(); // populate sourceData with modified or overwritten properties - const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); - }); + const bool savedProperties = SavePropertiesToSourceData( + exportFolder, sourceData, + [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); + }); if (!savedProperties) { @@ -375,17 +375,18 @@ namespace MaterialEditor return false; } + AZ::IO::BasicPath exportFolder(normalizedSavePath); + exportFolder.RemoveFilename(); + // create source data from properties MaterialSourceData sourceData; - sourceData.m_materialType = m_materialSourceData.m_materialType; - - AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null."); - sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); + sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; + sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); // Only assign a parent path if the source was a .material if (AzFramework::StringFunc::Path::IsExtension(m_relativePath.c_str(), MaterialSourceData::Extension)) { - sourceData.m_parentMaterial = m_relativePath; + sourceData.m_parentMaterial = AZ::IO::PathView(m_absolutePath).LexicallyRelative(exportFolder).StringAsPosix(); } // Force save data to store forward slashes @@ -393,9 +394,12 @@ namespace MaterialEditor AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); // populate sourceData with modified properties - const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); - }); + const bool savedProperties = SavePropertiesToSourceData( + exportFolder, sourceData, + [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); + }); if (!savedProperties) { @@ -590,7 +594,10 @@ namespace MaterialEditor } } - bool MaterialDocument::SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const + bool MaterialDocument::SavePropertiesToSourceData( + const AZ::IO::BasicPath& exportFolder, + AZ::RPI::MaterialSourceData& sourceData, + PropertyFilterFunction propertyFilter) const { using namespace AZ; using namespace RPI; @@ -598,7 +605,7 @@ namespace MaterialEditor bool result = true; // populate sourceData with properties that meet the filter - m_materialTypeSourceData.EnumerateProperties([this, &sourceData, &propertyFilter, &result](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { + m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { const MaterialPropertyId propertyId(groupName, propertyName); @@ -608,7 +615,7 @@ namespace MaterialEditor MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); if (propertyValue.IsValid()) { - if (!m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(exportFolder, propertyDefinition, propertyValue)) { AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str()); result = false; @@ -662,8 +669,6 @@ namespace MaterialEditor return false; } - AZStd::string materialTypeSourceFilePath; - // The material document and inspector are constructed from source data if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialSourceData::Extension)) { @@ -676,27 +681,29 @@ namespace MaterialEditor // We must also always load the material type data for a complete, ordered set of the // groups and properties that will be needed for comparison and building the inspector - materialTypeSourceFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); - auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath); - if (!materialTypeOutcome.IsSuccess()) + if (!m_materialSourceData.m_parentMaterial.empty()) { - AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", materialTypeSourceFilePath.c_str()); - return false; + m_materialSourceData.m_parentMaterial = + AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial); } - m_materialTypeSourceData = materialTypeOutcome.GetValue(); - - if (MaterialSourceData::ApplyVersionUpdatesResult::Failed == m_materialSourceData.ApplyVersionUpdates(m_absolutePath)) + + if (!m_materialSourceData.m_materialType.empty()) + { + m_materialSourceData.m_materialType = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); + } + + auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_materialSourceData.m_materialType); + if (!materialTypeOutcome.IsSuccess()) { - AZ_Error("MaterialDocument", false, "Material source data could not be auto updated to the latest version of the material type: '%s'.", m_materialSourceData.m_materialType.c_str()); + AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_materialSourceData.m_materialType.c_str()); return false; } + m_materialTypeSourceData = materialTypeOutcome.GetValue(); } else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension)) { - materialTypeSourceFilePath = m_absolutePath; - // Load the material type source data, which will be used for enumerating properties and building material source data - auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath); + auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_absolutePath); if (!materialTypeOutcome.IsSuccess()) { AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_absolutePath.c_str()); @@ -706,7 +713,7 @@ namespace MaterialEditor // The document represents a material, not a material type. // If the input data is a material type file we have to generate the material source data by referencing it. - m_materialSourceData.m_materialType = m_relativePath; + m_materialSourceData.m_materialType = m_absolutePath; m_materialSourceData.m_parentMaterial.clear(); } else @@ -877,7 +884,8 @@ namespace MaterialEditor m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); } - const MaterialFunctorSourceData::EditorContext editorContext = MaterialFunctorSourceData::EditorContext(materialTypeSourceFilePath, m_materialAsset->GetMaterialPropertiesLayout()); + const MaterialFunctorSourceData::EditorContext editorContext = + MaterialFunctorSourceData::EditorContext(m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout()); for (Ptr functorData : m_materialTypeSourceData.m_materialFunctorSourceData) { MaterialFunctorSourceData::FunctorResult result2 = functorData->CreateFunctor(editorContext); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h index 452111f99a..c4fd263014 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h @@ -104,7 +104,10 @@ namespace MaterialEditor void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) override; ////////////////////////////////////////////////////////////////////////// - bool SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const; + bool SavePropertiesToSourceData( + const AZ::IO::BasicPath& exportFolder, + AZ::RPI::MaterialSourceData& sourceData, + PropertyFilterFunction propertyFilter) const; bool OpenInternal(AZStd::string_view loadPath); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index d15db886d6..c775676e68 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -97,29 +98,38 @@ namespace AZ bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData) { + AZ::IO::BasicPath exportFolder(path); + exportFolder.RemoveFilename(); + // Construct the material source data object that will be exported AZ::RPI::MaterialSourceData exportData; // Converting absolute material paths to relative paths - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, - editData.m_materialTypeSourcePath.c_str(), info, watchFolder); - if (!result) + if (!editData.m_materialTypeSourcePath.empty()) { - AZ_Error( - "AZ::Render::EditorMaterialComponentUtil", false, - "Failed to get material type source file info while attempting to export: %s", path.c_str()); - return false; - } + bool result = false; + AZ::Data::AssetInfo info; + AZStd::string watchFolder; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, + editData.m_materialTypeSourcePath.c_str(), info, watchFolder); + if (!result) + { + AZ_Error( + "AZ::Render::EditorMaterialComponentUtil", false, + "Failed to get material type source file info while attempting to export: %s", path.c_str()); + return false; + } - exportData.m_materialType = info.m_relativePath; + exportData.m_materialType = + AZ::IO::PathView(editData.m_materialTypeSourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + } if (!editData.m_materialParentSourcePath.empty()) { - result = false; + bool result = false; + AZ::Data::AssetInfo info; + AZStd::string watchFolder; AzToolsFramework::AssetSystemRequestBus::BroadcastResult( result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, editData.m_materialParentSourcePath.c_str(), info, watchFolder); @@ -131,17 +141,19 @@ namespace AZ return false; } - exportData.m_parentMaterial = info.m_relativePath; + exportData.m_parentMaterial = + AZ::IO::PathView(editData.m_materialParentSourcePath).LexicallyRelative(exportFolder).StringAsPosix(); } // Copy all of the properties from the material asset to the source data that will be exported - result = true; - editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { + bool result = true; + editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition){ const AZ::RPI::MaterialPropertyId propertyId(groupName, propertyName); const AZ::RPI::MaterialPropertyIndex propertyIndex = editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); - AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; + AZ::RPI::MaterialPropertyValue propertyValue = + editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition.m_value; if (editData.m_materialParentAsset.IsReady()) @@ -151,12 +163,12 @@ namespace AZ // Check for and apply any property overrides before saving property values auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId.GetFullName()); - if(propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) + if (propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) { propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); } - if (!editData.m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(exportFolder, propertyDefinition, propertyValue)) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); result = false; From ed4f7965da6f9459be64e7cac8523041696dea0d Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 31 Oct 2021 22:49:14 -0500 Subject: [PATCH 06/36] =?UTF-8?q?=EF=BB=BFCreated=20function=20to=20get=20?= =?UTF-8?q?relative=20paths=20to=20referenced=20files=20that=20will=20fall?= =?UTF-8?q?=20back=20to=20asset=20folder=20relative=20paths=20under=20cert?= =?UTF-8?q?ain=20conditions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guthrie Adams --- .../Util/MaterialPropertyUtil.h | 14 ++++- .../Code/Source/Util/MaterialPropertyUtil.cpp | 46 ++++++++++++++++- .../Code/Source/Document/MaterialDocument.cpp | 51 ++++++++----------- .../Code/Source/Document/MaterialDocument.h | 4 +- .../Material/EditorMaterialComponentUtil.cpp | 11 ++-- 5 files changed, 84 insertions(+), 42 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h index d888c76553..b191e01bce 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h @@ -45,10 +45,22 @@ namespace AtomToolsFramework //! Convert the property value into the format that will be stored in the source data //! This is primarily needed to support conversions of special types like enums and images bool ConvertToExportFormat( - const AZ::IO::BasicPath& exportFolder, + const AZStd::string& exportPath, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, AZ::RPI::MaterialPropertyValue& propertyValue); + //! Generate a file path from the exported file to the external reference. + //! This function is to support copying or moving a folder containing materials, models, and textures without modifying the files. The + //! general case returns a relative path from the export file to the reference file. If the reference path is too different or distant + //! from the export path then it might be more difficult to work with than an asset folder relative path. For example, material types + //! that Atom provides live in a folder that should be accessible from anywhere. When materials are created in arbitrary gems and + //! project folders, a relative path to the material type would need to be updated whenever the materials are copied or moved. The same + //! thing will happen with parent materials or textures if their paths can’t be resolved. To alleviate some of this, we use the asset + //! folder relative path if the export folder relative path is too complex. An alternate solution would be to only use export folder + //! relative paths if the referenced path is in the same folder or a sub folder the assets are not generally packaged like that. + AZStd::string GetExteralReferencePath( + const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth = 2); + //! Traverse up the instance data node hierarchy to find the containing dynamic property object const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode); } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index b142977049..6ad9506fdd 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -166,10 +166,13 @@ namespace AtomToolsFramework } bool ConvertToExportFormat( - const AZ::IO::BasicPath& exportFolder, + const AZStd::string& exportPath, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, AZ::RPI::MaterialPropertyValue& propertyValue) { + AZ::IO::BasicPath exportFolder(exportPath); + exportFolder.RemoveFilename(); + if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) { const uint32_t index = propertyValue.GetValue(); @@ -206,6 +209,47 @@ namespace AtomToolsFramework return true; } + AZStd::string GetExteralReferencePath(const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth) + { + if (referencePath.empty()) + { + return {}; + } + + AZ::IO::BasicPath exportFolder(exportPath); + exportFolder.RemoveFilename(); + + const AZStd::string relativePath = AZ::IO::PathView(referencePath).LexicallyRelative(exportFolder).StringAsPosix(); + + // Count the difference in depth between the export file path and the referenced file path. + uint32_t parentFolderCount = 0; + AZStd::string::size_type pos = 0; + const AZStd::string parentFolderToken = ".."; + while ((pos = relativePath.find(parentFolderToken, pos)) != AZStd::string::npos) + { + parentFolderCount++; + pos += parentFolderToken.length(); + } + + // If the difference in depth is too great then revert to using the asset folder relative path. + // We could change this to only use relative paths for references in subfolders. + if (parentFolderCount > maxPathDepth) + { + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + bool sourceInfoFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, referencePath.c_str(), + assetInfo, watchFolder); + if (sourceInfoFound) + { + return assetInfo.m_relativePath; + } + } + + return relativePath; + } + const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode) { // Traverse up the hierarchy from the input node to search for an instance corresponding to material inspector property diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 1d3ada6457..2a0dcb36c2 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -228,18 +228,15 @@ namespace MaterialEditor return false; } - AZ::IO::BasicPath exportFolder(m_absolutePath); - exportFolder.RemoveFilename(); - // create source data from properties MaterialSourceData sourceData; - sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; - sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); - sourceData.m_parentMaterial = AZ::IO::PathView(m_materialSourceData.m_parentMaterial).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); + sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(m_absolutePath, m_materialSourceData.m_materialType); + sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(m_absolutePath, m_materialSourceData.m_parentMaterial); // populate sourceData with modified or overwritten properties const bool savedProperties = SavePropertiesToSourceData( - exportFolder, sourceData, + m_absolutePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) { return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); @@ -302,18 +299,16 @@ namespace MaterialEditor return false; } - AZ::IO::BasicPath exportFolder(normalizedSavePath); - exportFolder.RemoveFilename(); - // create source data from properties MaterialSourceData sourceData; - sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; - sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); - sourceData.m_parentMaterial = AZ::IO::PathView(m_materialSourceData.m_parentMaterial).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); + sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_materialType); + sourceData.m_parentMaterial = + AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); // populate sourceData with modified or overwritten properties const bool savedProperties = SavePropertiesToSourceData( - exportFolder, sourceData, + normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) { return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); @@ -375,27 +370,21 @@ namespace MaterialEditor return false; } - AZ::IO::BasicPath exportFolder(normalizedSavePath); - exportFolder.RemoveFilename(); - // create source data from properties MaterialSourceData sourceData; - sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version; - sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); + sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_materialType); // Only assign a parent path if the source was a .material if (AzFramework::StringFunc::Path::IsExtension(m_relativePath.c_str(), MaterialSourceData::Extension)) { - sourceData.m_parentMaterial = AZ::IO::PathView(m_absolutePath).LexicallyRelative(exportFolder).StringAsPosix(); + sourceData.m_parentMaterial = + AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); } - // Force save data to store forward slashes - AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/"); - AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); - // populate sourceData with modified properties const bool savedProperties = SavePropertiesToSourceData( - exportFolder, sourceData, + normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) { return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); @@ -595,9 +584,7 @@ namespace MaterialEditor } bool MaterialDocument::SavePropertiesToSourceData( - const AZ::IO::BasicPath& exportFolder, - AZ::RPI::MaterialSourceData& sourceData, - PropertyFilterFunction propertyFilter) const + const AZStd::string& exportPath, AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const { using namespace AZ; using namespace RPI; @@ -615,7 +602,7 @@ namespace MaterialEditor MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); if (propertyValue.IsValid()) { - if (!AtomToolsFramework::ConvertToExportFormat(exportFolder, propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyDefinition, propertyValue)) { AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str()); result = false; @@ -699,6 +686,12 @@ namespace MaterialEditor return false; } m_materialTypeSourceData = materialTypeOutcome.GetValue(); + + if (MaterialSourceData::ApplyVersionUpdatesResult::Failed == m_materialSourceData.ApplyVersionUpdates(m_absolutePath)) + { + AZ_Error("MaterialDocument", false, "Material source data could not be auto updated to the latest version of the material type: '%s'.", m_materialSourceData.m_materialType.c_str()); + return false; + } } else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension)) { diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h index c4fd263014..ceb3190f26 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h @@ -105,9 +105,7 @@ namespace MaterialEditor ////////////////////////////////////////////////////////////////////////// bool SavePropertiesToSourceData( - const AZ::IO::BasicPath& exportFolder, - AZ::RPI::MaterialSourceData& sourceData, - PropertyFilterFunction propertyFilter) const; + const AZStd::string& exportPath, AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const; bool OpenInternal(AZStd::string_view loadPath); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index c775676e68..8dc6da077e 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -98,9 +98,6 @@ namespace AZ bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData) { - AZ::IO::BasicPath exportFolder(path); - exportFolder.RemoveFilename(); - // Construct the material source data object that will be exported AZ::RPI::MaterialSourceData exportData; @@ -121,8 +118,7 @@ namespace AZ return false; } - exportData.m_materialType = - AZ::IO::PathView(editData.m_materialTypeSourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath); } if (!editData.m_materialParentSourcePath.empty()) @@ -141,8 +137,7 @@ namespace AZ return false; } - exportData.m_parentMaterial = - AZ::IO::PathView(editData.m_materialParentSourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath); } // Copy all of the properties from the material asset to the source data that will be exported @@ -168,7 +163,7 @@ namespace AZ propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); } - if (!AtomToolsFramework::ConvertToExportFormat(exportFolder, propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(path, propertyDefinition, propertyValue)) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); result = false; From b379c489b5dd28789e73587169eee92641dd2c25 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 31 Oct 2021 22:55:07 -0500 Subject: [PATCH 07/36] updated comment Signed-off-by: Guthrie Adams --- .../AtomToolsFramework/Util/MaterialPropertyUtil.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h index b191e01bce..0c1ab08b24 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h @@ -51,12 +51,8 @@ namespace AtomToolsFramework //! Generate a file path from the exported file to the external reference. //! This function is to support copying or moving a folder containing materials, models, and textures without modifying the files. The - //! general case returns a relative path from the export file to the reference file. If the reference path is too different or distant - //! from the export path then it might be more difficult to work with than an asset folder relative path. For example, material types - //! that Atom provides live in a folder that should be accessible from anywhere. When materials are created in arbitrary gems and - //! project folders, a relative path to the material type would need to be updated whenever the materials are copied or moved. The same - //! thing will happen with parent materials or textures if their paths can’t be resolved. To alleviate some of this, we use the asset - //! folder relative path if the export folder relative path is too complex. An alternate solution would be to only use export folder + //! general case returns a relative path from the export file to the reference file. If the relative path is too different or distant + //! from the export path then we return the asset folder relative path. An alternate solution would be to only use export folder //! relative paths if the referenced path is in the same folder or a sub folder the assets are not generally packaged like that. AZStd::string GetExteralReferencePath( const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth = 2); From b3f3a4245b95449b69bc7ba90b2458ef3070a61a Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 31 Oct 2021 23:08:16 -0500 Subject: [PATCH 08/36] updated image paths to use new function Signed-off-by: Guthrie Adams --- .../Code/Source/Util/MaterialPropertyUtil.cpp | 11 +++--- .../Code/Source/Document/MaterialDocument.cpp | 36 ++++++++----------- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index 6ad9506fdd..c49cd3fafb 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -170,9 +170,6 @@ namespace AtomToolsFramework const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, AZ::RPI::MaterialPropertyValue& propertyValue) { - AZ::IO::BasicPath exportFolder(exportPath); - exportFolder.RemoveFilename(); - if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) { const uint32_t index = propertyValue.GetValue(); @@ -192,16 +189,16 @@ namespace AtomToolsFramework if (propertyValue.Is>()) { const auto& imageAsset = propertyValue.GetValue>(); - const auto& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAsset.GetId()); - propertyValue = AZ::IO::PathView(sourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + const auto& imagePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAsset.GetId()); + propertyValue = GetExteralReferencePath(exportPath, imagePath); return true; } if (propertyValue.Is>()) { const auto& image = propertyValue.GetValue>(); - const auto& sourcePath = image ? AZ::RPI::AssetUtils::GetSourcePathByAssetId(image->GetAssetId()) : ""; - propertyValue = AZ::IO::PathView(sourcePath).LexicallyRelative(exportFolder).StringAsPosix(); + const auto& imagePath = image ? AZ::RPI::AssetUtils::GetSourcePathByAssetId(image->GetAssetId()) : ""; + propertyValue = GetExteralReferencePath(exportPath, imagePath); return true; } } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 2a0dcb36c2..c60da850a5 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -235,12 +235,10 @@ namespace MaterialEditor sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(m_absolutePath, m_materialSourceData.m_parentMaterial); // populate sourceData with modified or overwritten properties - const bool savedProperties = SavePropertiesToSourceData( - m_absolutePath, sourceData, - [](const AtomToolsFramework::DynamicProperty& property) - { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); - }); + const bool savedProperties = SavePropertiesToSourceData(m_absolutePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); + }); if (!savedProperties) { @@ -303,16 +301,13 @@ namespace MaterialEditor MaterialSourceData sourceData; sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_materialType); - sourceData.m_parentMaterial = - AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); + sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); // populate sourceData with modified or overwritten properties - const bool savedProperties = SavePropertiesToSourceData( - normalizedSavePath, sourceData, - [](const AtomToolsFramework::DynamicProperty& property) - { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); - }); + const bool savedProperties = SavePropertiesToSourceData(normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); + }); if (!savedProperties) { @@ -378,17 +373,14 @@ namespace MaterialEditor // Only assign a parent path if the source was a .material if (AzFramework::StringFunc::Path::IsExtension(m_relativePath.c_str(), MaterialSourceData::Extension)) { - sourceData.m_parentMaterial = - AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); + sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_absolutePath); } // populate sourceData with modified properties - const bool savedProperties = SavePropertiesToSourceData( - normalizedSavePath, sourceData, - [](const AtomToolsFramework::DynamicProperty& property) - { - return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); - }); + const bool savedProperties = SavePropertiesToSourceData(normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) + { + return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); + }); if (!savedProperties) { From 1689b880fe27a3564ea0ad1003a94fcb365aae00 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sun, 31 Oct 2021 23:28:15 -0500 Subject: [PATCH 09/36] added version to material component exporter deleted unnecessary checks Signed-off-by: Guthrie Adams --- .../Material/EditorMaterialComponentUtil.cpp | 47 ++++--------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index 8dc6da077e..0fd7b7164d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -98,47 +98,18 @@ namespace AZ bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData) { - // Construct the material source data object that will be exported - AZ::RPI::MaterialSourceData exportData; - - // Converting absolute material paths to relative paths - if (!editData.m_materialTypeSourcePath.empty()) + if (path.empty() || !editData.m_materialAsset.IsReady() || !editData.m_materialTypeAsset.IsReady() || + editData.m_materialTypeSourcePath.empty()) { - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, - editData.m_materialTypeSourcePath.c_str(), info, watchFolder); - if (!result) - { - AZ_Error( - "AZ::Render::EditorMaterialComponentUtil", false, - "Failed to get material type source file info while attempting to export: %s", path.c_str()); - return false; - } - - exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath); + AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Can not export: %s", path.c_str()); + return false; } - if (!editData.m_materialParentSourcePath.empty()) - { - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, - editData.m_materialParentSourcePath.c_str(), info, watchFolder); - if (!result) - { - AZ_Error( - "AZ::Render::EditorMaterialComponentUtil", false, - "Failed to get parent material source file info while attempting to export: %s", path.c_str()); - return false; - } - - exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath); - } + // Construct the material source data object that will be exported + AZ::RPI::MaterialSourceData exportData; + exportData.m_materialTypeVersion = editData.m_materialTypeAsset->GetVersion(); + exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath); + exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath); // Copy all of the properties from the material asset to the source data that will be exported bool result = true; From 7d51912a6e315b06dc08d03a8a7b4734f47556a0 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 1 Nov 2021 20:33:21 -0500 Subject: [PATCH 10/36] updated comments Signed-off-by: Guthrie Adams --- .../AtomToolsFramework/Util/MaterialPropertyUtil.h | 14 +++++++++----- .../Code/Source/Document/MaterialDocument.cpp | 12 +++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h index 0c1ab08b24..08f59f9e0b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h @@ -36,7 +36,7 @@ namespace AtomToolsFramework //! Convert and assign material property meta data fields to editor dynamic property configuration void ConvertToPropertyConfig(AtomToolsFramework::DynamicPropertyConfig& propertyConfig, const AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData); - //! Convert and assign editor dynamic property configuration fields to material property meta data + //! Convert and assign editor dynamic property configuration fields to material property meta data void ConvertToPropertyMetaData(AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData, const AtomToolsFramework::DynamicPropertyConfig& propertyConfig); //! Compare equality of data types and values of editor property stored in AZStd::any @@ -44,16 +44,20 @@ namespace AtomToolsFramework //! Convert the property value into the format that will be stored in the source data //! This is primarily needed to support conversions of special types like enums and images + //! @param exportPath absolute path of the file being saved + //! @param propertyDefinition describes type information and other details about propertyValue + //! @param propertyValue the value being converted before saving bool ConvertToExportFormat( const AZStd::string& exportPath, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, AZ::RPI::MaterialPropertyValue& propertyValue); //! Generate a file path from the exported file to the external reference. - //! This function is to support copying or moving a folder containing materials, models, and textures without modifying the files. The - //! general case returns a relative path from the export file to the reference file. If the relative path is too different or distant - //! from the export path then we return the asset folder relative path. An alternate solution would be to only use export folder - //! relative paths if the referenced path is in the same folder or a sub folder the assets are not generally packaged like that. + //! This function returns a relative path from the export file to the reference file. + //! If the relative path is too different or distant from the export path then we return the asset folder relative path. + //! @param exportPath absolute path of the file being saved + //! @param referencePath absolute path of a file that will be treated as an external reference + //! @param maxPathDepth the maximum relative depth or number of parent or child folders between the export path and the reference path AZStd::string GetExteralReferencePath( const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth = 2); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index c60da850a5..ea97a3f2c0 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -658,8 +658,8 @@ namespace MaterialEditor return false; } - // We must also always load the material type data for a complete, ordered set of the - // groups and properties that will be needed for comparison and building the inspector + // We always need the absolute path for the material type and parent material to load source data and resolving + // relative paths when saving. This will convert and store them as absolute paths for use within the document. if (!m_materialSourceData.m_parentMaterial.empty()) { m_materialSourceData.m_parentMaterial = @@ -671,6 +671,7 @@ namespace MaterialEditor m_materialSourceData.m_materialType = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); } + // Load the material type source data which provides the layout and default values of all of the properties auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_materialSourceData.m_materialType); if (!materialTypeOutcome.IsSuccess()) { @@ -687,7 +688,9 @@ namespace MaterialEditor } else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension)) { - // Load the material type source data, which will be used for enumerating properties and building material source data + // A material document can be created or loaded from material or material type source data. If we are attempting to load + // material type source data then the material source data object can be created just by referencing the document path as the + // material type path. auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_absolutePath); if (!materialTypeOutcome.IsSuccess()) { @@ -696,8 +699,7 @@ namespace MaterialEditor } m_materialTypeSourceData = materialTypeOutcome.GetValue(); - // The document represents a material, not a material type. - // If the input data is a material type file we have to generate the material source data by referencing it. + // We are storing absolute paths in the loaded version of the source data so that the files can be resolved at all times. m_materialSourceData.m_materialType = m_absolutePath; m_materialSourceData.m_parentMaterial.clear(); } From 01ce02ffec2b4d1f21894b1202067aaa60a08cd4 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 3 Nov 2021 14:02:21 -0500 Subject: [PATCH 11/36] Added basic unit test for relative path function Moved asset system stub to RPI utils Signed-off-by: Guthrie Adams --- Gems/Atom/RPI/Code/CMakeLists.txt | 1 + .../RPI/Code/Tests/Common/RPITestFixture.h | 2 +- Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake | 2 - .../AtomToolsFramework/Code/CMakeLists.txt | 28 +++++++ .../Code/Tests/AtomToolsFrameworkTest.cpp | 74 +++++++++++++++---- .../Code/atomtoolsframework_tests_files.cmake | 11 +++ Gems/Atom/Utils/Code/CMakeLists.txt | 21 ++++++ .../Include/Atom/Utils}/AssetSystemStub.h | 0 .../Code/Source}/AssetSystemStub.cpp | 2 +- .../Utils/Code/atom_utils_editor_files.cmake | 12 +++ 10 files changed, 135 insertions(+), 18 deletions(-) create mode 100644 Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake rename Gems/Atom/{RPI/Code/Tests/Common => Utils/Code/Include/Atom/Utils}/AssetSystemStub.h (100%) rename Gems/Atom/{RPI/Code/Tests/Common => Utils/Code/Source}/AssetSystemStub.cpp (99%) create mode 100644 Gems/Atom/Utils/Code/atom_utils_editor_files.cmake diff --git a/Gems/Atom/RPI/Code/CMakeLists.txt b/Gems/Atom/RPI/Code/CMakeLists.txt index 521178be20..7bf47d675a 100644 --- a/Gems/Atom/RPI/Code/CMakeLists.txt +++ b/Gems/Atom/RPI/Code/CMakeLists.txt @@ -160,6 +160,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Atom_RPI.Public Gem::Atom_RHI.Public Gem::Atom_RPI.Edit + Gem::Atom_Utils.Editor.Static ) ly_add_googletest( NAME Gem::Atom_RPI.Tests diff --git a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h index 48d404d268..b745e55ee8 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h @@ -21,7 +21,7 @@ #include #include #include -#include +#include namespace UnitTest { diff --git a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake index e99e4e456b..5d67948ac8 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake @@ -10,8 +10,6 @@ set(FILES Tests/Buffer/BufferTests.cpp Tests/Common/AssetManagerTestFixture.cpp Tests/Common/AssetManagerTestFixture.h - Tests/Common/AssetSystemStub.cpp - Tests/Common/AssetSystemStub.h Tests/Common/ErrorMessageFinder.cpp Tests/Common/ErrorMessageFinder.h Tests/Common/ErrorMessageFinderTests.cpp diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index e64c9b80e7..bb2ac1f513 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -61,3 +61,31 @@ ly_add_target( PRIVATE Gem::AtomToolsFramework.Static ) + +################################################################################ +# Tests +################################################################################ +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + + ly_add_target( + NAME AtomToolsFramework.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + atomtoolsframework_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + . + Tests + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + AZ::AzTestShared + Gem::AtomToolsFramework.Static + Gem::Atom_Utils.Editor.Static + ) + + ly_add_googletest( + NAME Gem::AtomToolsFramework.Tests + ) + +endif() \ No newline at end of file diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp index aee8e2a775..349c2b9ced 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp @@ -7,25 +7,71 @@ */ #include +#include +#include -class AtomToolsFrameworkTest - : public ::testing::Test +namespace UnitTest { -protected: - void SetUp() override + class AtomToolsFrameworkTest : public ::testing::Test { + protected: + void SetUp() override + { + if (!AZ::AllocatorInstance::IsReady()) + { + AZ::AllocatorInstance::Create(AZ::SystemAllocator::Descriptor()); + } - } + m_assetSystemStub.Activate(); - void TearDown() override - { + RegisterSourceAsset("objects/upgrades/materials/supercondor.material"); + RegisterSourceAsset("materials/condor.material"); + RegisterSourceAsset("materials/talisman.material"); + RegisterSourceAsset("materials/city.material"); + RegisterSourceAsset("materials/totem.material"); + RegisterSourceAsset("textures/orange.png"); + RegisterSourceAsset("textures/red.png"); + RegisterSourceAsset("textures/gold.png"); + RegisterSourceAsset("textures/fuzz.png"); + } - } -}; + void TearDown() override + { + m_assetSystemStub.Deactivate(); -TEST_F(AtomToolsFrameworkTest, SanityTest) -{ - ASSERT_TRUE(true); -} + if (AZ::AllocatorInstance::IsReady()) + { + AZ::AllocatorInstance::Destroy(); + } + } + + void RegisterSourceAsset(const AZStd::string& path) + { + const AZ::IO::BasicPath assetRootPath = AZ::IO::PathView(m_assetRoot).LexicallyNormal(); + const AZ::IO::BasicPath normalizedPath = AZ::IO::BasicPath(assetRootPath).Append(path).LexicallyNormal(); + + AZ::Data::AssetInfo assetInfo = {}; + assetInfo.m_assetId = AZ::Uuid::CreateRandom(); + assetInfo.m_relativePath = normalizedPath.LexicallyRelative(assetRootPath).StringAsPosix(); + m_assetSystemStub.RegisterSourceInfo(normalizedPath.StringAsPosix().c_str(), assetInfo, assetRootPath.StringAsPosix().c_str()); + } + + static constexpr const char* m_assetRoot = "d:/project/assets/"; + AssetSystemStub m_assetSystemStub; + }; + + TEST_F(AtomToolsFrameworkTest, GetExteralReferencePath_Succeeds) + { + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("", "", 2), ""); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/condor.material", "", 2), ""); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "", 2), ""); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "d:/project/assets/textures/gold.png", 2), "../textures/gold.png"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "d:/project/assets/textures/gold.png", 0), "textures/gold.png"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 3), "../../../materials/condor.material"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 2), "materials/condor.material"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 1), "materials/condor.material"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 0), "materials/condor.material"); + } -AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); + AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); +} // namespace UnitTest diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake new file mode 100644 index 0000000000..bd9ad9b3d8 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake @@ -0,0 +1,11 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + Tests/AtomToolsFrameworkTest.cpp +) \ No newline at end of file diff --git a/Gems/Atom/Utils/Code/CMakeLists.txt b/Gems/Atom/Utils/Code/CMakeLists.txt index 89bc8dd0a5..cbdfb016a1 100644 --- a/Gems/Atom/Utils/Code/CMakeLists.txt +++ b/Gems/Atom/Utils/Code/CMakeLists.txt @@ -27,6 +27,27 @@ ly_add_target( 3rdParty::libpng ) +if(PAL_TRAIT_BUILD_HOST_TOOLS) + + ly_add_target( + NAME Atom_Utils.Editor.Static STATIC + NAMESPACE Gem + FILES_CMAKE + atom_utils_editor_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PRIVATE + AZ::AtomCore + AZ::AzCore + AZ::AzFramework + AZ::AzToolsFramework + ) +endif() + ################################################################################ # Tests ################################################################################ diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetSystemStub.h similarity index 100% rename from Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h rename to Gems/Atom/Utils/Code/Include/Atom/Utils/AssetSystemStub.h diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp b/Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp similarity index 99% rename from Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp rename to Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp index 31a46e9a6f..f026e8bcd7 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp +++ b/Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include namespace UnitTest diff --git a/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake b/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake new file mode 100644 index 0000000000..7d7eb10e7c --- /dev/null +++ b/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + Include/Atom/Utils/AssetSystemStub.h + Source/AssetSystemStub.cpp +) From 172ec938ccf9126c1dd332488889a957595db925 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 3 Nov 2021 17:28:12 -0500 Subject: [PATCH 12/36] moved AssetSystemStub to TestUtils folder Signed-off-by: Guthrie Adams --- Gems/Atom/RPI/Code/CMakeLists.txt | 2 +- Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h | 2 +- Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt | 2 +- .../AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp | 2 +- Gems/Atom/Utils/Code/CMakeLists.txt | 2 +- .../Code/Include/Atom/Utils/{ => TestUtils}/AssetSystemStub.h | 0 .../Utils/Code/Source/{ => TestUtils}/AssetSystemStub.cpp | 2 +- Gems/Atom/Utils/Code/atom_utils_editor_files.cmake | 4 ++-- 8 files changed, 8 insertions(+), 8 deletions(-) rename Gems/Atom/Utils/Code/Include/Atom/Utils/{ => TestUtils}/AssetSystemStub.h (100%) rename Gems/Atom/Utils/Code/Source/{ => TestUtils}/AssetSystemStub.cpp (98%) diff --git a/Gems/Atom/RPI/Code/CMakeLists.txt b/Gems/Atom/RPI/Code/CMakeLists.txt index 7bf47d675a..f0459a23c2 100644 --- a/Gems/Atom/RPI/Code/CMakeLists.txt +++ b/Gems/Atom/RPI/Code/CMakeLists.txt @@ -160,7 +160,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Atom_RPI.Public Gem::Atom_RHI.Public Gem::Atom_RPI.Edit - Gem::Atom_Utils.Editor.Static + Gem::Atom_Utils.TestUtils.Static ) ly_add_googletest( NAME Gem::Atom_RPI.Tests diff --git a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h index b745e55ee8..0707528d7f 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h @@ -21,7 +21,7 @@ #include #include #include -#include +#include namespace UnitTest { diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index bb2ac1f513..40c8d7956e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -81,7 +81,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) AZ::AzTest AZ::AzTestShared Gem::AtomToolsFramework.Static - Gem::Atom_Utils.Editor.Static + Gem::Atom_Utils.TestUtils.Static ) ly_add_googletest( diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp index 349c2b9ced..df16cfbc43 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp @@ -7,7 +7,7 @@ */ #include -#include +#include #include namespace UnitTest diff --git a/Gems/Atom/Utils/Code/CMakeLists.txt b/Gems/Atom/Utils/Code/CMakeLists.txt index cbdfb016a1..90d7ce501b 100644 --- a/Gems/Atom/Utils/Code/CMakeLists.txt +++ b/Gems/Atom/Utils/Code/CMakeLists.txt @@ -30,7 +30,7 @@ ly_add_target( if(PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_target( - NAME Atom_Utils.Editor.Static STATIC + NAME Atom_Utils.TestUtils.Static STATIC NAMESPACE Gem FILES_CMAKE atom_utils_editor_files.cmake diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/AssetSystemStub.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/TestUtils/AssetSystemStub.h similarity index 100% rename from Gems/Atom/Utils/Code/Include/Atom/Utils/AssetSystemStub.h rename to Gems/Atom/Utils/Code/Include/Atom/Utils/TestUtils/AssetSystemStub.h diff --git a/Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp b/Gems/Atom/Utils/Code/Source/TestUtils/AssetSystemStub.cpp similarity index 98% rename from Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp rename to Gems/Atom/Utils/Code/Source/TestUtils/AssetSystemStub.cpp index f026e8bcd7..d57969ea9c 100644 --- a/Gems/Atom/Utils/Code/Source/AssetSystemStub.cpp +++ b/Gems/Atom/Utils/Code/Source/TestUtils/AssetSystemStub.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include namespace UnitTest diff --git a/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake b/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake index 7d7eb10e7c..6c4202fe09 100644 --- a/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake +++ b/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake @@ -7,6 +7,6 @@ # set(FILES - Include/Atom/Utils/AssetSystemStub.h - Source/AssetSystemStub.cpp + Include/Atom/Utils/TestUtils/AssetSystemStub.h + Source/TestUtils/AssetSystemStub.cpp ) From 198f225bbec7049fe71d4886d188c3df16c52d72 Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Wed, 10 Nov 2021 14:42:55 -0600 Subject: [PATCH 13/36] Updating parent path usage has part of cherry picked from stabilization combining source data changes with relative path changes Signed-off-by: Guthrie Adams --- .../Code/Source/Document/MaterialDocument.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index ea97a3f2c0..8635d1eb3e 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -742,25 +742,24 @@ namespace MaterialEditor if (!m_materialSourceData.m_parentMaterial.empty()) { AZ::RPI::MaterialSourceData parentMaterialSourceData; - const auto parentMaterialFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial); - if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialFilePath, parentMaterialSourceData)) + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(m_materialSourceData.m_parentMaterial, parentMaterialSourceData)) { - AZ_Error("MaterialDocument", false, "Material parent source data could not be loaded for: '%s'.", parentMaterialFilePath.c_str()); + AZ_Error("MaterialDocument", false, "Material parent source data could not be loaded for: '%s'.", m_materialSourceData.m_parentMaterial.c_str()); return false; } - const auto parentMaterialAssetIdResult = AssetUtils::MakeAssetId(parentMaterialFilePath, 0); + const auto parentMaterialAssetIdResult = AssetUtils::MakeAssetId(m_materialSourceData.m_parentMaterial, 0); if (!parentMaterialAssetIdResult) { - AZ_Error("MaterialDocument", false, "Material parent asset ID could not be created: '%s'.", parentMaterialFilePath.c_str()); + AZ_Error("MaterialDocument", false, "Material parent asset ID could not be created: '%s'.", m_materialSourceData.m_parentMaterial.c_str()); return false; } auto parentMaterialAssetResult = parentMaterialSourceData.CreateMaterialAssetFromSourceData( - parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, true, true); + parentMaterialAssetIdResult.GetValue(), m_materialSourceData.m_parentMaterial, true, true); if (!parentMaterialAssetResult) { - AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", parentMaterialFilePath.c_str()); + AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", m_materialSourceData.m_parentMaterial.c_str()); return false; } From c0df1846f4f34e7a8adb5191fbda213ff68a5a24 Mon Sep 17 00:00:00 2001 From: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> Date: Fri, 12 Nov 2021 11:03:43 -0800 Subject: [PATCH 14/36] Create desktop shortcut functionality (#5536) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Linux/ProjectManager_Traits_Linux.h | 1 + .../Platform/Linux/ProjectUtils_linux.cpp | 5 ++++ .../Platform/Mac/ProjectManager_Traits_Mac.h | 1 + .../Platform/Mac/ProjectUtils_mac.cpp | 5 ++++ .../Windows/ProjectManager_Traits_Windows.h | 1 + .../Platform/Windows/ProjectUtils_windows.cpp | 22 +++++++++++++++ .../Source/ProjectButtonWidget.cpp | 28 +++++++++++++++++++ .../ProjectManager/Source/ProjectUtils.cpp | 4 +-- .../ProjectManager/Source/ProjectUtils.h | 9 ++++++ 9 files changed, 74 insertions(+), 2 deletions(-) diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h index 7c0543361f..d7edcfcf12 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h @@ -9,3 +9,4 @@ #pragma once #define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false +#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp index dc3ec55dee..a7bd2dae08 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp @@ -96,5 +96,10 @@ namespace O3DE::ProjectManager { return AZ::Utils::GetExecutableDirectory(); } + + AZ::Outcome CreateDesktopShortcut([[maybe_unused]] const QString& filename, [[maybe_unused]] const QString& targetPath, [[maybe_unused]] const QStringList& arguments) + { + return AZ::Failure(QObject::tr("Creating desktop shortcuts functionality not implemented for this platform yet.")); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h index 7c0543361f..d7edcfcf12 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h @@ -9,3 +9,4 @@ #pragma once #define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false +#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp index b768200398..62011bf04b 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp @@ -137,5 +137,10 @@ namespace O3DE::ProjectManager return editorPath; } + + AZ::Outcome CreateDesktopShortcut([[maybe_unused]] const QString& filename, [[maybe_unused]] const QString& targetPath, [[maybe_unused]] const QStringList& arguments) + { + return AZ::Failure(QObject::tr("Creating desktop shortcuts functionality not implemented for this platform yet.")); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h index e6422b5a77..9e4d29b58f 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h @@ -9,3 +9,4 @@ #pragma once #define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true +#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT true diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp index 871f8e9567..d08da1d5e1 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -146,5 +147,26 @@ namespace O3DE::ProjectManager { return AZ::Utils::GetExecutableDirectory(); } + + AZ::Outcome CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments) + { + const QString cmd{"powershell.exe"}; + const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + const QString shortcutPath = QString("%1/%2.lnk").arg(desktopPath).arg(filename); + const QString arg = QString("$s=(New-Object -COM WScript.Shell).CreateShortcut('%1');$s.TargetPath='%2';$s.Arguments='%3';$s.Save();") + .arg(shortcutPath) + .arg(targetPath) + .arg(arguments.join(' ')); + auto createShortcutResult = ExecuteCommandResult(cmd, QStringList{"-Command", arg}, QProcessEnvironment::systemEnvironment()); + if (!createShortcutResult.IsSuccess()) + { + return AZ::Failure(QObject::tr("Failed to create desktop shortcut %1

" + "Please verify you have permission to create files at the specified location.

%2") + .arg(shortcutPath) + .arg(createShortcutResult.GetError())); + } + + return AZ::Success(QObject::tr("Desktop shortcut created at
%2").arg(desktopPath).arg(shortcutPath)); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp index c425c344e1..98916cccf6 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp @@ -8,7 +8,11 @@ #include #include +#include +#include #include +#include +#include #include #include @@ -23,6 +27,7 @@ #include #include #include +#include namespace O3DE::ProjectManager { @@ -205,6 +210,29 @@ namespace O3DE::ProjectManager { AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path); }); + +#if AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT + menu->addAction(tr("Create Editor desktop shortcut..."), this, [this]() + { + AZ::IO::FixedMaxPath executableDirectory = ProjectUtils::GetEditorDirectory(); + AZStd::string executableFilename = "Editor"; + AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION); + + const QString shortcutName = QString("%1 Editor").arg(m_projectInfo.m_displayName); + const QString arg = QString("--regset=\"/Amazon/AzCore/Bootstrap/project_path=%1\"").arg(m_projectInfo.m_path); + + auto result = ProjectUtils::CreateDesktopShortcut(shortcutName, editorExecutablePath.c_str(), { arg }); + if(result.IsSuccess()) + { + QMessageBox::information(this, tr("Desktop Shortcut Created"), result.GetValue()); + } + else + { + QMessageBox::critical(this, tr("Failed to create shortcut"), result.GetError()); + } + }); +#endif // AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT + menu->addSeparator(); menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo); }); menu->addSeparator(); diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index bb2bcd070e..4a0e1c153c 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -628,11 +628,11 @@ namespace O3DE::ProjectManager return AZ::Failure(QObject::tr("Process for command '%1' timed out at %2 seconds").arg(cmd).arg(commandTimeoutSeconds)); } int resultCode = execProcess.exitCode(); + QString resultOutput = execProcess.readAllStandardOutput(); if (resultCode != 0) { - return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2").arg(cmd).arg(resultCode)); + return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2) %3").arg(cmd).arg(resultCode).arg(resultOutput)); } - QString resultOutput = execProcess.readAllStandardOutput(); return AZ::Success(resultOutput); } diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index 890d50d2de..ee605b5117 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -68,6 +68,15 @@ namespace O3DE::ProjectManager AZ::Outcome GetProjectBuildPath(const QString& projectPath); AZ::Outcome OpenCMakeGUI(const QString& projectPath); AZ::Outcome RunGetPythonScript(const QString& enginePath); + + /** + * Create a desktop shortcut. + * @param filename the name of the desktop shorcut file + * @param target the path to the target to run + * @param arguments the argument list to provide to the target + * @return AZ::Outcome with the command result on success + */ + AZ::Outcome CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments); AZ::IO::FixedMaxPath GetEditorDirectory(); From b0dfe26232b318e520887af65cd579ec87016636 Mon Sep 17 00:00:00 2001 From: galibzon <66021303+galibzon@users.noreply.github.com> Date: Fri, 12 Nov 2021 13:51:07 -0600 Subject: [PATCH 15/36] The Build Time Stamp of ShaderAsset And (#5373) * The Build Time Stamp of ShaderAsset And ShaderVariantAsset Should Be Based On GetTimeUTCMilliSecond() GetTimeNowMicroseconds() is useful to measure time stamp differences. GetTimeUTCMilliSecond() is for time stamps based on absolute clock/wall time. * Updated DiffuseGlobalIllumination precompiled shaders Co-authored-by: dmcdiar Signed-off-by: galibzon <66021303+galibzon@users.noreply.github.com> --- .../AzslShaderBuilderSystemComponent.cpp | 4 ++-- .../Code/Source/Editor/ShaderAssetBuilder.cpp | 10 +++++----- .../Editor/ShaderVariantAssetBuilder.cpp | 2 +- .../Source/Editor/ShaderVariantAssetBuilder.h | 2 +- .../diffuseprobegridblenddistance.azshader | Bin 77447 -> 77447 bytes ...begridblenddistance_dx12_0.azshadervariant | Bin 8258 -> 8258 bytes ...begridblenddistance_null_0.azshadervariant | Bin 486 -> 486 bytes ...gridblenddistance_vulkan_0.azshadervariant | Bin 8286 -> 8286 bytes .../diffuseprobegridblendirradiance.azshader | Bin 77491 -> 77491 bytes ...gridblendirradiance_dx12_0.azshadervariant | Bin 9034 -> 9034 bytes ...gridblendirradiance_null_0.azshadervariant | Bin 486 -> 486 bytes ...idblendirradiance_vulkan_0.azshadervariant | Bin 10002 -> 10002 bytes ...iffuseprobegridborderupdatecolumn.azshader | Bin 27583 -> 27583 bytes ...dborderupdatecolumn_dx12_0.azshadervariant | Bin 4522 -> 4522 bytes ...dborderupdatecolumn_null_0.azshadervariant | Bin 486 -> 486 bytes ...orderupdatecolumn_vulkan_0.azshadervariant | Bin 2701 -> 2701 bytes .../diffuseprobegridborderupdaterow.azshader | Bin 27580 -> 27580 bytes ...gridborderupdaterow_dx12_0.azshadervariant | Bin 4338 -> 4338 bytes ...gridborderupdaterow_null_0.azshadervariant | Bin 486 -> 486 bytes ...idborderupdaterow_vulkan_0.azshadervariant | Bin 2222 -> 2222 bytes .../diffuseprobegridclassification.azshader | Bin 74952 -> 74952 bytes ...egridclassification_dx12_0.azshadervariant | Bin 6166 -> 6166 bytes ...egridclassification_null_0.azshadervariant | Bin 486 -> 486 bytes ...ridclassification_vulkan_0.azshadervariant | Bin 4962 -> 4962 bytes .../diffuseprobegridraytracing.azshader | Bin 142100 -> 142100 bytes ...probegridraytracing_dx12_0.azshadervariant | Bin 31950 -> 32042 bytes ...probegridraytracing_null_0.azshadervariant | Bin 486 -> 486 bytes ...obegridraytracing_vulkan_0.azshadervariant | Bin 34448 -> 34600 bytes ...fuseprobegridraytracingclosesthit.azshader | Bin 142110 -> 142110 bytes ...aytracingclosesthit_dx12_0.azshadervariant | Bin 13094 -> 13094 bytes ...aytracingclosesthit_null_0.azshadervariant | Bin 486 -> 486 bytes ...tracingclosesthit_vulkan_0.azshadervariant | Bin 5404 -> 5404 bytes .../diffuseprobegridraytracingmiss.azshader | Bin 142104 -> 142104 bytes ...egridraytracingmiss_dx12_0.azshadervariant | Bin 13262 -> 13262 bytes ...egridraytracingmiss_null_0.azshadervariant | Bin 486 -> 486 bytes ...ridraytracingmiss_vulkan_0.azshadervariant | Bin 6396 -> 6396 bytes .../diffuseprobegridrelocation.azshader | Bin 77960 -> 77960 bytes ...probegridrelocation_dx12_0.azshadervariant | Bin 8046 -> 8046 bytes ...probegridrelocation_null_0.azshadervariant | Bin 486 -> 486 bytes ...obegridrelocation_vulkan_0.azshadervariant | Bin 9442 -> 9442 bytes .../diffuseprobegridrender.azshader | Bin 203892 -> 218052 bytes ...fuseprobegridrender_dx12_0.azshadervariant | Bin 30799 -> 30631 bytes ...fuseprobegridrender_null_0.azshadervariant | Bin 589 -> 589 bytes ...seprobegridrender_vulkan_0.azshadervariant | Bin 22565 -> 22565 bytes .../Shader/ShaderVariantAssetCreator.h | 2 +- .../Atom/RPI.Reflect/Shader/ShaderAsset.h | 2 +- .../RPI.Reflect/Shader/ShaderVariantAsset.h | 4 ++-- .../Shader/ShaderVariantAssetCreator.cpp | 2 +- .../Code/Source/RPI.Public/Shader/Shader.cpp | 8 ++++---- .../RPI.Reflect/Shader/ShaderVariantAsset.cpp | 2 +- 50 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp index e41c04a0be..99b7c814d1 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp @@ -82,7 +82,7 @@ namespace AZ // Register Shader Asset Builder AssetBuilderSDK::AssetBuilderDesc shaderAssetBuilderDescriptor; shaderAssetBuilderDescriptor.m_name = "Shader Asset Builder"; - shaderAssetBuilderDescriptor.m_version = 107; // Required .azsl extension in .shader file references + shaderAssetBuilderDescriptor.m_version = 108; // The Build Time Stamp of ShaderAsset And ShaderVariantAsset Should Be Based On GetTimeUTCMilliSecond() // .shader file changes trigger rebuilds shaderAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern( AZStd::string::format("*.%s", RPI::ShaderSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); shaderAssetBuilderDescriptor.m_busId = azrtti_typeid(); @@ -108,7 +108,7 @@ namespace AZ shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder"; // Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update // ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder". - shaderVariantAssetBuilderDescriptor.m_version = 26; // [AZSL] Changing inlineConstant to rootConstant keyword work. + shaderVariantAssetBuilderDescriptor.m_version = 27; // The Build Time Stamp of ShaderAsset And ShaderVariantAsset Should Be Based On GetTimeUTCMilliSecond(). shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid(); shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp index 89e202a4bc..e431b74282 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp @@ -162,7 +162,7 @@ namespace AZ // has the same value, because later the ShaderVariantTreeAsset job will fetch this value from the local ShaderAsset // which could cross platforms (i.e. building an android ShaderVariantTreeAsset on PC would fetch the tiemstamp from // the PC's ShaderAsset). - AZStd::sys_time_t shaderAssetBuildTimestamp = AZStd::GetTimeNowMicroSecond(); + AZ::u64 shaderAssetBuildTimestamp = AZStd::GetTimeUTCMilliSecond(); // Need to get the name of the azsl file from the .shader source asset, to be able to declare a dependency to SRG Layout Job. // and the macro options to preprocess. @@ -229,8 +229,8 @@ namespace AZ } // for all request.m_enabledPlatforms AZ_TracePrintf( - ShaderAssetBuilderName, "CreateJobs for %s took %llu microseconds", shaderAssetSourceFileFullPath.c_str(), - AZStd::GetTimeNowMicroSecond() - shaderAssetBuildTimestamp); + ShaderAssetBuilderName, "CreateJobs for %s took %llu milliseconds", shaderAssetSourceFileFullPath.c_str(), + AZStd::GetTimeUTCMilliSecond() - shaderAssetBuildTimestamp); response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; } @@ -355,8 +355,8 @@ namespace AZ return; } - // Get the time stamp string as sys_time_t, and also convert back to string to make sure it was converted correctly. - AZStd::sys_time_t shaderAssetBuildTimestamp = 0; + // Get the time stamp string as u64, and also convert back to string to make sure it was converted correctly. + AZ::u64 shaderAssetBuildTimestamp = 0; auto shaderAssetBuildTimestampIterator = request.m_jobDescription.m_jobParameters.find(ShaderAssetBuildTimestampParam); if (shaderAssetBuildTimestampIterator != request.m_jobDescription.m_jobParameters.end()) { diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index bb40baca7d..5eaa0d9ddb 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -765,7 +765,7 @@ namespace AZ return; } - const AZStd::sys_time_t shaderVariantAssetBuildTimestamp = AZStd::GetTimeNowMicroSecond(); + const AZ::u64 shaderVariantAssetBuildTimestamp = AZStd::GetTimeUTCMilliSecond(); auto supervariantList = ShaderBuilderUtility::GetSupervariantListFromShaderSourceData(shaderSourceDescriptor); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h index 2eaf1d9d8b..b0457656af 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h @@ -38,7 +38,7 @@ namespace AZ const AZStd::string& m_tempDirPath; //! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset, //! especially during hot-reload. A (ShaderVariantAsset.timestamp) >= (ShaderAsset.timestamp). - const AZStd::sys_time_t m_assetBuildTimestamp; + const AZ::u64 m_assetBuildTimestamp; const RPI::ShaderSourceData& m_shaderSourceDataDescriptor; const RPI::ShaderOptionGroupLayout& m_shaderOptionGroupLayout; const MapOfStringToStageType& m_shaderEntryPoints; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader index 31fae5d98bb261ee35faac2489e4138379a5b952..a9b5567f6b19d075222ab9881cf3b3ff0aae7994 100644 GIT binary patch delta 197 zcmZp_%hGSXJF>B$A!A5q1tG&!~`R>+wZb~bi1Z&-jZvTS?i0X0UKX##$(JJmp7^1+Ru=81EeEc F5CH#RP;&qP delta 197 zcmZp_%hGCR;deEULvjXnnh1H;^}a@ir9Rat@<+5DZu3v==& z&pV^Cxm#z8>SXJF>B$A!A5q1tG&$DhZ@F6}v!P})Z&-jZvTS?i0X0X F1OVHsPiz1H diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant index 19e9fdfc8d23db9d1ac4b062b395258ab3eeb219..6d4b6d0fcafe1d8560e2f3087ef300047cdfb436 100644 GIT binary patch delta 36 scmX@)aL8eUnu5%=$Vy}Pv;HS`3MPMkv|*+d2Ll6Rt>EF)G7Jn103vG*;{X5v delta 36 rcmX@)aL8eUnu1KhjYUlhU%BbdWeI%yLVk@t2Ll7c+^=%kAwU`cBliut diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_null_0.azshadervariant index 43c4a615cf8f6719d802c538b340952a17738839..5d8800a6fe3f085a433044ce5befe9e60dd2c764 100644 GIT binary patch delta 36 scmaFH{ET_SDMp!Vk(I{oXZ=s?6ioj7Xv0h^4h9CsTEWAoWf&M304zxkHUIzs delta 36 rcmaFH{ET_SDMp!s8;hD2zH-x@%M$qZh5QxnJe7Lx3~@E!7ST diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_vulkan_0.azshadervariant index 75f070a03eeb2ae0c9f4f2917e2ad8ba69a7ce42..930f7898c4f3489f042e62275da78b4618124577 100644 GIT binary patch delta 36 scmccTaL-|blY-2($Vy}Pv;HS`3MPMkv|*+d2Ll6Rt>EF)G7Jn104;Y8Hvj+t delta 36 rcmccTaL-|blY&gajYUlhU%BbdWeI%yLVk@t2Ll7c+^=%kAwU`cF9Qw@ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader index 0025388bc13bae5830f46f3b79be2b4a3a0800ba..268020b431045dd424ae16fef2656c7fff34e431 100644 GIT binary patch delta 174 zcmdmdmu2%^mJNI?lRxedW@D@sJbW~AvpP!cIh4NxswME($tQ;E^j2&Z+_h8)S$|(kKR%Z!fWGjv=@^mZM zT+jMS4Z*&ry4g4A1T#k&pGkx9hvIpT41rHED7@iF{ySEFKkqitB04Q4yK>z>% delta 36 rcmX@*cFJvop0Z5AjYUlhU%BbdWeI%yLVk@t2Ll7c+^=$q!9W@SCz}nG diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant index 4a2b0e9944d9b41fe3c3c98f4c7607eebe0d3a2d..3253ddba376ea446e0dfb402ea83e1973fb71589 100644 GIT binary patch delta 36 scmaFH{ET_SDMp!Vk(I{oXZ=s?6ioj7Xv0h^4h9CsTEW9dBN-SN04*O5Z2$lO delta 36 rcmaFH{ET_SDMp!s8;hD2zH-x@%M$qZh5QxnJcJgMl;vEME=5 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant index c053a7db199279cf7ef8929b0a12157414db2ec6..c38b94c4f1f7288e2c3fe0d1bf48d2d471c17763 100644 GIT binary patch delta 36 scmbQ_H_30qH#M1Sk(I{oXZ=s?6ioj7Xv0h^4h9CsTEW9dBN-SN05iP~tN;K2 delta 36 rcmbQ_H_30qH#M1p8;hD2zH-x@%M$qZh5QxnJcJgMl;vGW`w! diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader index c507b125634fdfcdfb749d15380513cc8527c5f8..5c46d368cef5f778fecab7a7abe845a3df753804 100644 GIT binary patch delta 196 zcmdmgopJwl#tnijlGh?Djor`spV%pw{Q1#_nN}PO42-pchYxXV)?x`_Wb^Y6cTP&4 zT&Sm1U7JRB;P+NH$nUVjm_sp Ltpz9dXBz+js5DEj delta 196 zcmdmgopJwl#tnijk_9&wH7$JQraPA<@a+rvHToP33=DI>%6V+sti=+<$d=*~kX_*Tco-;ixM6WGAPp(3%Vrd26v{pRzc K)`FA!vkd@nK1;#? diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant index f60c7135977ac8215b5c78551c6f716448afb590..eb6938f8c9c8c853e2d0c06160096440aa8357fa 100644 GIT binary patch delta 36 rcmZ3byh?dPpPEE9K$-yn9)JzC delta 36 rcmZ3byh?dPpP)>^jYUlhU%BbdWeI%yLVk@t2Ll7c+^=#Tn}9R`AyN(F diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant index 3e810bcfb51b320702134c14db816f744549bb72..8c83c1e3ff64da49fc860a44915cbb4b8a233482 100644 GIT binary patch delta 36 rcmaFH{ET_SDMp!Vk(I{oXZ=s?6ioj7Xv0h^4h9CsTEWAIfHVUDE6ffV delta 36 rcmaFH{ET_SDMp!s8;hD2zH-x@%M$qZh5QxnJcxHUVh>E}jlY diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant index 5918f277b577ebd0685c1b784ad68aa7808ff1fc..2fbb9ffffee14a3a04cb4c7cd6be8cae358e5e64 100644 GIT binary patch delta 36 rcmeAb?G@cn$R%?vveMZ7tpACfg2|sBZJ24r!N9;+D|q-2kY)e?4uuUn delta 36 rcmeAb?G@cn$R$&7V^Pz>S8lp!);e#7&4E$Yf}4XqGhuds i6`l+{$~t*fz&B*WP6jq`aD3SJd7a(WeF;Eq*@6JVT0(UI delta 190 zcmdmUopH}~#tnQdk_9&wH7$JQraPA<@a+rvHToP33=DI>%KL8Etj-d|$mZf)5a8#s zxt{eC8-o3eb#tuHZYGW?hYXJzOPt-jSwS>F7%Dxvo>h7COpWs} ytQJ)>Yz~aF7Tg@{nF+H4tng&uQP#<;0=^*|b~3PmgJVJ1e5;nffro(FvIPN{x<`xv diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant index d38d779696b13c4fd7f5d21a534e2003d99c0abf..4bdbdddf334d634467a889a476ef3c6f474762ec 100644 GIT binary patch delta 36 scmeyQ_(^fYH36Axk(I{oXZ=s?6ioj7Xv0h^4h9CsTEWB5`4|`&06P;7vj6}9 delta 36 rcmeyQ_(^fYH36A|8;hD2zH-x@%M$qZh5QxnJddHvnk>Ju42n diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant index 6d7a604701b9a849b2be3939000072f11beb9371..77668a24503e7aedabd91d13903db31149c4c835 100644 GIT binary patch delta 36 scmaFH{ET_SDMp!Vk(I{oXZ=s?6ioj7Xv0h^4h9CsTEWB5`4|`&04$vjL;wH) delta 36 rcmaFH{ET_SDMp!s8;hD2zH-x@%M$qZh5QxnJddHvnk>F0~Fz diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant index dee941cfae644d19cb161c0826cae0801f7b7d54..fb3dd771caf01ab5c24094232f627f6568550a80 100644 GIT binary patch delta 36 scmZ1{xK41xBo3Ktk(I{oXZ=s?6ioj7Xv0h^4h9CsTEWB5`4|`&02>btzW@LL delta 36 rcmZ1{xK41xBo3K^8;hD2zH-x@%M$qZh5QxnJddHvnk>9VZRO diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader index e2e0fa90f5cb67db90fc3022210ada280ffb5e2f..eda8d533767910a172d89f101652e0ca7879c702 100644 GIT binary patch delta 195 zcmX?clI6rnmJPftlGh?Djor`spV%pw{Q1#_nN}PO42-pchwnbxti}?=$d>2mni%3d zd1JTgW&`aomC5tFq$i7LeMA+Xrp{re85+GuOnmd^b3p;ZP}$8JyQ@_;&+p=a83Pp9 ztj;&}b6$Nzwqx(>8R{HqnfE?DKgQ(; I(w8j=0H3K(AOHXW delta 195 zcmX?clI6rnmJPftk_9&wH7$JQraPA<@a+rvHToP33=DI>%IoTHR$~cbWGl$`^smUC zys=w#vw?P)%H;W7(vwBBKB9_GQ|H)q_Lo9tf^OXAb3p;ZP}$8JyQ@_;&+p=a83Pp9 zta=5o7b>u$ejt0004f5yRc$0000kGY<{` delta 36 rcmbPcFwJ1YFL9ZI8;hD2zH-x@%M$qZh5QxnJdV^?@`1Dv1rM diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant index 43408b26f3c17afb2a726971c1fad38f24d2fd42..f2458e692b5673dc5a2aaf5f94b5f182c0f09097 100644 GIT binary patch delta 36 ucmV+<0NelO1Lgy;$^jhKS$Q)@%}>a=5o7b>u$ejt0004f5yRc$0000lyAKWk delta 36 rcmaFH{ET_SDMp!s8;hD2zH-x@%M$qZh5QxnJdV^?@`1ED;T= diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_vulkan_0.azshadervariant index 877085446de04b3f129ebb6273698e848ee45de7..0e08e84f74b293a4499b78c9ebef97564cd11777 100644 GIT binary patch delta 36 scmaE)_DF4mo3PBa$Vy}Pv;HS`3MPMkv|*+d2Ll6Rt>EFij~Eyj04fg-+5i9m delta 36 rcmaE)_DF4mo3Kp5jYUlhU%BbdWeI%yLVk@t2Ll7c+^_Pw`al{0CS?tF diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader index 2c403c77f88b4e7213022796f694f866ba71160a..1cea4860a113c2b0f46cc9dd25931dc36f7130ab 100644 GIT binary patch delta 74 zcmV-Q0JZ;=)(Di=2(S$Vmmy*S69xf&5yQg}vnB-HrU*C=veu-YWTvwVt1h?*3a^bH gf3XRNw?Sh8J+}y}r+$CtGNcK!=c`^2m*gq}FgBDO^8f$< delta 88 zcmV-e0H^( diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant index 4bcc47ee43a6bcc8c2b33f451d22a0b963981210..5605a47e9cb0dfd9223151cdce9e306852f730c4 100644 GIT binary patch delta 10619 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 a3p+j!k^iUH^!_vo1QE7`w6@|qBL5E)baG|@ delta 10489 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 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_null_0.azshadervariant index f173416210a73847b2e552a0e2bdab355186d34b..15f3477cb5fc4baa7b937e388fc14ec277210841 100644 GIT binary patch delta 36 scmaFH{ET_SDMp!Vk(I{oXZ=s?6ioj7Xv0h^4h9CsTEWAI1sE6@04wnhA^-pY delta 36 rcmaFH{ET_SDMp!s8;hD2zH-x@%M$qZh5QwSD#V%|IFeF6s_h diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_vulkan_0.azshadervariant index 0eb04a25b814a01e4f4fcc3fcdc1506ad4eec5d8..c2bcd4ab07c8321b12d204a54ca52efa71d5e175 100644 GIT binary patch literal 34600 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%0AmO9S^Hh#js) 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 delta 93 zcmV-j0HXh%)(D=~2(T9f8F1L5f}!e0Eu92W?dTt@F9-kt0IruAtJuV*Uu diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant index 93cfb4781977a009b6b4aa6ca9c5baacdcf9a5e4..fbd1d902517b8c614396ab7b502495eb9b881f07 100644 GIT binary patch delta 36 scmZ3Mwk&M}m$A&X$Vy}Pv;HS`3MPMkv|*+d2Ll6Rt>EFKdJGH<03+KC`Tzg` delta 36 rcmZ3Mwk&M}m$6L2jYUlhU%BbdWeI%yLVk@t2Ll7cy6KXuZvkllCT$Kl diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant index 4a16e24211faaa39226db82f9bd88979700313f2..483be0eceb86381caef4e4ee7ec0e1622febdc23 100644 GIT binary patch delta 36 scmaFH{ET_SDMp!Vk(I{oXZ=s?6ioj7Xv0h^4h9CsTEW9d^%xi!04#G3LI3~& delta 36 rcmaFH{ET_SDMp!s8;hD2zH-x@%M$qZh5Qb<-tR-vZJAF9i;O diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant index df52c9c8d28c576b1905f49c9f898491ecad94aa..530eef2f102873570848ef8ead9ace35c905822e 100644 GIT binary patch delta 35 rcmbQEHAicKsLZv5{8&0cijV+6{C7 diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader index d95fd5b3b2bccd1f9153241ab9ac8bfa7dad6a3b..eddac4e2bd277eab358b589f4f556eb13486257c 100644 GIT binary patch delta 93 zcmV-j0HXhx)(Du^2(S?Z8P-{OGe^x&$hi??^Ww0XItTy&0eum}ze%$y1l^_xvFp}( z)U&c1vk$8-xCm#GqG{YrTsgDqt6vbeq;mn@rU;ux>)#HQRH?J;t6mV7=qds*&Gjp8 delta 93 zcmV-j0HXhx)(Du^2(S?Z8F1L5f}!e0Eu92W?dTt@F9-kt0IiRAaul;F1l^_x>)U=w zi30W4vk$8-xCo=LjNbjA(ZsXrt6vbeq;mn@rU<{9 delta 36 rcmX??elC5(CS#d`8;hD2zH-x@%M$qZh5Qwf*HqB0w4dL%0rz diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_null_0.azshadervariant index 40e18c215c93079ffdbe3931f9df13c625ef5468..527b42569a3e6556bc398f8232b5ed49dd11b29c 100644 GIT binary patch delta 36 scmaFH{ET_SDMp!Vk(I{oXZ=s?6ioj7Xv0h^4h9CsTEWBnJsB7n04%`{R{#J2 delta 36 rcmaFH{ET_SDMp!s8;hD2zH-x@%M$qZh5Qwf*HqB0w4dEW{1g diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant index 34761ccf98ae556858256ecf25608fd87d6c67ed..426d9559385e16ad59d7124796ed2f712b0f7a3f 100644 GIT binary patch delta 36 scmexk_{VU=0|}XHk(I{oXZ=s?6ioj7Xv0h^4h9CsTEWBnJsB7n07O|23;+NC delta 36 rcmexk_{VU=0|}Xe8;hD2zH-x@%M$qZh5Qwf*HqB0w4dL|hJw diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader index c19020dc84df5e5bf3c02c1496d86967dce3966c..08ed61ab03bc60c102e2fc65e020bd69f1e85358 100644 GIT binary patch delta 193 zcmeBp$kOqUWdkRRdtd{JfJV zCwx`hETikEHo1C&^kf#DkEr64G&xk1mkK^x{>*ywwy*$UWZ88S{nR#BPvAi@YTZPj z7KT@cKFwmuzq&aw+(vM7%b84=lFbQU3)Lp4eE9}72gu*5$uWO@bf{N)U($A2dB$u( E02+)=ApigX delta 193 zcmeBp$kOqUWdkRRWWkL^O$%SS>CR;deEULvjXnnh1H;^}ay|Z=l~{rp+0p`2T?@-5 zCwx`hETikEHo1C&^kf#DkEr64G&yYNid3BRnrOIrTUdZFvh2EverlVmC-9&cwQeF% zi=&Ka{D%6V- diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant index a7d44b55413ad60e422335b85570eae7f8ef57ad..d1012a896f24d3fa8b0caf6aae6aaa1ff82c9b6a 100644 GIT binary patch delta 36 scmaE7_s(uZki5*b$Vy}Pv;HS`3MPMkv|*+d2Ll6Rt>ED+5)2Fs05d)gX8-^I delta 36 rcmaE7_s(uZki1O6jYUlhU%BbdWeI%yLVk@t2Ll7c+^=#y{y-W4H9ihh diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant index 82e00652163427427f0e363c96a18d7135e11918..cb730be1df5626572cc2940e80934ad279099492 100644 GIT binary patch delta 36 scmaFH{ET_SDMp!Vk(I{oXZ=s?6ioj7Xv0h^4h9CsTEW9tBp4VN04!z>I{*Lx delta 36 rcmaFH{ET_SDMp!s8;hD2zH-x@%M$qZh5QxnJda{DCw8E@loW diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant index 20b81aee6c30ce6f6956ad4c8c50292b00350df7..b58af4c47357850ecf7ba75411a1051a27ff713f 100644 GIT binary patch delta 36 scmaFl`N(s_F%_9>k(I{oXZ=s?6ioj7Xv0h^4h9CsTEW9tBp4VN06~Nf-T(jq delta 36 rcmaFl`N(s_F%_AD8;hD2zH-x@%M$qZh5QxnJda{DCw8Lxc{? diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader index aec2786540c6611090a7e2ed7a270939a8fc40a6..56009d56abb497027e6d3aea639d3d232d0799b2 100644 GIT binary patch delta 7273 zcmeHLeQZ-z6zANP^47s7N`}Omor<;ehm^66d1!B~~8pEmc-}3Tjpc-)2c?}kesEZrK?shroHPuN(s(>A7l|H8;wUuB1_OeA2@t%3nT{| zf?AubeU*e$$Hp;AWtOC*{%VdcDM*G9Vr*Se`J1noEH5mnSjobdVfhGFfd^^DRLbbR z$`EbDeP1~%%VVM5A$mD4$H<511F3;dFpMUk6>93>Eug=+XEKR*6#S?ikSxMB;IVu( z=xE&RF#&aGJlg9RN1IlJXhTn$)X1a%w}<#!lG@(ReoS=-K`VtjSq=mjk5ycT3j?IX3Mh+S@2un=Fj?R2=YV)Q$-gspxR?Q)a zzQk!;IECPBe#JPoebn|*+h-9MY#(&Bf>+s(JgqvOhxQ^EOf9!lkwN={0IKJ-!&q8z zXdXmib~|JY0H#dQkzNz5o-|^_Gbdox0F%Jp-<<-hr;`-ZibM_S&yca$@>67tfsA>rHWHI7C#k5_Mh37wI^6%#j$*^HJ7@N_B*juR^-2gaN5>72B)S# zB<6K6U%rL;O6LiV{|G!ID)cF!p`*KEMW-VQ2uz%Ib%=1g8#;+Xd^SHkUAX!u6l%EI znz@Ah}Q@)z7lOEsJ9RmH6LZvoCjd0 z^`2_>nUtP^6*-LOXv=^CdCmR}>9C@R=x~2ipD_Ob#EV8|EcU_^?5o}j9|RpHkTUu4 zryZ~$@JJnxzs<~U?t}&=sP{0ENPq}z+ts(_+9M2>@;{c=7q*F3Hy7}pDJ+@tPx_3G z9Rwo|%VIk%f10qkEaO`Cc_3Z1KakENKZ8W0<4Ms$%!#L#<^+6px3s=Fg}5b`49f2@ z(I&5GGd3~o`7uqv1nbz(KR*Bh`N_H_= zv=0g)hGvJyvh90sk?F#neb6;jrjkA?jre`*wY!e{RMNO+o9E({a~YvjQXq5F$C;rwONnJN@lldnOAE0v*@*k;=!&CsfFCF9Y516N!Su0-l? zAw#$yS|M9WU;T3oUM_X)mI<={{FX}P{o7RD>i#oH$Kku|7Ru`> crA=%%eKUretY`6 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 delta 36 rcmX@ha+YO-A(KqOjYUlhU%BbdWeI%yLVk@t2Ll7cnh*RdlYuk<7Do+? diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant index c819e57c4c029d3645581a08520aca7ccbfd19ee..47789d9b9bd602bf760bf076fe039860dbfd562b 100644 GIT binary patch delta 84 zcmV-a0IUC{umPp80kB2^2)aQPtJ5ia=5o7b>u$ejt0004f5yQ~h0001x6d>UM delta 84 zcmZ3wfpO^u#tm+a9M{AG-v;wq)ou1;?BQY*+I*XP8V|>vRaT4jbawep_G6UXJW0Zy o2Pkn##oSn?;Krh+g|FOn=duL8eIdU_pM!ycVa*5rmB~OF058KHZvX%Q diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Shader/ShaderVariantAssetCreator.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Shader/ShaderVariantAssetCreator.h index fd069f21e0..488bfb09f8 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Shader/ShaderVariantAssetCreator.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Shader/ShaderVariantAssetCreator.h @@ -40,7 +40,7 @@ namespace AZ //! Set the timestamp value when the ProcessJob() started. //! This is needed to synchronize between the ShaderAsset and ShaderVariantAsset when hot-reloading shaders. //! The idea is that this timestamp must be greater or equal than the ShaderAsset. - void SetBuildTimestamp(AZStd::sys_time_t buildTimestamp); + void SetBuildTimestamp(AZ::u64 buildTimestamp); //! Assigns a shaderStageFunction, which contains the byte code, to the slot dictated by the shader stage. void SetShaderFunction(RHI::ShaderStage shaderStage, RHI::Ptr shaderStageFunction); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h index c5df9a4b51..5dc990d93a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h @@ -294,7 +294,7 @@ namespace AZ Name m_drawListName; //! Use to synchronize versions of the ShaderAsset and ShaderVariantTreeAsset, especially during hot-reload. - AZStd::sys_time_t m_shaderAssetBuildTimestamp = 0; + AZ::u64 m_shaderAssetBuildTimestamp = 0; /////////////////////////////////////////////////////////////////// diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h index 66bbd7b188..5146ae370a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h @@ -61,7 +61,7 @@ namespace AZ //! Return the timestamp when this asset was built, and it must be >= than the timestamp of the main ShaderAsset. //! This is used to synchronize versions of the ShaderAsset and ShaderVariantAsset, especially during hot-reload. - AZStd::sys_time_t GetBuildTimestamp() const; + AZ::u64 GetBuildTimestamp() const; bool IsRootVariant() const { return m_stableId == RPI::RootShaderVariantStableId; } @@ -80,7 +80,7 @@ namespace AZ AZStd::array, RHI::ShaderStageCount> m_functionsByStage; //! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset, especially during hot-reload. - AZStd::sys_time_t m_buildTimestamp = 0; + AZ::u64 m_buildTimestamp = 0; }; class ShaderVariantAssetHandler final diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantAssetCreator.cpp index e0e83cfce2..5b32edc0bf 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantAssetCreator.cpp @@ -92,7 +92,7 @@ namespace AZ ///////////////////////////////////////////////////////////////////// // Methods for all shader variant types - void ShaderVariantAssetCreator::SetBuildTimestamp(AZStd::sys_time_t buildTimestamp) + void ShaderVariantAssetCreator::SetBuildTimestamp(AZ::u64 buildTimestamp) { if (ValidateIsReady()) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp index a2d91fefd6..7dbeac7098 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp @@ -202,17 +202,17 @@ namespace AZ return; } AZ_Assert(m_asset->m_shaderAssetBuildTimestamp == m_reloadedRootShaderVariantAsset->GetBuildTimestamp(), - "shaderAsset timeStamp=%lld, but Root ShaderVariantAsset timeStamp=%lld", + "shaderAsset '%s' timeStamp=%lld, but Root ShaderVariantAsset timeStamp=%lld", m_asset.GetHint().c_str(), m_asset->m_shaderAssetBuildTimestamp, m_reloadedRootShaderVariantAsset->GetBuildTimestamp()); m_asset->UpdateRootShaderVariantAsset(m_supervariantIndex, m_reloadedRootShaderVariantAsset); m_reloadedRootShaderVariantAsset = {}; // Clear the temporary reference. if (ShaderReloadDebugTracker::IsEnabled()) { - auto makeTimeString = [](AZStd::sys_time_t timestamp, AZStd::sys_time_t now) + auto makeTimeString = [](AZ::u64 timestamp, AZ::u64 now) { - AZStd::sys_time_t elapsedMicroseconds = now - timestamp; - double elapsedSeconds = aznumeric_cast(elapsedMicroseconds / 1'000'000); + AZ::u64 elapsedMillis = now - timestamp; + double elapsedSeconds = aznumeric_cast(elapsedMillis / 1'000); AZStd::string timeString = AZStd::string::format("%lld (%f seconds ago)", timestamp, elapsedSeconds); return timeString; }; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp index 442fc6a79f..ec1a65a6d5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp @@ -60,7 +60,7 @@ namespace AZ } } - AZStd::sys_time_t ShaderVariantAsset::GetBuildTimestamp() const + AZ::u64 ShaderVariantAsset::GetBuildTimestamp() const { return m_buildTimestamp; } From 9898b6ee45fa715043cb5c6d163988dd56709924 Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Fri, 12 Nov 2021 13:47:30 -0800 Subject: [PATCH 16/36] Move SC runtime asset static initialization out of data loading threads Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com> --- .../Code/Editor/View/Widgets/CanvasWidget.cpp | 7 ++-- .../ScriptCanvas/Asset/RuntimeAsset.cpp | 1 + .../Include/ScriptCanvas/Asset/RuntimeAsset.h | 3 ++ .../Asset/RuntimeAssetHandler.cpp | 2 +- .../ScriptCanvas/Execution/ExecutionState.h | 4 +++ .../Interpreted/ExecutionInterpretedAPI.cpp | 2 ++ .../Interpreted/ExecutionStateInterpreted.cpp | 33 +++++++++++++++---- .../Execution/RuntimeComponent.cpp | 23 ++++++++----- 8 files changed, 57 insertions(+), 18 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp index e448f3ea40..dfa39b0047 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp @@ -84,9 +84,10 @@ namespace ScriptCanvasEditor { m_assetId = assetId; - EditorGraphRequests* editorGraphRequests = EditorGraphRequestBus::FindFirstHandler(m_scriptCanvasId); - - editorGraphRequests->SetAssetId(m_assetId); + if (EditorGraphRequests* editorGraphRequests = EditorGraphRequestBus::FindFirstHandler(m_scriptCanvasId)) + { + editorGraphRequests->SetAssetId(m_assetId); + } } const GraphCanvas::ViewId& CanvasWidget::GetViewId() const diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp index 0dcd8ebbbd..d55fcf7838 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp @@ -59,6 +59,7 @@ namespace ScriptCanvas m_script = AZStd::move(other.m_script); m_requiredAssets = AZStd::move(other.m_requiredAssets); m_requiredScriptEvents = AZStd::move(other.m_requiredScriptEvents); + m_areStaticsInitialized = AZStd::move(other.m_areStaticsInitialized); } return *this; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h index 24c83b20a1..cc59f90e69 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h @@ -76,6 +76,9 @@ namespace ScriptCanvas AZStd::vector m_activationInputStorage; Execution::ActivationInputRange m_activationInputRange; + // used to initialized statics only once, and not necessarily on the loading thread + bool m_areStaticsInitialized = false; + bool RequiresStaticInitialization() const; bool RequiresDependencyConstructionParameters() const; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp index df7b07d37b..05b6f4397b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp @@ -94,7 +94,6 @@ namespace ScriptCanvas RuntimeAsset* runtimeAsset = asset.GetAs(); AZ_Assert(runtimeAsset, "RuntimeAssetHandler::InitAsset This should be a Script Canvas runtime asset, as this is the only type this handler processes!"); Execution::Context::InitializeActivationData(runtimeAsset->GetData()); - Execution::InitializeInterpretedStatics(runtimeAsset->GetData()); } } @@ -157,4 +156,5 @@ namespace ScriptCanvas } } } + } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/ExecutionState.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/ExecutionState.h index 8c2f0a67c4..89ddf178f3 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/ExecutionState.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/ExecutionState.h @@ -19,6 +19,10 @@ #include #include +#if !defined(_RELEASE) +#define SCRIPT_CANVAS_RUNTIME_ASSET_CHECK +#endif + namespace AZ { class ReflectContext; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp index 4d7c8a2cda..bba56847ce 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp @@ -506,6 +506,8 @@ namespace ScriptCanvas #if defined(AZ_PROFILE_BUILD) || defined(AZ_DEBUG_BUILD) Execution::InitializeFromLuaStackFunctions(const_cast(runtimeData.m_debugMap)); #endif + AZ_WarningOnce("ScriptCanvas", !runtimeData.m_areStaticsInitialized, "ScriptCanvas runtime data already initalized"); + if (runtimeData.RequiresStaticInitialization()) { AZ::ScriptLoadResult result{}; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp index 9224d4f9a4..a92c13ac63 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp @@ -6,14 +6,13 @@ * */ -#include "ExecutionStateInterpreted.h" - #include #include #include - -#include "Execution/Interpreted/ExecutionStateInterpretedUtility.h" -#include "Execution/RuntimeComponent.h" +#include +#include +#include +#include namespace ExecutionStateInterpretedCpp { @@ -33,7 +32,29 @@ namespace ScriptCanvas ExecutionStateInterpreted::ExecutionStateInterpreted(const ExecutionStateConfig& config) : ExecutionState(config) , m_interpretedAsset(config.runtimeData.m_script) - {} + { + RuntimeAsset* runtimeAsset = config.asset.Get(); + +#if defined(SCRIPT_CANVAS_RUNTIME_ASSET_CHECK) + if (!runtimeAsset) + { + AZ_Error("ScriptCanvas", false + , "ExecutionStateInterpreted created with ExecutionStateConfig that contained bad runtime asset data. %s" + , config.asset.GetId().ToString().data()); + return; + } +#else + AZ_Assert(false + , "ExecutionStateInterpreted created with ExecutionStateConfig that contained bad runtime asset data. %s" + , config.asset.GetId().ToString().data()); +#endif + + if (!runtimeAsset->GetData().m_areStaticsInitialized) + { + runtimeAsset->GetData().m_areStaticsInitialized = true; + Execution::InitializeInterpretedStatics(runtimeAsset->GetData()); + } + } void ExecutionStateInterpreted::ClearLuaRegistryIndex() { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp index 5fe5c32a48..bc37bc05f6 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp @@ -19,9 +19,13 @@ #include #include -#if !defined(_RELEASE) -#define SCRIPT_CANVAS_RUNTIME_ASSET_CHECK -#endif +#include +#include + +namespace AZ +{ + AZ_TYPE_INFO_SPECIALIZE(AZ::Data::Asset, "{D9A4EB57-198B-4A0D-B1FB-D1B11FF88C66}"); +} AZ_DECLARE_BUDGET(ScriptCanvas); @@ -112,11 +116,13 @@ namespace ScriptCanvas #if defined(SCRIPT_CANVAS_RUNTIME_ASSET_CHECK) if (!m_runtimeOverrides.m_runtimeAsset.Get()) { - AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); + AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run" + , m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); return; } #else - AZ_Assert(m_runtimeOverrides.m_runtimeAsset.Get(), "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); + AZ_Assert(m_runtimeOverrides.m_runtimeAsset.Get(), "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run" + , m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); #endif AZ_PROFILE_SCOPE(ScriptCanvas, "RuntimeComponent::InitializeExecution (%s)", m_runtimeOverrides.m_runtimeAsset.GetId().ToString().c_str()); @@ -126,11 +132,13 @@ namespace ScriptCanvas #if defined(SCRIPT_CANVAS_RUNTIME_ASSET_CHECK) if (!m_executionState) { - AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s failed to create an execution state, possibly due to missing dependent asset, script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); + AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s failed to create an execution state, possibly due to missing dependent asset, script will not run" + , m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); return; } #else - AZ_Assert(m_executionState, "RuntimeComponent::m_runtimeAsset AssetId: %s failed to create an execution state, possibly due to missing dependent asset, script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); + AZ_Assert(m_executionState, "RuntimeComponent::m_runtimeAsset AssetId: %s failed to create an execution state, possibly due to missing dependent asset, script will not run" + , m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); #endif AZ::EntityBus::Handler::BusConnect(GetEntityId()); @@ -179,4 +187,3 @@ namespace ScriptCanvas } } -#undef SCRIPT_CANVAS_RUNTIME_ASSET_CHECK From 5ec582484978e61429ccd7a962405c3e9f1ba819 Mon Sep 17 00:00:00 2001 From: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> Date: Fri, 12 Nov 2021 14:16:44 -0800 Subject: [PATCH 17/36] Hide the "up one level" button temporarily. (#5595) Signed-off-by: Danilo Aimini Signed-off-by: Danilo Aimini <82231674+AMZN-daimini@users.noreply.github.com> --- .../UI/Prefab/PrefabViewportFocusPathHandler.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index 920e99665d..c1fc9138d1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -64,6 +64,9 @@ namespace AzToolsFramework::Prefab ); m_backButton->setToolTip("Up one level (-)"); + + // Currently hide this button until we can correctly disable/enable it based on context. + m_backButton->hide(); } void PrefabViewportFocusPathHandler::OnPrefabFocusChanged() From c140b882d25eb92cbf9ea5575fb9383d21d04e86 Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Fri, 12 Nov 2021 14:19:22 -0800 Subject: [PATCH 18/36] Fix mis-spelled comment Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com> --- .../ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h index cc59f90e69..8c5da5ac07 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h @@ -76,7 +76,7 @@ namespace ScriptCanvas AZStd::vector m_activationInputStorage; Execution::ActivationInputRange m_activationInputRange; - // used to initialized statics only once, and not necessarily on the loading thread + // used to initialize statics only once, and not necessarily on the loading thread bool m_areStaticsInitialized = false; bool RequiresStaticInitialization() const; From d0cf18e7789c991e9b42944ce89f1ecbc774737a Mon Sep 17 00:00:00 2001 From: carlitosan <82187351+carlitosan@users.noreply.github.com> Date: Fri, 12 Nov 2021 14:56:27 -0800 Subject: [PATCH 19/36] remove test code artifact Signed-off-by: carlitosan <82187351+carlitosan@users.noreply.github.com> --- .../Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp index bc37bc05f6..930b84abe4 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp @@ -22,11 +22,6 @@ #include #include -namespace AZ -{ - AZ_TYPE_INFO_SPECIALIZE(AZ::Data::Asset, "{D9A4EB57-198B-4A0D-B1FB-D1B11FF88C66}"); -} - AZ_DECLARE_BUDGET(ScriptCanvas); namespace RuntimeComponentCpp From 76b7e73f6f1b34a2499e3d192a7683dc91ce70e2 Mon Sep 17 00:00:00 2001 From: AMZN-nggieber <52797929+AMZN-nggieber@users.noreply.github.com> Date: Fri, 12 Nov 2021 16:23:04 -0800 Subject: [PATCH 20/36] Fully Replaces Remote Gems in Model and Selects Them When Downloading and Deleting (#5593) Signed-off-by: Alex Peterson <26804013+AMZN-alexpete@users.noreply.github.com> --- .../Source/GemCatalog/GemCatalogScreen.cpp | 58 ++++++++++++++----- .../Source/GemCatalog/GemModel.cpp | 24 ++++++-- .../Source/GemCatalog/GemModel.h | 4 +- .../Source/GemRepo/GemRepoScreen.cpp | 2 +- 4 files changed, 68 insertions(+), 20 deletions(-) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 6abbfe16ba..0dacbbb906 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -126,7 +126,8 @@ namespace O3DE::ProjectManager // Select the first entry after everything got correctly sized QTimer::singleShot(200, [=]{ QModelIndex firstModelIndex = m_gemModel->index(0, 0); - m_gemModel->GetSelectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); + QModelIndex proxyIndex = m_proxyModel->mapFromSource(firstModelIndex); + m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); }); } @@ -209,7 +210,7 @@ namespace O3DE::ProjectManager const bool gemFound = gemInfoHash.contains(gemName); if (!gemFound && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index)) { - m_gemModel->removeRow(i); + m_gemModel->RemoveGem(index); } else { @@ -239,7 +240,7 @@ namespace O3DE::ProjectManager m_filterWidget->ResetAllFilters(); // Reselect the same selection to proc UI updates - m_proxyModel->GetSelectionModel()->select(m_proxyModel->GetSelectionModel()->selection(), QItemSelectionModel::Select); + m_proxyModel->GetSelectionModel()->setCurrentIndex(m_proxyModel->GetSelectionModel()->currentIndex(), QItemSelectionModel::Select); } void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) @@ -268,7 +269,7 @@ namespace O3DE::ProjectManager if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded) { m_downloadController->AddGemDownload(GemModel::GetName(modelIndex)); - GemModel::SetDownloadStatus(*m_proxyModel, m_proxyModel->mapFromSource(modelIndex), GemInfo::DownloadStatus::Downloading); + GemModel::SetDownloadStatus(*m_gemModel, modelIndex, GemInfo::DownloadStatus::Downloading); } } @@ -300,7 +301,7 @@ namespace O3DE::ProjectManager } QModelIndex proxyIndex = m_proxyModel->mapFromSource(modelIndex); - m_proxyModel->GetSelectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect); + m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); m_gemListView->scrollTo(proxyIndex); } @@ -362,6 +363,9 @@ namespace O3DE::ProjectManager { const QString selectedGemPath = m_gemModel->GetPath(modelIndex); + // Remove gem from gems to be added + GemModel::SetIsAdded(*m_gemModel, modelIndex, false); + // Unregister the gem auto unregisterResult = PythonBindingsInterface::Get()->UnregisterGem(selectedGemPath); if (!unregisterResult) @@ -370,8 +374,10 @@ namespace O3DE::ProjectManager } else { + const QString selectedGemName = m_gemModel->GetName(modelIndex); + // Remove gem from model - m_gemModel->removeRow(modelIndex.row()); + m_gemModel->RemoveGem(modelIndex); // Delete uninstalled gem directory if (!ProjectUtils::DeleteProjectFiles(selectedGemPath, /*force*/true)) @@ -382,6 +388,11 @@ namespace O3DE::ProjectManager // Show undownloaded remote gem again Refresh(); + + // Select remote gem + QModelIndex remoteGemIndex = m_gemModel->FindIndexByNameString(selectedGemName); + QModelIndex proxyIndex = m_proxyModel->mapFromSource(remoteGemIndex); + m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); } } } @@ -564,7 +575,8 @@ namespace O3DE::ProjectManager if (succeeded) { // refresh the information for downloaded gems - const AZ::Outcome, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath); + const AZ::Outcome, AZStd::string>& allGemInfosResult = + PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath); if (allGemInfosResult.IsSuccess()) { // we should find the gem name now in all gem infos @@ -572,15 +584,33 @@ namespace O3DE::ProjectManager { if (gemInfo.m_name == gemName) { - QModelIndex index = m_gemModel->FindIndexByNameString(gemName); - if (index.isValid()) + QModelIndex oldIndex = m_gemModel->FindIndexByNameString(gemName); + if (oldIndex.isValid()) { - m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadSuccessful, GemModel::RoleDownloadStatus); - m_gemModel->setData(index, gemInfo.m_path, GemModel::RolePath); - m_gemModel->setData(index, gemInfo.m_path, GemModel::RoleDirectoryLink); + // Check if old gem is selected + bool oldGemSelected = false; + if (m_gemModel->GetSelectionModel()->currentIndex() == oldIndex) + { + oldGemSelected = true; + } + + // Remove old remote gem + m_gemModel->RemoveGem(oldIndex); + + // Add new downloaded version of gem + QModelIndex newIndex = m_gemModel->AddGem(gemInfo); + GemModel::SetDownloadStatus(*m_gemModel, newIndex, GemInfo::DownloadSuccessful); + GemModel::SetIsAdded(*m_gemModel, newIndex, true); + + // Select new version of gem if it was previously selected + if (oldGemSelected) + { + QModelIndex proxyIndex = m_proxyModel->mapFromSource(newIndex); + m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); + } } - return; + break; } } } @@ -590,7 +620,7 @@ namespace O3DE::ProjectManager QModelIndex index = m_gemModel->FindIndexByNameString(gemName); if (index.isValid()) { - m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadFailed, GemModel::RoleDownloadStatus); + GemModel::SetDownloadStatus(*m_gemModel, index, GemInfo::DownloadFailed); } } } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 886b9e57c7..95fdc8e1e2 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -26,14 +26,14 @@ namespace O3DE::ProjectManager return m_selectionModel; } - void GemModel::AddGem(const GemInfo& gemInfo) + QModelIndex GemModel::AddGem(const GemInfo& gemInfo) { if (FindIndexByNameString(gemInfo.m_name).isValid()) { // do not add gems with duplicate names // this can happen by mistake or when a gem repo has a gem with the same name as a local gem AZ_TracePrintf("GemModel", "Ignoring duplicate gem: %s", gemInfo.m_name.toUtf8().constData()); - return; + return QModelIndex(); } QStandardItem* item = new QStandardItem(); @@ -67,6 +67,22 @@ namespace O3DE::ProjectManager const QModelIndex modelIndex = index(rowCount()-1, 0); m_nameToIndexMap[gemInfo.m_name] = modelIndex; + + return modelIndex; + } + + void GemModel::RemoveGem(const QModelIndex& modelIndex) + { + removeRow(modelIndex.row()); + } + + void GemModel::RemoveGem(const QString& gemName) + { + auto nameFind = m_nameToIndexMap.find(gemName); + if (nameFind != m_nameToIndexMap.end()) + { + removeRow(nameFind->row()); + } } void GemModel::Clear() @@ -391,11 +407,11 @@ namespace O3DE::ProjectManager // Select a valid row if currently selected row was removed if (selectedRowRemoved) { - for (const QModelIndex& index : m_nameToIndexMap) + for (const QModelIndex& index : m_nameToIndexMap) { if (index.isValid()) { - GetSelectionModel()->select(index, QItemSelectionModel::ClearAndSelect); + GetSelectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); break; } } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 87a718d8c7..bb89d46861 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -55,7 +55,9 @@ namespace O3DE::ProjectManager RoleRepoUri }; - void AddGem(const GemInfo& gemInfo); + QModelIndex AddGem(const GemInfo& gemInfo); + void RemoveGem(const QModelIndex& modelIndex); + void RemoveGem(const QString& gemName); void Clear(); void UpdateGemDependencies(); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 794635a3e3..91432c2346 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -75,7 +75,7 @@ namespace O3DE::ProjectManager // Select the first entry after everything got correctly sized QTimer::singleShot(200, [=]{ QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0); - m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); + m_gemRepoListView->selectionModel()->setCurrentIndex(firstModelIndex, QItemSelectionModel::ClearAndSelect); }); } From 1925d08f41d7888ce246fd6d098de7eed57e4acb Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Sat, 13 Nov 2021 13:52:56 -0600 Subject: [PATCH 21/36] Fixing double registration of hair asset Signed-off-by: Guthrie Adams --- Gems/AtomTressFX/Code/Builders/HairBuilderComponent.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Gems/AtomTressFX/Code/Builders/HairBuilderComponent.cpp b/Gems/AtomTressFX/Code/Builders/HairBuilderComponent.cpp index f80261f4b5..7f99e4c55f 100644 --- a/Gems/AtomTressFX/Code/Builders/HairBuilderComponent.cpp +++ b/Gems/AtomTressFX/Code/Builders/HairBuilderComponent.cpp @@ -46,14 +46,6 @@ namespace AZ { m_hairAssetBuilder.RegisterBuilder(); m_hairAssetHandler.Register(); - - // Add asset types and extensions to AssetCatalog. - auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); - if (assetCatalog) - { - assetCatalog->EnableCatalogForAsset(azrtti_typeid()); - assetCatalog->AddExtension(AMD::TFXCombinedFileExtension); - } } void HairBuilderComponent::Deactivate() From f2068397fa4542bd034e9d34002cca4b976c31b1 Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Mon, 15 Nov 2021 11:51:16 +0100 Subject: [PATCH 22/36] CameraRigComponent - Disable Component Checkbox when the two others are toggled (#5546) * Disable component checkbox when the other two components are already ignored. Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Fixed EditContext Indents Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Fixed Header file Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * Fixed Spaces Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> * fixed new line Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> --- .../SlideAlongAxisBasedOnAngle.cpp | 72 +++++++++++++------ .../SlideAlongAxisBasedOnAngle.h | 10 ++- 2 files changed, 57 insertions(+), 25 deletions(-) diff --git a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp index 5031f149b8..1d8d6adf6c 100644 --- a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp +++ b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp @@ -9,8 +9,8 @@ #include "SlideAlongAxisBasedOnAngle.h" #include "StartingPointCamera/StartingPointCameraUtilities.h" #include -#include #include +#include namespace Camera { @@ -32,31 +32,43 @@ namespace Camera AZ::EditContext* editContext = serializeContext->GetEditContext(); if (editContext) { - editContext->Class("SlideAlongAxisBasedOnAngle", "Slide 0..SlideDistance along Axis based on Angle Type. Maps from 90..-90 degrees") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_axisToSlideAlong, "Axis to slide along", "The Axis to slide along") - ->EnumAttribute(RelativeAxisType::ForwardBackward, "Forwards and Backwards") - ->EnumAttribute(RelativeAxisType::LeftRight, "Right and Left") - ->EnumAttribute(RelativeAxisType::UpDown, "Up and Down") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_angleTypeToChangeFor, "Angle Type", "The angle type to base the slide off of") - ->EnumAttribute(EulerAngleType::Pitch, "Pitch") - ->EnumAttribute(EulerAngleType::Roll, "Roll") - ->EnumAttribute(EulerAngleType::Yaw, "Yaw") - ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumPositiveSlideDistance, "Max Positive Slide Distance", "The maximum distance to slide in the positive") - ->Attribute(AZ::Edit::Attributes::Suffix, "m") - ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumNegativeSlideDistance, "Max Negative Slide Distance", "The maximum distance to slide in the negative") - ->Attribute(AZ::Edit::Attributes::Suffix, "m") - ->ClassElement(AZ::Edit::ClassElements::Group, "Vector Components To Ignore") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreX, "X", "When active, the X Component will be ignored.") - ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreY, "Y", "When active, the Y Component will be ignored.") - ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreZ, "Z", "When active, the Z Component will be ignored.") + editContext->Class("SlideAlongAxisBasedOnAngle", + "Slide 0..SlideDistance along Axis based on Angle Type. Maps from 90..-90 degrees") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_axisToSlideAlong, "Axis to slide along", + "The Axis to slide along") + ->EnumAttribute(RelativeAxisType::ForwardBackward, "Forwards and Backwards") + ->EnumAttribute(RelativeAxisType::LeftRight, "Right and Left") + ->EnumAttribute(RelativeAxisType::UpDown, "Up and Down") + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_angleTypeToChangeFor, "Angle Type", + "The angle type to base the slide off of") + ->EnumAttribute(EulerAngleType::Pitch, "Pitch") + ->EnumAttribute(EulerAngleType::Roll, "Roll") + ->EnumAttribute(EulerAngleType::Yaw, "Yaw") + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumPositiveSlideDistance, "Max Positive Slide Distance", + "The maximum distance to slide in the positive") + ->Attribute(AZ::Edit::Attributes::Suffix, "m") + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumNegativeSlideDistance, "Max Negative Slide Distance", + "The maximum distance to slide in the negative") + ->Attribute(AZ::Edit::Attributes::Suffix, "m") + ->ClassElement(AZ::Edit::ClassElements::Group, "Vector Components To Ignore") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreX, "X", "When active, the X Component will be ignored.") + ->Attribute(AZ::Edit::Attributes::ReadOnly, &SlideAlongAxisBasedOnAngle::YAndZIgnored) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreY, "Y", "When active, the Y Component will be ignored.") + ->Attribute(AZ::Edit::Attributes::ReadOnly, &SlideAlongAxisBasedOnAngle::XAndZIgnored) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreZ, "Z", "When active, the Z Component will be ignored.") + ->Attribute(AZ::Edit::Attributes::ReadOnly, &SlideAlongAxisBasedOnAngle::XAndYIgnored) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ; } } } - void SlideAlongAxisBasedOnAngle::AdjustLookAtTarget([[maybe_unused]] float deltaTime, [[maybe_unused]] const AZ::Transform& targetTransform, AZ::Transform& outLookAtTargetTransform) + void SlideAlongAxisBasedOnAngle::AdjustLookAtTarget( + [[maybe_unused]] float deltaTime, [[maybe_unused]] const AZ::Transform& targetTransform, AZ::Transform& outLookAtTargetTransform) { float angle = GetEulerAngleFromTransform(outLookAtTargetTransform, m_angleTypeToChangeFor); float currentPositionOnRange = -angle / AZ::Constants::HalfPi; @@ -67,4 +79,20 @@ namespace Camera outLookAtTargetTransform.SetTranslation(outLookAtTargetTransform.GetTranslation() + basis * currentPositionOnRange * slideScale); } -} + + bool SlideAlongAxisBasedOnAngle::XAndYIgnored() const + { + return m_ignoreX && m_ignoreY; + } + + bool SlideAlongAxisBasedOnAngle::XAndZIgnored() const + { + return m_ignoreX && m_ignoreZ; + } + + bool SlideAlongAxisBasedOnAngle::YAndZIgnored() const + { + return m_ignoreY && m_ignoreZ; + } + +} // namespace Camera diff --git a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h index 2c756d1ac7..e517b6ffbd 100644 --- a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h +++ b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h @@ -6,11 +6,11 @@ * */ #pragma once -#include -#include -#include #include "StartingPointCamera/StartingPointCameraConstants.h" +#include #include +#include +#include namespace Camera { @@ -38,6 +38,10 @@ namespace Camera void Activate(AZ::EntityId) override {} void Deactivate() override {} + bool XAndYIgnored() const; + bool XAndZIgnored() const; + bool YAndZIgnored() const; + private: ////////////////////////////////////////////////////////////////////////// // Reflected data From d9746647e10a7f9d2a8599063191826e613ad0fc Mon Sep 17 00:00:00 2001 From: Guthrie Adams Date: Mon, 15 Nov 2021 10:54:34 -0600 Subject: [PATCH 23/36] Bug fix for material editor not taking focus when opening a new document from the main editor or outside of the material editor Signed-off-by: Guthrie Adams --- .../Code/Source/Window/AtomToolsMainWindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp index aeca51230a..f07fd9c536 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp @@ -50,8 +50,9 @@ namespace AtomToolsFramework void AtomToolsMainWindow::ActivateWindow() { - activateWindow(); + show(); raise(); + activateWindow(); } bool AtomToolsMainWindow::AddDockWidget(const AZStd::string& name, QWidget* widget, uint32_t area, uint32_t orientation) From c44d03a40df0899851c6cbd929a673fac48ce82b Mon Sep 17 00:00:00 2001 From: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Date: Mon, 15 Nov 2021 09:10:04 -0800 Subject: [PATCH 24/36] Asset bundler test fixes (#5548) * Cleaning up errors with default assets, used in bundled release builds Signed-off-by: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Updated simple asset references to be to the product, not source assets Signed-off-by: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Fixed test_WindowsAndMac_FilesMarkedSkip_FilesAreSkipped to pass again. Updated the test to verify the assets are actually skipped and not just missing, by having it first run without the skip command and verify they are in the first run. Also updated logging to print out sorted lists, to make it easier to debug failures on Jenkins in the future. Signed-off-by: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Removed a test marked skip for legacy levels that featured a lot of assets that are no longer valid. I don't think we need this specific test anymore in the future because prefabs replace the level system, and prefabs should have their own tests for product dependencies. Signed-off-by: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Updated project path to use absolute path (#5459) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Updated project path to work with latest project path changes Signed-off-by: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Changed to workspace.paths.project() for getting full path to projects Signed-off-by: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Co-authored-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- .../bundler_batch_setup_fixture.py | 2 +- .../asset_bundler_batch_tests.py | 277 ++++-------------- 2 files changed, 56 insertions(+), 223 deletions(-) diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py index ff362c732c..9281d5947e 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py @@ -158,7 +158,7 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) -> else: cmd.append(f"--{key}") if append_defaults: - cmd.append(f"--project-path={workspace.project}") + cmd.append(f"--project-path={workspace.paths.project()}") return cmd # ****** diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py index 7f85e5e317..f5e5642573 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py @@ -88,214 +88,6 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): bundler_batch_helper.call_bundles(help="") bundler_batch_helper.call_bundleSeed(help="") - @pytest.mark.BAT - @pytest.mark.assetpipeline - @pytest.mark.test_case_id("C16877175") - @pytest.mark.skip("'animations/animationeditorfiles/sample1.animgraph' missing, needs investigation") - def test_WindowsAndMac_CreateAssetList_DependenciesCorrect(self, workspace, bundler_batch_helper): - r""" - Tests that an asset list created maps dependencies correctly. - testdependencieslevel\level.pak and lists of known dependencies are used for validation - - Test Steps: - 1. Create an asset list from the level.pak - 2. Create Lists of expected assets in the level.pak - 3. Add lists of expected assets to a single list - 4. Compare list of expected assets to actual assets - """ - helper = bundler_batch_helper - - # Create the asset list file - helper.call_assetLists( - addSeed=r"levels\testdependencieslevel\level.pak", - assetListFile=helper['asset_info_file_request'] - ) - - assert os.path.isfile(helper["asset_info_file_result"]) - - # Lists of known relative locations of assets - default_level_assets = [ - "engineassets/texturemsg/defaultnouvs.dds", - "engineassets/texturemsg/defaultnouvs.dds.1", - "engineassets/texturemsg/defaultnouvs.dds.2", - "engineassets/texturemsg/defaultnouvs.dds.3", - "engineassets/texturemsg/defaultnouvs.dds.4", - "engineassets/texturemsg/defaultnouvs.dds.5", - "engineassets/texturemsg/defaultnouvs.dds.6", - "engineassets/texturemsg/defaultnouvs.dds.7", - "engineassets/texturemsg/defaultnouvs_ddn.dds", - "engineassets/texturemsg/defaultnouvs_ddn.dds.1", - "engineassets/texturemsg/defaultnouvs_ddn.dds.2", - "engineassets/texturemsg/defaultnouvs_ddn.dds.3", - "engineassets/texturemsg/defaultnouvs_ddn.dds.4", - "engineassets/texturemsg/defaultnouvs_ddn.dds.5", - "engineassets/texturemsg/defaultnouvs_spec.dds", - "engineassets/texturemsg/defaultnouvs_spec.dds.1", - "engineassets/texturemsg/defaultnouvs_spec.dds.2", - "engineassets/texturemsg/defaultnouvs_spec.dds.3", - "engineassets/texturemsg/defaultnouvs_spec.dds.4", - "engineassets/texturemsg/defaultnouvs_spec.dds.5", - "engineassets/textures/defaults/16_grey.dds", - "engineassets/textures/cubemap/default_level_cubemap.dds", - "engineassets/textures/cubemap/default_level_cubemap.dds.1", - "engineassets/textures/cubemap/default_level_cubemap.dds.2", - "engineassets/textures/cubemap/default_level_cubemap.dds.3", - "engineassets/textures/cubemap/default_level_cubemap.dds.4", - "engineassets/textures/cubemap/default_level_cubemap_diff.dds", - "engineassets/materials/water/ocean_default.mtl", - "engineassets/textures/defaults/spot_default.dds", - "engineassets/textures/defaults/spot_default.dds.1", - "engineassets/textures/defaults/spot_default.dds.2", - "engineassets/textures/defaults/spot_default.dds.3", - "engineassets/textures/defaults/spot_default.dds.4", - "engineassets/textures/defaults/spot_default.dds.5", - "materials/material_terrain_default.mtl", - "textures/skys/night/half_moon.dds", - "textures/skys/night/half_moon.dds.1", - "textures/skys/night/half_moon.dds.2", - "textures/skys/night/half_moon.dds.3", - "textures/skys/night/half_moon.dds.4", - "textures/skys/night/half_moon.dds.5", - "textures/skys/night/half_moon.dds.6", - "engineassets/materials/sky/sky.mtl", - "levels/testdependencieslevel/level.pak", - "levels/testdependencieslevel/terrain/cover.ctc", - "levels/testdependencieslevel/terraintexture.pak", - ] - - sequence_material_cube_assets = [ - "textures/test_texture_sequence/test_texture_sequence000.dds", - "textures/test_texture_sequence/test_texture_sequence001.dds", - "textures/test_texture_sequence/test_texture_sequence002.dds", - "textures/test_texture_sequence/test_texture_sequence003.dds", - "textures/test_texture_sequence/test_texture_sequence004.dds", - "textures/test_texture_sequence/test_texture_sequence005.dds", - "objects/_primitives/_box_1x1.cgf", - "materials/test_texture_sequence.mtl", - "objects/_primitives/_box_1x1.mtl", - "textures/_primitives/middle_gray_checker.dds", - "textures/_primitives/middle_gray_checker.dds.1", - "textures/_primitives/middle_gray_checker.dds.2", - "textures/_primitives/middle_gray_checker.dds.3", - "textures/_primitives/middle_gray_checker.dds.4", - "textures/_primitives/middle_gray_checker.dds.5", - "textures/_primitives/middle_gray_checker_ddn.dds", - "textures/_primitives/middle_gray_checker_ddn.dds.1", - "textures/_primitives/middle_gray_checker_ddn.dds.2", - "textures/_primitives/middle_gray_checker_ddn.dds.3", - "textures/_primitives/middle_gray_checker_ddn.dds.4", - "textures/_primitives/middle_gray_checker_ddn.dds.5", - "textures/_primitives/middle_gray_checker_spec.dds", - "textures/_primitives/middle_gray_checker_spec.dds.1", - "textures/_primitives/middle_gray_checker_spec.dds.2", - "textures/_primitives/middle_gray_checker_spec.dds.3", - "textures/_primitives/middle_gray_checker_spec.dds.4", - "textures/_primitives/middle_gray_checker_spec.dds.5", - ] - - character_with_simplified_material_assets = [ - "objects/characters/jack/jack.actor", - "objects/characters/jack/jack.mtl", - "objects/characters/jack/textures/jack_diff.dds", - "objects/characters/jack/textures/jack_diff.dds.1", - "objects/characters/jack/textures/jack_diff.dds.2", - "objects/characters/jack/textures/jack_diff.dds.3", - "objects/characters/jack/textures/jack_diff.dds.4", - "objects/characters/jack/textures/jack_diff.dds.5", - "objects/characters/jack/textures/jack_diff.dds.6", - "objects/characters/jack/textures/jack_diff.dds.7", - "objects/characters/jack/textures/jack_spec.dds", - "objects/characters/jack/textures/jack_spec.dds.1", - "objects/characters/jack/textures/jack_spec.dds.2", - "objects/characters/jack/textures/jack_spec.dds.3", - "objects/characters/jack/textures/jack_spec.dds.4", - "objects/characters/jack/textures/jack_spec.dds.5", - "objects/characters/jack/textures/jack_spec.dds.6", - "objects/characters/jack/textures/jack_spec.dds.7", - "objects/default/editorprimitive.mtl", - "engineassets/textures/grey.dds", - "animations/animationeditorfiles/sample0.animgraph", - "animations/motions/jack_death_fall_back_zup.motion", - "animations/animationeditorfiles/sample1.animgraph", - "animations/animationeditorfiles/sample0.motionset", - "animations/motions/rin_jump.motion", - "animations/animationeditorfiles/sample1.motionset", - "animations/motions/rin_idle.motion", - "animations/motions/jack_idle_aim_zup.motion", - ] - - spawner_assets = [ - "slices/sphere.dynamicslice", - "objects/default/primitive_sphere.cgf", - "test1.luac", - "test2.luac", - ] - - ui_canvas_assets = [ - "fonts/vera.ttf", - "fonts/vera.font", - "scriptcanvas/mainmenu.scriptcanvas_compiled", - "fonts/vera.fontfamily", - "ui/canvas/start.uicanvas", - "fonts/vera-italic.font", - "ui/textureatlas/sample.texatlasidx", - "fonts/vera-bold-italic.ttf", - "fonts/vera-bold.font", - "ui/textures/prefab/button_normal.dds", - "ui/textures/prefab/button_normal.sprite", - "fonts/vera-italic.ttf", - "ui/textureatlas/sample.dds", - "fonts/vera-bold-italic.font", - "fonts/vera-bold.ttf", - "ui/textures/prefab/button_disabled.dds", - "ui/textures/prefab/button_disabled.sprite", - ] - - wwise_and_atl_assets = [ - "libs/gameaudio/wwise/levels/testdependencieslevel/test_dependencies_level.xml", - "sounds/wwise/test_bank3.bnk", - "sounds/wwise/test_bank4.bnk", - "sounds/wwise/test_bank5.bnk", - "sounds/wwise/test_bank1.bnk", - "sounds/wwise/init.bnk", - "sounds/wwise/499820003.wem", - "sounds/wwise/196049145.wem", - ] - - particle_library_assets = [ - "libs/particles/milestone2particles.xml", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds.1", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds.2", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds.3", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds.4", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds.5", - "textures/milestone2/particles/fx_sparkstreak_01.dds", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.1", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.2", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.3", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.4", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.5", - ] - - lens_flares_library_assets = ["libs/flares/flares.xml", "textures/lights/flare01.dds"] - - expected_assets_list = default_level_assets - expected_assets_list.extend(sequence_material_cube_assets) - expected_assets_list.extend(character_with_simplified_material_assets) - expected_assets_list.extend(spawner_assets) - expected_assets_list.extend(ui_canvas_assets) - expected_assets_list.extend(wwise_and_atl_assets) - expected_assets_list.extend(particle_library_assets) - expected_assets_list.extend(lens_flares_library_assets) # All expected assets - - # Get actual calculated dependencies from the asset list created - actual_assets_list = [] - for rel_path in helper.get_asset_relative_paths(helper["asset_info_file_result"]): - actual_assets_list.append(rel_path) - - assert sorted(actual_assets_list) == sorted(expected_assets_list) @pytest.mark.BAT @pytest.mark.assetpipeline @@ -310,9 +102,9 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): 3. Read and store contents of asset list into memory 4. Attempt to create a new asset list in without using --allowOverwrites 5. Verify that Asset Bundler returns false - 6. Verify that file contents of the orignally created asset list did not change from what was stored in memory + 6. Verify that file contents of the originally created asset list did not change from what was stored in memory 7. Attempt to create a new asset list without debug while allowing overwrites - 8. Verify that file contents of the orignally created asset list changed from what was stored in memory + 8. Verify that file contents of the originally created asset list changed from what was stored in memory """ helper = bundler_batch_helper seed_list = os.path.join(workspace.paths.engine_root(), "Assets", "Engine", "SeedAssetList.seed") # Engine seed list @@ -919,7 +711,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): # Extra arguments for pattern comparison cmd.extend([f"--filePatternType={pattern_type}", f"--filePattern={pattern}"]) if workspace.project: - cmd.append(f'--project-path={project_name}') + cmd.append(f'--project-path={workspace.paths.project()}') return cmd # End generate_compare_command() @@ -960,7 +752,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): output_mac_asset_list = helper.platform_file_name(last_output_arg, platform) # Build execution command - cmd = generate_compare_command(platform_arg, workspace.project) + cmd = generate_compare_command(platform_arg, workspace.paths.project()) # Execute command subprocess.check_call(cmd) @@ -995,7 +787,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): f"--comparisonRulesFile={rule_file}", f"--comparisonType={args[1]}", r"--addComparison", - f"--project-path={workspace.project}", + f"--project-path={workspace.paths.project()}", ] if args[1] == "4": # If pattern comparison, append a few extra arguments @@ -1117,7 +909,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): "--addDefaultSeedListFiles", "--platform=pc", "--print", - f"--project-path={workspace.project}" + f"--project-path={workspace.paths.project()}" ], universal_newlines=True, ) @@ -1189,7 +981,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): # Make sure file gets deleted on teardown request.addfinalizer(lambda: fs.delete([bundle_result_path], True, False)) - bundles_folder = os.path.join(workspace.paths.engine_root(), workspace.project, "Bundles") + bundles_folder = os.path.join(workspace.paths.project(), "Bundles") level_pak = r"levels\testdependencieslevel\level.pak" bundle_request_path = os.path.join(bundles_folder, "bundle.pak") bundle_result_path = os.path.join(bundles_folder, @@ -1243,23 +1035,64 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): 2. Verify file was created 3. Verify that only the expected assets are present in the created asset list """ - expected_assets = [ + expected_assets = sorted([ "ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas", - "ui/textures/prefab/button_normal.sprite" - ] + "ui/textures/prefab/button_disabled.tif.streamingimage", + "ui/textures/prefab/tooltip_sliced.tif.streamingimage", + "ui/textures/prefab/button_normal.tif.streamingimage" + ]) + # Printing these lists out can save a step in debugging if this test fails on Jenkins. + logger.info(f"expected_assets: {expected_assets}") + + skip_assets = sorted([ + "ui/scripts/lyshineexamples/animation/multiplesequences.luac", + "ui/scripts/lyshineexamples/unloadthiscanvasbutton.luac", + "fonts/vera.fontfamily", + "fonts/vera-italic.font", + "fonts/vera.font", + "fonts/vera-bold.font", + "fonts/vera-bold-italic.font", + "fonts/vera-italic.ttf", + "fonts/vera.ttf", + "fonts/vera-bold.ttf", + "fonts/vera-bold-italic.ttf" + ]) + logger.info(f"skip_assets: {skip_assets}") + + expected_and_skip_assets = sorted(expected_assets + skip_assets) + # Printing both together to make it quick to compare the results in the logs for a test failure on Jenkins + logger.info(f"expected_and_skip_assets: {expected_and_skip_assets}") + + # First, generate an asset info file without skipping, to get a list that can be used as a baseline to verify + # the files were actually skipped, and not just missing. + bundler_batch_helper.call_assetLists( + assetListFile=bundler_batch_helper['asset_info_file_request'], + addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas" + ) + assert os.path.isfile(bundler_batch_helper["asset_info_file_result"]) + assets_in_no_skip_list = [] + for rel_path in bundler_batch_helper.get_asset_relative_paths(bundler_batch_helper["asset_info_file_result"]): + assets_in_no_skip_list.append(rel_path) + assets_in_no_skip_list = sorted(assets_in_no_skip_list) + logger.info(f"assets_in_no_skip_list: {assets_in_no_skip_list}") + assert assets_in_no_skip_list == expected_and_skip_assets + + # Now generate an asset info file using the skip command, and verify the skip files are not in the list. bundler_batch_helper.call_assetLists( assetListFile=bundler_batch_helper['asset_info_file_request'], addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas", - skip="ui/textures/prefab/button_disabled.sprite,ui/scripts/lyshineexamples/animation/multiplesequences.luac," - "ui/textures/prefab/tooltip_sliced.sprite,ui/scripts/lyshineexamples/unloadthiscanvasbutton.luac,fonts/vera.fontfamily,fonts/vera-italic.font," - "fonts/vera.font,fonts/vera-bold.font,fonts/vera-bold-italic.font,fonts/vera-italic.ttf,fonts/vera.ttf,fonts/vera-bold.ttf,fonts/vera-bold-italic.ttf" + allowOverwrites="", + skip=','.join(skip_assets) ) + assert os.path.isfile(bundler_batch_helper["asset_info_file_result"]) assets_in_list = [] for rel_path in bundler_batch_helper.get_asset_relative_paths(bundler_batch_helper["asset_info_file_result"]): assets_in_list.append(rel_path) + assets_in_list = sorted(assets_in_list) + logger.info(f"assets_in_list: {assets_in_list}") + assert assets_in_list == expected_assets - assert sorted(assets_in_list) == sorted(expected_assets) @pytest.mark.BAT @pytest.mark.assetpipeline From 533b80095b48857e02f4bfeba5a0ecfd1ad85b16 Mon Sep 17 00:00:00 2001 From: mrieggeramzn <61609885+mrieggeramzn@users.noreply.github.com> Date: Mon, 15 Nov 2021 10:16:06 -0800 Subject: [PATCH 25/36] Fix for cascade shadow map clipping out too close to the camera (#5509) Signed-off-by: mrieggeramzn --- .../Atom/Features/Shadow/DirectionalLightShadow.azsli | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli index a7122aaf3a..59817af701 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli @@ -166,7 +166,7 @@ float DirectionalLightShadow::GetThickness(uint lightIndex, float3 shadowCoords[ bool2 DirectionalLightShadow::IsShadowed(float3 shadowCoord, uint indexOfCascade) { static const float PixelMargin = 1.5; // avoiding artifact between cascade levels. - static const float DepthMargin = 0.01; // avoiding artifact when near depth bounds. + static const float DepthMargin = 1e-8; // avoiding artifact when near depth bounds. // size is the shadowap's width and height. const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize; @@ -210,8 +210,8 @@ float DirectionalLightShadow::GetVisibilityFromLightNoFilter() float DirectionalLightShadow::GetVisibilityFromLightPcf() { - static const float DepthMargin = 0.01; // avoiding artifact when near depth bounds. static const float PixelMargin = 1.5; // avoiding artifact between cascade levels. + static const float DepthMargin = 1e-8; // avoiding artifact when near depth bounds. const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize; const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount; From 5c0fe6a54f14d1770334679e0457702a37a946c2 Mon Sep 17 00:00:00 2001 From: mrieggeramzn <61609885+mrieggeramzn@users.noreply.github.com> Date: Mon, 15 Nov 2021 10:16:25 -0800 Subject: [PATCH 26/36] Fix for CSM shimmering (#5607) * Fix for CSM shimmering Signed-off-by: mrieggeramzn * removing debug code Signed-off-by: mrieggeramzn --- .../DirectionalLightFeatureProcessor.cpp | 46 ++++++++++++++++--- .../DirectionalLightFeatureProcessor.h | 3 ++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index 410c80dbdc..ce5d3cc363 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -1248,6 +1248,32 @@ namespace AZ property.m_shadowmapViewNeedsUpdate = true; } + float DirectionalLightFeatureProcessor::GetShadowmapSizeFromCameraView(const LightHandle handle, const RPI::View* cameraView) const + { + const DirectionalLightShadowData& shadowData = m_shadowData.at(cameraView).GetData(handle.GetIndex()); + return static_cast(shadowData.m_shadowmapSize); + } + + void DirectionalLightFeatureProcessor::SnapAabbToPixelIncrements(const float invShadowmapSize, Vector3& orthoMin, Vector3& orthoMax) + { + // This function stops the cascaded shadowmap from shimmering as the camera moves. + // See CascadedShadowsManager.cpp in the Microsoft CascadedShadowMaps11 sample for details. + + const Vector3 normalizeByBufferSize = Vector3(invShadowmapSize, invShadowmapSize, invShadowmapSize); + + const Vector3 worldUnitsPerTexel = (orthoMax - orthoMin) * normalizeByBufferSize; + + // We snap the camera to 1 pixel increments so that moving the camera does not cause the shadows to jitter. + // This is a matter of dividing by the world space size of a texel + orthoMin /= worldUnitsPerTexel; + orthoMin = orthoMin.GetFloor(); + orthoMin *= worldUnitsPerTexel; + + orthoMax /= worldUnitsPerTexel; + orthoMax = orthoMax.GetFloor(); + orthoMax *= worldUnitsPerTexel; + } + void DirectionalLightFeatureProcessor::UpdateShadowmapViews(LightHandle handle) { ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex()); @@ -1259,18 +1285,26 @@ namespace AZ for (auto& segmentIt : property.m_segments) { + const float invShadowmapSize = 1.0f / GetShadowmapSizeFromCameraView(handle, segmentIt.first); + for (uint16_t cascadeIndex = 0; cascadeIndex < segmentIt.second.size(); ++cascadeIndex) { - const Aabb viewAabb = CalculateShadowViewAabb( - handle, segmentIt.first, cascadeIndex, lightTransform); + const Aabb viewAabb = CalculateShadowViewAabb(handle, segmentIt.first, cascadeIndex, lightTransform); if (viewAabb.IsValid() && viewAabb.IsFinite()) { + const float cascadeNear = viewAabb.GetMin().GetY(); + const float cascadeFar = viewAabb.GetMax().GetY(); + + Vector3 snappedAabbMin = viewAabb.GetMin(); + Vector3 snappedAabbMax = viewAabb.GetMax(); + + SnapAabbToPixelIncrements(invShadowmapSize, snappedAabbMin, snappedAabbMax); + Matrix4x4 viewToClipMatrix = Matrix4x4::CreateIdentity(); - MakeOrthographicMatrixRH(viewToClipMatrix, - viewAabb.GetMin().GetElement(0), viewAabb.GetMax().GetElement(0), - viewAabb.GetMin().GetElement(2), viewAabb.GetMax().GetElement(2), - viewAabb.GetMin().GetElement(1), viewAabb.GetMax().GetElement(1)); + MakeOrthographicMatrixRH( + viewToClipMatrix, snappedAabbMin.GetElement(0), snappedAabbMax.GetElement(0), snappedAabbMin.GetElement(2), + snappedAabbMax.GetElement(2), cascadeNear, cascadeFar); CascadeSegment& segment = segmentIt.second[cascadeIndex]; segment.m_aabb = viewAabb; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h index 8d7a9d76e4..77f2db38d6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h @@ -341,6 +341,9 @@ namespace AZ //! This draws bounding boxes of cascades. void DrawCascadeBoundingBoxes(LightHandle handle); + float GetShadowmapSizeFromCameraView(const LightHandle handle, const RPI::View* cameraView) const; + void SnapAabbToPixelIncrements(const float invShadowmapSize, Vector3& orthoMin, Vector3& orthoMax); + IndexedDataVector m_shadowProperties; // [GFX TODO][ATOM-2012] shadow for multiple directional lights LightHandle m_shadowingLightHandle; From b3e2c3f075db1f28277c0a35987318449b4eeeb9 Mon Sep 17 00:00:00 2001 From: Mikhail Naumov <82239319+AMZN-mnaumov@users.noreply.github.com> Date: Mon, 15 Nov 2021 13:01:42 -0600 Subject: [PATCH 27/36] SetComponentProperty is now supported by undo operation (#5599) * Adding undo support to SetComponentProperty to make it function with prefab system Signed-off-by: Mikhail Naumov * Renaming a variable Signed-off-by: Mikhail Naumov * PR feedback Signed-off-by: Mikhail Naumov --- .../AzToolsFramework/Component/EditorComponentAPIComponent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp index 2cca3804ea..20a15643c6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp @@ -597,11 +597,13 @@ namespace AzToolsFramework pte.SetVisibleEnforcement(true); } + ScopedUndoBatch undo("Modify Entity Property"); PropertyOutcome result = pte.SetProperty(propertyPath, value); if (result.IsSuccess()) { PropertyEditorEntityChangeNotificationBus::Event(componentInstance.GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, componentInstance.GetComponentId()); } + undo.MarkEntityDirty(componentInstance.GetEntityId()); return result; } From fc547d902c2e110b671a095b9731aff18154e68d Mon Sep 17 00:00:00 2001 From: amzn-sj Date: Mon, 15 Nov 2021 12:09:43 -0800 Subject: [PATCH 28/36] Add message to indicate Json serialization of bitset is not supported (#5590) Signed-off-by: amzn-sj --- .../AzCore/Serialization/Json/JsonSystemComponent.cpp | 2 ++ .../Serialization/Json/UnsupportedTypesSerializer.cpp | 7 +++++++ .../Serialization/Json/UnsupportedTypesSerializer.h | 10 ++++++++++ 3 files changed, 19 insertions(+) diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp index da02e70181..0ba44e4e61 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp @@ -104,6 +104,8 @@ namespace AZ ->HandlesType(); jsonContext->Serializer() ->HandlesType(); + jsonContext->Serializer() + ->HandlesType(); MathReflect(jsonContext); } diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp index 2392ff435f..ad1839f974 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp @@ -15,6 +15,7 @@ namespace AZ AZ_CLASS_ALLOCATOR_IMPL(JsonAnySerializer, SystemAllocator, 0); AZ_CLASS_ALLOCATOR_IMPL(JsonVariantSerializer, SystemAllocator, 0); AZ_CLASS_ALLOCATOR_IMPL(JsonOptionalSerializer, SystemAllocator, 0); + AZ_CLASS_ALLOCATOR_IMPL(JsonBitsetSerializer, SystemAllocator, 0); JsonSerializationResult::Result JsonUnsupportedTypesSerializer::Load(void*, const Uuid&, const rapidjson::Value&, JsonDeserializerContext& context) @@ -49,4 +50,10 @@ namespace AZ return "The Json Serialization doesn't support AZStd::optional by design. No JSON format has yet been found that wasn't deemed too " "complex or overly verbose."; } + + AZStd::string_view JsonBitsetSerializer::GetMessage() const + { + return "The Json Serialization doesn't support AZStd::bitset by design. No JSON format has yet been found that is content creator " + "friendly i.e., easy to comprehend the intent."; + } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h index d913289d3d..fdcac4c761 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h @@ -65,4 +65,14 @@ namespace AZ protected: AZStd::string_view GetMessage() const override; }; + + class JsonBitsetSerializer : public JsonUnsupportedTypesSerializer + { + public: + AZ_RTTI(JsonBitsetSerializer, "{10CE969D-D69E-4B3F-8593-069736F8F705}", JsonUnsupportedTypesSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + protected: + AZStd::string_view GetMessage() const override; + }; } // namespace AZ From 8b7e538dd32f1eb3a96bedd225dfd6fc861f1ed3 Mon Sep 17 00:00:00 2001 From: amzn-mike <80125227+amzn-mike@users.noreply.github.com> Date: Mon, 15 Nov 2021 16:14:43 -0600 Subject: [PATCH 29/36] Cherry Pick: [LYN-7463] Fix insert streaming request failure (#5604) (#5622) * Fix race condition where asset would finish loading and another request would start before the streamer request could be cleared Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Re-enable disabled test which was failing for the same reason. Fix test timeout which was way too long. Reduce test iterations to keep test time safely under 5 seconds. Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> * Instead of using a mutex, re-order the statements to remove the streamer request first Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> (cherry picked from commit 0cea59d66998585f07c54e55f68dd117363fb4ea) Signed-off-by: amzn-mike <80125227+amzn-mike@users.noreply.github.com> --- Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp | 6 +++++- .../AzCore/Tests/Asset/AssetManagerLoadingTests.cpp | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp index 06bb0b0cac..b03e1affdc 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp @@ -1677,9 +1677,13 @@ namespace AZ // they will trigger a ReleaseAsset call sometime after the AssetManager has begun to shut down, which can lead to // race conditions. + // Make sure the streamer request is removed first before the asset is released + // If the asset is released first it could lead to a race condition where another thread starts loading the asset + // again and attempts to add a new streamer request with the same ID before the old one has been removed, causing + // that load request to fail + RemoveActiveStreamerRequest(assetId); weakAsset = {}; loadingAsset.Reset(); - RemoveActiveStreamerRequest(assetId); }; auto&& [deadline, priority] = GetEffectiveDeadlineAndPriority(*handler, asset.GetType(), loadParams); diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index e33dbce9c1..3f2d9491a7 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -652,7 +652,7 @@ namespace UnitTest threads.emplace_back([this, &threadCount, &cv, assetUuid]() { bool checkLoaded = true; - for (int i = 0; i < 5000; i++) + for (int i = 0; i < 1000; i++) { Asset asset1 = m_testAssetManager->GetAsset(assetUuid, azrtti_typeid(), AZ::Data::AssetLoadBehavior::PreLoad); @@ -678,7 +678,7 @@ namespace UnitTest while (threadCount > 0 && !timedOut) { AZStd::unique_lock lock(mutex); - timedOut = (AZStd::cv_status::timeout == cv.wait_until(lock, AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds * 20000)); + timedOut = (AZStd::cv_status::timeout == cv.wait_until(lock, AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds)); } ASSERT_EQ(threadCount, 0) << "Thread count is non-zero, a thread has likely deadlocked. Test will not shut down cleanly."; @@ -1190,7 +1190,7 @@ namespace UnitTest #if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) #else - TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) + TEST_F(AssetJobsFloodTest, ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) #endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS { m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect(); From e1fb2ad368ca933fe6e299df5aeeb328e301c8be Mon Sep 17 00:00:00 2001 From: allisaurus <34254888+allisaurus@users.noreply.github.com> Date: Mon, 15 Nov 2021 14:48:32 -0800 Subject: [PATCH 30/36] Update resource mapping schema to make default account ID optional (#5475) Signed-off-by: Stanko --- .../aws_metrics_automation_test.py | 54 +++++++++++++++++++ .../core/test_aws_resource_interaction.py | 49 +++++++++++++++++ .../AWS/common/resource_mappings.py | 14 +++++ .../AWSResourceMappingConstants.h | 2 +- .../AWSResourceMappingManagerTest.cpp | 43 +++++++++++++++ 5 files changed, 161 insertions(+), 1 deletion(-) diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py index 34b2217916..6f3113d771 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py @@ -14,6 +14,7 @@ from datetime import datetime import ly_test_tools.log.log_monitor from AWS.common import constants +from AWS.common.resource_mappings import AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY from .aws_metrics_custom_thread import AWSMetricsThread # fixture imports @@ -200,6 +201,59 @@ class TestAWSMetricsWindows(object): for thread in operational_threads: thread.join() + @pytest.mark.parametrize('level', ['AWS/Metrics']) + def test_realtime_and_batch_analytics_no_global_accountid(self, + level: str, + launcher: pytest.fixture, + asset_processor: pytest.fixture, + workspace: pytest.fixture, + aws_utils: pytest.fixture, + resource_mappings: pytest.fixture, + aws_metrics_utils: pytest.fixture): + """ + Verify that the metrics events are sent to CloudWatch and S3 for analytics. + """ + # Remove top-level account ID from resource mappings + resource_mappings.clear_select_keys([AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY]) + # Start Kinesis analytics application on a separate thread to avoid blocking the test. + kinesis_analytics_application_thread = AWSMetricsThread(target=update_kinesis_analytics_application_status, + args=(aws_metrics_utils, resource_mappings, True)) + kinesis_analytics_application_thread.start() + + log_monitor = setup(launcher, asset_processor) + + # Kinesis analytics application needs to be in the running state before we start the game launcher. + kinesis_analytics_application_thread.join() + launcher.args = ['+LoadLevel', level] + launcher.args.extend(['-rhi=null']) + start_time = datetime.utcnow() + with launcher.start(launch_ap=False): + monitor_metrics_submission(log_monitor) + + # Verify that real-time analytics metrics are delivered to CloudWatch. + aws_metrics_utils.verify_cloud_watch_delivery( + AWS_METRICS_FEATURE_NAME, + 'TotalLogins', + [], + start_time) + logger.info('Real-time metrics are sent to CloudWatch.') + + # Run time-consuming operations on separate threads to avoid blocking the test. + operational_threads = list() + operational_threads.append( + AWSMetricsThread(target=query_metrics_from_s3, + args=(aws_metrics_utils, resource_mappings))) + operational_threads.append( + AWSMetricsThread(target=verify_operational_metrics, + args=(aws_metrics_utils, resource_mappings, start_time))) + operational_threads.append( + AWSMetricsThread(target=update_kinesis_analytics_application_status, + args=(aws_metrics_utils, resource_mappings, False))) + for thread in operational_threads: + thread.start() + for thread in operational_threads: + thread.join() + @pytest.mark.parametrize('level', ['AWS/Metrics']) def test_unauthorized_user_request_rejected(self, level: str, diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py index 949186ad50..59c517fd1c 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py @@ -18,6 +18,7 @@ import ly_test_tools.environment.process_utils as process_utils import ly_test_tools.o3de.asset_processor_utils as asset_processor_utils from AWS.common import constants +from AWS.common.resource_mappings import AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY # fixture imports from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor @@ -141,3 +142,51 @@ class TestAWSCoreAWSResourceInteraction(object): 'The expected file wasn\'t successfully downloaded.' # clean up the file directories. shutil.rmtree(s3_download_dir) + + @pytest.mark.parametrize('expected_lines', [ + ['(Script) - [S3] Head object request is done', + '(Script) - [S3] Head object success: Object example.txt is found.', + '(Script) - [S3] Get object success: Object example.txt is downloaded.', + '(Script) - [Lambda] Completed Invoke', + '(Script) - [Lambda] Invoke success: {"statusCode": 200, "body": {}}', + '(Script) - [DynamoDB] Results finished']]) + @pytest.mark.parametrize('unexpected_lines', [ + ['(Script) - [S3] Head object error: No response body.', + '(Script) - [S3] Get object error: Request validation failed, output file directory doesn\'t exist.', + '(Script) - Request validation failed, output file miss full path.', + '(Script) - ']]) + def test_scripting_behavior_no_global_accountid(self, + level: str, + launcher: pytest.fixture, + workspace: pytest.fixture, + asset_processor: pytest.fixture, + resource_mappings: pytest.fixture, + aws_utils: pytest.fixture, + expected_lines: typing.List[str], + unexpected_lines: typing.List[str]): + """ + Setup: Updates resource mapping file using existing CloudFormation stacks. + Tests: Interact with AWS S3, DynamoDB and Lambda services. + Verification: Script canvas nodes can communicate with AWS services successfully. + """ + + resource_mappings.clear_select_keys([AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY]) + log_monitor, s3_download_dir = setup(launcher, asset_processor) + write_test_data_to_dynamodb_table(resource_mappings, aws_utils) + + launcher.args = ['+LoadLevel', level] + launcher.args.extend(['-rhi=null']) + + with launcher.start(launch_ap=False): + result = log_monitor.monitor_log_for_lines( + expected_lines=expected_lines, + unexpected_lines=unexpected_lines, + halt_on_unexpected=True + ) + + assert result, "Expected lines weren't found." + + assert os.path.exists(os.path.join(s3_download_dir, 'output.txt')), \ + 'The expected file wasn\'t successfully downloaded.' + # clean up the file directories. + shutil.rmtree(s3_download_dir) diff --git a/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py b/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py index 5f01ecdbf8..988d5bf1fc 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py @@ -102,3 +102,17 @@ class ResourceMappings: def get_resource_name_id(self, resource_key: str): return self._resource_mappings[AWS_RESOURCE_MAPPINGS_KEY][resource_key]['Name/ID'] + + def clear_select_keys(self, resource_keys=None) -> None: + """ + Clears values from select resource mapping keys. + :param resource_keys: list of keys to clear out + """ + with open(self._resource_mapping_file_path) as file_content: + resource_mappings = json.load(file_content) + + for key in resource_keys: + resource_mappings[key] = '' + + with open(self._resource_mapping_file_path, 'w') as file_content: + json.dump(resource_mappings, file_content, indent=4) \ No newline at end of file diff --git a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h index 97eb5b6492..a3d18c1ea1 100644 --- a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h +++ b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h @@ -68,7 +68,7 @@ namespace AWSCore }, "AccountIdString": { "type": "string", - "pattern": "^[0-9]{12}$|EMPTY" + "pattern": "^[0-9]{12}$|EMPTY|^$" }, "NonEmptyString": { "type": "string", diff --git a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp index fb03dea4c0..a90518006f 100644 --- a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp +++ b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp @@ -59,6 +59,34 @@ R"({ "Version": "1.0.0" })"; +static constexpr const char TEST_VALID_EMPTY_ACCOUNTID_RESOURCE_MAPPING_CONFIG_FILE[] = + R"({ + "AWSResourceMappings": { + "TestLambda": { + "Type": "AWS::Lambda::Function", + "Name/ID": "MyTestLambda", + "Region": "us-east-1", + "AccountId": "012345678912" + }, + "TestS3Bucket": { + "Type": "AWS::S3::Bucket", + "Name/ID": "MyTestS3Bucket" + }, + "TestService.RESTApiId": { + "Type": "AWS::ApiGateway::RestApi", + "Name/ID": "1234567890" + }, + "TestService.RESTApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Name/ID": "prod", + "Region": "us-east-1" + } + }, + "AccountId": "", + "Region": "us-west-2", + "Version": "1.0.0" +})"; + static constexpr const char TEST_INVALID_RESOURCE_MAPPING_CONFIG_FILE[] = R"({ "AWSResourceMappings": {}, @@ -237,6 +265,21 @@ TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_Confi EXPECT_TRUE(actualEbusCalls == testThreadNumber); } +TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_GlobalAccountIdEmpty) +{ + CreateTestConfigFile(TEST_VALID_EMPTY_ACCOUNTID_RESOURCE_MAPPING_CONFIG_FILE); + m_resourceMappingManager->ActivateManager(); + + AZStd::string actualAccountId; + AZStd::string actualRegion; + AWSResourceMappingRequestBus::BroadcastResult(actualAccountId, &AWSResourceMappingRequests::GetDefaultAccountId); + AWSResourceMappingRequestBus::BroadcastResult(actualRegion, &AWSResourceMappingRequests::GetDefaultRegion); + EXPECT_EQ(m_reloadConfigurationCounter, 0); + EXPECT_TRUE(actualAccountId.empty()); + EXPECT_FALSE(actualRegion.empty()); + EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::Ready); +} + TEST_F(AWSResourceMappingManagerTest, DeactivateManager_AfterActivatingWithValidConfigFile_ConfigDataGetCleanedUp) { CreateTestConfigFile(TEST_VALID_RESOURCE_MAPPING_CONFIG_FILE); From 7031147e324602fb20fcfe2070a942bf9eb4594a Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Mon, 15 Nov 2021 17:01:47 -0600 Subject: [PATCH 31/36] Added event to signal when the Editor is fully initialized so test scripts can listen for that instead of needed arbitrary wait commands. (#5623) Signed-off-by: Chris Galvan --- Code/Editor/CryEdit.cpp | 2 ++ .../AzToolsFramework/API/ToolsApplicationAPI.h | 3 +++ .../AzToolsFramework/Application/ToolsApplication.cpp | 8 +++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 4008710786..b77c6c4b3a 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -4181,6 +4181,8 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[]) "\nThis could be because of incorrectly configured components, or missing required gems." "\nSee other errors for more details."); + AzToolsFramework::EditorEventsBus::Broadcast(&AzToolsFramework::EditorEvents::NotifyEditorInitialized); + if (didCryEditStart) { app->EnableOnIdle(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h index fd4196a296..282898c37d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h @@ -927,6 +927,9 @@ namespace AzToolsFramework /// Notify that the MainWindow has been fully initialized virtual void NotifyMainWindowInitialized(QMainWindow* /*mainWindow*/) {} + /// Notify that the Editor has been fully initialized + virtual void NotifyEditorInitialized() {} + /// Signal that an asset should be highlighted / selected virtual void SelectAsset(const QString& /* assetPath */) {} }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index 3c7495e836..056872edab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -214,12 +214,17 @@ namespace AzToolsFramework , public AZ::BehaviorEBusHandler { AZ_EBUS_BEHAVIOR_BINDER(EditorEventsBusHandler, "{352F80BB-469A-40B6-B322-FE57AB51E4DA}", AZ::SystemAllocator, - NotifyRegisterViews); + NotifyRegisterViews, NotifyEditorInitialized); void NotifyRegisterViews() override { Call(FN_NotifyRegisterViews); } + + void NotifyEditorInitialized() override + { + Call(FN_NotifyEditorInitialized); + } }; } // Internal @@ -443,6 +448,7 @@ namespace AzToolsFramework ->Attribute(AZ::Script::Attributes::Module, "editor") ->Handler() ->Event("NotifyRegisterViews", &EditorEvents::NotifyRegisterViews) + ->Event("NotifyEditorInitialized", &EditorEvents::NotifyEditorInitialized) ; behaviorContext->EBus("ViewPaneCallbackBus") From a5adf33427e3b2163c2f21c75148598b3364d8d4 Mon Sep 17 00:00:00 2001 From: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> Date: Tue, 16 Nov 2021 11:47:02 +0100 Subject: [PATCH 32/36] Deactivate new Asset Picker View by default in the Editor (#5614) Signed-off-by: AMZN-Igarri <82394219+AMZN-Igarri@users.noreply.github.com> --- .../AssetBrowser/AssetPicker/AssetPickerDialog.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp index 4ebeb03a71..eae8ec2a1e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp @@ -31,7 +31,10 @@ AZ_POP_DISABLE_WARNING AZ_CVAR( bool, ed_hideAssetPickerPathColumn, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Hide AssetPicker path column for a clearer view."); -AZ_CVAR_EXTERNED(bool, ed_useNewAssetBrowserTableView); + +AZ_CVAR( + bool, ed_useNewAssetPickerView, false, nullptr, AZ::ConsoleFunctorFlags::Null, + "Uses the new Asset Picker View."); namespace AzToolsFramework { @@ -106,7 +109,7 @@ namespace AzToolsFramework m_persistentState = AZ::UserSettings::CreateFind(AZ::Crc32(("AssetBrowserTreeView_Dialog_" + name).toUtf8().data()), AZ::UserSettings::CT_GLOBAL); m_ui->m_assetBrowserTableViewWidget->setVisible(false); - if (ed_useNewAssetBrowserTableView) + if (ed_useNewAssetPickerView) { m_ui->m_assetBrowserTreeViewWidget->setVisible(false); m_ui->m_assetBrowserTableViewWidget->setVisible(true); From 7da0913900b6c93a0dfaa77f6880316ac70e7852 Mon Sep 17 00:00:00 2001 From: amzn-sean <75276488+amzn-sean@users.noreply.github.com> Date: Tue, 16 Nov 2021 10:57:32 +0000 Subject: [PATCH 33/36] Fixed empty cluster UI appearing in joints component mode. (#5547) Happens if 'limits' or 'breakable' settings are off on the joint when entering component mode. Signed-off-by: amzn-sean <75276488+amzn-sean@users.noreply.github.com> --- .../Joints/JointsComponentMode.cpp | 128 +++++++++++------- 1 file changed, 78 insertions(+), 50 deletions(-) diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp index ce95e27db3..08e31a89f0 100644 --- a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp @@ -307,7 +307,16 @@ namespace PhysX AZStd::vector JointsComponentMode::PopulateViewportUiImpl() { - return AZStd::vector(m_modeSelectionClusterIds.begin(), m_modeSelectionClusterIds.end()); + AZStd::vector ids; + ids.reserve(m_modeSelectionClusterIds.size()); + for (auto clusterid : m_modeSelectionClusterIds) + { + if (clusterid != AzToolsFramework::ViewportUi::InvalidClusterId) + { + ids.emplace_back(clusterid); + } + } + return ids; } void JointsComponentMode::SetCurrentMode(JointsComponentModeCommon::SubComponentModes::ModeType newMode, ButtonData& buttonData) @@ -353,31 +362,64 @@ namespace PhysX void JointsComponentMode::SetupSubModes(const AZ::EntityComponentIdPair& entityComponentIdPair) { - //create the 3 cluster groups - for (auto& clusterId : m_modeSelectionClusterIds) - { - AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( - clusterId, AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, - AzToolsFramework::ViewportUi::Alignment::TopLeft); - } - //retrieve the enabled sub components from the entity AZStd::vector subModesState; EditorJointRequestBus::EventResult(subModesState, entityComponentIdPair, &EditorJointRequests::GetSubComponentModesState); + //group 1 is always available so create it + AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( + m_modeSelectionClusterIds[static_cast(ClusterGroups::Group1)], AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, AzToolsFramework::ViewportUi::Alignment::TopLeft); + + //check if groups 2 and/or 3 need to be created + for (auto [modeType, _] : subModesState) + { + const AzToolsFramework::ViewportUi::ClusterId group2Id = GetClusterId(ClusterGroups::Group2); + const AzToolsFramework::ViewportUi::ClusterId group3Id = GetClusterId(ClusterGroups::Group3); + switch (modeType) + { + case JointsComponentModeCommon::SubComponentModes::ModeType::Damping: + case JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness: + case JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits: + case JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits: + { + if (group2Id == AzToolsFramework::ViewportUi::InvalidClusterId) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( + m_modeSelectionClusterIds[static_cast(ClusterGroups::Group2)], + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, + AzToolsFramework::ViewportUi::Alignment::TopLeft); + } + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce: + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque: + { + if (group3Id == AzToolsFramework::ViewportUi::InvalidClusterId) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( + m_modeSelectionClusterIds[static_cast(ClusterGroups::Group3)], + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, + AzToolsFramework::ViewportUi::Alignment::TopLeft); + } + } + break; + default: + AZ_Error("Joints", false, "Joints component mode cluster UI setup found unknown sub mode."); + break; + } + //if both are created - break; + if (group2Id != AzToolsFramework::ViewportUi::InvalidClusterId && group3Id != AzToolsFramework::ViewportUi::InvalidClusterId) + { + break; + } + } + const AzToolsFramework::ViewportUi::ClusterId group1ClusterId = GetClusterId(ClusterGroups::Group1); const AzToolsFramework::ViewportUi::ClusterId group2ClusterId = GetClusterId(ClusterGroups::Group2); - //hide cluster 2, if something is added to it. it will make is visible - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, - group2ClusterId, false); - const AzToolsFramework::ViewportUi::ClusterId group3ClusterId = GetClusterId(ClusterGroups::Group3); - // hide cluster 3, if something is added to it. it will make is visible - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, - group3ClusterId, false); //translation and rotation are enabled for all joints in group 1 m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Translation] = @@ -408,10 +450,6 @@ namespace PhysX Internal::RegisterClusterButton(group3ClusterId, "joints/MaxForce", SubModeData::MaxForceToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce] = ButtonData{ group3ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group3ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque: @@ -424,10 +462,6 @@ namespace PhysX Internal::RegisterClusterButton(group3ClusterId, "joints/MaxTorque", SubModeData::MaxTorqueToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque] = ButtonData{ group3ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group3ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::Damping: @@ -439,10 +473,6 @@ namespace PhysX const AzToolsFramework::ViewportUi::ButtonId buttonId = Internal::RegisterClusterButton(group2ClusterId, "joints/Damping", SubModeData::DampingToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Damping] = ButtonData{ group2ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness: @@ -455,10 +485,6 @@ namespace PhysX Internal::RegisterClusterButton(group2ClusterId, "joints/Stiffness", SubModeData::StiffnessToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness] = ButtonData{ group2ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits: @@ -473,10 +499,6 @@ namespace PhysX Internal::RegisterClusterButton(group2ClusterId, "joints/TwistLimits", SubModeData::TwistLimitsToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits] = ButtonData{ group2ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits: @@ -489,10 +511,6 @@ namespace PhysX Internal::RegisterClusterButton(group2ClusterId, "joints/SwingLimits", SubModeData::SwingLimitsToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits] = ButtonData{ group2ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition: @@ -517,6 +535,9 @@ namespace PhysX ButtonData{ group1ClusterId, buttonId }; } break; + default: + AZ_Error("Joints", false, "Joints component mode cluster button setup found unknown sub mode."); + break; } } @@ -560,10 +581,13 @@ namespace PhysX for (int i = 0; i < static_cast(ClusterGroups::GroupCount); i++) { - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, m_modeSelectionClusterIds[i], - m_modeSelectionHandlers[i]); + if (m_modeSelectionClusterIds[i] != AzToolsFramework::ViewportUi::InvalidClusterId) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, + m_modeSelectionClusterIds[i], m_modeSelectionHandlers[i]); + } } // set the translate as enabled by default. @@ -588,10 +612,14 @@ namespace PhysX { for (auto clusterid : m_modeSelectionClusterIds) { - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, - clusterid); + if (clusterid != AzToolsFramework::ViewportUi::InvalidClusterId) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, clusterid); + } } + m_modeSelectionClusterIds.assign(static_cast(ClusterGroups::GroupCount), AzToolsFramework::ViewportUi::InvalidClusterId); } AzToolsFramework::ViewportUi::ClusterId JointsComponentMode::GetClusterId(ClusterGroups group) From ce10906671fcf47c6614285c94ac53905fa4a2c1 Mon Sep 17 00:00:00 2001 From: Chris Galvan Date: Tue, 16 Nov 2021 08:08:53 -0600 Subject: [PATCH 34/36] Updated splash screen and about dialog with Stable 21.11 name Signed-off-by: Chris Galvan --- Code/Editor/AboutDialog.ui | 2 +- Code/Editor/StartupLogoDialog.ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Code/Editor/AboutDialog.ui b/Code/Editor/AboutDialog.ui index a6c5bb5d52..a36d65e35b 100644 --- a/Code/Editor/AboutDialog.ui +++ b/Code/Editor/AboutDialog.ui @@ -125,7 +125,7 @@ - General Availability + Stable 21.11 Qt::AutoText diff --git a/Code/Editor/StartupLogoDialog.ui b/Code/Editor/StartupLogoDialog.ui index c0b8115cb0..c2cbfcfd69 100644 --- a/Code/Editor/StartupLogoDialog.ui +++ b/Code/Editor/StartupLogoDialog.ui @@ -103,7 +103,7 @@ - General Availability + Stable 21.11 From b20a9b5f39b025475d74f166a2634f74b835fdca Mon Sep 17 00:00:00 2001 From: bosnichd Date: Tue, 16 Nov 2021 08:27:32 -0700 Subject: [PATCH 35/36] Some modifications required for restricted platforms: (#5624) - Replace AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS with AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS that allows the number of threads created by the job manager to be set directly. - Add AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS that allows the number of threads created by the task graph to be set directly. - Add a define that forces the AsyncUploadQueue to use the primary copy queue instead of creating a secondary copy queue. Signed-off-by: bosnichd --- .../AzCore/AzCore/Jobs/JobManagerComponent.cpp | 7 ++++--- .../AzCore/AzCore/Task/TaskGraphSystemComponent.cpp | 7 ++++++- .../Platform/Android/AzCore/AzCore_Traits_Android.h | 1 - .../AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h | 1 - .../AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h | 1 - .../Platform/Windows/AzCore/AzCore_Traits_Windows.h | 1 - .../AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h | 1 - .../Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp | 10 +++++++++- 8 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp index 6f5ccc93e4..2307a9372c 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp @@ -56,11 +56,12 @@ namespace AZ int numberOfWorkerThreads = m_numberOfWorkerThreads; if (numberOfWorkerThreads <= 0) // spawn default number of threads { + #if (AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS) + numberOfWorkerThreads = AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS; + #else uint32_t scaledHardwareThreads = Threading::CalcNumWorkerThreads(cl_jobThreadsConcurrencyRatio, cl_jobThreadsMinNumber, cl_jobThreadsNumReserved); numberOfWorkerThreads = AZ::GetMin(static_cast(desc.m_workerThreads.capacity()), scaledHardwareThreads); - #if (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS) - numberOfWorkerThreads = AZ::GetMin(numberOfWorkerThreads, AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS); - #endif // (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS) + #endif // (AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS) } threadDesc.m_cpuId = AFFINITY_MASK_USERTHREADS; diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp index 56b56e96a1..1cacef7ff3 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp @@ -30,8 +30,13 @@ namespace AZ if (Interface::Get() == nullptr) { + #if (AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS) + const uint32_t numberOfWorkerThreads = AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS; + #else + const uint32_t numberOfWorkerThreads = Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved); + #endif // (AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS) Interface::Register(this); // small window that another thread can try to use taskgraph between this line and the set instance. - m_taskExecutor = aznew TaskExecutor(Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved)); + m_taskExecutor = aznew TaskExecutor(numberOfWorkerThreads); TaskExecutor::SetInstance(m_taskExecutor); } } diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h index 495c8d5f2c..e05e000a4e 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h +++ b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h @@ -75,7 +75,6 @@ #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 0 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0 -#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0 #define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 diff --git a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h index 6ba369e86d..2c0d554078 100644 --- a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h +++ b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h @@ -75,7 +75,6 @@ #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0 -#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0 #define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 diff --git a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h index a41b5c6baa..816a28b728 100644 --- a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h +++ b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h @@ -75,7 +75,6 @@ #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0 -#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0 #define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h index 2f9fcefdbd..83cff9b54f 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h @@ -75,7 +75,6 @@ #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 1 -#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0 #define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 1 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 diff --git a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h index d53f4b057e..b0832c54f6 100644 --- a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h +++ b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h @@ -76,7 +76,6 @@ #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0 -#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0 #define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp index 5f85d3ad03..fc80cc50d6 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp @@ -33,12 +33,20 @@ namespace AZ ID3D12DeviceX* dx12Device = device.GetDevice(); m_copyQueue = CommandQueue::Create(); - + + // The async upload queue should always use the primary copy queue, + // but because this change is being made in the stabilization branch + // we will put it behind a define out of an abundance of caution, and + // change it to always do this once the change gets back to development. + #if defined(AZ_DX12_USE_PRIMARY_COPY_QUEUE_FOR_ASYNC_UPLOAD_QUEUE) + m_copyQueue = &device.GetCommandQueueContext().GetCommandQueue(RHI::HardwareQueueClass::Copy); + #else // Make a secondary Copy queue, the primary queue is owned by the CommandQueueContext CommandQueueDescriptor commandQueueDesc; commandQueueDesc.m_hardwareQueueClass = RHI::HardwareQueueClass::Copy; commandQueueDesc.m_hardwareQueueSubclass = HardwareQueueSubclass::Secondary; m_copyQueue->Init(device, commandQueueDesc); + #endif // defined(AZ_DX12_ASYNC_UPLOAD_QUEUE_USE_PRIMARY_COPY_QUEUE) m_uploadFence.Init(dx12Device, RHI::FenceState::Signaled); for (size_t i = 0; i < descriptor.m_frameCount; ++i) From c3dacb1e5228c05ae146b711c007ee38e4b7ef1c Mon Sep 17 00:00:00 2001 From: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> Date: Tue, 16 Nov 2021 08:07:20 -0800 Subject: [PATCH 36/36] Unlocked a mutex after modifying the associated variable (#5625) * Unlocked a mutex after modifying the variable the mutex was meant for. This fixes an issue where mounting bundles in the Editor was causing the Editor to freeze up, because the following line, m_levelOpenEvent.Signal, resulted in another attempt to lock that same mutex. Signed-off-by: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> * Added a comment describing why the unlock is necessary. Signed-off-by: AMZN-stankowi <4838196+AMZN-stankowi@users.noreply.github.com> --- Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp index c1c5775958..0fede85aa7 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp @@ -1241,6 +1241,10 @@ namespace AZ::IO m_arrZips.insert(revItZip.base(), desc); + // This lock is for m_arrZips. + // Unlock it now because the modification is complete, and events responding to this signal + // will attempt to lock the same mutex, causing the application to lock up. + lock.unlock(); m_levelOpenEvent.Signal(levelDirs); }