diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/aws_client_auth_automation_test.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/aws_client_auth_automation_test.py index 198fb934d9..077a068a18 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/aws_client_auth_automation_test.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/client_auth/aws_client_auth_automation_test.py @@ -12,6 +12,7 @@ import pytest import ly_test_tools.log.log_monitor 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 @@ -70,6 +71,41 @@ class TestAWSClientAuthWindows(object): halt_on_unexpected=True, ) assert result, 'Anonymous credentials fetched successfully.' + + @pytest.mark.parametrize('level', ['AWS/ClientAuth']) + def test_anonymous_credentials_no_global_accountid(self, + level: str, + launcher: pytest.fixture, + resource_mappings: pytest.fixture, + workspace: pytest.fixture, + asset_processor: pytest.fixture + ): + """ + Test to verify AWS Cognito Identity pool anonymous authorization. + + Setup: Updates resource mapping file using existing CloudFormation stacks. + Tests: Getting credentials when no credentials are configured + Verification: Log monitor looks for success credentials log. + """ + # Remove top-level account ID from resource mappings + resource_mappings.clear_select_keys([AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY]) + + asset_processor.start() + asset_processor.wait_for_idle() + + file_to_monitor = os.path.join(launcher.workspace.paths.project_log(), constants.GAME_LOG_NAME) + log_monitor = ly_test_tools.log.log_monitor.LogMonitor(launcher=launcher, log_file_path=file_to_monitor) + + launcher.args = ['+LoadLevel', level] + launcher.args.extend(['-rhi=null']) + + with launcher.start(launch_ap=False): + result = log_monitor.monitor_log_for_lines( + expected_lines=['(Script) - Success anonymous credentials'], + unexpected_lines=['(Script) - Fail anonymous credentials'], + halt_on_unexpected=True, + ) + assert result, 'Anonymous credentials fetched successfully.' def test_password_signin_credentials(self, launcher: pytest.fixture, diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test_case.py b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test_case.py index 8d418222ce..112fd013bf 100644 --- a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test_case.py +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test_case.py @@ -8,42 +8,54 @@ import azlmbr.bus import azlmbr.asset import azlmbr.editor import azlmbr.math -import azlmbr.legacy.general -def raise_and_stop(msg): - print (msg) +print('Starting mock asset tests') +handler = azlmbr.editor.EditorEventBusHandler() + +def on_notify_editor_initialized(args): + # These tests are meant to check that the test_asset.mock source asset turned into + # a test_asset.mock_asset product asset via the Python asset builder system + mockAssetType = azlmbr.math.Uuid_CreateString('{9274AD17-3212-4651-9F3B-7DCCB080E467}', 0) + mockAssetPath = 'gem/pythontests/pythonassetbuilder/test_asset.mock_asset' + assetId = azlmbr.asset.AssetCatalogRequestBus(azlmbr.bus.Broadcast, 'GetAssetIdByPath', mockAssetPath, mockAssetType, False) + if (assetId.is_valid() is False): + print(f'Mock AssetId is not valid! Got {assetId.to_string()} instead') + else: + print(f'Mock AssetId is valid!') + + assetIdString = assetId.to_string() + if (assetIdString.endswith(':528cca58') is False): + print(f'Mock AssetId {assetIdString} has unexpected sub-id for {mockAssetPath}!') + else: + print(f'Mock AssetId has expected sub-id for {mockAssetPath}!') + + print ('Mock asset exists') + + # These tests detect if the geom_group.fbx file turns into a number of azmodel product assets + def test_azmodel_product(generatedModelAssetPath): + azModelAssetType = azlmbr.math.Uuid_CreateString('{2C7477B6-69C5-45BE-8163-BCD6A275B6D8}', 0) + assetId = azlmbr.asset.AssetCatalogRequestBus(azlmbr.bus.Broadcast, 'GetAssetIdByPath', generatedModelAssetPath, azModelAssetType, False) + assetIdString = assetId.to_string() + if (assetId.is_valid()): + print(f'AssetId found for asset ({generatedModelAssetPath}) found') + else: + print(f'Asset at path {generatedModelAssetPath} has unexpected asset ID ({assetIdString})!') + + test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive_1.azmodel') + test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative_1.azmodel') + test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive_1.azmodel') + test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative_1.azmodel') + test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive_1.azmodel') + test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative_1.azmodel') + test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center_1.azmodel') + + # clear up notification handler + global handler + handler.disconnect() + handler = None + + print('Finished mock asset tests') azlmbr.editor.EditorToolsApplicationRequestBus(azlmbr.bus.Broadcast, 'ExitNoPrompt') -# These tests are meant to check that the test_asset.mock source asset turned into -# a test_asset.mock_asset product asset via the Python asset builder system -mockAssetType = azlmbr.math.Uuid_CreateString('{9274AD17-3212-4651-9F3B-7DCCB080E467}', 0) -mockAssetPath = 'gem/pythontests/pythonassetbuilder/test_asset.mock_asset' -assetId = azlmbr.asset.AssetCatalogRequestBus(azlmbr.bus.Broadcast, 'GetAssetIdByPath', mockAssetPath, mockAssetType, False) -if (assetId.is_valid() is False): - raise_and_stop(f'Mock AssetId is not valid! Got {assetId.to_string()} instead') - -assetIdString = assetId.to_string() -if (assetIdString.endswith(':528cca58') is False): - raise_and_stop(f'Mock AssetId {assetIdString} has unexpected sub-id for {mockAssetPath}!') - -print ('Mock asset exists') - -# These tests detect if the geom_group.fbx file turns into a number of azmodel product assets -def test_azmodel_product(generatedModelAssetPath): - azModelAssetType = azlmbr.math.Uuid_CreateString('{2C7477B6-69C5-45BE-8163-BCD6A275B6D8}', 0) - assetId = azlmbr.asset.AssetCatalogRequestBus(azlmbr.bus.Broadcast, 'GetAssetIdByPath', generatedModelAssetPath, azModelAssetType, False) - assetIdString = assetId.to_string() - if (assetId.is_valid()): - print(f'AssetId found for asset ({generatedModelAssetPath}) found') - else: - raise_and_stop(f'Asset at path {generatedModelAssetPath} has unexpected asset ID ({assetIdString})!') - -test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_positive_1.azmodel') -test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_z_negative_1.azmodel') -test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_positive_1.azmodel') -test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_y_negative_1.azmodel') -test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_positive_1.azmodel') -test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_x_negative_1.azmodel') -test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center_1.azmodel') - -azlmbr.editor.EditorToolsApplicationRequestBus(azlmbr.bus.Broadcast, 'ExitNoPrompt') +handler.connect() +handler.add_callback('NotifyEditorInitialized', on_notify_editor_initialized) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/PythonLoader.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/PythonLoader.h new file mode 100644 index 0000000000..29125667d6 --- /dev/null +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/PythonLoader.h @@ -0,0 +1,25 @@ +/* + * 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 + +namespace AzToolsFramework::EmbeddedPython +{ + // When using embedded Python, some platforms need to explicitly load the python library. + // For any modules that depend on 3rdParty::Python package, the AZ::Module should inherit this class. + class PythonLoader + { + public: + PythonLoader(); + ~PythonLoader(); + + private: + void* m_embeddedLibPythonHandle{ nullptr }; + }; + +} // namespace AzToolsFramework::EmbeddedPython diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake index b57eedcd81..d61d6486a9 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/aztoolsframework_files.cmake @@ -47,6 +47,7 @@ set(FILES API/EntityCompositionRequestBus.h API/EntityCompositionNotificationBus.h API/EditorViewportIconDisplayInterface.h + API/PythonLoader.h API/ViewPaneOptions.h API/ViewportEditorModeTrackerInterface.h Application/Ticker.h diff --git a/Code/Framework/AzToolsFramework/Platform/Common/Default/AzToolsFramework/API/PythonLoader_Default.cpp b/Code/Framework/AzToolsFramework/Platform/Common/Default/AzToolsFramework/API/PythonLoader_Default.cpp new file mode 100644 index 0000000000..42fef21db6 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Platform/Common/Default/AzToolsFramework/API/PythonLoader_Default.cpp @@ -0,0 +1,20 @@ +/* +* 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 + +namespace AzToolsFramework::EmbeddedPython +{ + PythonLoader::PythonLoader() + { + } + + PythonLoader::~PythonLoader() + { + } +} diff --git a/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/API/PythonLoader_Linux.cpp b/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/API/PythonLoader_Linux.cpp new file mode 100644 index 0000000000..76fa36a048 --- /dev/null +++ b/Code/Framework/AzToolsFramework/Platform/Linux/AzToolsFramework/API/PythonLoader_Linux.cpp @@ -0,0 +1,34 @@ +/* + * 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 + +namespace AzToolsFramework::EmbeddedPython +{ + PythonLoader::PythonLoader() + { + constexpr char libPythonName[] = "libpython3.7m.so.1.0"; + if (m_embeddedLibPythonHandle = dlopen(libPythonName, RTLD_NOW | RTLD_GLOBAL); + m_embeddedLibPythonHandle == nullptr) + { + char* err = dlerror(); + AZ_Error("PythonLoader", false, "Failed to load %s with error: %s\n", libPythonName, err ? err : "Unknown Error"); + } + } + + PythonLoader::~PythonLoader() + { + if (m_embeddedLibPythonHandle) + { + dlclose(m_embeddedLibPythonHandle); + } + } + +} // namespace AzToolsFramework::EmbeddedPython diff --git a/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake b/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake index c2c5a11c4c..3b04a903a4 100644 --- a/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake +++ b/Code/Framework/AzToolsFramework/Platform/Linux/platform_linux_files.cmake @@ -7,4 +7,5 @@ # set(FILES + AzToolsFramework/API/PythonLoader_Linux.cpp ) diff --git a/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake b/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake index c2c5a11c4c..6342747a38 100644 --- a/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake +++ b/Code/Framework/AzToolsFramework/Platform/Mac/platform_mac_files.cmake @@ -7,4 +7,5 @@ # set(FILES + ../Common/Default/AzToolsFramework/API/PythonLoader_Default.cpp ) diff --git a/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake b/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake index c2c5a11c4c..6342747a38 100644 --- a/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake +++ b/Code/Framework/AzToolsFramework/Platform/Windows/platform_windows_files.cmake @@ -7,4 +7,5 @@ # set(FILES + ../Common/Default/AzToolsFramework/API/PythonLoader_Default.cpp ) diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp index f9b5d6aef7..b5323dd419 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp @@ -23,6 +23,8 @@ #include ////////////////////////////////////////////////////////////////////////// +#include + namespace AssetBuilderSDK { const char* const ErrorWindow = "Error"; //Use this window name to log error messages. @@ -1599,4 +1601,70 @@ namespace AssetBuilderSDK { return m_errorsOccurred; } + + AZ::u64 GetHashFromIOStream(AZ::IO::GenericStream& readStream, AZ::IO::SizeType* bytesReadOut, int hashMsDelay) + { + constexpr AZ::u64 HashBufferSize = 1024 * 64; + char buffer[HashBufferSize]; + + if(readStream.IsOpen() && readStream.CanRead()) + { + AZ::IO::SizeType bytesRead; + + auto* state = XXH64_createState(); + + if(state == nullptr) + { + AZ_Assert(false, "Failed to create hash state"); + return 0; + } + + if (XXH64_reset(state, 0) == XXH_ERROR) + { + AZ_Assert(false, "Failed to reset hash state"); + return 0; + } + + do + { + // In edge cases where another process is writing to this file while this hashing is occuring and that file wasn't locked, + // the following read check can fail because it performs an end of file check, and asserts and shuts down if the read size + // was smaller than the buffer and the read is not at the end of the file. The logic used to check end of file internal to read + // will be out of date in the edge cases where another process is actively writing to this file while this hash is running. + // The stream's length ends up more accurate in this case, preventing this assert and shut down. + // One area this occurs is the navigation mesh file (mnmnavmission0.bai) that's temporarily created when exporting a level, + // the navigation system can still be writing to this file when hashing begins, causing the EoF marker to change. + AZ::IO::SizeType remainingToRead = AZStd::min(readStream.GetLength() - readStream.GetCurPos(), aznumeric_cast(AZ_ARRAY_SIZE(buffer))); + bytesRead = readStream.Read(remainingToRead, buffer); + + if(bytesReadOut) + { + *bytesReadOut += bytesRead; + } + + XXH64_update(state, buffer, bytesRead); + + // Used by unit tests to force the race condition mentioned above, to verify the crash fix. + if(hashMsDelay > 0) + { + AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(hashMsDelay)); + } + + } while (bytesRead > 0); + + auto hash = XXH64_digest(state); + + XXH64_freeState(state); + + return hash; + } + return 0; + } + + AZ::u64 GetFileHash(const char* filePath, AZ::IO::SizeType* bytesReadOut, int hashMsDelay) + { + constexpr bool ErrorOnReadFailure = true; + AZ::IO::FileIOStream readStream(filePath, AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeBinary, ErrorOnReadFailure); + return GetHashFromIOStream(readStream, bytesReadOut, hashMsDelay); + } } diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h index c85c45dd3e..6fb099e6d3 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.h @@ -910,6 +910,19 @@ namespace AssetBuilderSDK //! There can be multiple builders running at once, so we need to filter out ones coming from other builders AZStd::thread_id m_jobThreadId; }; + + //! Get hash for a whole file + //! @filePath the path for the file + //! @bytesReadOut output the read file size in bytes + //! @hashMsDelay [Do not use except for unit test] add a delay in ms for between each block reading. + AZ::u64 GetFileHash(const char* filePath, AZ::IO::SizeType* bytesReadOut = nullptr, int hashMsDelay = 0); + + //! Get hash for a generic IO stream + //! @readStream the input readable stream + //! @bytesReadOut output the read size in bytes + //! @hashMsDelay [Do not use except for unit test] add a delay in ms for between each block reading. + AZ::u64 GetHashFromIOStream(AZ::IO::GenericStream& readStream, AZ::IO::SizeType* bytesReadOut = nullptr, int hashMsDelay = 0); + } // namespace AssetBuilderSDK namespace AZ diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/CMakeLists.txt b/Code/Tools/AssetProcessor/AssetBuilderSDK/CMakeLists.txt index 635cd55f6c..bfbcc35663 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/CMakeLists.txt +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/CMakeLists.txt @@ -32,6 +32,7 @@ ly_add_target( PUBLIC AZ::AzFramework AZ::AzToolsFramework + 3rdParty::xxhash ) ly_add_source_properties( SOURCES AssetBuilderSDK/AssetBuilderSDK.cpp diff --git a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp index cacd6c4cc9..340f5343bd 100644 --- a/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp +++ b/Code/Tools/AssetProcessor/native/utilities/assetUtils.cpp @@ -1161,7 +1161,7 @@ namespace AssetUtilities { #ifndef AZ_TESTS_ENABLED // Only used for unit tests, speed is critical for GetFileHash. - AZ_UNUSED(hashMsDelay); + hashMsDelay = 0; #endif bool useFileHashing = ShouldUseFileHashing(); @@ -1170,10 +1170,10 @@ namespace AssetUtilities return 0; } + AZ::u64 hash = 0; if(!force) { auto* fileStateInterface = AZ::Interface::Get(); - AZ::u64 hash = 0; if (fileStateInterface && fileStateInterface->GetHash(filePath, &hash)) { @@ -1181,64 +1181,8 @@ namespace AssetUtilities } } - char buffer[FileHashBufferSize]; - - constexpr bool ErrorOnReadFailure = true; - AZ::IO::FileIOStream readStream(filePath, AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeBinary, ErrorOnReadFailure); - - if(readStream.IsOpen() && readStream.CanRead()) - { - AZ::IO::SizeType bytesRead; - - auto* state = XXH64_createState(); - - if(state == nullptr) - { - AZ_Assert(false, "Failed to create hash state"); - return 0; - } - - if (XXH64_reset(state, 0) == XXH_ERROR) - { - AZ_Assert(false, "Failed to reset hash state"); - return 0; - } - - do - { - // In edge cases where another process is writing to this file while this hashing is occuring and that file wasn't locked, - // the following read check can fail because it performs an end of file check, and asserts and shuts down if the read size - // was smaller than the buffer and the read is not at the end of the file. The logic used to check end of file internal to read - // will be out of date in the edge cases where another process is actively writing to this file while this hash is running. - // The stream's length ends up more accurate in this case, preventing this assert and shut down. - // One area this occurs is the navigation mesh file (mnmnavmission0.bai) that's temporarily created when exporting a level, - // the navigation system can still be writing to this file when hashing begins, causing the EoF marker to change. - AZ::IO::SizeType remainingToRead = AZStd::min(readStream.GetLength() - readStream.GetCurPos(), aznumeric_cast(AZ_ARRAY_SIZE(buffer))); - bytesRead = readStream.Read(remainingToRead, buffer); - - if(bytesReadOut) - { - *bytesReadOut += bytesRead; - } - - XXH64_update(state, buffer, bytesRead); -#ifdef AZ_TESTS_ENABLED - // Used by unit tests to force the race condition mentioned above, to verify the crash fix. - if(hashMsDelay > 0) - { - AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(hashMsDelay)); - } -#endif - - } while (bytesRead > 0); - - auto hash = XXH64_digest(state); - - XXH64_freeState(state); - - return hash; - } - return 0; + hash = AssetBuilderSDK::GetFileHash(filePath, bytesReadOut, hashMsDelay); + return hash; } AZ::u64 AdjustTimestamp(QDateTime timestamp) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 0dacbbb906..b26dddac71 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -363,7 +363,10 @@ namespace O3DE::ProjectManager { const QString selectedGemPath = m_gemModel->GetPath(modelIndex); - // Remove gem from gems to be added + const bool wasAdded = GemModel::WasPreviouslyAdded(modelIndex); + const bool wasAddedDependency = GemModel::WasPreviouslyAddedDependency(modelIndex); + + // Remove gem from gems to be added to update any dependencies GemModel::SetIsAdded(*m_gemModel, modelIndex, false); // Unregister the gem @@ -391,6 +394,8 @@ namespace O3DE::ProjectManager // Select remote gem QModelIndex remoteGemIndex = m_gemModel->FindIndexByNameString(selectedGemName); + GemModel::SetWasPreviouslyAdded(*m_gemModel, remoteGemIndex, wasAdded); + GemModel::SetWasPreviouslyAddedDependency(*m_gemModel, remoteGemIndex, wasAddedDependency); QModelIndex proxyIndex = m_proxyModel->mapFromSource(remoteGemIndex); m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); } @@ -523,7 +528,9 @@ namespace O3DE::ProjectManager const QString& gemPath = GemModel::GetPath(modelIndex); // make sure any remote gems we added were downloaded successfully - if (GemModel::GetGemOrigin(modelIndex) == GemInfo::Remote && GemModel::GetDownloadStatus(modelIndex) != GemInfo::Downloaded) + const GemInfo::DownloadStatus status = GemModel::GetDownloadStatus(modelIndex); + if (GemModel::GetGemOrigin(modelIndex) == GemInfo::Remote && + !(status == GemInfo::Downloaded || status == GemInfo::DownloadSuccessful)) { QMessageBox::critical( nullptr, "Cannot add gem that isn't downloaded", diff --git a/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp b/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp index 7981e9d758..ecb125ae4e 100644 --- a/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectBuilderController.cpp @@ -9,12 +9,14 @@ #include #include #include +#include + +#include #include #include #include - namespace O3DE::ProjectManager { ProjectBuilderController::ProjectBuilderController(const ProjectInfo& projectInfo, ProjectButton* projectButton, QWidget* parent) @@ -27,6 +29,15 @@ namespace O3DE::ProjectManager m_worker = new ProjectBuilderWorker(m_projectInfo); m_worker->moveToThread(&m_workerThread); + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry) + { + // Remove key here in case Project Manager crashing while building that causes HandleResults to not be called + QString settingsKey = GetProjectBuiltSuccessfullyKey(m_projectInfo.m_projectName); + settingsRegistry->Remove(settingsKey.toStdString().c_str()); + SaveProjectManagerSettings(); + } + connect(&m_workerThread, &QThread::finished, m_worker, &ProjectBuilderWorker::deleteLater); connect(&m_workerThread, &QThread::started, m_worker, &ProjectBuilderWorker::BuildProject); connect(m_worker, &ProjectBuilderWorker::Done, this, &ProjectBuilderController::HandleResults); @@ -80,6 +91,8 @@ namespace O3DE::ProjectManager void ProjectBuilderController::HandleResults(const QString& result) { + QString settingsKey = GetProjectBuiltSuccessfullyKey(m_projectInfo.m_projectName); + if (!result.isEmpty()) { if (result.contains(tr("log"))) @@ -109,12 +122,26 @@ namespace O3DE::ProjectManager emit NotifyBuildProject(m_projectInfo); } + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry) + { + settingsRegistry->Remove(settingsKey.toStdString().c_str()); + SaveProjectManagerSettings(); + } + emit Done(false); return; } else { m_projectInfo.m_buildFailed = false; + + auto settingsRegistry = AZ::SettingsRegistry::Get(); + if (settingsRegistry) + { + settingsRegistry->Set(settingsKey.toStdString().c_str(), true); + SaveProjectManagerSettings(); + } } emit Done(true); diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerSettings.cpp b/Code/Tools/ProjectManager/Source/ProjectManagerSettings.cpp new file mode 100644 index 0000000000..3049a6d70c --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ProjectManagerSettings.cpp @@ -0,0 +1,54 @@ +/* + * 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 "ProjectManagerSettings.h" + +#include +#include +#include + +namespace O3DE::ProjectManager +{ + void SaveProjectManagerSettings() + { + auto settingsRegistry = AZ::SettingsRegistry::Get(); + AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings; + dumperSettings.m_prettifyOutput = true; + dumperSettings.m_jsonPointerPrefix = ProjectManagerKeyPrefix; + + AZStd::string stringBuffer; + AZ::IO::ByteContainerStream stringStream(&stringBuffer); + if (!AZ::SettingsRegistryMergeUtils::DumpSettingsRegistryToStream( + *settingsRegistry, ProjectManagerKeyPrefix, stringStream, dumperSettings)) + { + AZ_Warning("ProjectManager", false, "Could not save Project Manager settings to stream"); + return; + } + + AZ::IO::FixedMaxPath o3deUserPath = AZ::Utils::GetO3deManifestDirectory(); + o3deUserPath /= AZ::SettingsRegistryInterface::RegistryFolder; + o3deUserPath /= "ProjectManager.setreg"; + + bool saved = false; + constexpr auto configurationMode = + AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY; + + AZ::IO::SystemFile outputFile; + if (outputFile.Open(o3deUserPath.c_str(), configurationMode)) + { + saved = outputFile.Write(stringBuffer.data(), stringBuffer.size()) == stringBuffer.size(); + } + + AZ_Warning("ProjectManager", saved, "Unable to save Project Manager registry file to path: %s", o3deUserPath.c_str()); + } + + QString GetProjectBuiltSuccessfullyKey(const QString& projectName) + { + return QString("%1/Projects/%2/BuiltSuccessfully").arg(ProjectManagerKeyPrefix).arg(projectName); + } +} diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerSettings.h b/Code/Tools/ProjectManager/Source/ProjectManagerSettings.h new file mode 100644 index 0000000000..3454909062 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ProjectManagerSettings.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. + * For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#endif + +namespace O3DE::ProjectManager +{ + static constexpr char ProjectManagerKeyPrefix[] = "/O3DE/ProjectManager"; + + void SaveProjectManagerSettings(); + QString GetProjectBuiltSuccessfullyKey(const QString& projectName); +} diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp index 72bae4da54..4a82783949 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include @@ -270,17 +272,36 @@ namespace O3DE::ProjectManager // Add any missing project buttons and restore buttons to default state for (const ProjectInfo& project : projectsVector) { + ProjectButton* currentButton = nullptr; if (!m_projectButtons.contains(QDir::toNativeSeparators(project.m_path))) { - m_projectButtons.insert(QDir::toNativeSeparators(project.m_path), CreateProjectButton(project)); + currentButton = CreateProjectButton(project); + m_projectButtons.insert(QDir::toNativeSeparators(project.m_path), currentButton); } else { auto projectButtonIter = m_projectButtons.find(QDir::toNativeSeparators(project.m_path)); if (projectButtonIter != m_projectButtons.end()) { - projectButtonIter.value()->RestoreDefaultState(); - m_projectsFlowLayout->addWidget(projectButtonIter.value()); + currentButton = projectButtonIter.value(); + currentButton->RestoreDefaultState(); + m_projectsFlowLayout->addWidget(currentButton); + } + } + + // Check whether project manager has successfully built the project + if (currentButton) + { + auto settingsRegistry = AZ::SettingsRegistry::Get(); + bool projectBuiltSuccessfully = false; + if (settingsRegistry) + { + QString settingsKey = GetProjectBuiltSuccessfullyKey(project.m_projectName); + settingsRegistry->Get(projectBuiltSuccessfully, settingsKey.toStdString().c_str()); + } + if (!projectBuiltSuccessfully) + { + currentButton->ShowBuildRequired(); } } } diff --git a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp index bed1e7dfc7..4c2e9764dc 100644 --- a/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp +++ b/Code/Tools/ProjectManager/Source/UpdateProjectCtrl.cpp @@ -15,6 +15,9 @@ #include #include #include +#include + +#include #include #include @@ -300,6 +303,21 @@ namespace O3DE::ProjectManager } } + if (newProjectSettings.m_projectName != m_projectInfo.m_projectName) + { + // update reg key + QString oldSettingsKey = GetProjectBuiltSuccessfullyKey(m_projectInfo.m_projectName); + QString newSettingsKey = GetProjectBuiltSuccessfullyKey(newProjectSettings.m_projectName); + + auto settingsRegistry = AZ::SettingsRegistry::Get(); + bool projectBuiltSuccessfully = false; + if (settingsRegistry && settingsRegistry->Get(projectBuiltSuccessfully, oldSettingsKey.toStdString().c_str())) + { + settingsRegistry->Set(newSettingsKey.toStdString().c_str(), projectBuiltSuccessfully); + SaveProjectManagerSettings(); + } + } + if (!newProjectSettings.m_newPreviewImagePath.isEmpty()) { if (!ProjectUtils::ReplaceProjectFile( diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index fcfae2f336..43c11edacc 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -58,6 +58,8 @@ set(FILES Source/CreateProjectCtrl.cpp Source/UpdateProjectCtrl.h Source/UpdateProjectCtrl.cpp + Source/ProjectManagerSettings.h + Source/ProjectManagerSettings.cpp Source/ProjectsScreen.h Source/ProjectsScreen.cpp Source/ProjectSettingsScreen.h diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h new file mode 100644 index 0000000000..ad7faf4671 --- /dev/null +++ b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h @@ -0,0 +1,44 @@ +/* + * 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 AWSClientAuth +{ + //! Cognito Caching Credentials Provider implementation that is derived from AWS Native SDK. + //! For use with authenticated credentials. + class AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider + : public Aws::Auth::CognitoCachingCredentialsProvider + { + public: + AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider( + const std::shared_ptr& identityRepository, + const std::shared_ptr& cognitoIdentityClient = nullptr); + + protected: + Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome GetCredentialsFromCognito() const override; + }; + + //! Cognito Caching Credentials Provider implementation that is eventually derived from AWS Native SDK. + //! For use with anonymous credentials. + class AWSClientAuthCachingAnonymousCredsProvider : public AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider + { + public: + AWSClientAuthCachingAnonymousCredsProvider( + const std::shared_ptr& identityRepository, + const std::shared_ptr& cognitoIdentityClient = nullptr); + + protected: + Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome GetCredentialsFromCognito() const override; + }; + +} // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationController.h b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationController.h index 042be8fe89..1378feff19 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationController.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationController.h @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -51,8 +52,8 @@ namespace AWSClientAuth std::shared_ptr m_persistentCognitoIdentityProvider; std::shared_ptr m_persistentAnonymousCognitoIdentityProvider; - std::shared_ptr m_cognitoCachingCredentialsProvider; - std::shared_ptr m_cognitoCachingAnonymousCredentialsProvider; + std::shared_ptr m_cognitoCachingCredentialsProvider; + std::shared_ptr m_cognitoCachingAnonymousCredentialsProvider; AZStd::string m_cognitoIdentityPoolId; AZStd::string m_formattedCognitoUserPoolId; diff --git a/Gems/AWSClientAuth/Code/Source/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.cpp b/Gems/AWSClientAuth/Code/Source/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.cpp new file mode 100644 index 0000000000..2492afa441 --- /dev/null +++ b/Gems/AWSClientAuth/Code/Source/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.cpp @@ -0,0 +1,122 @@ +/* + * 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 + + +namespace AWSClientAuth +{ + static const char* AUTH_LOG_TAG = "AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider"; + static const char* ANON_LOG_TAG = "AWSClientAuthCachingAnonymousCredsProvider"; + + // Modification of https://github.com/aws/aws-sdk-cpp/blob/main/aws-cpp-sdk-identity-management/source/auth/CognitoCachingCredentialsProvider.cpp#L92 + // to work around account ID requirement. Account id is not required for call to succeed and is not set unless provided. + // see: https://github.com/aws/aws-sdk-cpp/issues/1448 + Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome FetchCredsFromCognito( + const Aws::CognitoIdentity::CognitoIdentityClient& cognitoIdentityClient, + Aws::Auth::PersistentCognitoIdentityProvider& identityRepository, + const char* logTag, + bool includeLogins) + { + auto logins = identityRepository.GetLogins(); + Aws::Map cognitoLogins; + for (auto& login : logins) + { + cognitoLogins[login.first] = login.second.accessToken; + } + + if (!identityRepository.HasIdentityId()) + { + auto accountId = identityRepository.GetAccountId(); + auto identityPoolId = identityRepository.GetIdentityPoolId(); + + Aws::CognitoIdentity::Model::GetIdRequest getIdRequest; + getIdRequest.SetIdentityPoolId(identityPoolId); + + if (!accountId.empty()) // new check + { + getIdRequest.SetAccountId(accountId); + AWS_LOGSTREAM_INFO(logTag, "Identity not found, requesting an id for accountId " + << accountId << " identity pool id " + << identityPoolId << " with logins."); + } + else + { + AWS_LOGSTREAM_INFO( + logTag, "Identity not found, requesting an id for identity pool id %s" << identityPoolId << " with logins."); + } + if (includeLogins) + { + getIdRequest.SetLogins(cognitoLogins); + } + + auto getIdOutcome = cognitoIdentityClient.GetId(getIdRequest); + if (getIdOutcome.IsSuccess()) + { + auto identityId = getIdOutcome.GetResult().GetIdentityId(); + AWS_LOGSTREAM_INFO(logTag, "Successfully retrieved identity: " << identityId); + identityRepository.PersistIdentityId(identityId); + } + else + { + AWS_LOGSTREAM_ERROR( + logTag, + "Failed to retrieve identity. Error: " << getIdOutcome.GetError().GetExceptionName() << " " + << getIdOutcome.GetError().GetMessage()); + return Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome(getIdOutcome.GetError()); + } + } + + Aws::CognitoIdentity::Model::GetCredentialsForIdentityRequest getCredentialsForIdentityRequest; + getCredentialsForIdentityRequest.SetIdentityId(identityRepository.GetIdentityId()); + if (includeLogins) + { + getCredentialsForIdentityRequest.SetLogins(cognitoLogins); + } + + return cognitoIdentityClient.GetCredentialsForIdentity(getCredentialsForIdentityRequest); + } + + AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider::AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider( + const std::shared_ptr& identityRepository, + const std::shared_ptr& cognitoIdentityClient) + : CognitoCachingCredentialsProvider(identityRepository, cognitoIdentityClient) + { + } + + Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome + AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider::GetCredentialsFromCognito() const + { + return FetchCredsFromCognito(*m_cognitoIdentityClient, *m_identityRepository, AUTH_LOG_TAG, true); + } + + AWSClientAuthCachingAnonymousCredsProvider::AWSClientAuthCachingAnonymousCredsProvider( + const std::shared_ptr& identityRepository, + const std::shared_ptr& cognitoIdentityClient) + : AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider(identityRepository, cognitoIdentityClient) + { + } + + Aws::CognitoIdentity::Model::GetCredentialsForIdentityOutcome AWSClientAuthCachingAnonymousCredsProvider:: + GetCredentialsFromCognito() const + { + return FetchCredsFromCognito(*m_cognitoIdentityClient, *m_identityRepository, ANON_LOG_TAG, false); + } + + +} // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp b/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp index 3af28582d6..f53149c90f 100644 --- a/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -38,10 +39,12 @@ namespace AWSClientAuth auto identityClient = AZ::Interface::Get()->GetCognitoIdentityClient(); m_cognitoCachingCredentialsProvider = - std::make_shared(m_persistentCognitoIdentityProvider, identityClient); + std::make_shared( + m_persistentCognitoIdentityProvider, identityClient); m_cognitoCachingAnonymousCredentialsProvider = - std::make_shared(m_persistentAnonymousCognitoIdentityProvider, identityClient); + std::make_shared( + m_persistentAnonymousCognitoIdentityProvider, identityClient); } AWSCognitoAuthorizationController::~AWSCognitoAuthorizationController() @@ -65,9 +68,13 @@ namespace AWSClientAuth AWSCore::AWSResourceMappingRequestBus::BroadcastResult( m_cognitoIdentityPoolId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoIdentityPoolIdResourceMappingKey); - if (m_awsAccountId.empty() || m_cognitoIdentityPoolId.empty()) + if (m_awsAccountId.empty()) + { + AZ_TracePrintf("AWSCognitoAuthorizationController", "AWS account id not not configured. Proceeding without it."); + } + + if (m_cognitoIdentityPoolId.empty()) { - AZ_Warning("AWSCognitoAuthorizationController", !m_awsAccountId.empty(), "Missing AWS account id not configured."); AZ_Warning("AWSCognitoAuthorizationController", !m_cognitoIdentityPoolId.empty(), "Missing Cognito Identity pool id in resource mappings."); return false; } diff --git a/Gems/AWSClientAuth/Code/Tests/Authorization/AWSCognitoAuthorizationControllerTest.cpp b/Gems/AWSClientAuth/Code/Tests/Authorization/AWSCognitoAuthorizationControllerTest.cpp index 9f31891512..ca1d58aea4 100644 --- a/Gems/AWSClientAuth/Code/Tests/Authorization/AWSCognitoAuthorizationControllerTest.cpp +++ b/Gems/AWSClientAuth/Code/Tests/Authorization/AWSCognitoAuthorizationControllerTest.cpp @@ -62,6 +62,14 @@ TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Success) ASSERT_TRUE(m_mockController->m_cognitoIdentityPoolId == AWSClientAuthUnitTest::TEST_RESOURCE_NAME_ID); } +TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Success_GetAWSAccountEmpty) +{ + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(2); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultAccountId()).Times(1).WillOnce(testing::Return("")); + EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultRegion()).Times(1); + ASSERT_TRUE(m_mockController->Initialize()); +} + TEST_F(AWSCognitoAuthorizationControllerTest, RequestAWSCredentials_WithLogins_Success) { AWSClientAuth::AuthenticationTokens tokens( @@ -121,7 +129,7 @@ TEST_F(AWSCognitoAuthorizationControllerTest, MultipleCalls_UsesCacheCredentials m_mockController->RequestAWSCredentialsAsync(); } -TEST_F(AWSCognitoAuthorizationControllerTest, RequestAWSCredentials_Fail_GetIdError) +TEST_F(AWSCognitoAuthorizationControllerTest, RequestAWSCredentials_Fail_GetIdError) // fail { AWSClientAuth::AuthenticationTokens cognitoTokens( AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, @@ -321,7 +329,7 @@ TEST_F(AWSCognitoAuthorizationControllerTest, GetCredentialsProvider_NoPersisted EXPECT_TRUE(actualCredentialsProvider == m_mockController->m_cognitoCachingAnonymousCredentialsProvider); } -TEST_F(AWSCognitoAuthorizationControllerTest, GetCredentialsProvider_NoPersistedLogins_NoAnonymousCredentials_ResultNullPtr) +TEST_F(AWSCognitoAuthorizationControllerTest, GetCredentialsProvider_NoPersistedLogins_NoAnonymousCredentials_ResultNullPtr) // fails { Aws::Client::AWSError error; error.SetExceptionName(AWSClientAuthUnitTest::TEST_EXCEPTION); @@ -431,11 +439,3 @@ TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Fail_GetResourceNameEmp EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultAccountId()).Times(1); ASSERT_FALSE(m_mockController->Initialize()); } - -TEST_F(AWSCognitoAuthorizationControllerTest, Initialize_Fail_GetAWSAccountEmpty) -{ - EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetResourceNameId(testing::_)).Times(1); - EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultAccountId()).Times(1).WillOnce(testing::Return("")); - EXPECT_CALL(m_awsResourceMappingRequestBusMock, GetDefaultRegion()).Times(0); - ASSERT_FALSE(m_mockController->Initialize()); -} diff --git a/Gems/AWSClientAuth/Code/awsclientauth_files.cmake b/Gems/AWSClientAuth/Code/awsclientauth_files.cmake index bd4c971377..3b07b710e7 100644 --- a/Gems/AWSClientAuth/Code/awsclientauth_files.cmake +++ b/Gems/AWSClientAuth/Code/awsclientauth_files.cmake @@ -24,6 +24,7 @@ set(FILES Include/Private/Authorization/AWSCognitoAuthorizationController.h Include/Private/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h + Include/Private/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.h Include/Private/UserManagement/AWSCognitoUserManagementController.h Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h @@ -45,6 +46,7 @@ set(FILES Source/Authorization/ClientAuthAWSCredentials.cpp Source/Authorization/AWSCognitoAuthorizationController.cpp Source/Authorization/AWSClientAuthPersistentCognitoIdentityProvider.cpp + Source/Authorization/AWSClientAuthCognitoCachingAuthenticatedCredentialsProvider.cpp Source/UserManagement/AWSCognitoUserManagementController.cpp ) diff --git a/Gems/AWSCore/cdk/README.md b/Gems/AWSCore/cdk/README.md index d50ca40279..644c22d36b 100644 --- a/Gems/AWSCore/cdk/README.md +++ b/Gems/AWSCore/cdk/README.md @@ -65,6 +65,22 @@ them to your `setup.py` file and rerun the `pip install -r requirements.txt` command. ## Optional Features + +Optional features are activated by passing [runtime context variables](https://docs.aws.amazon.com/cdk/latest/guide/context.html). To use multiple optional features together provide one key-value pair at a time: +``` +cdk synth --context key1=value1 --context key2=value2 MyStack +``` + +### Automatic S3 and DynamoDB Cleanup +The S3 bucket and Dynamodb created by the sample will be left behind as the CDK defaults to retaining such storage (both have default policies to retain resources on destroy). To delete +the storage resources created when using CDK destroy, use the following commands to synthesize and destroy the CDK application. +``` +cdk synth -c remove_all_storage_on_destroy=true --all +cdk deploy -c remove_all_storage_on_destroy=true --all +cdk destroy --all +``` + +### Server Access Logging Server access logging is enabled by default. To disable the feature, use the following commands to synthesize and deploy this CDK application. ``` diff --git a/Gems/AWSCore/cdk/core/core_stack.py b/Gems/AWSCore/cdk/core/core_stack.py index c124cb72ab..4124b7b566 100755 --- a/Gems/AWSCore/cdk/core/core_stack.py +++ b/Gems/AWSCore/cdk/core/core_stack.py @@ -86,13 +86,21 @@ class CoreStack(core.Stack): # Create an S3 bucket for Amazon S3 server access logging # See https://docs.aws.amazon.com/AmazonS3/latest/dev/security-best-practices.html if self.node.try_get_context('disable_access_log') != 'true': + + # Auto cleanup bucket and data if requested + _remove_storage = self.node.try_get_context('remove_all_storage_on_destroy') == 'true' + _removal_policy = core.RemovalPolicy.DESTROY if _remove_storage else core.RemovalPolicy.RETAIN + self._server_access_logs_bucket = s3.Bucket( self, f'{self._project_name}-{self._feature_name}-Access-Log-Bucket', + access_control=s3.BucketAccessControl.LOG_DELIVERY_WRITE, + auto_delete_objects = _remove_storage, block_public_access=s3.BlockPublicAccess.BLOCK_ALL, encryption=s3.BucketEncryption.S3_MANAGED, - access_control=s3.BucketAccessControl.LOG_DELIVERY_WRITE + removal_policy=_removal_policy ) + self._server_access_logs_bucket.grant_read(self._admin_group) # Export access log bucket name diff --git a/Gems/AWSCore/cdk/example/example_resources_stack.py b/Gems/AWSCore/cdk/example/example_resources_stack.py index ac229cb313..6a67ed9406 100755 --- a/Gems/AWSCore/cdk/example/example_resources_stack.py +++ b/Gems/AWSCore/cdk/example/example_resources_stack.py @@ -126,11 +126,17 @@ class ExampleResources(core.Stack): core.Fn.import_value(f"{self._project_name}:ServerAccessLogsBucket") ) + # Auto cleanup bucket and data if requested + _remove_storage = self.node.try_get_context('remove_all_storage_on_destroy') == 'true' + _removal_policy = core.RemovalPolicy.DESTROY if _remove_storage else core.RemovalPolicy.RETAIN + example_bucket = s3.Bucket( self, f'{self._project_name}-{self._feature_name}-Example-S3bucket', + auto_delete_objects=_remove_storage, block_public_access=s3.BlockPublicAccess.BLOCK_ALL, encryption=s3.BucketEncryption.S3_MANAGED, + removal_policy=_removal_policy, server_access_logs_bucket= server_access_logs_bucket if server_access_logs_bucket else None, server_access_logs_prefix= @@ -170,6 +176,11 @@ class ExampleResources(core.Stack): type=dynamo.AttributeType.STRING ) ) + + # Auto-delete the table when requested + if self.node.try_get_context('remove_all_storage_on_destroy') == 'true': + demo_table.apply_removal_policy(core.RemovalPolicy.DESTROY) + return demo_table def __create_outputs(self) -> None: diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Albedo.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Albedo.preset similarity index 60% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/Albedo.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Albedo.preset index fe2e7e0cb4..dc1f38d2da 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Albedo.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Albedo.preset @@ -7,16 +7,6 @@ "UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}", "Name": "Albedo", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_basecolor", - "_diff", - "_color", - "_col", - "_albedo", - "_alb", - "_bc", - "_diffuse" - ], "PixelFormat": "BC1", "DiscardAlpha": true, "IsPowerOf2": true, @@ -29,16 +19,6 @@ "UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}", "Name": "Albedo", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_col", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "ASTC_6x6", "MaxTextureSize": 2048, "DiscardAlpha": true, @@ -51,16 +31,6 @@ "UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}", "Name": "Albedo", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_col", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "ASTC_6x6", "MaxTextureSize": 2048, "DiscardAlpha": true, @@ -73,16 +43,6 @@ "UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}", "Name": "Albedo", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_col", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "BC1", "DiscardAlpha": true, "IsPowerOf2": true, @@ -94,16 +54,6 @@ "UUID": "{08A95286-ADB2-41E4-96EB-DB48F4726D6A}", "Name": "Albedo", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_col", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "BC1", "DiscardAlpha": true, "IsPowerOf2": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/AlbedoWithCoverage.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithCoverage.preset similarity index 60% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/AlbedoWithCoverage.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithCoverage.preset index fda5a9cc52..439a057410 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/AlbedoWithCoverage.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithCoverage.preset @@ -7,15 +7,6 @@ "UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}", "Name": "AlbedoWithCoverage", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "BC1a", "IsPowerOf2": true, "MipMapSetting": { @@ -27,15 +18,6 @@ "UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}", "Name": "AlbedoWithCoverage", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "ASTC_6x6", "IsPowerOf2": true, "MipMapSetting": { @@ -46,15 +28,6 @@ "UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}", "Name": "AlbedoWithCoverage", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "ASTC_6x6", "IsPowerOf2": true, "MipMapSetting": { @@ -65,15 +38,6 @@ "UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}", "Name": "AlbedoWithCoverage", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "BC1a", "IsPowerOf2": true, "MipMapSetting": { @@ -84,15 +48,6 @@ "UUID": "{57ED16B1-407B-4E29-BCFC-D3BAE60F2C85}", "Name": "AlbedoWithCoverage", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "BC1a", "IsPowerOf2": true, "MipMapSetting": { diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/AlbedoWithGenericAlpha.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithGenericAlpha.preset similarity index 55% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/AlbedoWithGenericAlpha.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithGenericAlpha.preset index 19d2b2bbe6..c315ede21c 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/AlbedoWithGenericAlpha.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AlbedoWithGenericAlpha.preset @@ -7,17 +7,7 @@ "UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}", "Name": "AlbedoWithGenericAlpha", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], - "PixelFormat": "BC3", - "IsPowerOf2": true, + "PixelFormat": "ASTC_4x4", "MipMapSetting": { "MipGenType": "Box" } @@ -27,18 +17,8 @@ "UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}", "Name": "AlbedoWithGenericAlpha", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "ASTC_6x6", "MaxTextureSize": 2048, - "IsPowerOf2": true, "MipMapSetting": { "MipGenType": "Box" } @@ -47,18 +27,8 @@ "UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}", "Name": "AlbedoWithGenericAlpha", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "ASTC_6x6", "MaxTextureSize": 2048, - "IsPowerOf2": true, "MipMapSetting": { "MipGenType": "Box" } @@ -67,17 +37,7 @@ "UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}", "Name": "AlbedoWithGenericAlpha", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "BC3", - "IsPowerOf2": true, "MipMapSetting": { "MipGenType": "Box" } @@ -86,17 +46,7 @@ "UUID": "{5D9ECB52-4CD9-4CB8-80E3-10CAE5EFB8A2}", "Name": "AlbedoWithGenericAlpha", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_diff", - "_color", - "_albedo", - "_alb", - "_basecolor", - "_bc", - "_diffuse" - ], "PixelFormat": "BC3", - "IsPowerOf2": true, "MipMapSetting": { "MipGenType": "Box" } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/AmbientOcclusion.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AmbientOcclusion.preset similarity index 64% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/AmbientOcclusion.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AmbientOcclusion.preset index d5acef34d6..573de18b88 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/AmbientOcclusion.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/AmbientOcclusion.preset @@ -8,12 +8,6 @@ "Name": "AmbientOcclusion", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ao", - "_ambocc", - "_amb", - "_ambientocclusion" - ], "PixelFormat": "BC4" }, "PlatformsPresets": { @@ -22,12 +16,6 @@ "Name": "AmbientOcclusion", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ao", - "_ambocc", - "_amb", - "_ambientocclusion" - ], "MaxTextureSize": 2048, "PixelFormat": "ASTC_4x4" }, @@ -36,12 +24,6 @@ "Name": "AmbientOcclusion", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ao", - "_ambocc", - "_amb", - "_ambientocclusion" - ], "MaxTextureSize": 2048, "PixelFormat": "ASTC_4x4" }, @@ -50,12 +32,6 @@ "Name": "AmbientOcclusion", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ao", - "_ambocc", - "_amb", - "_ambientocclusion" - ], "PixelFormat": "BC4" }, "provo": { @@ -63,12 +39,6 @@ "Name": "AmbientOcclusion", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ao", - "_ambocc", - "_amb", - "_ambientocclusion" - ], "PixelFormat": "BC4" } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/ConvolvedCubemap.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ConvolvedCubemap.preset similarity index 88% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/ConvolvedCubemap.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ConvolvedCubemap.preset index abdf6501be..1ef15ada45 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/ConvolvedCubemap.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ConvolvedCubemap.preset @@ -8,10 +8,6 @@ "Name": "ConvolvedCubemap", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ccm", - "_convolvedcubemap" - ], "SuppressEngineReduce": true, "PixelFormat": "R9G9B9E5", "DiscardAlpha": true, @@ -35,10 +31,6 @@ "Name": "ConvolvedCubemap", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ccm", - "_convolvedcubemap" - ], "SuppressEngineReduce": true, "PixelFormat": "R9G9B9E5", "DiscardAlpha": true, @@ -61,10 +53,6 @@ "Name": "ConvolvedCubemap", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ccm", - "_convolvedcubemap" - ], "SuppressEngineReduce": true, "PixelFormat": "R9G9B9E5", "DiscardAlpha": true, @@ -87,10 +75,6 @@ "Name": "ConvolvedCubemap", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ccm", - "_convolvedcubemap" - ], "SuppressEngineReduce": true, "PixelFormat": "R9G9B9E5", "DiscardAlpha": true, @@ -113,10 +97,6 @@ "Name": "ConvolvedCubemap", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ccm", - "_convolvedcubemap" - ], "SuppressEngineReduce": true, "PixelFormat": "R9G9B9E5", "DiscardAlpha": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Decal_AlbedoWithOpacity.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Decal_AlbedoWithOpacity.preset similarity index 86% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/Decal_AlbedoWithOpacity.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Decal_AlbedoWithOpacity.preset index e2e009afc5..873d434380 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Decal_AlbedoWithOpacity.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Decal_AlbedoWithOpacity.preset @@ -6,9 +6,6 @@ "DefaultPreset": { "UUID": "{E06B5087-2640-49B6-B9BA-D40048162B90}", "Name": "Decal_AlbedoWithOpacity", - "FileMasks": [ - "_decal" - ], "PixelFormat": "BC7t", "IsPowerOf2": true, "MipMapSetting": { @@ -21,9 +18,6 @@ "android": { "UUID": "{E06B5087-2640-49B6-B9BA-D40048162B90}", "Name": "Decal_AlbedoWithOpacity", - "FileMasks": [ - "_decal" - ], "PixelFormat": "ASTC_4x4", "MaxTextureSize": 2048, "IsPowerOf2": true, @@ -36,9 +30,6 @@ "ios": { "UUID": "{E06B5087-2640-49B6-B9BA-D40048162B90}", "Name": "Decal_AlbedoWithOpacity", - "FileMasks": [ - "_decal" - ], "PixelFormat": "ASTC_4x4", "MaxTextureSize": 2048, "IsPowerOf2": true, @@ -51,9 +42,6 @@ "mac": { "UUID": "{E06B5087-2640-49B6-B9BA-D40048162B90}", "Name": "Decal_AlbedoWithOpacity", - "FileMasks": [ - "_decal" - ], "PixelFormat": "BC3", "IsPowerOf2": true, "MipMapSetting": { @@ -65,9 +53,6 @@ "provo": { "UUID": "{E06B5087-2640-49B6-B9BA-D40048162B90}", "Name": "Decal_AlbedoWithOpacity", - "FileMasks": [ - "_decal" - ], "PixelFormat": "BC7t", "IsPowerOf2": true, "MipMapSetting": { diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Displacement.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Displacement.preset similarity index 59% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/Displacement.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Displacement.preset index 28ac84d646..04f35dbd6f 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Displacement.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Displacement.preset @@ -8,18 +8,6 @@ "Name": "Displacement", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_displ", - "_disp", - "_dsp", - "_d", - "_dm", - "_displacement", - "_height", - "_hm", - "_ht", - "_h" - ], "PixelFormat": "BC4", "DiscardAlpha": true, "IsPowerOf2": true, @@ -33,18 +21,6 @@ "Name": "Displacement", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_displ", - "_disp", - "_dsp", - "_d", - "_dm", - "_displacement", - "_height", - "_hm", - "_ht", - "_h" - ], "PixelFormat": "ASTC_4x4", "MaxTextureSize": 2048, "DiscardAlpha": true, @@ -59,18 +35,6 @@ "Name": "Displacement", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_displ", - "_disp", - "_dsp", - "_d", - "_dm", - "_displacement", - "_height", - "_hm", - "_ht", - "_h" - ], "PixelFormat": "ASTC_4x4", "MaxTextureSize": 2048, "DiscardAlpha": true, @@ -84,18 +48,6 @@ "Name": "Displacement", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_displ", - "_disp", - "_dsp", - "_d", - "_dm", - "_displacement", - "_height", - "_hm", - "_ht", - "_h" - ], "PixelFormat": "BC4", "DiscardAlpha": true, "IsPowerOf2": true, @@ -108,18 +60,6 @@ "Name": "Displacement", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_displ", - "_disp", - "_dsp", - "_d", - "_dm", - "_displacement", - "_height", - "_hm", - "_ht", - "_h" - ], "PixelFormat": "BC4", "DiscardAlpha": true, "IsPowerOf2": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Emissive.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Emissive.preset similarity index 61% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/Emissive.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Emissive.preset index f5e3a79357..798b8d1657 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Emissive.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Emissive.preset @@ -7,13 +7,6 @@ "UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}", "Name": "Emissive", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_emissive", - "_e", - "_glow", - "_em", - "_emit" - ], "PixelFormat": "BC7", "DiscardAlpha": true }, @@ -22,13 +15,6 @@ "UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}", "Name": "Emissive", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_emissive", - "_e", - "_glow", - "_em", - "_emit" - ], "PixelFormat": "ASTC_6x6", "MaxTextureSize": 2048, "DiscardAlpha": true @@ -37,13 +23,6 @@ "UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}", "Name": "Emissive", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_emissive", - "_e", - "_glow", - "_em", - "_emit" - ], "PixelFormat": "ASTC_6x6", "MaxTextureSize": 2048, "DiscardAlpha": true @@ -52,13 +31,6 @@ "UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}", "Name": "Emissive", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_emissive", - "_e", - "_glow", - "_em", - "_emit" - ], "PixelFormat": "BC7", "DiscardAlpha": true }, @@ -66,13 +38,6 @@ "UUID": "{07041D83-E0C3-4726-8735-CA0FE550C9A0}", "Name": "Emissive", "RGB_Weight": "CIEXYZ", - "FileMasks": [ - "_emissive", - "_e", - "_glow", - "_em", - "_emit" - ], "PixelFormat": "BC7", "DiscardAlpha": true } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Gradient.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Gradient.preset similarity index 100% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/Gradient.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Gradient.preset diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Greyscale.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Greyscale.preset similarity index 77% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/Greyscale.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Greyscale.preset index c71ada1269..19439bad2d 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Greyscale.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Greyscale.preset @@ -8,11 +8,8 @@ "Name": "Greyscale", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_mask" - ], "PixelFormat": "BC4", - "IsPowerOf2": true, + "Swizzle": "rrr1", "MipMapSetting": { "MipGenType": "Box" } @@ -23,11 +20,8 @@ "Name": "Greyscale", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_mask" - ], "PixelFormat": "ASTC_4x4", - "IsPowerOf2": true, + "Swizzle": "rrr1", "MipMapSetting": { "MipGenType": "Box" } @@ -37,11 +31,8 @@ "Name": "Greyscale", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_mask" - ], "PixelFormat": "ASTC_4x4", - "IsPowerOf2": true, + "Swizzle": "rrr1", "MipMapSetting": { "MipGenType": "Box" } @@ -51,11 +42,8 @@ "Name": "Greyscale", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_mask" - ], "PixelFormat": "BC4", - "IsPowerOf2": true, + "Swizzle": "rrr1", "MipMapSetting": { "MipGenType": "Box" } @@ -65,11 +53,8 @@ "Name": "Greyscale", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_mask" - ], "PixelFormat": "BC4", - "IsPowerOf2": true, + "Swizzle": "rrr1", "MipMapSetting": { "MipGenType": "Box" } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLDiffuse.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLDiffuse.preset similarity index 90% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/IBLDiffuse.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLDiffuse.preset index 8bd6b348d1..845f8e13e4 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLDiffuse.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLDiffuse.preset @@ -7,9 +7,6 @@ "UUID": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}", "Name": "IBLDiffuse", "Description": "The input cubemap generates an IBL diffuse output cubemap.", - "FileMasks": [ - "_ibldiffusecm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -31,9 +28,6 @@ "android": { "UUID": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}", "Name": "IBLDiffuse", - "FileMasks": [ - "_ibldiffusecm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -54,9 +48,6 @@ "ios": { "UUID": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}", "Name": "IBLDiffuse", - "FileMasks": [ - "_ibldiffusecm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -77,9 +68,6 @@ "mac": { "UUID": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}", "Name": "IBLDiffuse", - "FileMasks": [ - "_ibldiffusecm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -100,9 +88,6 @@ "provo": { "UUID": "{E3706342-BF21-4D9C-AE28-9670EB3EF3C5}", "Name": "IBLDiffuse", - "FileMasks": [ - "_ibldiffusecm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLGlobal.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLGlobal.preset similarity index 83% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/IBLGlobal.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLGlobal.preset index 717157f2aa..51daf44d6e 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLGlobal.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLGlobal.preset @@ -8,11 +8,6 @@ "Name": "IBLGlobal", "Description": "The input cubemap generates IBL specular and diffuse cubemaps.", "GenerateIBLOnly": true, - "FileMasks": [ - "_iblglobalcm", - "_cubemap", - "_cm" - ], "CubemapSettings": { "GenerateIBLSpecular": true, "IBLSpecularPreset": "IBLSpecular", diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSkybox.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSkybox.preset similarity index 90% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSkybox.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSkybox.preset index eee9af4cea..1a596468bd 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSkybox.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSkybox.preset @@ -7,9 +7,6 @@ "UUID": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}", "Name": "IBLSkybox", "Description": "The input cubemap generates a skybox, IBL specular, and IBL diffuse output cubemaps.", - "FileMasks": [ - "_iblskyboxcm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -29,9 +26,6 @@ "android": { "UUID": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}", "Name": "IBLSkybox", - "FileMasks": [ - "_iblskyboxcm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -50,9 +44,6 @@ "ios": { "UUID": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}", "Name": "IBLSkybox", - "FileMasks": [ - "_iblskyboxcm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -71,9 +62,6 @@ "mac": { "UUID": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}", "Name": "IBLSkybox", - "FileMasks": [ - "_iblskyboxcm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -92,9 +80,6 @@ "provo": { "UUID": "{E6441EAC-9843-484B-8EFC-C03B2935B48D}", "Name": "IBLSkybox", - "FileMasks": [ - "_iblskyboxcm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecular.preset similarity index 87% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecular.preset index 4f935c73ff..691f554540 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecular.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecular.preset @@ -7,10 +7,6 @@ "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", "Description": "The input cubemap generates an IBL specular output cubemap.", - "FileMasks": [ - "_iblspecularcm", - "_iblspecularcm256" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -34,10 +30,6 @@ "android": { "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", - "FileMasks": [ - "_iblspecularcm", - "_iblspecularcm256" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -60,10 +52,6 @@ "ios": { "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", - "FileMasks": [ - "_iblspecularcm", - "_iblspecularcm256" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -86,10 +74,6 @@ "mac": { "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", - "FileMasks": [ - "_iblspecularcm", - "_iblspecularcm256" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -112,10 +96,6 @@ "provo": { "UUID": "{908DA68C-97FB-4C4A-97BC-5A55F30F14FA}", "Name": "IBLSpecular", - "FileMasks": [ - "_iblspecularcm", - "_iblspecularcm256" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularHigh.preset similarity index 90% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularHigh.preset index ff4e143326..b436386864 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularHigh.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularHigh.preset @@ -7,9 +7,6 @@ "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", "Name": "IBLSpecularHigh", "Description": "The input cubemap generates an IBL specular output cubemap.", - "FileMasks": [ - "_iblspecularcm512" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -33,9 +30,6 @@ "android": { "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", "Name": "IBLSpecularHigh", - "FileMasks": [ - "_iblspecularcm512" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -58,9 +52,6 @@ "ios": { "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", "Name": "IBLSpecularHigh", - "FileMasks": [ - "_iblspecularcm512" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -83,9 +74,6 @@ "mac": { "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", "Name": "IBLSpecularHigh", - "FileMasks": [ - "_iblspecularcm512" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -108,9 +96,6 @@ "provo": { "UUID": "{B66395E1-8D0E-4159-989B-FC2B9F091B75}", "Name": "IBLSpecularHigh", - "FileMasks": [ - "_iblspecularcm512" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularLow.preset similarity index 90% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularLow.preset index ee9ddd6ac7..7810028efa 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularLow.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularLow.preset @@ -7,9 +7,6 @@ "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", "Name": "IBLSpecularLow", "Description": "The input cubemap generates an IBL specular output cubemap.", - "FileMasks": [ - "_iblspecularcm128" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -33,9 +30,6 @@ "android": { "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", "Name": "IBLSpecularLow", - "FileMasks": [ - "_iblspecularcm128" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -58,9 +52,6 @@ "ios": { "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", "Name": "IBLSpecularLow", - "FileMasks": [ - "_iblspecularcm128" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -83,9 +74,6 @@ "mac": { "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", "Name": "IBLSpecularLow", - "FileMasks": [ - "_iblspecularcm128" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -108,9 +96,6 @@ "provo": { "UUID": "{7273ACAE-6E34-487C-AF71-99423A6E1CB0}", "Name": "IBLSpecularLow", - "FileMasks": [ - "_iblspecularcm128" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularVeryHigh.preset similarity index 90% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularVeryHigh.preset index 08d9416935..a18885dad9 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryHigh.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularVeryHigh.preset @@ -7,9 +7,6 @@ "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", "Name": "IBLSpecularVeryHigh", "Description": "The input cubemap generates an IBL specular output cubemap.", - "FileMasks": [ - "_iblspecularcm1024" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -33,9 +30,6 @@ "android": { "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", "Name": "IBLSpecularVeryHigh", - "FileMasks": [ - "_iblspecularcm1024" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -58,9 +52,6 @@ "ios": { "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", "Name": "IBLSpecularVeryHigh", - "FileMasks": [ - "_iblspecularcm1024" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -83,9 +74,6 @@ "mac": { "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", "Name": "IBLSpecularVeryHigh", - "FileMasks": [ - "_iblspecularcm1024" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -108,9 +96,6 @@ "provo": { "UUID": "{5CD1AFA6-915B-4716-893C-A5B1F4074C22}", "Name": "IBLSpecularVeryHigh", - "FileMasks": [ - "_iblspecularcm1024" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularVeryLow.preset similarity index 90% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularVeryLow.preset index c5c0788848..fb910b563a 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/IBLSpecularVeryLow.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/IBLSpecularVeryLow.preset @@ -7,9 +7,6 @@ "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", "Name": "IBLSpecularVeryLow", "Description": "The input cubemap generates an IBL specular output cubemap.", - "FileMasks": [ - "_iblspecularcm64" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -33,9 +30,6 @@ "android": { "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", "Name": "IBLSpecularVeryLow", - "FileMasks": [ - "_iblspecularcm64" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -58,9 +52,6 @@ "ios": { "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", "Name": "IBLSpecularVeryLow", - "FileMasks": [ - "_iblspecularcm64" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -83,9 +74,6 @@ "mac": { "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", "Name": "IBLSpecularVeryLow", - "FileMasks": [ - "_iblspecularcm64" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -108,9 +96,6 @@ "provo": { "UUID": "{8293C236-D3E8-4352-8B18-C2E82EEE6547}", "Name": "IBLSpecularVeryLow", - "FileMasks": [ - "_iblspecularcm64" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ImageBuilder.settings b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ImageBuilder.settings new file mode 100644 index 0000000000..b26ae03260 --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ImageBuilder.settings @@ -0,0 +1,150 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "BuilderSettingManager", + "ClassData": { + "BuildSettings": { + "android": { + "GlossScale": 16.0, + "GlossBias": 0.0, + "Streaming": false, + "Enable": true + }, + "ios": { + "GlossScale": 16.0, + "GlossBias": 0.0, + "Streaming": false, + "Enable": true + }, + "mac": { + "GlossScale": 16.0, + "GlossBias": 0.0, + "Streaming": false, + "Enable": true + }, + "pc": { + "GlossScale": 16.0, + "GlossBias": 0.0, + "Streaming": false, + "Enable": true + }, + "linux": { + "GlossScale": 16.0, + "GlossBias": 0.0, + "Streaming": false, + "Enable": true + }, + "provo": { + "GlossScale": 16.0, + "GlossBias": 0.0, + "Streaming": false, + "Enable": false + } + }, + "PresetsByFileMask": { + // albedo + "_basecolor": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ], + "_diff": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ], + "_diffuse": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ], + "_color": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ], + "_col": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ], + "_albedo": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ], + "_alb": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ], + "_bc": [ "Albedo", "AlbedoWithGenericAlpha", "AlbedoWithCoverage" ], + // normals + "_ddn": [ "Normals" ], + "_normal": [ "Normals" ], + "_normalmap": [ "Normals" ], + "_normals": [ "Normals" ], + "_norm": [ "Normals" ], + "_nor": [ "Normals" ], + "_nrm": [ "Normals" ], + "_nm": [ "Normals" ], + "_n": [ "Normals" ], + "_ddna": [ "NormalsWithSmoothness" ], + "_normala": [ "NormalsWithSmoothness" ], + "_nrma": [ "NormalsWithSmoothness" ], + "_nma": [ "NormalsWithSmoothness" ], + "_na": [ "NormalsWithSmoothness" ], + // refelctance + "_spec": [ "Reflectance" ], + "_specular": [ "Reflectance" ], + "_metallic": [ "Reflectance" ], + "_refl": [ "Reflectance" ], + "_ref": [ "Reflectance" ], + "_rf": [ "Reflectance" ], + "_gloss": [ "Reflectance" ], + "_g": [ "Reflectance" ], + "_f0": [ "Reflectance" ], + "_specf0": [ "Reflectance" ], + "_metal": [ "Reflectance" ], + "_mtl": [ "Reflectance" ], + "_m": [ "Reflectance" ], + "_mt": [ "Reflectance" ], + "_metalness": [ "Reflectance" ], + "_rough": [ "Reflectance" ], + "_roughness": [ "Reflectance" ], + // opacity + "_sss": [ "Opacity" ], + "_trans": [ "Opacity" ], + "_opac": [ "Opacity" ], + "_opacity": [ "Opacity" ], + "_o": [ "Opacity" ], + "_op": [ "Opacity" ], + "_mask": [ "Opacity", "Greyscale" ], + "_msk": [ "Opacity" ], + "_blend": [ "Opacity" ], + // AO + "_ao": [ "AmbientOcclusion" ], + "_ambocc": [ "AmbientOcclusion" ], + "_amb": [ "AmbientOcclusion" ], + "_ambientocclusion": [ "AmbientOcclusion" ], + // emissive + "_emissive": [ "Emissive" ], + "_e": [ "Emissive" ], + "_glow": [ "Emissive" ], + "_em": [ "Emissive" ], + "_emit": [ "Emissive" ], + // displacement + "_displ": [ "Emissive" ], + "_disp": [ "Emissive" ], + "_dsp": [ "Emissive" ], + "_d": [ "Emissive" ], + "_dm": [ "Emissive" ], + "_displacement": [ "Emissive" ], + "_height": [ "Emissive" ], + "_hm": [ "Emissive" ], + "_ht": [ "Emissive" ], + "_h": [ "Emissive" ], + // cubemap + "_ibldiffusecm": [ "IBLDiffuse" ], + "_iblskyboxcm": [ "IBLSkybox" ], + "_iblspecularcm": [ "IBLSpecular" ], + "_iblspecularcm128": [ "IBLSpecularLow" ], + "_iblspecularcm256": [ "IBLSpecular" ], + "_iblspecularcm512": [ "IBLSpecularHigh" ], + "_iblspecularcm1024": [ "IBLSpecularVeryHigh" ], + "_skyboxcm": [ "Skybox" ], + "_ccm": [ "ConvolvedCubemap" ], + "_convolvedcubemap": [ "ConvolvedCubemap" ], + "_iblglobalcm": [ "IBLGlobal" ], + "_cubemap": [ "IBLGlobal" ], + "_cm": [ "IBLGlobal" ], + // lut + "_lut": [ "LUT_RG8" ], + "_lutr32f": [ "LUT_R32F" ], + "_lutrgba16": [ "LUT_RGBA16" ], + "_lutrg32f": [ "LUT_RG32F" ], + "_lutrgba32f": [ "LUT_RGBA32F" ], + // layer mask + "_layers": [ "LayerMask" ], + "_rgbmask": [ "LayerMask" ], + // decal + "_decal": [ "Decal_AlbedoWithOpacity" ], + // ui + "_ui": [ "UserInterface_Lossless" ] + }, + "DefaultPreset": "Albedo", + "DefaultPresetAlpha": "AlbedoWithGenericAlpha" + } +} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_R32F.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_R32F.preset similarity index 97% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_R32F.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_R32F.preset index 1bb23c6e96..693f268304 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_R32F.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_R32F.preset @@ -6,7 +6,6 @@ "DefaultPreset": { "UUID": "{10D4D7D8-23E2-4FC5-BE6A-DA9949D2C603}", "Name": "LUT_R32F", - "FileMasks": ["_lutr32f"], "SourceColor": "Linear", "DestColor": "Linear", "PixelFormat": "R32F" diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RG16.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RG16.preset similarity index 100% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RG16.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RG16.preset diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RG32F.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RG32F.preset similarity index 97% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RG32F.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RG32F.preset index 2cf0c6ca0a..7277a4b111 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RG32F.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RG32F.preset @@ -6,7 +6,6 @@ "DefaultPreset": { "UUID": "{52470B8B-0798-4E03-B0D3-039D5141CFEC}", "Name": "LUT_RG32F", - "FileMasks": ["_lutrg32f"], "SourceColor": "Linear", "DestColor": "Linear", "PixelFormat": "R32G32F" diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RG8.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RG8.preset similarity index 79% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RG8.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RG8.preset index 9838d532b2..051cc2bedc 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RG8.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RG8.preset @@ -8,9 +8,6 @@ "Name": "LUT_RG8", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lut" - ], "PixelFormat": "R8G8" }, "PlatformsPresets": { @@ -19,9 +16,6 @@ "Name": "LUT_RG8", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lut" - ], "PixelFormat": "R8G8" }, "ios": { @@ -29,9 +23,6 @@ "Name": "LUT_RG8", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lut" - ], "PixelFormat": "R8G8" }, "mac": { @@ -39,9 +30,6 @@ "Name": "LUT_RG8", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lut" - ], "PixelFormat": "R8G8" }, "provo": { @@ -49,9 +37,6 @@ "Name": "LUT_RG8", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lut" - ], "PixelFormat": "R8G8" } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA16.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA16.preset similarity index 78% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA16.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA16.preset index f36d566d7e..ed940e5f25 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA16.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA16.preset @@ -8,9 +8,6 @@ "Name": "LUT_RGBA16", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lutrgba16" - ], "PixelFormat": "R16G16B16A16" }, "PlatformsPresets": { @@ -19,9 +16,6 @@ "Name": "LUT_RGBA16", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lutrgba16" - ], "PixelFormat": "R16G16B16A16" }, "ios": { @@ -29,9 +23,6 @@ "Name": "LUT_RGBA16", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lutrgba16" - ], "PixelFormat": "R16G16B16A16" }, "osx_gl": { @@ -39,9 +30,6 @@ "Name": "LUT_RGBA16", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lutrgba16" - ], "PixelFormat": "R16G16B16A16" }, "provo": { @@ -49,9 +37,6 @@ "Name": "LUT_RGBA16", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lutrgba16" - ], "PixelFormat": "R16G16B16A16" } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA16F.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA16F.preset similarity index 78% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA16F.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA16F.preset index 367c5101b3..f5d109b4a1 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA16F.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA16F.preset @@ -8,9 +8,6 @@ "Name": "LUT_RGBA16F", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lutrgba16f" - ], "PixelFormat": "R16G16B16A16F" }, "PlatformsPresets": { @@ -19,9 +16,6 @@ "Name": "LUT_RGBA16F", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lutrgba16f" - ], "PixelFormat": "R16G16B16A16F" }, "ios": { @@ -29,9 +23,6 @@ "Name": "LUT_RGBA16F", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lutrgba16f" - ], "PixelFormat": "R16G16B16A16F" }, "osx_gl": { @@ -39,9 +30,6 @@ "Name": "LUT_RGBA16F", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lutrgba16f" - ], "PixelFormat": "R16G16B16A16F" }, "provo": { @@ -49,9 +37,6 @@ "Name": "LUT_RGBA16F", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_lutrgba16f" - ], "PixelFormat": "R16G16B16A16F" } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA32F.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA32F.preset similarity index 97% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA32F.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA32F.preset index 3a456825bf..b85cb66c9d 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA32F.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA32F.preset @@ -6,7 +6,6 @@ "DefaultPreset": { "UUID": "{AC4C49D4-2C70-425A-8DBF-E7FB2C61CF8D}", "Name": "LUT_RGBA32F", - "FileMasks": ["_lutrgba32f"], "SourceColor": "Linear", "DestColor": "Linear", "PixelFormat": "R32G32B32A32F" diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA8.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA8.preset similarity index 100% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/LUT_RGBA8.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LUT_RGBA8.preset diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/LayerMask.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LayerMask.preset similarity index 72% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/LayerMask.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LayerMask.preset index 5ce06aaea2..d33db40547 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/LayerMask.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/LayerMask.preset @@ -8,10 +8,6 @@ "Name": "LayerMask", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_layers", - "_rgbmask" - ], "PixelFormat": "R8G8B8X8" }, "PlatformsPresets": { @@ -20,10 +16,6 @@ "Name": "LayerMask", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_layers", - "_rgbmask" - ], "PixelFormat": "R8G8B8X8" }, "ios": { @@ -31,10 +23,6 @@ "Name": "LayerMask", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_layers", - "_rgbmask" - ], "PixelFormat": "R8G8B8X8" }, "mac": { @@ -42,10 +30,6 @@ "Name": "LayerMask", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_layers", - "_rgbmask" - ], "PixelFormat": "R8G8B8X8" }, "provo": { @@ -53,10 +37,6 @@ "Name": "LayerMask", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_layers", - "_rgbmask" - ], "PixelFormat": "R8G8B8X8" } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Normals.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Normals.preset similarity index 62% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/Normals.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Normals.preset index eee0b88686..3f7a9ff111 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Normals.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Normals.preset @@ -8,17 +8,6 @@ "Name": "Normals", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ddn", - "_normal", - "_normalmap", - "_normals", - "_norm", - "_nor", - "_nrm", - "_nm", - "_n" - ], "PixelFormat": "BC5s", "DiscardAlpha": true, "IsPowerOf2": true, @@ -33,17 +22,6 @@ "Name": "Normals", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ddn", - "_normal", - "_normalmap", - "_normals", - "_norm", - "_nor", - "_nrm", - "_nm", - "_n" - ], "PixelFormat": "ASTC_4x4", "DiscardAlpha": true, "MaxTextureSize": 1024, @@ -58,17 +36,6 @@ "Name": "Normals", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ddn", - "_normal", - "_normalmap", - "_normals", - "_norm", - "_nor", - "_nrm", - "_nm", - "_n" - ], "PixelFormat": "ASTC_4x4", "DiscardAlpha": true, "MaxTextureSize": 1024, @@ -83,17 +50,6 @@ "Name": "Normals", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ddn", - "_normal", - "_normalmap", - "_normals", - "_norm", - "_nor", - "_nrm", - "_nm", - "_n" - ], "PixelFormat": "BC5s", "DiscardAlpha": true, "IsPowerOf2": true, @@ -107,17 +63,6 @@ "Name": "Normals", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ddn", - "_normal", - "_normalmap", - "_normals", - "_norm", - "_nor", - "_nrm", - "_nm", - "_n" - ], "PixelFormat": "BC5s", "DiscardAlpha": true, "IsPowerOf2": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsWithSmoothness.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/NormalsWithSmoothness.preset similarity index 74% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsWithSmoothness.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/NormalsWithSmoothness.preset index 2c66cf9190..fd0abf3467 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/NormalsWithSmoothness.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/NormalsWithSmoothness.preset @@ -8,13 +8,6 @@ "Name": "NormalsWithSmoothness", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ddna", - "_normala", - "_nrma", - "_nma", - "_na" - ], "PixelFormat": "BC5s", "PixelFormatAlpha": "BC4", "IsPowerOf2": true, @@ -30,13 +23,6 @@ "Name": "NormalsWithSmoothness", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ddna", - "_normala", - "_nrma", - "_nma", - "_na" - ], "PixelFormat": "ASTC_4x4", "PixelFormatAlpha": "ASTC_4x4", "MaxTextureSize": 2048, @@ -52,13 +38,6 @@ "Name": "NormalsWithSmoothness", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ddna", - "_normala", - "_nrma", - "_nma", - "_na" - ], "PixelFormat": "ASTC_4x4", "PixelFormatAlpha": "ASTC_4x4", "MaxTextureSize": 2048, @@ -74,13 +53,6 @@ "Name": "NormalsWithSmoothness", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ddna", - "_normala", - "_nrma", - "_nma", - "_na" - ], "PixelFormat": "BC5s", "PixelFormatAlpha": "BC4", "IsPowerOf2": true, @@ -95,13 +67,6 @@ "Name": "NormalsWithSmoothness", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_ddna", - "_normala", - "_nrma", - "_nma", - "_na" - ], "PixelFormat": "BC5s", "PixelFormatAlpha": "BC4", "IsPowerOf2": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Opacity.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Opacity.preset similarity index 56% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/Opacity.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Opacity.preset index 53998583cc..e896b74522 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Opacity.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Opacity.preset @@ -8,19 +8,8 @@ "Name": "Opacity", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_sss", - "_trans", - "_opac", - "_opacity", - "_o", - "_opac", - "_op", - "_mask", - "_msk", - "_blend" - ], "PixelFormat": "BC4", + "Swizzle": "rrr1", "IsPowerOf2": true, "MipMapSetting": { "MipGenType": "Box" @@ -32,19 +21,8 @@ "Name": "Opacity", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_sss", - "_trans", - "_opac", - "_opacity", - "_o", - "_opac", - "_op", - "_mask", - "_msk", - "_blend" - ], "PixelFormat": "ASTC_4x4", + "Swizzle": "rrr1", "MaxTextureSize": 2048, "IsPowerOf2": true, "MipMapSetting": { @@ -56,19 +34,8 @@ "Name": "Opacity", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_sss", - "_trans", - "_opac", - "_opacity", - "_o", - "_opac", - "_op", - "_mask", - "_msk", - "_blend" - ], "PixelFormat": "ASTC_4x4", + "Swizzle": "rrr1", "MaxTextureSize": 2048, "IsPowerOf2": true, "MipMapSetting": { @@ -80,19 +47,8 @@ "Name": "Opacity", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_sss", - "_trans", - "_opac", - "_opacity", - "_o", - "_opac", - "_op", - "_mask", - "_msk", - "_blend" - ], "PixelFormat": "BC4", + "Swizzle": "rrr1", "IsPowerOf2": true, "MipMapSetting": { "MipGenType": "Box" @@ -103,19 +59,8 @@ "Name": "Opacity", "SourceColor": "Linear", "DestColor": "Linear", - "FileMasks": [ - "_sss", - "_trans", - "_opac", - "_opacity", - "_o", - "_opac", - "_op", - "_mask", - "_msk", - "_blend" - ], "PixelFormat": "BC4", + "Swizzle": "rrr1", "IsPowerOf2": true, "MipMapSetting": { "MipGenType": "Box" diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/ReferenceImage.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ReferenceImage.preset similarity index 100% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/ReferenceImage.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ReferenceImage.preset diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/ReferenceImage_HDRLinear.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ReferenceImage_HDRLinear.preset similarity index 100% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/ReferenceImage_HDRLinear.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ReferenceImage_HDRLinear.preset diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/ReferenceImage_HDRLinearUncompressed.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ReferenceImage_HDRLinearUncompressed.preset similarity index 100% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/ReferenceImage_HDRLinearUncompressed.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ReferenceImage_HDRLinearUncompressed.preset diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/ReferenceImage_Linear.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ReferenceImage_Linear.preset similarity index 100% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/ReferenceImage_Linear.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/ReferenceImage_Linear.preset diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Reflectance.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Reflectance.preset new file mode 100644 index 0000000000..e6fd73b1be --- /dev/null +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Reflectance.preset @@ -0,0 +1,66 @@ +{ + "Type": "JsonSerialization", + "Version": 1, + "ClassName": "MultiplatformPresetSettings", + "ClassData": { + "DefaultPreset": { + "UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", + "Name": "Reflectance", + "SourceColor": "Linear", + "DestColor": "Linear", + "PixelFormat": "BC1", + "IsPowerOf2": true, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "PlatformsPresets": { + "android": { + "UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", + "Name": "Reflectance", + "SourceColor": "Linear", + "DestColor": "Linear", + "PixelFormat": "ASTC_6x6", + "MaxTextureSize": 2048, + "IsPowerOf2": true, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "ios": { + "UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", + "Name": "Reflectance", + "SourceColor": "Linear", + "DestColor": "Linear", + "PixelFormat": "ASTC_6x6", + "MaxTextureSize": 2048, + "IsPowerOf2": true, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "mac": { + "UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", + "Name": "Reflectance", + "SourceColor": "Linear", + "DestColor": "Linear", + "PixelFormat": "BC1", + "IsPowerOf2": true, + "MipMapSetting": { + "MipGenType": "Box" + } + }, + "provo": { + "UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", + "Name": "Reflectance", + "SourceColor": "Linear", + "DestColor": "Linear", + "PixelFormat": "BC1", + "IsPowerOf2": true, + "MipMapSetting": { + "MipGenType": "Box" + } + } + } + } +} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Skybox.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Skybox.preset similarity index 86% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/Skybox.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Skybox.preset index 4f71855ecf..b502872f92 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Skybox.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/Skybox.preset @@ -6,9 +6,6 @@ "DefaultPreset": { "UUID": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}", "Name": "Skybox", - "FileMasks": [ - "_skyboxcm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -24,9 +21,6 @@ "android": { "UUID": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}", "Name": "Skybox", - "FileMasks": [ - "_skyboxcm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -41,9 +35,6 @@ "ios": { "UUID": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}", "Name": "Skybox", - "FileMasks": [ - "_skyboxcm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -58,9 +49,6 @@ "mac": { "UUID": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}", "Name": "Skybox", - "FileMasks": [ - "_skyboxcm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, @@ -75,9 +63,6 @@ "provo": { "UUID": "{F359CD3B-37E6-4627-B4F6-2DFC2C0E3C1C}", "Name": "Skybox", - "FileMasks": [ - "_skyboxcm" - ], "SourceColor": "Linear", "DestColor": "Linear", "SuppressEngineReduce": true, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/UserInterface_Compressed.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/UserInterface_Compressed.preset similarity index 95% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/UserInterface_Compressed.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/UserInterface_Compressed.preset index 13334de700..7e2c42fa6b 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/UserInterface_Compressed.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/UserInterface_Compressed.preset @@ -9,8 +9,7 @@ "SuppressEngineReduce": true, "PixelFormat": "R8G8B8A8", "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ "_ui" ] + "DestColor": "Linear" }, "PlatformsPresets": { "android": { diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/UserInterface_Lossless.preset b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/UserInterface_Lossless.preset similarity index 95% rename from Gems/Atom/Asset/ImageProcessingAtom/Config/UserInterface_Lossless.preset rename to Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/UserInterface_Lossless.preset index 39066b242b..bec6a604ef 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/UserInterface_Lossless.preset +++ b/Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/UserInterface_Lossless.preset @@ -9,8 +9,7 @@ "SuppressEngineReduce": true, "PixelFormat": "R8G8B8A8", "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ "_ui" ] + "DestColor": "Linear" }, "PlatformsPresets": { "android": { diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp index a4ba846f1b..2b24fc1bc4 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.cpp @@ -8,6 +8,7 @@ #include "BuilderSettingManager.h" +#include #include #include #include @@ -17,8 +18,9 @@ #include #include #include -#include #include +#include +#include #include #include @@ -41,13 +43,18 @@ namespace ImageProcessingAtom { - const char* BuilderSettingManager::s_defaultConfigRelativeFolder = "Gems/Atom/Asset/ImageProcessingAtom/Config/"; + const char* BuilderSettingManager::s_defaultConfigRelativeFolder = "Gems/Atom/Asset/ImageProcessingAtom/Assets/Config/"; const char* BuilderSettingManager::s_projectConfigRelativeFolder = "Config/AtomImageBuilder/"; const char* BuilderSettingManager::s_builderSettingFileName = "ImageBuilder.settings"; - const char* BuilderSettingManager::s_presetFileExtension = ".preset"; + const char* BuilderSettingManager::s_presetFileExtension = "preset"; const char FileMaskDelimiter = '_'; + namespace + { + static constexpr const char* const LogWindow = "Image Processing"; + } + #if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) #define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3) \ namespace ImageProcess##PrivateName \ @@ -69,13 +76,15 @@ namespace ImageProcessingAtom if (serialize) { serialize->Class() - ->Version(1) - ->Field("AnalysisFingerprint", &BuilderSettingManager::m_analysisFingerprint) + ->Version(2) ->Field("BuildSettings", &BuilderSettingManager::m_builderSettings) - ->Field("DefaultPresetsByFileMask", &BuilderSettingManager::m_defaultPresetByFileMask) + ->Field("PresetsByFileMask", &BuilderSettingManager::m_presetFilterMap) ->Field("DefaultPreset", &BuilderSettingManager::m_defaultPreset) ->Field("DefaultPresetAlpha", &BuilderSettingManager::m_defaultPresetAlpha) - ->Field("DefaultPresetNonePOT", &BuilderSettingManager::m_defaultPresetNonePOT); + ->Field("DefaultPresetNonePOT", &BuilderSettingManager::m_defaultPresetNonePOT) + // deprecated properties + ->Field("DefaultPresetsByFileMask", &BuilderSettingManager::m_defaultPresetByFileMask) + ->Field("AnalysisFingerprint", &BuilderSettingManager::m_analysisFingerprint); } } @@ -122,7 +131,7 @@ namespace ImageProcessingAtom s_globalInstance.Reset(); } - const PresetSettings* BuilderSettingManager::GetPreset(const PresetName& presetName, const PlatformName& platform, AZStd::string_view* settingsFilePathOut) + const PresetSettings* BuilderSettingManager::GetPreset(const PresetName& presetName, const PlatformName& platform, AZStd::string_view* settingsFilePathOut) const { AZStd::lock_guard lock(m_presetMapLock); auto itr = m_presets.find(presetName); @@ -137,16 +146,17 @@ namespace ImageProcessingAtom return nullptr; } - const BuilderSettings* BuilderSettingManager::GetBuilderSetting(const PlatformName& platform) + const BuilderSettings* BuilderSettingManager::GetBuilderSetting(const PlatformName& platform) const { - if (m_builderSettings.find(platform) != m_builderSettings.end()) + auto itr = m_builderSettings.find(platform); + if (itr != m_builderSettings.end()) { - return &m_builderSettings[platform]; + return &itr->second; } return nullptr; } - const PlatformNameList BuilderSettingManager::GetPlatformList() + const PlatformNameList BuilderSettingManager::GetPlatformList() const { PlatformNameList platforms; @@ -161,7 +171,7 @@ namespace ImageProcessingAtom return platforms; } - const AZStd::map >& BuilderSettingManager::GetPresetFilterMap() + const AZStd::map >& BuilderSettingManager::GetPresetFilterMap() const { AZStd::lock_guard lock(m_presetMapLock); return m_presetFilterMap; @@ -188,7 +198,6 @@ namespace ImageProcessingAtom m_presetFilterMap.clear(); m_builderSettings.clear(); m_presets.clear(); - m_defaultPresetByFileMask.clear(); } StringOutcome BuilderSettingManager::LoadConfig() @@ -198,44 +207,53 @@ namespace ImageProcessingAtom auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); if (fileIoBase == nullptr) { - return AZ::Failure(AZStd::string("File IO instance needs to be initialized to resolve ImageProcessing builder file aliases")); + return AZ::Failure( + AZStd::string("File IO instance needs to be initialized to resolve ImageProcessing builder file aliases")); } - // Construct the default setting path - - AZ::IO::FixedMaxPath defaultConfigFolder; if (auto engineRoot = fileIoBase->ResolvePath("@engroot@"); engineRoot.has_value()) { - defaultConfigFolder = *engineRoot; - defaultConfigFolder /= s_defaultConfigRelativeFolder; + m_defaultConfigFolder = *engineRoot; + m_defaultConfigFolder /= s_defaultConfigRelativeFolder; } - AZ::IO::FixedMaxPath projectConfigFolder; if (auto sourceGameRoot = fileIoBase->ResolvePath("@projectroot@"); sourceGameRoot.has_value()) { - projectConfigFolder = *sourceGameRoot; - projectConfigFolder /= s_projectConfigRelativeFolder; + m_projectConfigFolder = *sourceGameRoot; + m_projectConfigFolder /= s_projectConfigRelativeFolder; } AZStd::lock_guard lock(m_presetMapLock); ClearSettings(); - outcome = LoadSettings((projectConfigFolder / s_builderSettingFileName).Native()); - - if (!outcome.IsSuccess()) - { - outcome = LoadSettings((defaultConfigFolder / s_builderSettingFileName).Native()); - } + outcome = LoadSettings(); if (outcome.IsSuccess()) { // Load presets in default folder first, then load from project folder. // The same presets which loaded last will overwrite previous loaded one. - LoadPresets(defaultConfigFolder.Native()); - LoadPresets(projectConfigFolder.Native()); + LoadPresets(m_defaultConfigFolder.Native()); + LoadPresets(m_projectConfigFolder.Native()); + } - // Regenerate file mask mapping after all presets loaded - RegenerateMappings(); + // Collect extra file masks from preset files + CollectFileMasksFromPresets(); + + + if (QCoreApplication::instance()) + { + m_fileWatcher.reset(new QFileSystemWatcher); + // track preset files + // Note, the QT signal would only works for AP but not AssetBuilder + // We use file time stamp to track preset file change in builder's CreateJob + for (auto& preset : m_presets) + { + m_fileWatcher.data()->addPath(QString(preset.second.m_presetFilePath.c_str())); + } + m_fileWatcher.data()->addPath(QString(m_defaultConfigFolder.c_str())); + m_fileWatcher.data()->addPath(QString(m_projectConfigFolder.c_str())); + QObject::connect(m_fileWatcher.data(), &QFileSystemWatcher::fileChanged, this, &BuilderSettingManager::OnFileChanged); + QObject::connect(m_fileWatcher.data(), &QFileSystemWatcher::directoryChanged, this, &BuilderSettingManager::OnFolderChanged); } return outcome; @@ -243,36 +261,84 @@ namespace ImageProcessingAtom void BuilderSettingManager::LoadPresets(AZStd::string_view presetFolder) { - AZStd::lock_guard lock(m_presetMapLock); - QDirIterator it(presetFolder.data(), QStringList() << "*.preset", QDir::Files, QDirIterator::NoIteratorFlags); while (it.hasNext()) { QString filePath = it.next(); - QFileInfo fileInfo = it.fileInfo(); + LoadPreset(filePath.toUtf8().data()); + } + } - MultiplatformPresetSettings preset; - auto result = AZ::JsonSerializationUtils::LoadObjectFromFile(preset, filePath.toUtf8().data()); - if (!result.IsSuccess()) + bool BuilderSettingManager::LoadPreset(const AZStd::string& filePath) + { + QFileInfo fileInfo (filePath.c_str()); + + if (!fileInfo.exists()) + { + return false; + } + + MultiplatformPresetSettings preset; + auto result = AZ::JsonSerializationUtils::LoadObjectFromFile(preset, filePath); + if (!result.IsSuccess()) + { + AZ_Warning(LogWindow, false, "Failed to load preset file %s. Error: %s", + filePath.c_str(), result.GetError().c_str()); + return false; + } + + PresetName presetName(fileInfo.baseName().toUtf8().data()); + + AZ_Warning(LogWindow, presetName == preset.GetPresetName(), "Preset file name '%s' is not" + " same as preset name '%s'. Using preset file name as preset name", + filePath.c_str(), preset.GetPresetName().GetCStr()); + + preset.SetPresetName(presetName); + + m_presets[presetName] = PresetEntry{preset, filePath.c_str(), fileInfo.lastModified()}; + return true; + } + + void BuilderSettingManager::ReloadPreset(const PresetName& presetName) + { + // Find the preset file from project or default config folder + AZStd::string presetFileName = AZStd::string::format("%s.%s", presetName.GetCStr(), s_presetFileExtension); + AZ::IO::FixedMaxPath filePath = m_projectConfigFolder/presetFileName; + QFileInfo fileInfo (filePath.c_str()); + if (!fileInfo.exists()) + { + filePath = (m_defaultConfigFolder/presetFileName).c_str(); + fileInfo = QFileInfo(filePath.c_str()); + } + + AZStd::lock_guard lock(m_presetMapLock); + + //Skip the loading if the file wasn't chagned + if (fileInfo.exists()) + { + if (m_presets.find(presetName) != m_presets.end()) { - AZ_Warning("Image Processing", false, "Failed to load preset file %s. Error: %s", - filePath.toUtf8().data(), result.GetError().c_str()); + if (m_presets[presetName].m_lastModifiedTime == fileInfo.lastModified() + && m_presets[presetName].m_presetFilePath == filePath.c_str()) + { + return; + } } + } - PresetName presetName(fileInfo.baseName().toUtf8().data()); + // remove preset + m_presets.erase(presetName); - AZ_Warning("Image Processing", presetName == preset.GetPresetName(), "Preset file name '%s' is not" - " same as preset name '%s'. Using preset file name as preset name", - filePath.toUtf8().data(), preset.GetPresetName().GetCStr()); - - preset.SetPresetName(presetName); - - m_presets[presetName] = PresetEntry{preset, filePath.toUtf8().data()}; + if (fileInfo.exists()) + { + LoadPreset(filePath.c_str()); } } StringOutcome BuilderSettingManager::LoadConfigFromFolder(AZStd::string_view configFolder) { + AZStd::lock_guard lock(m_presetMapLock); + // Load builder settings AZStd::string settingFilePath = AZStd::string::format("%.*s%s", aznumeric_cast(configFolder.size()), configFolder.data(), s_builderSettingFileName); @@ -282,12 +348,108 @@ namespace ImageProcessingAtom if (result.IsSuccess()) { LoadPresets(configFolder); - RegenerateMappings(); } return result; } + void BuilderSettingManager::ReportDeprecatedSettings() + { + // reported deprecated attributes in image builder settings + if (!m_analysisFingerprint.empty()) + { + AZ_Warning(LogWindow, false, "'AnalysisFingerprint' is deprecated and it should be removed from file [%s]", s_builderSettingFileName); + } + if (!m_defaultPresetByFileMask.empty()) + { + AZ_Warning(LogWindow, false, "'DefaultPresetsByFileMask' is deprecated and it should be removed from file [%s]. Use PresetsByFileMask instead", s_builderSettingFileName); + } + } + + StringOutcome BuilderSettingManager::LoadSettings() + { + // If the project image build setting file exist, it will merge image builder settings from project folder to the settings from default config folder. + bool needMerge = false; + AZStd::string projectSettingFile{ (m_projectConfigFolder / s_builderSettingFileName).Native() }; + + if (AZ::IO::SystemFile::Exists(projectSettingFile.c_str())) + { + needMerge = true; + } + + AZ::Outcome outcome; + AZStd::string defaultSettingFile{ (m_defaultConfigFolder / s_builderSettingFileName).Native() }; + if (needMerge) + { + auto outcome1 = AZ::JsonSerializationUtils::ReadJsonFile(defaultSettingFile); + auto outcome2 = AZ::JsonSerializationUtils::ReadJsonFile(projectSettingFile); + + // return error if it failed to load default settings + if (!outcome1.IsSuccess()) + { + return STRING_OUTCOME_ERROR(outcome1.GetError()); + } + + // if project config was loaded successfully, apply merge patch + rapidjson::Document& originDoc = outcome1.GetValue(); + if (outcome2.IsSuccess()) + { + const rapidjson::Document& patchDoc = outcome2.GetValue(); + AZ::JsonSerializationResult::ResultCode result = + AZ::JsonSerialization::ApplyPatch(originDoc, originDoc.GetAllocator(), patchDoc, AZ::JsonMergeApproach::JsonMergePatch); + + if (result.GetProcessing() == AZ::JsonSerializationResult::Processing::Completed) + { + AZStd::vector outBuffer; + AZ::IO::ByteContainerStream> outStream{ &outBuffer }; + AZ::JsonSerializationUtils::WriteJsonStream(originDoc, outStream); + + outStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN); + + outcome = AZ::JsonSerializationUtils::LoadObjectFromStream(*this, outStream); + if (!outcome.IsSuccess()) + { + return STRING_OUTCOME_ERROR(outcome.GetError()); + } + + ReportDeprecatedSettings(); + + + // Generate config file fingerprint + outStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN); + AZ::u64 hash = AssetBuilderSDK::GetHashFromIOStream(outStream); + m_analysisFingerprint = AZStd::string::format("%llX", hash); + } + else + { + needMerge = false; + AZ_Warning(LogWindow, false, "Failed to fully merge data into image builder settings. Skipping project build setting file [%s]", projectSettingFile.c_str()); + } + } + else + { + AZ_Warning(LogWindow, false, "Failed to load project setting file [%s]. Skipping", projectSettingFile.c_str()); + } + } + + if (!needMerge) + { + outcome = AZ::JsonSerializationUtils::LoadObjectFromFile(*this, defaultSettingFile); + if (!outcome.IsSuccess()) + { + return STRING_OUTCOME_ERROR(outcome.GetError()); + } + + ReportDeprecatedSettings(); + + // Generate config file fingerprint + AZ::u64 hash = AssetBuilderSDK::GetFileHash(defaultSettingFile.c_str()); + m_analysisFingerprint = AZStd::string::format("%llX", hash); + } + + return STRING_OUTCOME_SUCCESS; + } + StringOutcome BuilderSettingManager::LoadSettings(AZStd::string_view filepath) { AZStd::lock_guard lock(m_presetMapLock); @@ -336,13 +498,13 @@ namespace ImageProcessingAtom return m_analysisFingerprint; } - void BuilderSettingManager::RegenerateMappings() + void BuilderSettingManager::CollectFileMasksFromPresets() { AZStd::lock_guard lock(m_presetMapLock); AZStd::string noFilter = AZStd::string(); - - m_presetFilterMap.clear(); + + AZStd::string extraString; for (const auto& presetIter : m_presets) { @@ -357,22 +519,31 @@ namespace ImageProcessingAtom { if (filemask.empty() || filemask[0] != FileMaskDelimiter) { - AZ_Warning("Image Processing", false, "File mask '%s' is invalid. It must start with '%c'.", filemask.c_str(), FileMaskDelimiter); + AZ_Warning(LogWindow, false, "File mask '%s' is invalid. It must start with '%c'.", filemask.c_str(), FileMaskDelimiter); continue; } else if (filemask.size() < 2) { - AZ_Warning("Image Processing", false, "File mask '%s' is invalid. The '%c' must be followed by at least one other character.", filemask.c_str()); + AZ_Warning(LogWindow, false, "File mask '%s' is invalid. The '%c' must be followed by at least one other character.", filemask.c_str()); continue; } else if (filemask.find(FileMaskDelimiter, 1) != AZStd::string::npos) { - AZ_Warning("Image Processing", false, "File mask '%s' is invalid. It must contain only a single '%c' character.", filemask.c_str(), FileMaskDelimiter); + AZ_Warning(LogWindow, false, "File mask '%s' is invalid. It must contain only a single '%c' character.", filemask.c_str(), FileMaskDelimiter); continue; } + + extraString += (filemask + preset.m_name.GetCStr()); + m_presetFilterMap[filemask].insert(preset.m_name); } } + + if (!extraString.empty()) + { + AZ::u64 hash = AZStd::hash{}(extraString); + m_analysisFingerprint += AZStd::string::format("%llX", hash); + } } void BuilderSettingManager::MetafilePathFromImagePath(AZStd::string_view imagePath, AZStd::string& metafilePath) @@ -419,38 +590,15 @@ namespace ImageProcessingAtom return m_presets.find(presetName) != m_presets.end(); } - PresetName BuilderSettingManager::GetSuggestedPreset(AZStd::string_view imageFilePath, IImageObjectPtr imageFromFile) + PresetName BuilderSettingManager::GetSuggestedPreset(AZStd::string_view imageFilePath) const { PresetName emptyPreset; - //load the image to get its size for later use - IImageObjectPtr image = imageFromFile; - //if the input image is empty we will try to load it from the path - if (imageFromFile == nullptr) - { - image = IImageObjectPtr(LoadImageFromFile(imageFilePath)); - } - - if (image == nullptr) - { - return emptyPreset; - } - //get file mask of this image file AZStd::string fileMask = GetFileMask(imageFilePath); PresetName outPreset = emptyPreset; - //check default presets for some file masks - if (m_defaultPresetByFileMask.find(fileMask) != m_defaultPresetByFileMask.end()) - { - outPreset = m_defaultPresetByFileMask[fileMask]; - if (!IsValidPreset(outPreset)) - { - outPreset = emptyPreset; - } - } - //use the preset filter map to find if (outPreset.IsEmpty() && !fileMask.empty()) { @@ -461,54 +609,21 @@ namespace ImageProcessingAtom } } - const PresetSettings* presetInfo = nullptr; - - if (!outPreset.IsEmpty()) - { - presetInfo = GetPreset(outPreset); - - //special case for cubemap - if (presetInfo && presetInfo->m_cubemapSetting) - { - // If it's not a latitude-longitude map or it doesn't match any cubemap layouts then reset its preset - if (!IsValidLatLongMap(image) && CubemapLayout::GetCubemapLayoutInfo(image) == nullptr) - { - outPreset = emptyPreset; - } - } - } - if (outPreset == emptyPreset) { - if (image->GetAlphaContent() == EAlphaContent::eAlphaContent_Absent) - { - outPreset = m_defaultPreset; - } - else - { - outPreset = m_defaultPresetAlpha; - } + outPreset = m_defaultPreset; } - //get the pixel format for selected preset - presetInfo = GetPreset(outPreset); + return outPreset; + } - if (presetInfo) - { - //valid whether image size work with pixel format - if (CPixelFormats::GetInstance().IsImageSizeValid(presetInfo->m_pixelFormat, - image->GetWidth(0), image->GetHeight(0), false)) - { - return outPreset; - } - else - { - AZ_Warning("Image Processing", false, "Image dimensions are not compatible with preset '%s'. The default preset will be used.", presetInfo->m_name.GetCStr()); - } - } - - //uncompressed one which could be used for almost everything - return m_defaultPresetNonePOT; + AZStd::vector BuilderSettingManager::GetPossiblePresetPaths(const PresetName& presetName) const + { + AZStd::vector paths; + AZStd::string presetFile = AZStd::string::format("%s.preset", presetName.GetCStr()); + paths.push_back((m_defaultConfigFolder / presetFile).c_str()); + paths.push_back((m_projectConfigFolder / presetFile).c_str()); + return paths; } bool BuilderSettingManager::DoesSupportPlatform(AZStd::string_view platformId) @@ -526,18 +641,50 @@ namespace ImageProcessingAtom AZStd::string filePath; if (!AzFramework::StringFunc::Path::Join(outputFolder.data(), fileName.c_str(), filePath)) { - AZ_Warning("Image Processing", false, "Failed to construct path with folder '%.*s' and file: '%s' to save preset", + AZ_Warning(LogWindow, false, "Failed to construct path with folder '%.*s' and file: '%s' to save preset", aznumeric_cast(outputFolder.size()), outputFolder.data(), filePath.c_str()); continue; } auto result = AZ::JsonSerializationUtils::SaveObjectToFile(&presetEntry.m_multiPreset, filePath); if (!result.IsSuccess()) { - AZ_Warning("Image Processing", false, "Failed to save preset '%s' to file '%s'. Error: %s", + AZ_Warning(LogWindow, false, "Failed to save preset '%s' to file '%s'. Error: %s", presetEntry.m_multiPreset.GetDefaultPreset().m_name.GetCStr(), filePath.c_str(), result.GetError().c_str()); } } } + void BuilderSettingManager::OnFileChanged(const QString &path) + { + // handles preset file change + // Note: this signal only works with AP but not AssetBuilder + AZ_TracePrintf(LogWindow, "File changed %s\n", path.toUtf8().data()); + QFileInfo info(path); + // skip if the file is not a preset file + // Note: for .settings file change it's handled when restart AP. + if (info.suffix() != s_presetFileExtension) + { + return; + } + + ReloadPreset(PresetName(info.baseName().toUtf8().data())); + } + + void BuilderSettingManager::OnFolderChanged([[maybe_unused]] const QString &path) + { + // handles new file added or removed + // Note: this signal only works with AP but not AssetBuilder + AZ_TracePrintf(LogWindow, "folder changed %s\n", path.toUtf8().data()); + + AZStd::lock_guard lock(m_presetMapLock); + m_presets.clear(); + LoadPresets(m_defaultConfigFolder.Native()); + LoadPresets(m_projectConfigFolder.Native()); + + for (auto& preset : m_presets) + { + m_fileWatcher.data()->addPath(QString(preset.second.m_presetFilePath.c_str())); + } + } } // namespace ImageProcessingAtom diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.h index 3bbb71ea43..e4d45f4186 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/BuilderSettings/BuilderSettingManager.h @@ -10,10 +10,15 @@ #include #include -#include #include +#include +#include #include +#include +#include +#include + class QSettings; class QString; @@ -36,6 +41,7 @@ namespace ImageProcessingAtom * Each preset setting may have different values on different platform, but they are using same uuid. */ class BuilderSettingManager + : public QObject // required for using QFileSystemWatcher { friend class ImageProcessingTest; @@ -49,17 +55,17 @@ namespace ImageProcessingAtom static void DestroyInstance(); static void Reflect(AZ::ReflectContext* context); - const PresetSettings* GetPreset(const PresetName& presetName, const PlatformName& platform = "", AZStd::string_view* settingsFilePathOut = nullptr); + const PresetSettings* GetPreset(const PresetName& presetName, const PlatformName& platform = "", AZStd::string_view* settingsFilePathOut = nullptr) const; - const BuilderSettings* GetBuilderSetting(const PlatformName& platform); + const BuilderSettings* GetBuilderSetting(const PlatformName& platform) const; //! Return A list of platform supported - const PlatformNameList GetPlatformList(); + const PlatformNameList GetPlatformList() const; //! Return A map of preset settings based on their filemasks. //! @key filemask string, empty string means no filemask //! @value set of preset setting names supporting the specified filemask - const AZStd::map>& GetPresetFilterMap(); + const AZStd::map>& GetPresetFilterMap() const; //! Find preset name based on the preset id. const PresetName GetPresetNameFromId(const AZ::Uuid& presetId); @@ -68,7 +74,11 @@ namespace ImageProcessingAtom StringOutcome LoadConfig(); //! Load configurations files from a folder which includes builder settings and presets - StringOutcome LoadConfigFromFolder(AZStd::string_view configFolder); + //! Note: this is only used for unit test. Use LoadConfig() for editor or game launcher + StringOutcome LoadConfigFromFolder(AZStd::string_view configFolder); + + //! Reload preset from config folders + void ReloadPreset(const PresetName& presetName); const AZStd::string& GetAnalysisFingerprint() const; @@ -81,7 +91,12 @@ namespace ImageProcessingAtom //! @param imageFilePath: Filepath string of the image file. The function may load the image from the path for better detection //! @param image: an optional image object which can be used for preset selection if there is no match based file mask. //! @return suggested preset name. - PresetName GetSuggestedPreset(AZStd::string_view imageFilePath, IImageObjectPtr image = nullptr); + PresetName GetSuggestedPreset(AZStd::string_view imageFilePath) const; + + //! Get the possible preset config's full file paths + //! This function is only used for setting up image's source dependency if a preset file is missing + //! Otherwise, the preset's file path can be retrieved in GetPreset() function + AZStd::vector GetPossiblePresetPaths(const PresetName& presetName) const; bool IsValidPreset(PresetName presetName) const; @@ -105,25 +120,41 @@ namespace ImageProcessingAtom private: // functions AZ_DISABLE_COPY_MOVE(BuilderSettingManager); + // Write image builder setting to the file specified by filepath StringOutcome WriteSettings(AZStd::string_view filepath); + // Load image builder settings from the file specified by filepath StringOutcome LoadSettings(AZStd::string_view filepath); + // Load merge image builder settings (project and default) + StringOutcome LoadSettings(); + + // report warnings for the deprecated properties in image builder setting data + void ReportDeprecatedSettings(); + // Clear Builder Settings and any cached maps/lists void ClearSettings(); - // Regenerate Builder Settings and any cached maps/lists - void RegenerateMappings(); + // collect file masks + void CollectFileMasksFromPresets(); // Functions to save/load preset from a folder void SavePresets(AZStd::string_view outputFolder); void LoadPresets(AZStd::string_view presetFolder); + // Load a preset to m_presets and return true if success + bool LoadPreset(const AZStd::string& filePath); + + // handle preset files changes + void OnFileChanged(const QString &path); + void OnFolderChanged(const QString &path); + private: // variables struct PresetEntry { MultiplatformPresetSettings m_multiPreset; AZStd::string m_presetFilePath; // Can be used for debug output + QDateTime m_lastModifiedTime; }; // Builder settings for each platform @@ -131,13 +162,13 @@ namespace ImageProcessingAtom AZStd::unordered_map m_presets; - // Cached list of presets mapped by their file masks. + // a list of presets mapped by their file masks. // @Key file mask, use empty string to indicate all presets without filtering // @Value set of preset names that matches the file mask AZStd::map > m_presetFilterMap; - // A mutex to protect when modifying any map in this manager - AZStd::recursive_mutex m_presetMapLock; + // A mutex to protect when modifying any map in this manager + mutable AZStd::recursive_mutex m_presetMapLock; // Default presets for certain file masks AZStd::map m_defaultPresetByFileMask; @@ -153,5 +184,14 @@ namespace ImageProcessingAtom // Image builder's version AZStd::string m_analysisFingerprint; + + // default config folder + AZ::IO::FixedMaxPath m_defaultConfigFolder; + + // project config folder + AZ::IO::FixedMaxPath m_projectConfigFolder; + + // File system watcher to detect preset file changes + QScopedPointer m_fileWatcher; }; } // namespace ImageProcessingAtom diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.cpp index 067faf3dab..ca999fcd10 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Editor/EditorCommon.cpp @@ -171,7 +171,7 @@ namespace ImageProcessingAtomEditor if (!preset) { AZ_Warning("Texture Editor", false, "Cannot find preset %s! Will assign a suggested one for the texture.", presetName.GetCStr()); - presetName = BuilderSettingManager::Instance()->GetSuggestedPreset(m_fullPath, m_img); + presetName = BuilderSettingManager::Instance()->GetSuggestedPreset(m_fullPath); for (auto& settingIter : m_settingsMap) { diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp index 90d45ae65a..57596f4a71 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/ImageBuilderComponent.cpp @@ -221,6 +221,58 @@ namespace ImageProcessingAtom m_isShuttingDown = true; } + PresetName GetImagePreset(const AZStd::string& filepath) + { + // first let preset from asset info + TextureSettings textureSettings; + StringOutcome output = TextureSettings::LoadTextureSetting(filepath, textureSettings); + + if (!textureSettings.m_preset.IsEmpty()) + { + return textureSettings.m_preset; + } + + return BuilderSettingManager::Instance()->GetSuggestedPreset(filepath); + } + + void HandlePresetDependency(PresetName presetName, AZStd::vector& sourceDependencyList) + { + // Reload preset if it was changed + ImageProcessingAtom::BuilderSettingManager::Instance()->ReloadPreset(presetName); + + AZStd::string_view filePath; + auto presetSettings = BuilderSettingManager::Instance()->GetPreset(presetName, /*default platform*/"", &filePath); + + AssetBuilderSDK::SourceFileDependency sourceFileDependency; + sourceFileDependency.m_sourceDependencyType = AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Absolute; + + // Need to watch any possibe preset paths + AZStd::vector possiblePresetPaths = BuilderSettingManager::Instance()->GetPossiblePresetPaths(presetName); + for (const auto& path:possiblePresetPaths) + { + sourceFileDependency.m_sourceFileDependencyPath = path; + sourceDependencyList.push_back(sourceFileDependency); + } + + if (presetSettings) + { + // handle special case here + // Cubemap setting may reference some other presets + if (presetSettings->m_cubemapSetting) + { + if (presetSettings->m_cubemapSetting->m_generateIBLDiffuse && !presetSettings->m_cubemapSetting->m_iblDiffusePreset.IsEmpty()) + { + HandlePresetDependency(presetSettings->m_cubemapSetting->m_iblDiffusePreset, sourceDependencyList); + } + + if (presetSettings->m_cubemapSetting->m_generateIBLSpecular && !presetSettings->m_cubemapSetting->m_iblSpecularPreset.IsEmpty()) + { + HandlePresetDependency(presetSettings->m_cubemapSetting->m_iblSpecularPreset, sourceDependencyList); + } + } + } + } + // this happens early on in the file scanning pass // this function should consistently always create the same jobs, and should do no checking whether the job is up to date or not - just be consistent. void ImageBuilderWorker::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) @@ -242,13 +294,26 @@ namespace ImageProcessingAtom if (ImageProcessingAtom::BuilderSettingManager::Instance()->DoesSupportPlatform(platformInfo.m_identifier)) { AssetBuilderSDK::JobDescriptor descriptor; - descriptor.m_jobKey = ext + " Atom Compile"; + descriptor.m_jobKey = "Image Compile: " + ext; descriptor.SetPlatformIdentifier(platformInfo.m_identifier.c_str()); descriptor.m_critical = false; + descriptor.m_additionalFingerprintInfo = ""; response.m_createJobOutputs.push_back(descriptor); } } + // add source dependency for .assetinfo file + AssetBuilderSDK::SourceFileDependency sourceFileDependency; + sourceFileDependency.m_sourceDependencyType = AssetBuilderSDK::SourceFileDependency::SourceFileDependencyType::Absolute; + sourceFileDependency.m_sourceFileDependencyPath = request.m_sourceFile; + AZ::StringFunc::Path::ReplaceExtension(sourceFileDependency.m_sourceFileDependencyPath, TextureSettings::ExtensionName); + response.m_sourceFileDependencyList.push_back(sourceFileDependency); + + // add source dependencies for .preset files + // Get the preset for this file + auto presetName = GetImagePreset(request.m_sourceFile); + HandlePresetDependency(presetName, response.m_sourceFileDependencyList); + response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; return; } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp index 5b23009cff..471472486d 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -229,12 +230,24 @@ namespace ImageProcessingAtom AZStd::unique_ptr& cubemapSettings = m_input->m_presetSetting.m_cubemapSetting; if (cubemapSettings->m_generateIBLSpecular && !cubemapSettings->m_iblSpecularPreset.IsEmpty()) { - CreateIBLCubemap(cubemapSettings->m_iblSpecularPreset, SpecularCubemapSuffix, m_iblSpecularCubemapImage); + bool success = CreateIBLCubemap(cubemapSettings->m_iblSpecularPreset, SpecularCubemapSuffix, m_iblSpecularCubemapImage); + if (!success) + { + m_isSucceed = false; + m_isFinished = true; + break; + } } if (cubemapSettings->m_generateIBLDiffuse && !cubemapSettings->m_iblDiffusePreset.IsEmpty()) { - CreateIBLCubemap(cubemapSettings->m_iblDiffusePreset, DiffuseCubemapSuffix, m_iblDiffuseCubemapImage); + bool success = CreateIBLCubemap(cubemapSettings->m_iblDiffusePreset, DiffuseCubemapSuffix, m_iblDiffuseCubemapImage); + if (!success) + { + m_isSucceed = false; + m_isFinished = true; + break; + } } } @@ -251,7 +264,12 @@ namespace ImageProcessingAtom { if (m_input->m_presetSetting.m_cubemapSetting->m_requiresConvolve) { - FillCubemapMipmaps(); + bool success = FillCubemapMipmaps(); + if (!success) + { + m_isSucceed = false; + m_isFinished = true; + } } } else @@ -268,9 +286,7 @@ namespace ImageProcessingAtom // get gloss from normal for all mipmaps and save to alpha channel if (m_input->m_presetSetting.m_glossFromNormals) { - bool hasAlpha = (m_alphaContent == EAlphaContent::eAlphaContent_OnlyBlack - || m_alphaContent == EAlphaContent::eAlphaContent_OnlyBlackAndWhite - || m_alphaContent == EAlphaContent::eAlphaContent_Greyscale); + bool hasAlpha = Utils::NeedAlphaChannel(m_alphaContent); m_image->Get()->GlossFromNormals(hasAlpha); // set alpha content so it won't be ignored later. @@ -347,7 +363,11 @@ namespace ImageProcessingAtom } else { - AZ_TracePrintf("Image Processing", "Image converted with preset [%s] [%s] and saved to [%s] (%d bytes) taking %f seconds\n", + + [[maybe_unused]] const PixelFormatInfo* formatInfo = CPixelFormats::GetInstance().GetPixelFormatInfo(m_image->Get()->GetPixelFormat()); + AZ_TracePrintf("Image Processing", "Image [%dx%d] [%s] converted with preset [%s] [%s] and saved to [%s] (%d bytes) taking %f seconds\n", + m_image->Get()->GetWidth(0), m_image->Get()->GetHeight(0), + formatInfo->szName, m_input->m_presetSetting.m_name.GetCStr(), m_input->m_filePath.c_str(), m_input->m_outputFolder.c_str(), sizeTotal, m_processTime); @@ -421,6 +441,17 @@ namespace ImageProcessingAtom outHeight >>= 1; outReduce++; } + + // resize to min texture size if it's smaller + if (outWidth < presetSettings->m_minTextureSize) + { + outWidth = presetSettings->m_minTextureSize; + } + + if (outHeight < presetSettings->m_minTextureSize) + { + outHeight = presetSettings->m_minTextureSize; + } } bool ImageConvertProcess::ConvertToLinear() @@ -647,7 +678,7 @@ namespace ImageProcessingAtom } else if (!CPixelFormats::GetInstance().IsImageSizeValid(dstFmt, dwWidth, dwHeight, false)) { - AZ_Warning("Image Processing", false, "Image size will be scaled for pixel format %s", CPixelFormats::GetInstance().GetPixelFormatInfo(dstFmt)->szName); + AZ_TracePrintf("Image processing", "Image size will be scaled for pixel format %s\n", CPixelFormats::GetInstance().GetPixelFormatInfo(dstFmt)->szName); } #if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) @@ -758,7 +789,7 @@ namespace ImageProcessingAtom // in very rare user case, an old texture setting file may not have a preset. We fix it over here too. if (textureSettings.m_preset.IsEmpty()) { - textureSettings.m_preset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilePath, srcImage); + textureSettings.m_preset = BuilderSettingManager::Instance()->GetSuggestedPreset(imageFilePath); } // Get preset @@ -795,7 +826,7 @@ namespace ImageProcessingAtom return process; } - void ImageConvertProcess::CreateIBLCubemap(PresetName preset, const char* fileNameSuffix, IImageObjectPtr& cubemapImage) + bool ImageConvertProcess::CreateIBLCubemap(PresetName preset, const char* fileNameSuffix, IImageObjectPtr& cubemapImage) { const AZStd::string& platformId = m_input->m_platform; AZStd::string_view filePath; @@ -803,7 +834,7 @@ namespace ImageProcessingAtom if (presetSettings == nullptr) { AZ_Error("Image Processing", false, "Couldn't find preset for IBL cubemap generation"); - return; + return false; } // generate export file name @@ -838,14 +869,14 @@ namespace ImageProcessingAtom if (!imageConvertProcess) { AZ_Error("Image Processing", false, "Failed to create image convert process for the IBL cubemap"); - return; + return false; } imageConvertProcess->ProcessAll(); if (!imageConvertProcess->IsSucceed()) { AZ_Error("Image Processing", false, "Image convert process for the IBL cubemap failed"); - return; + return false; } // append the output products to the job's product list @@ -853,6 +884,7 @@ namespace ImageProcessingAtom // store the output cubemap so it can be accessed by unit tests cubemapImage = imageConvertProcess->m_image->Get(); + return true; } bool ConvertImageFile(const AZStd::string& imageFilePath, const AZStd::string& exportDir, diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h index fe57b1a89f..0d06b15c39 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageConvert.h @@ -160,7 +160,7 @@ namespace ImageProcessingAtom bool FillCubemapMipmaps(); //IBL cubemap generation, this creates a separate ImageConvertProcess - void CreateIBLCubemap(PresetName preset, const char* fileNameSuffix, IImageObjectPtr& cubemapImage); + bool CreateIBLCubemap(PresetName preset, const char* fileNameSuffix, IImageObjectPtr& cubemapImage); //convert color space to linear with pixel format rgba32f bool ConvertToLinear(); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.cpp index 465d992ef6..758df462ec 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/ImageObjectImpl.cpp @@ -183,10 +183,9 @@ namespace ImageProcessingAtom return EAlphaContent::eAlphaContent_Absent; } - //if it's compressed format, return indeterminate. if user really want to know the content, they may convert the format to ARGB8 first if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat)) { - AZ_Assert(false, "the function only works right with uncompressed formats. convert to uncompressed format if you get accurate result"); + AZ_TracePrintf("Image processing", "GetAlphaContent() was called for compressed format\n"); return EAlphaContent::eAlphaContent_Indeterminate; } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.cpp index 29ba8c3351..20e1b18e77 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.cpp @@ -385,6 +385,13 @@ namespace ImageProcessingAtom } return true; } + + bool NeedAlphaChannel(EAlphaContent alphaContent) + { + return (alphaContent == EAlphaContent::eAlphaContent_OnlyBlack + || alphaContent == EAlphaContent::eAlphaContent_OnlyBlackAndWhite + || alphaContent == EAlphaContent::eAlphaContent_Greyscale); + } } } // namespace ImageProcessingAtom diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.h b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.h index d5905eddbc..59503a2366 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.h +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Source/Processing/Utils.h @@ -26,5 +26,7 @@ namespace ImageProcessingAtom IImageObjectPtr LoadImageFromImageAsset(const AZ::Data::Asset& asset); bool SaveImageToDdsFile(IImageObjectPtr image, AZStd::string_view filePath); + + bool NeedAlphaChannel(EAlphaContent alphaContent); } } diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp index d0029ffc86..91b0952a06 100644 --- a/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp +++ b/Gems/Atom/Asset/ImageProcessingAtom/Code/Tests/ImageProcessing_Test.cpp @@ -203,7 +203,7 @@ namespace UnitTest m_gemFolder = AZ::Test::GetEngineRootPath() + "/Gems/Atom/Asset/ImageProcessingAtom/"; m_outputFolder = m_gemFolder + AZStd::string("Code/Tests/TestAssets/temp/"); - m_defaultSettingFolder = m_gemFolder + AZStd::string("Config/"); + m_defaultSettingFolder = m_gemFolder + AZStd::string("Assets/Config/"); m_testFileFolder = m_gemFolder + AZStd::string("Code/Tests/TestAssets/"); InitialImageFilenames(); diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/ImageBuilder.settings b/Gems/Atom/Asset/ImageProcessingAtom/Config/ImageBuilder.settings deleted file mode 100644 index 466ac4b71d..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/ImageBuilder.settings +++ /dev/null @@ -1,67 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "BuilderSettingManager", - "ClassData": { - "AnalysisFingerprint": "2", - "BuildSettings": { - "android": { - "GlossScale": 16.0, - "GlossBias": 0.0, - "Streaming": false, - "Enable": true - }, - "ios": { - "GlossScale": 16.0, - "GlossBias": 0.0, - "Streaming": false, - "Enable": true - }, - "mac": { - "GlossScale": 16.0, - "GlossBias": 0.0, - "Streaming": false, - "Enable": true - }, - "pc": { - "GlossScale": 16.0, - "GlossBias": 0.0, - "Streaming": false, - "Enable": true - }, - "linux": { - "GlossScale": 16.0, - "GlossBias": 0.0, - "Streaming": false, - "Enable": true - }, - "provo": { - "GlossScale": 16.0, - "GlossBias": 0.0, - "Streaming": false, - "Enable": false - } - }, - "DefaultPresetsByFileMask": { - "_basecolor": "Albedo", - "_diff": "Albedo", - "_diffuse": "Albedo", - "_ddn": "Normals", - "_normal": "Normals", - "_ddna": "NormalsWithSmoothness", - "_glossness": "Reflectance", - "_spec": "Reflectance", - "_specular": "Reflectance", - "_metallic": "Reflectance", - "_refl": "Reflectance", - "_roughness": "Reflectance", - "_ibldiffusecm": "IBLDiffuse", - "_iblskyboxcm": "IBLSkybox", - "_iblspecularcm": "IBLSpecular", - "_skyboxcm": "Skybox" - }, - "DefaultPreset": "Albedo", - "DefaultPresetAlpha": "AlbedoWithGenericAlpha", - "DefaultPresetNonePOT": "ReferenceImage" - } -} diff --git a/Gems/Atom/Asset/ImageProcessingAtom/Config/Reflectance.preset b/Gems/Atom/Asset/ImageProcessingAtom/Config/Reflectance.preset deleted file mode 100644 index 2ac88dca85..0000000000 --- a/Gems/Atom/Asset/ImageProcessingAtom/Config/Reflectance.preset +++ /dev/null @@ -1,157 +0,0 @@ -{ - "Type": "JsonSerialization", - "Version": 1, - "ClassName": "MultiplatformPresetSettings", - "ClassData": { - "DefaultPreset": { - "UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", - "Name": "Reflectance", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_spec", - "_refl", - "_ref", - "_rf", - "_gloss", - "_g", - "_f0", - "_specf0", - "_specular", - "_metal", - "_mtl", - "_m", - "_mt", - "_metalness", - "_metallic", - "_roughness", - "_rough" - ], - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "PlatformsPresets": { - "android": { - "UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", - "Name": "Reflectance", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_spec", - "_refl", - "_ref", - "_rf", - "_gloss", - "_g", - "_f0", - "_specf0", - "_metal", - "_mtl", - "_m", - "_mt", - "_metalness", - "_metallic", - "_roughness", - "_rough" - ], - "PixelFormat": "ASTC_6x6", - "MaxTextureSize": 2048, - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "ios": { - "UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", - "Name": "Reflectance", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_spec", - "_refl", - "_ref", - "_rf", - "_gloss", - "_g", - "_f0", - "_specf0", - "_metal", - "_mtl", - "_m", - "_mt", - "_metalness", - "_metallic", - "_roughness", - "_rough" - ], - "PixelFormat": "ASTC_6x6", - "MaxTextureSize": 2048, - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "mac": { - "UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", - "Name": "Reflectance", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_spec", - "_refl", - "_ref", - "_rf", - "_gloss", - "_g", - "_f0", - "_specf0", - "_metal", - "_mtl", - "_m", - "_mt", - "_metalness", - "_metallic", - "_roughness", - "_rough" - ], - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - }, - "provo": { - "UUID": "{7A3CC95E-0A0C-4CA1-8357-5712B028B77D}", - "Name": "Reflectance", - "SourceColor": "Linear", - "DestColor": "Linear", - "FileMasks": [ - "_spec", - "_refl", - "_ref", - "_rf", - "_gloss", - "_g", - "_f0", - "_specf0", - "_metal", - "_mtl", - "_m", - "_mt", - "_metalness", - "_metallic", - "_roughness", - "_rough" - ], - "PixelFormat": "BC1", - "IsPowerOf2": true, - "MipMapSetting": { - "MipGenType": "Box" - } - } - } - } -} diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli index daed3a2921..3b8379e7fa 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/ProjectedShadow.azsli @@ -14,6 +14,7 @@ #include #include "BicubicPcfFilters.azsli" #include "Shadow.azsli" +#include "NormalOffsetShadows.azsli" // ProjectedShadow calculates shadowed area projected from a light. class ProjectedShadow @@ -123,6 +124,7 @@ float ProjectedShadow::GetThickness(uint shadowIndex, float3 worldPosition) ProjectedShadow shadow; shadow.m_worldPosition = worldPosition; + shadow.m_normalVector = 0; // The normal vector is used to reduce acne, this is not an issue when using the shadowmap to determine thickness. shadow.m_shadowIndex = shadowIndex; shadow.SetShadowPosition(); return shadow.GetThickness(); @@ -317,8 +319,13 @@ bool ProjectedShadow::IsShadowed(float3 shadowPosition) void ProjectedShadow::SetShadowPosition() { + const float normalBias = ViewSrg::m_projectedShadows[m_shadowIndex].m_normalShadowBias; + const float shadowmapSize = ViewSrg::m_projectedFilterParams[m_shadowIndex].m_shadowmapSize; + const float3 shadowOffset = ComputeNormalShadowOffset(normalBias, m_normalVector, shadowmapSize); const float4x4 depthBiasMatrix = ViewSrg::m_projectedShadows[m_shadowIndex].m_depthBiasMatrix; - float4 shadowPositionHomogeneous = mul(depthBiasMatrix, float4(m_worldPosition, 1)); + + float4 shadowPositionHomogeneous = mul(depthBiasMatrix, float4(m_worldPosition + shadowOffset, 1)); + m_shadowPosition = shadowPositionHomogeneous.xyz / shadowPositionHomogeneous.w; m_bias = ViewSrg::m_projectedShadows[m_shadowIndex].m_bias / shadowPositionHomogeneous.w; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h index 5aa2dfb800..98220fae15 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h @@ -86,6 +86,8 @@ namespace AZ virtual void SetShadowsEnabled(LightHandle handle, bool enabled) = 0; //! Sets the shadow bias virtual void SetShadowBias(LightHandle handle, float bias) = 0; + //! Sets the normal shadow bias + virtual void SetNormalShadowBias(LightHandle handle, float bias) = 0; //! Sets the shadowmap size (width and height) of the light. virtual void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) = 0; //! Specifies filter method of shadows. diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h index 1a5a776cdf..52b1402b24 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/CoreLights/PointLightFeatureProcessorInterface.h @@ -74,6 +74,8 @@ namespace AZ virtual void SetFilteringSampleCount(LightHandle handle, uint16_t count) = 0; //! Sets the Esm exponent to use. Higher values produce a steeper falloff in the border areas between light and shadow. virtual void SetEsmExponent(LightHandle handle, float exponent) = 0; + //! Sets the normal shadow bias. Reduces acne by biasing the shadowmap lookup along the geometric normal. + virtual void SetNormalShadowBias(LightHandle handle, float bias) = 0; //! Sets all of the the point data for the provided LightHandle. virtual void SetPointData(LightHandle handle, const PointLightData& data) = 0; }; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index ce5d3cc363..8a1ff95f29 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -343,7 +343,6 @@ namespace AZ m_shadowBufferNeedsUpdate = true; m_shadowProperties.GetData(index).m_cameraConfigurations[nullptr] = {}; - m_shadowProperties.GetData(index).m_cameraTransforms[nullptr] = Transform::CreateIdentity(); const LightHandle handle(index); m_shadowingLightHandle = handle; // only the recent light has shadows. @@ -495,20 +494,10 @@ namespace AZ void DirectionalLightFeatureProcessor::SetCameraTransform( LightHandle handle, - const Transform& cameraTransform, - const RPI::RenderPipelineId& renderPipelineId) + const Transform&, + const RPI::RenderPipelineId&) { ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex()); - - if (RPI::RenderPipeline* renderPipeline = GetParentScene()->GetRenderPipeline(renderPipelineId).get()) - { - const RPI::View* cameraView = renderPipeline->GetDefaultView().get(); - property.m_cameraTransforms[cameraView] = cameraTransform; - } - else - { - property.m_cameraTransforms[nullptr] = cameraTransform; - } property.m_shadowmapViewNeedsUpdate = true; } @@ -934,17 +923,6 @@ namespace AZ return property.m_cameraConfigurations.at(nullptr); } - const Transform& DirectionalLightFeatureProcessor::GetCameraTransform(LightHandle handle, const RPI::View* cameraView) const - { - const ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex()); - const auto findIt = property.m_cameraTransforms.find(cameraView); - if (findIt != property.m_cameraTransforms.end()) - { - return findIt->second; - } - return property.m_cameraTransforms.at(nullptr); - } - void DirectionalLightFeatureProcessor::UpdateFrustums( LightHandle handle) { @@ -1365,10 +1343,11 @@ namespace AZ // If we used an AABB whose Y-direction range is from a segment, // the depth value on the shadowmap saturated to 0 or 1, // and we could not draw shadow correctly. + const Transform cameraTransform = cameraView->GetCameraTransform(); const Vector3 entireFrustumCenterLight = - lightTransform.GetInverseFast() * (GetCameraTransform(handle, cameraView).TransformPoint(property.m_entireFrustumCenterLocal)); + lightTransform.GetInverseFast() * (cameraTransform.TransformPoint(property.m_entireFrustumCenterLocal)); const float entireCenterY = entireFrustumCenterLight.GetElement(1); - const Vector3 cameraLocationWorld = GetCameraTransform(handle, cameraView).GetTranslation(); + const Vector3 cameraLocationWorld = cameraTransform.GetTranslation(); const Vector3 cameraLocationLight = lightTransformInverse * cameraLocationWorld; // Extend light view frustum by camera depth far in order to avoid shadow lacking behind camera. const float cameraBehindMinY = cameraLocationLight.GetElement(1) - GetCameraConfiguration(handle, cameraView).GetDepthFar(); @@ -1428,8 +1407,8 @@ namespace AZ GetCameraConfiguration(handle, cameraView).GetDepthCenter(depthNear, depthFar), depthFar); - const Vector3 localCenter{ 0.f, depthCenter, 0.f }; - return GetCameraTransform(handle, cameraView).TransformPoint(localCenter); + const Vector3 localCenter{ 0.f, depthCenter, 0.f }; + return cameraView->GetCameraTransform().TransformPoint(localCenter); } float DirectionalLightFeatureProcessor::GetRadius( @@ -1483,7 +1462,7 @@ namespace AZ const ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex()); const Vector3& boundaryCenter = GetWorldCenterPosition(handle, cameraView, depthNear, depthFar); const CascadeShadowCameraConfiguration& cameraConfiguration = GetCameraConfiguration(handle, cameraView); - const Transform& cameraTransform = GetCameraTransform(handle, cameraView); + const Transform cameraTransform = cameraView->GetCameraTransform(); const Vector3& cameraFwd = cameraTransform.GetBasis(1); const Vector3& cameraUp = cameraTransform.GetBasis(2); const Vector3 cameraToBoundaryCenter = boundaryCenter - cameraTransform.GetTranslation(); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h index 77f2db38d6..c206a5097f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h @@ -134,9 +134,6 @@ namespace AZ // Default far depth of each cascade. AZStd::array m_defaultFarDepths; - // Transforms of camera who offers view frustum for each camera view. - AZStd::unordered_map m_cameraTransforms; - // Configuration offers shape of the camera view frustum for each camera view. AZStd::unordered_map m_cameraConfigurations; @@ -259,11 +256,6 @@ namespace AZ //! it returns one of the fallback render pipeline ID. const CascadeShadowCameraConfiguration& GetCameraConfiguration(LightHandle handle, const RPI::View* cameraView) const; - //! This returns the camera transform. - //! If it has not been registered for the given camera view. - //! it returns one of the fallback render pipeline ID. - const Transform& GetCameraTransform(LightHandle handle, const RPI::View* cameraView) const; - //! This update view frustum of camera. void UpdateFrustums(LightHandle handle); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp index acf81ede32..e362ee3afc 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.cpp @@ -313,6 +313,11 @@ namespace AZ SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowBias, bias); } + void DiskLightFeatureProcessor::SetNormalShadowBias(LightHandle handle, float bias) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetNormalShadowBias, bias); + } + void DiskLightFeatureProcessor::SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) { SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution, shadowmapSize); diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h index 275712f84f..bafddacc65 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DiskLightFeatureProcessor.h @@ -51,6 +51,7 @@ namespace AZ void SetConeAngles(LightHandle handle, float innerDegrees, float outerDegrees) override; void SetShadowsEnabled(LightHandle handle, bool enabled) override; void SetShadowBias(LightHandle handle, float bias) override; + void SetNormalShadowBias(LightHandle handle, float bias) override; void SetShadowmapMaxResolution(LightHandle handle, ShadowmapSize shadowmapSize) override; void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp index dcf412c35d..c5d6c3bf78 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.cpp @@ -302,5 +302,10 @@ namespace AZ SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetEsmExponent, esmExponent); } + void PointLightFeatureProcessor::SetNormalShadowBias(LightHandle handle, float bias) + { + SetShadowSetting(handle, &ProjectedShadowFeatureProcessor::SetNormalShadowBias, bias); + } + } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h index 54cb0303cc..df97fa0a52 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/PointLightFeatureProcessor.h @@ -52,6 +52,7 @@ namespace AZ void SetShadowFilterMethod(LightHandle handle, ShadowFilterMethod method) override; void SetFilteringSampleCount(LightHandle handle, uint16_t count) override; void SetEsmExponent(LightHandle handle, float esmExponent) override; + void SetNormalShadowBias(LightHandle handle, float bias) override; void SetPointData(LightHandle handle, const PointLightData& data) override; const Data::Instance GetLightBuffer() const; diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp index 70ccaa5702..c0cc93d7e0 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.cpp @@ -155,8 +155,9 @@ namespace AZ::Render { AZ_Assert(id.IsValid(), "Invalid ShadowId passed to ProjectedShadowFeatureProcessor::SetNormalShadowBias()."); - ShadowProperty& shadowProperty = GetShadowPropertyFromShadowId(id); - shadowProperty.m_normalShadowBias = normalShadowBias; + ShadowData& shadowData = m_shadowData.GetElement(id.GetIndex()); + shadowData.m_normalShadowBias = normalShadowBias; + m_deviceBufferNeedsUpdate = true; } void ProjectedShadowFeatureProcessor::SetShadowmapMaxResolution(ShadowId id, ShadowmapSize size) diff --git a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h index 8939f1845d..a892e77b7f 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/Shadows/ProjectedShadowFeatureProcessor.h @@ -68,7 +68,7 @@ namespace AZ::Render uint32_t m_filteringSampleCount = 0; AZStd::array m_unprojectConstants = { {0, 0} }; float m_bias; - float m_normalShadowBias; + float m_normalShadowBias = 0; float m_esmExponent = 87.0f; float m_padding[3]; }; @@ -79,7 +79,6 @@ namespace AZ::Render ProjectedShadowDescriptor m_desc; RPI::ViewPtr m_shadowmapView; float m_bias = 0.1f; - float m_normalShadowBias = 0.0f; ShadowId m_shadowId; }; diff --git a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/__init__.py b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/__init__.py index d500d6e09c..7e244dcfb2 100644 --- a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/__init__.py +++ b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/__init__.py @@ -163,6 +163,7 @@ _LOGGER.debug('Invoking __init__.py for {0}.'.format({_PACKAGENAME})) # ------------------------------------------------------------------------- +# ------------------------------------------------------------------------- def get_datadir() -> pathlib.Path: """ persistent application data. diff --git a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/capture_displaymapperpassthrough.py b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/capture_displaymapper.py similarity index 65% rename from Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/capture_displaymapperpassthrough.py rename to Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/capture_displaymapper.py index 76cdd8450a..bfcdf4c79e 100644 --- a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/capture_displaymapperpassthrough.py +++ b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/capture_displaymapper.py @@ -10,9 +10,7 @@ """Frame capture of the Displaymapper Passthrough (outputs .dds image)""" # ------------------------------------------------------------------------ import logging as _logging -from env_bool import env_bool -# ------------------------------------------------------------------------ _MODULENAME = 'ColorGrading.capture_displaymapperpassthrough' import ColorGrading.initialize @@ -27,25 +25,35 @@ _LOGGER.debug('Initializing: {0}.'.format({_MODULENAME})) import azlmbr.bus import azlmbr.atom -default_passtree = ["Root", +# This requires the level to have the DisplayMapper component added +# and configured to 'Passthrough' +# but now we can capture the parent input +# so this is here for reference for how it previously worked +passtree_displaymapperpassthrough = ["Root", + "MainPipeline_0", + "MainPipeline", + "PostProcessPass", + "LightAdaptation", + "DisplayMapperPass", + "DisplayMapperPassthrough"] + +# we can grad the parent pass input to the displaymapper directly +passtree_default = ["Root", "MainPipeline_0", "MainPipeline", "PostProcessPass", "LightAdaptation", - "DisplayMapperPass", - "DisplayMapperPassthrough"] + "DisplayMapperPass"] -default_path = "FrameCapture\DisplayMapperPassthrough.dds" - -# To Do: we should try to set display mapper to passthrough, -# then back after capture? +default_path = "FrameCapture\DisplayMappeInput.dds" # To Do: we can wrap this, to call from a PySide2 GUI def capture(command="CapturePassAttachment", - passtree=default_passtree, - pass_type="Output", + passtree=passtree_default, + pass_type="Input", output_path=default_path): + """Writes frame capture into project cache""" azlmbr.atom.FrameCaptureRequestBus(azlmbr.bus.Broadcast, command, passtree, diff --git a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/initialize.py b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/initialize.py index ac64ade322..24fcd08f02 100644 --- a/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/initialize.py +++ b/Gems/Atom/Feature/Common/Editor/Scripts/ColorGrading/initialize.py @@ -32,10 +32,7 @@ if DCCSI_GDEBUG: DCCSI_LOGLEVEL = int(10) # set up logger with both console and file _logging -if DCCSI_GDEBUG: - _LOGGER = initialize_logger(_PACKAGENAME, log_to_file=True, default_log_level=DCCSI_LOGLEVEL) -else: - _LOGGER = initialize_logger(_PACKAGENAME, log_to_file=False, default_log_level=DCCSI_LOGLEVEL) +_LOGGER = initialize_logger(_PACKAGENAME, log_to_file=DCCSI_GDEBUG, default_log_level=DCCSI_LOGLEVEL) _LOGGER.debug('Initializing: {0}.'.format({_MODULENAME})) @@ -46,7 +43,7 @@ if DCCSI_DEV_MODE: APPDATA = get_datadir() # os APPDATA APPDATA_WING = Path(APPDATA, f"Wing Pro {DCCSI_WING_VERSION_MAJOR}").resolve() if APPDATA_WING.exists(): - site.addsitedir(pathlib.PureWindowsPath(APPDATA_WING).as_posix()) + site.addsitedir(APPDATA_WING.resolve()) import wingdbstub as debugger try: debugger.Ensure() @@ -75,8 +72,7 @@ def start(): try: _O3DE_DEV = Path(os.getenv('O3DE_DEV')) - _O3DE_DEV = _O3DE_DEV.resolve() - os.environ['O3DE_DEV'] = pathlib.PureWindowsPath(_O3DE_DEV).as_posix() + os.environ['O3DE_DEV'] = _O3DE_DEV.as_posix() _LOGGER.debug(f'O3DE_DEV is: {_O3DE_DEV}') except EnvironmentError as e: _LOGGER.error('O3DE engineroot not set or found') @@ -86,23 +82,22 @@ def start(): _TAG_LY_BUILD_PATH = os.getenv('TAG_LY_BUILD_PATH', 'build') _DEFAULT_BIN_PATH = Path(str(_O3DE_DEV), _TAG_LY_BUILD_PATH, 'bin', 'profile') _O3DE_BIN_PATH = Path(os.getenv('O3DE_BIN_PATH', _DEFAULT_BIN_PATH)) - _O3DE_BIN_PATH = _O3DE_BIN_PATH.resolve() - os.environ['O3DE_BIN_PATH'] = pathlib.PureWindowsPath(_O3DE_BIN_PATH).as_posix() + os.environ['O3DE_BIN_PATH'] = _O3DE_BIN_PATH.as_posix() _LOGGER.debug(f'O3DE_BIN_PATH is: {_O3DE_BIN_PATH}') - site.addsitedir(pathlib.PureWindowsPath(_O3DE_BIN_PATH).as_posix()) + site.addsitedir(_O3DE_BIN_PATH.resolve()) except EnvironmentError as e: _LOGGER.error('O3DE bin folder not set or found') raise e if running_editor: _O3DE_DEV = Path(os.getenv('O3DE_DEV', Path(azlmbr.paths.engroot))) - os.environ['O3DE_DEV'] = pathlib.PureWindowsPath(_O3DE_DEV).as_posix() + os.environ['O3DE_DEV'] = _O3DE_DEV.as_posix() _LOGGER.debug(_O3DE_DEV) _O3DE_BIN_PATH = Path(str(_O3DE_DEV),Path(azlmbr.paths.executableFolder)) _O3DE_BIN = Path(os.getenv('O3DE_BIN', _O3DE_BIN_PATH.resolve())) - os.environ['O3DE_BIN'] = pathlib.PureWindowsPath(_O3DE_BIN).as_posix() + os.environ['O3DE_BIN'] = _O3DE_BIN_PATH.as_posix() _LOGGER.debug(_O3DE_BIN) diff --git a/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/CMD_ColorGradingTools.bat b/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/CMD_ColorGradingTools.bat index 56021c0801..89dd86be80 100644 --- a/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/CMD_ColorGradingTools.bat +++ b/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/CMD_ColorGradingTools.bat @@ -34,15 +34,15 @@ SETLOCAL ENABLEDELAYEDEXPANSION IF EXIST "%~dp0User_Env.bat" CALL %~dp0User_Env.bat :: Initialize env -echo +echo. echo ... calling Env_Core.bat CALL %~dp0\Env_Core.bat -echo +echo. echo ... calling Env_Python.bat CALL %~dp0\Env_Python.bat -echo +echo. echo ... calling Env_Tools.bat CALL %~dp0\Env_Tools.bat diff --git a/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/Env_Python.bat b/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/Env_Python.bat index fc4afc964e..ffb34b06e5 100644 --- a/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/Env_Python.bat +++ b/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/Env_Python.bat @@ -27,37 +27,19 @@ echo ~ O3DE Color Grading Python Env ... echo _____________________________________________________________________ echo. -:: Python Version -:: Ideally these are set to match the O3DE python distribution -:: \python\runtime -IF "%DCCSI_PY_VERSION_MAJOR%"=="" (set DCCSI_PY_VERSION_MAJOR=3) -echo DCCSI_PY_VERSION_MAJOR = %DCCSI_PY_VERSION_MAJOR% - -:: PY version Major -IF "%DCCSI_PY_VERSION_MINOR%"=="" (set DCCSI_PY_VERSION_MINOR=7) -echo DCCSI_PY_VERSION_MINOR = %DCCSI_PY_VERSION_MINOR% - -IF "%DCCSI_PY_VERSION_RELEASE%"=="" (set DCCSI_PY_VERSION_RELEASE=10) -echo DCCSI_PY_VERSION_RELEASE = %DCCSI_PY_VERSION_RELEASE% - -:: shared location for 64bit python 3.7 DEV location -:: this defines a DCCsi sandbox for lib site-packages by version -:: \Gems\AtomLyIntegration\TechnicalArt\DccScriptingInterface\3rdParty\Python\Lib -set DCCSI_PYTHON_PATH=%DCCSIG_PATH%\3rdParty\Python -echo DCCSI_PYTHON_PATH = %DCCSI_PYTHON_PATH% - -:: add access to a Lib location that matches the py version (example: 3.7.x) -:: switch this for other python versions like maya (2.7.x) -IF "%DCCSI_PYTHON_LIB_PATH%"=="" (set DCCSI_PYTHON_LIB_PATH=%DCCSI_PYTHON_PATH%\Lib\%DCCSI_PY_VERSION_MAJOR%.x\%DCCSI_PY_VERSION_MAJOR%.%DCCSI_PY_VERSION_MINOR%.x\site-packages) -echo DCCSI_PYTHON_LIB_PATH = %DCCSI_PYTHON_LIB_PATH% - -:: add to the PATH -SET PATH=%DCCSI_PYTHON_LIB_PATH%;%PATH% - :: shared location for default O3DE python location set DCCSI_PYTHON_INSTALL=%O3DE_DEV%\Python echo DCCSI_PYTHON_INSTALL = %DCCSI_PYTHON_INSTALL% +:: Warning, many DCC tools (like Maya) include thier own versioned python interpretter. +:: Some apps may not operate correctly if PYTHONHOME is set/propogated. +:: This is definitely the case with Maya, doing so causes Maya to not boot. +FOR /F "tokens=* USEBACKQ" %%F IN (`%DCCSI_PYTHON_INSTALL%\python.cmd %DCCSI_PYTHON_INSTALL%\get_python_path.py`) DO (SET PYTHONHOME=%%F) +echo PYTHONHOME - is now the folder containing O3DE python executable +echo PYTHONHOME = %PYTHONHOME% + +SET PYTHON=%PYTHONHOME%\python.exe + :: location for O3DE python 3.7 location set DCCSI_PY_BASE=%DCCSI_PYTHON_INSTALL%\python.cmd echo DCCSI_PY_BASE = %DCCSI_PY_BASE% @@ -65,10 +47,7 @@ echo DCCSI_PY_BASE = %DCCSI_PY_BASE% :: ide and debugger plug set DCCSI_PY_DEFAULT=%DCCSI_PY_BASE% -IF "%DCCSI_PY_REV%"=="" (set DCCSI_PY_REV=rev2) -IF "%DCCSI_PY_PLATFORM%"=="" (set DCCSI_PY_PLATFORM=windows) - -set DCCSI_PY_IDE=%DCCSI_PYTHON_INSTALL%\runtime\python-%DCCSI_PY_VERSION_MAJOR%.%DCCSI_PY_VERSION_MINOR%.%DCCSI_PY_VERSION_RELEASE%-%DCCSI_PY_REV%-%DCCSI_PY_PLATFORM%\python +set DCCSI_PY_IDE=%PYTHONHOME% echo DCCSI_PY_IDE = %DCCSI_PY_IDE% :: Wing and other IDEs probably prefer access directly to the python.exe @@ -91,11 +70,6 @@ SET PATH=%DCCSI_PYTHON_INSTALL%;%DCCSI_PY_IDE%;%DCCSI_PY_IDE_PACKAGES%;%DCCSI_PY set PYTHONPATH=%DCCSIG_PATH%;%DCCSI_PYTHON_LIB_PATH%;%O3DE_BIN_PATH%;%DCCSI_COLORGRADING_SCRIPTS%;%DCCSI_FEATURECOMMON_SCRIPTS%;%PYTHONPATH% echo PYTHONPATH = %PYTHONPATH% -:: used for debugging in WingIDE (but needs to be here) -IF "%TAG_USERNAME%"=="" (set TAG_USERNAME=NOT_SET) -echo TAG_USERNAME = %TAG_USERNAME% -IF "%TAG_USERNAME%"=="NOT_SET" (echo Add TAG_USERNAME to User_Env.bat) - :: Set flag so we don't initialize dccsi environment twice SET O3DE_ENV_PY_INIT=1 GOTO END_OF_FILE diff --git a/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/User_Env.bat.template b/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/User_Env.bat.template index 973d6d5afd..7ab970c98e 100644 --- a/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/User_Env.bat.template +++ b/Gems/Atom/Feature/Common/Tools/ColorGrading/cmdline/User_Env.bat.template @@ -25,11 +25,6 @@ SET TAG_LY_BUILD_PATH=build SET DCCSI_GDEBUG=True SET DCCSI_DEV_MODE=True -:: set the your user name here for windows path -SET TAG_USERNAME=NOT_SET -SET DCCSI_PY_REV=rev1 -SET DCCSI_PY_PLATFORM=windows - :: Set flag so we don't initialize dccsi environment twice SET O3DE_USER_ENV_INIT=1 GOTO END_OF_FILE diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.h index 759b2558bf..ae60220314 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/AtomToolsFrameworkModule.h @@ -9,11 +9,13 @@ #pragma once #include +#include namespace AtomToolsFramework { class AtomToolsFrameworkModule : public AZ::Module + , public AzToolsFramework::EmbeddedPython::PythonLoader { public: AZ_RTTI(AtomToolsFrameworkModule, "{B58B7CA8-98C9-4DC8-8607-E094989BBBE2}", AZ::Module); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h index 72c4ef97a8..b9c62e6fe2 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightBus.h @@ -132,6 +132,13 @@ namespace AZ //! Sets the Esm exponent. Higher values produce a steeper falloff between light and shadow. virtual void SetEsmExponent(float exponent) = 0; + //! Reduces acne by biasing the shadowmap lookup along the geometric normal. + //! @return Returns the amount of bias to apply. + virtual float GetNormalShadowBias() const = 0; + + //! Reduces acne by biasing the shadowmap lookup along the geometric normal. + //! @param normalShadowBias Sets the amount of normal shadow bias to apply. + virtual void SetNormalShadowBias(float normalShadowBias) = 0; }; //! The EBus for requests to for setting and getting light component properties. diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h index c76c922385..130e066e1a 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Include/AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h @@ -57,6 +57,7 @@ namespace AZ // Shadows (only used for supported shapes) bool m_enableShadow = false; float m_bias = 0.1f; + float m_normalShadowBias = 0.0f; ShadowmapSize m_shadowmapMaxSize = ShadowmapSize::Size256; ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None; uint16_t m_filteringSampleCount = 12; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp index f0418a5024..91f8f1aa36 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentConfig.cpp @@ -34,6 +34,7 @@ namespace AZ // Shadows ->Field("Enable Shadow", &AreaLightComponentConfig::m_enableShadow) ->Field("Shadow Bias", &AreaLightComponentConfig::m_bias) + ->Field("Normal Shadow Bias", &AreaLightComponentConfig::m_normalShadowBias) ->Field("Shadowmap Max Size", &AreaLightComponentConfig::m_shadowmapMaxSize) ->Field("Shadow Filter Method", &AreaLightComponentConfig::m_shadowFilterMethod) ->Field("Filtering Sample Count", &AreaLightComponentConfig::m_filteringSampleCount) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp index 36cb2a7f5a..7668477690 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.cpp @@ -70,6 +70,8 @@ namespace AZ::Render ->Event("SetEnableShadow", &AreaLightRequestBus::Events::SetEnableShadow) ->Event("GetShadowBias", &AreaLightRequestBus::Events::GetShadowBias) ->Event("SetShadowBias", &AreaLightRequestBus::Events::SetShadowBias) + ->Event("GetNormalShadowBias", &AreaLightRequestBus::Events::GetNormalShadowBias) + ->Event("SetNormalShadowBias", &AreaLightRequestBus::Events::SetNormalShadowBias) ->Event("GetShadowmapMaxSize", &AreaLightRequestBus::Events::GetShadowmapMaxSize) ->Event("SetShadowmapMaxSize", &AreaLightRequestBus::Events::SetShadowmapMaxSize) ->Event("GetShadowFilterMethod", &AreaLightRequestBus::Events::GetShadowFilterMethod) @@ -91,6 +93,7 @@ namespace AZ::Render ->VirtualProperty("ShadowsEnabled", "GetEnableShadow", "SetEnableShadow") ->VirtualProperty("ShadowBias", "GetShadowBias", "SetShadowBias") + ->VirtualProperty("NormalShadowBias", "GetNormalShadowBias", "SetNormalShadowBias") ->VirtualProperty("ShadowmapMaxSize", "GetShadowmapMaxSize", "SetShadowmapMaxSize") ->VirtualProperty("ShadowFilterMethod", "GetShadowFilterMethod", "SetShadowFilterMethod") ->VirtualProperty("FilteringSampleCount", "GetFilteringSampleCount", "SetFilteringSampleCount") @@ -302,6 +305,7 @@ namespace AZ::Render if (m_configuration.m_enableShadow) { m_lightShapeDelegate->SetShadowBias(m_configuration.m_bias); + m_lightShapeDelegate->SetNormalShadowBias(m_configuration.m_normalShadowBias); m_lightShapeDelegate->SetShadowmapMaxSize(m_configuration.m_shadowmapMaxSize); m_lightShapeDelegate->SetShadowFilterMethod(m_configuration.m_shadowFilterMethod); m_lightShapeDelegate->SetFilteringSampleCount(m_configuration.m_filteringSampleCount); @@ -474,6 +478,20 @@ namespace AZ::Render } } + void AreaLightComponentController::SetNormalShadowBias(float bias) + { + m_configuration.m_normalShadowBias = bias; + if (m_lightShapeDelegate) + { + m_lightShapeDelegate->SetNormalShadowBias(bias); + } + } + + float AreaLightComponentController::GetNormalShadowBias() const + { + return m_configuration.m_normalShadowBias; + } + ShadowmapSize AreaLightComponentController::GetShadowmapMaxSize() const { return m_configuration.m_shadowmapMaxSize; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h index cc6223e7e5..81299a0372 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/AreaLightComponentController.h @@ -86,6 +86,8 @@ namespace AZ void SetFilteringSampleCount(uint32_t count) override; float GetEsmExponent() const override; void SetEsmExponent(float exponent) override; + float GetNormalShadowBias() const override; + void SetNormalShadowBias(float bias) override; void HandleDisplayEntityViewport( const AzFramework::ViewportInfo& viewportInfo, diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp index dfb6cf6946..f060018099 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.cpp @@ -138,6 +138,14 @@ namespace AZ::Render } } + void DiskLightDelegate::SetNormalShadowBias(float bias) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetNormalShadowBias(GetLightHandle(), bias); + } + } + void DiskLightDelegate::SetShadowmapMaxSize(ShadowmapSize size) { if (GetShadowsEnabled() && GetLightHandle().IsValid()) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h index 2be782c69c..c19a8d37ae 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DiskLightDelegate.h @@ -46,6 +46,7 @@ namespace AZ void SetShadowFilterMethod(ShadowFilterMethod method) override; void SetFilteringSampleCount(uint32_t count) override; void SetEsmExponent(float exponent) override; + void SetNormalShadowBias(float bias) override; private: diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index db46434d9a..02c9f77436 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -136,7 +136,7 @@ namespace AZ ->Attribute(Edit::Attributes::Min, 0.0f) ->Attribute(Edit::Attributes::Max, 100.0f) ->Attribute(Edit::Attributes::SoftMin, 0.0f) - ->Attribute(Edit::Attributes::SoftMax, 2.0f) + ->Attribute(Edit::Attributes::SoftMax, 10.0f) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled) @@ -171,7 +171,16 @@ namespace AZ ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsEsmDisabled) - ; + ->DataElement( + Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_normalShadowBias, "Normal Shadow Bias\n", + "Reduces acne by biasing the shadowmap lookup along the geometric normal.\n" + "If this is 0, no biasing is applied.") + ->Attribute(Edit::Attributes::Min, 0.f) + ->Attribute(Edit::Attributes::Max, 10.0f) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) + ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::ShadowsDisabled) + ; } } diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h index 336c67f55d..8b096b0367 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateBase.h @@ -58,7 +58,8 @@ namespace AZ void SetShadowFilterMethod([[maybe_unused]] ShadowFilterMethod method) override {}; void SetFilteringSampleCount([[maybe_unused]] uint32_t count) override {}; void SetEsmExponent([[maybe_unused]] float esmExponent) override{}; - + void SetNormalShadowBias([[maybe_unused]] float bias) override{}; + protected: void InitBase(EntityId entityId); diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h index 9bb8188898..40ffaf392d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/LightDelegateInterface.h @@ -79,6 +79,8 @@ namespace AZ virtual void SetFilteringSampleCount(uint32_t count) = 0; //! Sets the Esm exponent to use. Higher values produce a steeper falloff between light and shadow. virtual void SetEsmExponent(float exponent) = 0; + //! Sets the normal bias. Reduces acne by biasing the shadowmap lookup along the geometric normal. + virtual void SetNormalShadowBias(float bias) = 0; }; } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp index 661b0c6b25..f2e1f41008 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.cpp @@ -107,4 +107,13 @@ namespace AZ::Render GetFeatureProcessor()->SetEsmExponent(GetLightHandle(), esmExponent); } } + + void SphereLightDelegate::SetNormalShadowBias(float bias) + { + if (GetShadowsEnabled() && GetLightHandle().IsValid()) + { + GetFeatureProcessor()->SetNormalShadowBias(GetLightHandle(), bias); + } + } + } // namespace AZ::Render diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h index 8bdee2442a..bad00e597c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/SphereLightDelegate.h @@ -36,6 +36,7 @@ namespace AZ void SetShadowFilterMethod(ShadowFilterMethod method) override; void SetFilteringSampleCount(uint32_t count) override; void SetEsmExponent(float esmExponent) override; + void SetNormalShadowBias(float bias) override; private: diff --git a/Gems/EditorPythonBindings/Code/Source/EditorPythonBindingsModule.cpp b/Gems/EditorPythonBindings/Code/Source/EditorPythonBindingsModule.cpp index cef8931722..f168cc5ab2 100644 --- a/Gems/EditorPythonBindings/Code/Source/EditorPythonBindingsModule.cpp +++ b/Gems/EditorPythonBindings/Code/Source/EditorPythonBindingsModule.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include #include @@ -18,6 +20,7 @@ namespace EditorPythonBindings { class EditorPythonBindingsModule : public AZ::Module + , public AzToolsFramework::EmbeddedPython::PythonLoader { public: AZ_RTTI(EditorPythonBindingsModule, "{851B9E35-4FD5-49B1-8207-E40D4BBA36CC}", AZ::Module); diff --git a/Gems/PythonAssetBuilder/Code/Source/PythonAssetBuilderModule.cpp b/Gems/PythonAssetBuilder/Code/Source/PythonAssetBuilderModule.cpp index d7143a159a..1d330c90df 100644 --- a/Gems/PythonAssetBuilder/Code/Source/PythonAssetBuilderModule.cpp +++ b/Gems/PythonAssetBuilder/Code/Source/PythonAssetBuilderModule.cpp @@ -9,12 +9,15 @@ #include #include +#include + #include namespace PythonAssetBuilder { class PythonAssetBuilderModule : public AZ::Module + , public AzToolsFramework::EmbeddedPython::PythonLoader { public: AZ_RTTI(PythonAssetBuilderModule, "{35C9457E-54C2-474C-AEBE-5A70CC1D435D}", AZ::Module); diff --git a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl index 9cfa568b9a..024cccf337 100644 --- a/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl +++ b/Gems/Terrain/Assets/Shaders/Terrain/TerrainPBR_ForwardPass.azsl @@ -80,26 +80,38 @@ ForwardPassOutput TerrainPBR_MainPassPS(VSOutput IN) // ------- Macro Color / Normal ------- float3 macroColor = TerrainMaterialSrg::m_baseColor.rgb; - [unroll] for (uint i = 0; i < 4 && (i < ObjectSrg::m_macroMaterialCount); ++i) + + // There's a bug that shows up with an NVidia GTX 1660 Super card happening on driver versions as recent as 496.49 (10/26/21) in which + // the IN.m_uv values will intermittently "flicker" to 0.0 after entering and exiting game mode. + // (See https://github.com/o3de/o3de/issues/5014) + // This bug has only shown up on PCs when using the DX12 RHI. It doesn't show up with Vulkan or when capturing frames with PIX or + // RenderDoc. Our best guess is that it is a driver bug. The workaround is to use the IN.m_uv values in a calculation prior to the + // point that we actually use them for macroUv below. The "if(any(!isnan(IN.m_uv)))" seems to be sufficient for the workaround. The + // if statement will always be true, but just the act of reading these values in the if statement makes the values stable. Removing + // the if statement causes the flickering to occur using the steps documented in the bug. + if (any(!isnan(IN.m_uv))) { - float2 macroUvMin = ObjectSrg::m_macroMaterialData[i].m_uvMin; - float2 macroUvMax = ObjectSrg::m_macroMaterialData[i].m_uvMax; - float2 macroUv = lerp(macroUvMin, macroUvMax, IN.m_uv); - if (macroUv.x >= 0.0 && macroUv.x <= 1.0 && macroUv.y >= 0.0 && macroUv.y <= 1.0) + [unroll] for (uint i = 0; i < 4 && (i < ObjectSrg::m_macroMaterialCount); ++i) { - if ((ObjectSrg::m_macroMaterialData[i].m_mapsInUse & 1) > 0) + float2 macroUvMin = ObjectSrg::m_macroMaterialData[i].m_uvMin; + float2 macroUvMax = ObjectSrg::m_macroMaterialData[i].m_uvMax; + float2 macroUv = lerp(macroUvMin, macroUvMax, IN.m_uv); + if (macroUv.x >= 0.0 && macroUv.x <= 1.0 && macroUv.y >= 0.0 && macroUv.y <= 1.0) { - macroColor = GetBaseColorInput(ObjectSrg::m_macroColorMap[i], TerrainMaterialSrg::m_sampler, macroUv, macroColor, true); + if ((ObjectSrg::m_macroMaterialData[i].m_mapsInUse & 1) > 0) + { + macroColor = GetBaseColorInput(ObjectSrg::m_macroColorMap[i], TerrainMaterialSrg::m_sampler, macroUv, macroColor, true); + } + if ((ObjectSrg::m_macroMaterialData[i].m_mapsInUse & 2) > 0) + { + bool flipX = ObjectSrg::m_macroMaterialData[i].m_flipNormalX; + bool flipY = ObjectSrg::m_macroMaterialData[i].m_flipNormalY; + bool factor = ObjectSrg::m_macroMaterialData[i].m_normalFactor; + macroNormal = GetNormalInputTS(ObjectSrg::m_macroNormalMap[i], TerrainMaterialSrg::m_sampler, + macroUv, flipX, flipY, CreateIdentity3x3(), true, factor); + } + break; } - if ((ObjectSrg::m_macroMaterialData[i].m_mapsInUse & 2) > 0) - { - bool flipX = ObjectSrg::m_macroMaterialData[i].m_flipNormalX; - bool flipY = ObjectSrg::m_macroMaterialData[i].m_flipNormalY; - bool factor = ObjectSrg::m_macroMaterialData[i].m_normalFactor; - macroNormal = GetNormalInputTS(ObjectSrg::m_macroNormalMap[i], TerrainMaterialSrg::m_sampler, - macroUv, flipX, flipY, CreateIdentity3x3(), true, factor); - } - break; } } diff --git a/Templates/PythonToolGem/Template/Code/Source/${Name}EditorModule.cpp b/Templates/PythonToolGem/Template/Code/Source/${Name}EditorModule.cpp index 0027af011a..fdd971440e 100644 --- a/Templates/PythonToolGem/Template/Code/Source/${Name}EditorModule.cpp +++ b/Templates/PythonToolGem/Template/Code/Source/${Name}EditorModule.cpp @@ -10,6 +10,7 @@ #include <${Name}ModuleInterface.h> #include <${Name}EditorSystemComponent.h> +#include void Init${SanitizedCppName}Resources() { @@ -21,6 +22,7 @@ namespace ${SanitizedCppName} { class ${SanitizedCppName}EditorModule : public ${SanitizedCppName}ModuleInterface + , public AzToolsFramework::EmbeddedPython::PythonLoader { public: AZ_RTTI(${SanitizedCppName}EditorModule, "${ModuleClassId}", ${SanitizedCppName}ModuleInterface); diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index c677aba7cf..e8c14ac8a0 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -33,6 +33,34 @@ set(gems_json_template [[ [=[ }]=] ) +#!ly_detect_cycle_through_visitation: Detects if there is a cycle based on a list of visited +# items. If the passed item is in the list, then there is a cycle. +# \arg:item - item being checked for the cycle +# \arg:visited_items - list of visited items +# \arg:visited_items_var - list of visited items variable, "item" will be added to the list +# \arg:cycle(variable) - empty string if there is no cycle (an empty string in cmake evaluates +# to false). If there is a cycle a cycle dependency string detailing the sequence of items +# that produce a cycle, e.g. A --> B --> C --> A +# +function(ly_detect_cycle_through_visitation item visited_items visited_items_var cycle) + if(item IN_LIST visited_items) + unset(dependency_cycle_loop) + foreach(visited_item IN LISTS visited_items) + string(APPEND dependency_cycle_loop ${visited_item}) + if(visited_item STREQUAL item) + string(APPEND dependency_cycle_loop " (cycle starts)") + endif() + string(APPEND dependency_cycle_loop " --> ") + endforeach() + string(APPEND dependency_cycle_loop "${item} (cycle ends)") + set(${cycle} "${dependency_cycle_loop}" PARENT_SCOPE) + else() + set(cycle "" PARENT_SCOPE) # no cycles + endif() + list(APPEND visited_items ${item}) + set(${visited_items_var} "${visited_items}" PARENT_SCOPE) +endfunction() + #!ly_get_gem_load_dependencies: Retrieves the list of "load" dependencies for a target # Visits through only MANUALLY_ADDED_DEPENDENCIES of targets with a GEM_MODULE property # to determine which gems a target needs to load @@ -44,6 +72,13 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) if(NOT TARGET ${ly_TARGET}) return() # Nothing to do endif() + # Internally we use a third parameter to pass the list of targets that we have traversed. This is + # used to detect runtime cycles + if(ARGC EQUAL 3) + set(ly_CYCLE_DETECTION_TARGETS ${ARGV2}) + else() + set(ly_CYCLE_DETECTION_TARGETS "") + endif() # Optimize the search by caching gem load dependencies get_property(are_dependencies_cached GLOBAL PROPERTY LY_GEM_LOAD_DEPENDENCIES_${ly_TARGET} SET) @@ -54,6 +89,13 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) return() endif() + # detect cycles + unset(cycle_detected) + ly_detect_cycle_through_visitation(${ly_TARGET} "${ly_CYCLE_DETECTION_TARGETS}" ly_CYCLE_DETECTION_TARGETS cycle_detected) + if(cycle_detected) + message(FATAL_ERROR "Runtime dependency detected: ${cycle_detected}") + endif() + unset(all_gem_load_dependencies) # For load dependencies, we want to copy over the dependency and traverse them @@ -69,7 +111,7 @@ function(ly_get_gem_load_dependencies ly_GEM_LOAD_DEPENDENCIES ly_TARGET) # and recurse into its manually added dependencies if (is_gem_target) unset(dependencies) - ly_get_gem_load_dependencies(dependencies ${dealias_load_dependency}) + ly_get_gem_load_dependencies(dependencies ${dealias_load_dependency} "${ly_CYCLE_DETECTION_TARGETS}") list(APPEND all_gem_load_dependencies ${dependencies}) list(APPEND all_gem_load_dependencies ${dealias_load_dependency}) endif() diff --git a/scripts/build/Platform/Windows/deploy_cdk_applications.cmd b/scripts/build/Platform/Windows/deploy_cdk_applications.cmd index 006e0158c0..f3d68d2fe8 100644 --- a/scripts/build/Platform/Windows/deploy_cdk_applications.cmd +++ b/scripts/build/Platform/Windows/deploy_cdk_applications.cmd @@ -7,7 +7,7 @@ REM SPDX-License-Identifier: Apache-2.0 OR MIT REM REM -REM Deploy the CDK applcations for AWS gems (Windows only) +REM Deploy the CDK applications for AWS gems (Windows only) REM Prerequisites: REM 1) Node.js is installed REM 2) Node.js version >= 10.13.0, except for versions 13.0.0 - 13.6.0. A version in active long-term support is recommended. @@ -57,7 +57,7 @@ IF ERRORLEVEL 1 ( exit /b 1 ) -CALL :DeployCDKApplication AWSCore "-c disable_access_log=true --all" +CALL :DeployCDKApplication AWSCore "-c disable_access_log=true -c remove_all_storage_on_destroy=true --all" IF ERRORLEVEL 1 ( exit /b 1 ) diff --git a/scripts/o3de/o3de/disable_gem.py b/scripts/o3de/o3de/disable_gem.py index 01324d8500..158507fca1 100644 --- a/scripts/o3de/o3de/disable_gem.py +++ b/scripts/o3de/o3de/disable_gem.py @@ -69,7 +69,7 @@ def disable_gem_in_project(gem_name: str = None, return 1 gem_path = pathlib.Path(gem_path).resolve() # make sure this gem already exists if we're adding. We can always remove a gem. - if not gem_path.is_dir(): + if not gem_path.exists(): logger.error(f'Gem Path {gem_path} does not exist.') return 1 diff --git a/scripts/o3de/o3de/download.py b/scripts/o3de/o3de/download.py index 9b7c8cc782..dfec6b1aaa 100644 --- a/scripts/o3de/o3de/download.py +++ b/scripts/o3de/o3de/download.py @@ -48,26 +48,25 @@ def validate_downloaded_zip_sha256(download_uri_json_data: dict, download_zip_pa ' We cannot verify this is the actually the advertised object!!!') return 1 else: - sha256B = hashlib.sha256(download_zip_path.open('rb').read()).hexdigest() - if sha256A != sha256B: - logger.error(f'SECURITY VIOLATION: Downloaded zip sha256 {sha256B} does not match' - f' the advertised "sha256":{sha256A} in the f{manifest_json_name}.') - return 0 + with download_zip_path.open('rb') as f: + sha256B = hashlib.sha256(f.read()).hexdigest() + if sha256A != sha256B: + logger.error(f'SECURITY VIOLATION: Downloaded zip sha256 {sha256B} does not match' + f' the advertised "sha256":{sha256A} in the f{manifest_json_name}.') + return 0 unzipped_manifest_json_data = unzip_manifest_json_data(download_zip_path, manifest_json_name) - # remove the sha256 if present in the advertised downloadable manifest json - # then compare it to the json in the zip, they should now be identical - try: - del download_uri_json_data['sha256'] - except KeyError as e: - pass + # do not include the data we know will not match/exist + for key in ['sha256','repo_name']: + if key in download_uri_json_data: + del download_uri_json_data[key] + if key in unzipped_manifest_json_data: + del unzipped_manifest_json_data[key] - sha256A = hashlib.sha256(json.dumps(download_uri_json_data, indent=4).encode('utf8')).hexdigest() - sha256B = hashlib.sha256(json.dumps(unzipped_manifest_json_data, indent=4).encode('utf8')).hexdigest() - if sha256A != sha256B: - logger.error('SECURITY VIOLATION: Downloaded manifest json does not match' - ' the advertised manifest json.') + if download_uri_json_data != unzipped_manifest_json_data: + logger.error(f'SECURITY VIOLATION: Downloaded {manifest_json_name} contents do not match' + ' the advertised manifest json contents.') return 0 return 1 @@ -102,7 +101,7 @@ def download_o3de_object(object_name: str, default_folder_name: str, dest_path: logger.error(f'Downloadable o3de object {object_name} not found.') return 1 - origin_uri = downloadable_object_data['originuri'] + origin_uri = downloadable_object_data['origin_uri'] parsed_uri = urllib.parse.urlparse(origin_uri) download_zip_result = utils.download_zip_file(parsed_uri, download_zip_path, force_overwrite, download_progress_callback) diff --git a/scripts/o3de/o3de/repo.py b/scripts/o3de/o3de/repo.py index c8fac38605..3ff2a7d982 100644 --- a/scripts/o3de/o3de/repo.py +++ b/scripts/o3de/o3de/repo.py @@ -9,7 +9,6 @@ import json import logging import pathlib -import shutil import urllib.parse import urllib.request import hashlib @@ -217,10 +216,10 @@ def search_repo(manifest_json_data: dict, json_key = 'gem_name' search_func = lambda manifest_json_data: manifest_json_data if manifest_json_data.get(json_key, '') == gem_name else None elif isinstance(template_name, str) or isinstance(template_name, pathlib.PurePath): - o3de_object_uris = manifest_json_data['template'] + o3de_object_uris = manifest_json_data['templates'] manifest_json = 'template.json' json_key = 'template_name' - search_func = lambda manifest_json_data: manifest_json_data if manifest_json_data.get(json_key, '') == template_name_name else None + search_func = lambda manifest_json_data: manifest_json_data if manifest_json_data.get(json_key, '') == template_name else None elif isinstance(restricted_name, str) or isinstance(restricted_name, pathlib.PurePath): o3de_object_uris = manifest_json_data['restricted'] manifest_json = 'restricted.json'