diff --git a/.gitignore b/.gitignore index 24af068c53..eb24d72701 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ _savebackup/ #Output folder for test results when running Automated Tests TestResults/** *.swatches +/imgui.ini diff --git a/AutomatedTesting/Assets/ImageGradients/image_grad_test_gsi.png b/AutomatedTesting/Assets/ImageGradients/image_grad_test_gsi.png new file mode 100644 index 0000000000..228aa877ce --- /dev/null +++ b/AutomatedTesting/Assets/ImageGradients/image_grad_test_gsi.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:171f38d536d7b805cc644513d22dae5552a4eef2bffb88e97e089898cf769530 +size 2126 diff --git a/AutomatedTesting/Assets/ImageGradients/lumberyard_gsi.png b/AutomatedTesting/Assets/ImageGradients/lumberyard_gsi.png deleted file mode 100644 index eab76f1f78..0000000000 --- a/AutomatedTesting/Assets/ImageGradients/lumberyard_gsi.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:6388466c97009fd3993e5d3b59a2b0961f623c6becbd0a12a0a5eb7bd8da5d4e -size 12302 diff --git a/AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake b/AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake index 617816dcd0..0a1541bcfc 100644 --- a/AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake +++ b/AutomatedTesting/Gem/Code/Platform/Windows/runtime_dependencies.cmake @@ -12,4 +12,5 @@ set(GEM_DEPENDENCIES Gem::Atom_RHI_Vulkan.Private Gem::Atom_RHI_DX12.Private + Gem::Atom_RHI_Null.Private ) \ No newline at end of file diff --git a/AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake b/AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake index d13d0fb180..ddd3bfa6a7 100644 --- a/AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake +++ b/AutomatedTesting/Gem/Code/Platform/Windows/tool_dependencies.cmake @@ -15,5 +15,7 @@ set(GEM_DEPENDENCIES Gem::Atom_RHI_Vulkan.Builders Gem::Atom_RHI_DX12.Private Gem::Atom_RHI_DX12.Builders + Gem::Atom_RHI_Null.Private + Gem::Atom_RHI_Null.Builders Gem::Atom_RHI_Metal.Builders ) \ No newline at end of file diff --git a/AutomatedTesting/Gem/Editor/Scripts/__init__.py b/AutomatedTesting/Gem/Editor/Scripts/__init__.py new file mode 100644 index 0000000000..79f8fa4422 --- /dev/null +++ b/AutomatedTesting/Gem/Editor/Scripts/__init__.py @@ -0,0 +1,10 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" diff --git a/AutomatedTesting/Gem/Editor/Scripts/bootstrap.py b/AutomatedTesting/Gem/Editor/Scripts/bootstrap.py new file mode 100644 index 0000000000..e41f9c1767 --- /dev/null +++ b/AutomatedTesting/Gem/Editor/Scripts/bootstrap.py @@ -0,0 +1,13 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" +import sys, os +sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../../PythonTests') +from PythonAssetBuilder import bootstrap_tests diff --git a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt index ea9c365978..c527aea98c 100644 --- a/AutomatedTesting/Gem/PythonTests/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/CMakeLists.txt @@ -134,10 +134,30 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) ) endif() +## Python Asset Builder ## +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) + ly_add_pytest( + NAME AutomatedTesting::PythonAssetBuilder + TEST_SUITE periodic + TEST_SERIAL + PATH ${CMAKE_CURRENT_LIST_DIR}/PythonAssetBuilder + TIMEOUT 3600 + RUNTIME_DEPENDENCIES + Legacy::Editor + Legacy::CryRenderNULL + AZ::AssetProcessor + AutomatedTesting.Assets + Gem::EditorPythonBindings.Editor + Gem::PythonAssetBuilder.Editor + COMPONENT TestTools + ) +endif() + ## Blast ## if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) ly_add_pytest( NAME AutomatedTesting::BlastTests + TEST_SUITE sandbox TEST_SERIAL TRUE PATH ${CMAKE_CURRENT_LIST_DIR}/Blast/TestSuite_Active.py TIMEOUT 3600 diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test.py b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test.py new file mode 100644 index 0000000000..e914182542 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test.py @@ -0,0 +1,57 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" +# +# This launches the AssetProcessor and Editor then attempts to find the expected +# assets created by a Python Asset Builder and the output of a scene pipeline script +# +import sys +import os +import pytest +import logging +pytest.importorskip('ly_test_tools') + +import ly_test_tools.environment.file_system as file_system +import ly_test_tools.log.log_monitor +import ly_test_tools.environment.waiter as waiter + +@pytest.mark.SUITE_sandbox +@pytest.mark.parametrize('launcher_platform', ['windows_editor']) +@pytest.mark.parametrize('project', ['AutomatedTesting']) +@pytest.mark.parametrize('level', ['auto_test']) +class TestPythonAssetProcessing(object): + def test_DetectPythonCreatedAsset(self, request, editor, level, launcher_platform): + unexpected_lines = [] + expected_lines = [ + 'Mock asset exists', + 'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel) found', + 'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_X_negative.azmodel) found', + 'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_X_positive.azmodel) found', + 'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel) found', + 'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel) found', + 'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel) found', + 'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel) found', + 'Expected subId for asset (gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel) found' + ] + timeout = 180 + halt_on_unexpected = False + test_directory = os.path.join(os.path.dirname(__file__)) + testFile = os.path.join(test_directory, 'AssetBuilder_test_case.py') + editor.args.extend(['-NullRenderer', "--skipWelcomeScreenDialog", "--autotest_mode", "--runpythontest", testFile]) + + with editor.start(): + editorlog_file = os.path.join(editor.workspace.paths.project_log(), 'Editor.log') + log_monitor = ly_test_tools.log.log_monitor.LogMonitor(editor, editorlog_file) + waiter.wait_for( + lambda: editor.is_alive(), + timeout, + exc=("Log file '{}' was never opened by another process.".format(editorlog_file)), + interval=1) + log_monitor.monitor_log_for_lines(expected_lines, unexpected_lines, halt_on_unexpected, timeout) diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test_case.py b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test_case.py new file mode 100644 index 0000000000..54857c2067 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/AssetBuilder_test_case.py @@ -0,0 +1,52 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" +import azlmbr.bus +import azlmbr.asset +import azlmbr.editor +import azlmbr.math +import azlmbr.legacy.general + +def raise_and_stop(msg): + print (msg) + 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') + +if (assetId.to_string().endswith(':54c06b89') is False): + raise_and_stop(f'Mock AssetId 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, expectedSubId): + 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 (assetIdString.endswith(':' + expectedSubId) is False): + raise_and_stop(f'Asset has unexpected asset ID ({assetIdString}) for ({generatedModelAssetPath})!') + else: + print(f'Expected subId for asset ({generatedModelAssetPath}) found') + +test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_center.azmodel', '10412075') +test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_X_positive.azmodel', '10d16e68') +test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_X_negative.azmodel', '10a71973') +test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_Y_positive.azmodel', '10130556') +test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_Y_negative.azmodel', '1065724d') +test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_Z_positive.azmodel', '1024be55') +test_azmodel_product('gem/pythontests/pythonassetbuilder/geom_group_fbx_cube_100cm_Z_negative.azmodel', '1052c94e') + +azlmbr.editor.EditorToolsApplicationRequestBus(azlmbr.bus.Broadcast, 'ExitNoPrompt') diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/__init__.py b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/__init__.py new file mode 100644 index 0000000000..6ed3dc4bda --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/__init__.py @@ -0,0 +1,10 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/bootstrap_tests.py b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/bootstrap_tests.py new file mode 100644 index 0000000000..9e7b738a4d --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/bootstrap_tests.py @@ -0,0 +1,17 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" +import os +import sys +try: + sys.path.append(os.path.dirname(os.path.abspath(__file__))) + import mock_asset_builder +except: + print ('skipping asset builder testing via mock_asset_builder') diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/export_chunks_builder.py b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/export_chunks_builder.py new file mode 100644 index 0000000000..ad68a486b1 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/export_chunks_builder.py @@ -0,0 +1,88 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" +import uuid, os +import azlmbr.scene as sceneApi +import azlmbr.scene.graph +from scene_api import scene_data as sceneData + +def get_mesh_node_names(sceneGraph): + meshDataList = [] + node = sceneGraph.get_root() + children = [] + + while node.IsValid(): + # store children to process after siblings + if sceneGraph.has_node_child(node): + children.append(sceneGraph.get_node_child(node)) + + # store any node that has mesh data content + nodeContent = sceneGraph.get_node_content(node) + if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'): + if sceneGraph.is_node_end_point(node) is False: + meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node))) + + # advance to next node + if sceneGraph.has_node_sibling(node): + node = sceneGraph.get_node_sibling(node) + elif children: + node = children.pop() + else: + node = azlmbr.scene.graph.NodeIndex() + + return meshDataList + +def update_manifest(scene): + graph = sceneData.SceneGraph(scene.graph) + meshNameList = get_mesh_node_names(graph) + sceneManifest = sceneData.SceneManifest() + sourceFilenameOnly = os.path.basename(scene.sourceFilename) + sourceFilenameOnly = sourceFilenameOnly.replace('.','_') + + for activeMeshIndex in range(len(meshNameList)): + chunkName = meshNameList[activeMeshIndex] + chunkPath = chunkName.get_path() + meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name()) + meshGroup = sceneManifest.add_mesh_group(meshGroupName) + meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}' + sceneManifest.mesh_group_add_comment(meshGroup, 'auto generated by scene manifest') + sceneManifest.mesh_group_add_advanced_coordinate_system(meshGroup, None, None, None, 1.0) + + # create selection node list + pathSet = set() + for meshIndex in range(len(meshNameList)): + targetPath = meshNameList[meshIndex].get_path() + if (activeMeshIndex == meshIndex): + sceneManifest.mesh_group_select_node(meshGroup, targetPath) + else: + if targetPath not in pathSet: + pathSet.update(targetPath) + sceneManifest.mesh_group_unselect_node(meshGroup, targetPath) + + return sceneManifest.export() + +mySceneJobHandler = None + +def on_update_manifest(args): + scene = args[0] + result = update_manifest(scene) + global mySceneJobHandler + mySceneJobHandler.disconnect() + mySceneJobHandler = None + return result + +def main(): + global mySceneJobHandler + mySceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler() + mySceneJobHandler.connect() + mySceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest) + +if __name__ == "__main__": + main() diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/geom_group.fbx b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/geom_group.fbx new file mode 100644 index 0000000000..8945a5505a --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/geom_group.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:66d38948309ef273adf74b63eaa38f8fc2e2bdfbab3933d2ee082ce6a8cb108e +size 30496 diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/geom_group.fbx.assetinfo b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/geom_group.fbx.assetinfo new file mode 100644 index 0000000000..707c6f3705 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/geom_group.fbx.assetinfo @@ -0,0 +1,9 @@ +{ + "values": + [ + { + "$type": "ScriptProcessorRule", + "scriptFilename": "Gem/PythonTests/PythonAssetBuilder/export_chunks_builder.py" + } + ] +} diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py new file mode 100644 index 0000000000..3b695e3ccd --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/mock_asset_builder.py @@ -0,0 +1,121 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" +import azlmbr.asset +import azlmbr.asset.builder +import azlmbr.bus +import azlmbr.math +import os, traceback, binascii, sys + +jobKeyName = 'Mock Asset' + +def log_exception_traceback(): + exc_type, exc_value, exc_tb = sys.exc_info() + data = traceback.format_exception(exc_type, exc_value, exc_tb) + print(str(data)) + +# creates a single job to compile for each platform +def create_jobs(request): + # create job descriptor for each platform + jobDescriptorList = [] + for platformInfo in request.enabledPlatforms: + jobDesc = azlmbr.asset.builder.JobDescriptor() + jobDesc.jobKey = jobKeyName + jobDesc.set_platform_identifier(platformInfo.identifier) + jobDescriptorList.append(jobDesc) + + response = azlmbr.asset.builder.CreateJobsResponse() + response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess + response.createJobOutputs = jobDescriptorList + return response + +def on_create_jobs(args): + try: + request = args[0] + return create_jobs(request) + except: + log_exception_traceback() + # returing back a default CreateJobsResponse() records an asset error + return azlmbr.asset.builder.CreateJobsResponse() + +def process_file(request): + # prepare output folder + basePath, _ = os.path.split(request.sourceFile) + outputPath = os.path.join(request.tempDirPath, basePath) + os.makedirs(outputPath, exist_ok=True) + + # write out a mock file + basePath, sourceFile = os.path.split(request.sourceFile) + mockFilename = os.path.splitext(sourceFile)[0] + '.mock_asset' + mockFilename = os.path.join(basePath, mockFilename) + mockFilename = mockFilename.replace('\\', '/') + tempFilename = os.path.join(request.tempDirPath, mockFilename) + + # write out a tempFilename like a JSON + fileOutput = open(tempFilename, "w") + fileOutput.write('{}') + fileOutput.close() + + # generate a product asset file entry + subId = binascii.crc32(mockFilename.encode()) + mockAssetType = azlmbr.math.Uuid_CreateString('{9274AD17-3212-4651-9F3B-7DCCB080E467}', 0) + product = azlmbr.asset.builder.JobProduct(mockFilename, mockAssetType, subId) + product.dependenciesHandled = True + productOutputs = [] + productOutputs.append(product) + + # fill out response object + response = azlmbr.asset.builder.ProcessJobResponse() + response.outputProducts = productOutputs + response.resultCode = azlmbr.asset.builder.ProcessJobResponse_Success + response.dependenciesHandled = True + return response + +# using the incoming 'request' find the type of job via 'jobKey' to determine what to do +def on_process_job(args): + try: + request = args[0] + if (request.jobDescription.jobKey.startswith(jobKeyName)): + return process_file(request) + except: + log_exception_traceback() + # returning back an empty ProcessJobResponse() will record an error + return azlmbr.asset.builder.ProcessJobResponse() + +# register asset builder +def register_asset_builder(busId): + assetPattern = azlmbr.asset.builder.AssetBuilderPattern() + assetPattern.pattern = '*.mock' + assetPattern.type = azlmbr.asset.builder.AssetBuilderPattern_Wildcard + + builderDescriptor = azlmbr.asset.builder.AssetBuilderDesc() + builderDescriptor.name = "Mock Builder" + builderDescriptor.patterns = [assetPattern] + builderDescriptor.busId = busId + builderDescriptor.version = 1 + + outcome = azlmbr.asset.builder.PythonAssetBuilderRequestBus(azlmbr.bus.Broadcast, 'RegisterAssetBuilder', builderDescriptor) + if outcome.IsSuccess(): + # created the asset builder to hook into the notification bus + handler = azlmbr.asset.builder.PythonBuilderNotificationBusHandler() + handler.connect(busId) + handler.add_callback('OnCreateJobsRequest', on_create_jobs) + handler.add_callback('OnProcessJobRequest', on_process_job) + return handler + +# create the asset builder handler +busIdString = '{CF5C74C1-9ED4-5851-95B1-0B15090DBEC7}' +busId = azlmbr.math.Uuid_CreateString(busIdString, 0) +handler = None +try: + handler = register_asset_builder(busId) +except: + handler = None + log_exception_traceback() diff --git a/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/test_asset.mock b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/test_asset.mock new file mode 100644 index 0000000000..6d6a52e643 --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/PythonAssetBuilder/test_asset.mock @@ -0,0 +1 @@ +mock data \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py index 6b4a8bf17c..ccc8c3f101 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_ProcessedImageAssignedSuccessfully.py @@ -77,13 +77,13 @@ class TestImageGradient(EditorTestHelper): # 3) Assign the processed gradient signal image as the Image Gradient's image asset and verify success # First, check for the base image in the workspace - base_image = "lumberyard_gsi.png" + base_image = "image_grad_test_gsi.png" base_image_path = os.path.join("AutomatedTesting", "Assets", "ImageGradients", base_image) if os.path.isfile(base_image_path): print(f"{base_image} was found in the workspace") # Next, assign the processed image to the Image Gradient's Image Asset property - processed_image_path = os.path.join("Assets", "ImageGradients", "lumberyard_gsi.gradimage") + processed_image_path = os.path.join("Assets", "ImageGradients", "image_grad_test_gsi.gradimage") asset_id = asset.AssetCatalogRequestBus(bus.Broadcast, "GetAssetIdByPath", processed_image_path, math.Uuid(), False) hydra.get_set_test(image_gradient_entity, 0, "Configuration|Image Asset", asset_id) diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_ImageGradient.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_ImageGradient.py index 11712f8b65..8fc582c2c8 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_ImageGradient.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/test_ImageGradient.py @@ -57,7 +57,7 @@ class TestImageGradientRequiresShape(object): "Entity has a Image Gradient component", "Entity has a Gradient Transform Modifier component", "Entity has a Box Shape component", - "lumberyard_gsi.png was found in the workspace", + "image_grad_test_gsi.png was found in the workspace", "Entity Configuration|Image Asset: SUCCESS", "ImageGradient_ProcessedImageAssignedSucessfully: result=SUCCESS", ] diff --git a/AutomatedTesting/LightingPresets/greenwich_park_02.lightingconfig.json b/AutomatedTesting/LightingPresets/greenwich_park_02.lightingconfig.json index 1646dd18a2..bfb92bbb6f 100644 --- a/AutomatedTesting/LightingPresets/greenwich_park_02.lightingconfig.json +++ b/AutomatedTesting/LightingPresets/greenwich_park_02.lightingconfig.json @@ -1,7 +1,6 @@ { "configurations": [ { - "autoSelect": false, "displayName": "Greenwich Park 02", "skyboxImageAsset": { "assetId": { @@ -64,7 +63,6 @@ "shadowCatcherOpacity": 0.20000000298023225 }, { - "autoSelect": false, "displayName": "Greenwich Park 02 (Alt)", "skyboxImageAsset": { "assetId": { diff --git a/CMakeLists.txt b/CMakeLists.txt index c09cfc9588..6da92f9c2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,15 +23,11 @@ endif() include(cmake/Version.cmake) -set(INSTALLED_ENGINE TRUE) - if(NOT PROJECT_NAME) project(O3DE LANGUAGES C CXX VERSION ${LY_VERSION_STRING} ) - - set(INSTALLED_ENGINE FALSE) endif() include(cmake/Initialize.cmake) diff --git a/Code/CryEngine/CryCommon/IMovieSystem.h b/Code/CryEngine/CryCommon/IMovieSystem.h index 654ccfd240..7a1125ae2b 100644 --- a/Code/CryEngine/CryCommon/IMovieSystem.h +++ b/Code/CryEngine/CryCommon/IMovieSystem.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -914,9 +915,18 @@ struct IAnimStringTable */ struct IAnimSequence { - AZ_RTTI(IAnimSequence, "{A60F95F5-5A4A-47DB-B3BB-525BBC0BC8DB}") + AZ_RTTI(IAnimSequence, "{A60F95F5-5A4A-47DB-B3BB-525BBC0BC8DB}"); + AZ_CLASS_ALLOCATOR(IAnimSequence, AZ::SystemAllocator, 0); - static const int kSequenceVersion = 4; + static const int kSequenceVersion = 5; + + static void Reflect(AZ::ReflectContext* context) + { + if (auto serializeContext = azrtti_cast(context); serializeContext != nullptr) + { + serializeContext->Class(); + } + } //! Flags used for SetFlags(),GetFlags(),SetParentFlags(),GetParentFlags() methods. enum EAnimSequenceFlags diff --git a/Code/CryEngine/RenderDll/Common/PerInstanceConstantBufferPool.cpp b/Code/CryEngine/RenderDll/Common/PerInstanceConstantBufferPool.cpp index 7fa69f6026..f2475c0b48 100644 --- a/Code/CryEngine/RenderDll/Common/PerInstanceConstantBufferPool.cpp +++ b/Code/CryEngine/RenderDll/Common/PerInstanceConstantBufferPool.cpp @@ -274,6 +274,10 @@ void PerInstanceConstantBufferPool::SetConstantBuffer(SRendItem* renderItem) deviceManager.BindConstantBuffer(eHWSC_Vertex, m_PooledIndirectConstantBuffer[indirectId], eConstantBufferShaderSlot_SPIIndex); deviceManager.BindConstantBuffer(eHWSC_Pixel, m_PooledIndirectConstantBuffer[indirectId], eConstantBufferShaderSlot_SPIIndex); #else + AZ::u32 itemIndex = directId % SPI_NUM_INSTS_PER_CB; + AZ::u32 first[1] = {itemIndex * static_cast(sizeof(HLSL_PerInstanceConstantBuffer))}; + AZ::u32 count[1] = {static_cast(sizeof(HLSL_PerInstanceConstantBuffer))}; + deviceManager.BindConstantBuffer(eHWSC_Vertex, m_PooledConstantBuffer[bufferIndex], eConstantBufferShaderSlot_SPI, first[0], count[0]); deviceManager.BindConstantBuffer(eHWSC_Pixel, m_PooledConstantBuffer[bufferIndex], eConstantBufferShaderSlot_SPI, first[0], count[0]); #endif diff --git a/Code/CryEngine/RenderDll/Common/RenderMesh.cpp b/Code/CryEngine/RenderDll/Common/RenderMesh.cpp index 10bbfbf0e6..357731fc6d 100644 --- a/Code/CryEngine/RenderDll/Common/RenderMesh.cpp +++ b/Code/CryEngine/RenderDll/Common/RenderMesh.cpp @@ -755,6 +755,7 @@ lSysUpdate: buffer_handle_t nVB = ~0u; # if BUFFER_ENABLE_DIRECT_ACCESS && !defined(NULL_RENDERER) nVB = MS->m_nID; + int nFrame = gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nFillThreadID].m_nFrameUpdateID; if ((nVB != ~0u && (MS->m_nFrameCreate != nFrame || MS->m_nElements != m_nVerts)) || !CRenderer::CV_r_buffer_enable_lockless_updates) # endif goto lSysCreate; diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp index b8d3e12712..a3af2648cf 100644 --- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp +++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp @@ -178,14 +178,16 @@ namespace AZ //! on an update to '/Amazon/AzCore/Bootstrap/project_path' key. struct UpdateProjectSettingsEventHandler { - UpdateProjectSettingsEventHandler(AZ::SettingsRegistryInterface& registry) + UpdateProjectSettingsEventHandler(AZ::SettingsRegistryInterface& registry, AZ::CommandLine& commandLine) : m_registry{ registry } + , m_commandLine{ commandLine } { } void operator()(AZStd::string_view path, AZ::SettingsRegistryInterface::Type) { using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; + // #1 Update the project settings when the project path is set const auto projectPathKey = FixedValueString(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + "/project_path"; AZ::IO::FixedMaxPath newProjectPath; if (SettingsRegistryMergeUtils::IsPathAncestorDescendantOrEqual(projectPathKey, path) @@ -194,6 +196,7 @@ namespace AZ UpdateProjectSettingsFromProjectPath(AZ::IO::PathView(newProjectPath)); } + // #2 Update the project specialization when the project name is set const auto projectNameKey = FixedValueString(AZ::SettingsRegistryMergeUtils::ProjectSettingsRootKey) + "/project_name"; FixedValueString newProjectName; if (SettingsRegistryMergeUtils::IsPathAncestorDescendantOrEqual(projectNameKey, path) @@ -201,6 +204,12 @@ namespace AZ { UpdateProjectSpecializationFromProjectName(newProjectName); } + + // #3 Update the ComponentApplication CommandLine instance when the command line settings are merged into the Settings Registry + if (path == AZ::SettingsRegistryMergeUtils::CommandLineValueChangedKey) + { + UpdateCommandLine(); + } } //! Add the project name as a specialization underneath the /Amazon/AzCore/Settings/Specializations path @@ -233,10 +242,16 @@ namespace AZ AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(m_registry); } + void UpdateCommandLine() + { + AZ::SettingsRegistryMergeUtils::GetCommandLineFromRegistry(m_registry, m_commandLine); + } + private: AZ::IO::FixedMaxPath m_oldProjectPath; AZ::SettingsRegistryInterface::FixedValueString m_oldProjectName; AZ::SettingsRegistryInterface& m_registry; + AZ::CommandLine& m_commandLine; }; void ComponentApplication::Descriptor::AllocatorRemapping::Reflect(ReflectContext* context, ComponentApplication* app) @@ -415,6 +430,12 @@ namespace AZ // Add the Command Line arguments into the SettingsRegistry SettingsRegistryMergeUtils::StoreCommandLineToRegistry(*m_settingsRegistry, m_commandLine); + // Add a notifier to update the project_settings when + // 1. The 'project_path' key changes + // 2. The project specialization when the 'project-name' key changes + // 3. The ComponentApplication command line when the command line is stored to the registry + m_projectChangedHandler = m_settingsRegistry->RegisterNotifier(UpdateProjectSettingsEventHandler{ *m_settingsRegistry, m_commandLine }); + // Merge Command Line arguments constexpr bool executeRegDumpCommands = false; SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_settingsRegistry, m_commandLine, executeRegDumpCommands); @@ -429,10 +450,6 @@ namespace AZ // for the application root. CalculateAppRoot(); - // Add a notifier to update the /Amazon/AzCore/Settings/Specializations - // when the 'project_path' property changes within the SettingsRegistry - m_projectChangedHandler = m_settingsRegistry->RegisterNotifier(UpdateProjectSettingsEventHandler{ *m_settingsRegistry }); - // Merge the bootstrap.cfg file into the Settings Registry as soon as the OSAllocator has been created. SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(*m_settingsRegistry); SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(*m_settingsRegistry, AZ_TRAIT_OS_PLATFORM_CODENAME, {}); @@ -909,6 +926,8 @@ namespace AZ SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif + // Update the Runtime file paths in case the "{BootstrapSettingsRootKey}/assets" key was overriden by a setting registry + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); } void ComponentApplication::SetSettingsRegistrySpecializations(SettingsRegistryInterface::Specializations& specializations) diff --git a/Code/Framework/AzCore/AzCore/Component/TransformBus.h b/Code/Framework/AzCore/AzCore/Component/TransformBus.h index b0e617f220..2003b949e2 100644 --- a/Code/Framework/AzCore/AzCore/Component/TransformBus.h +++ b/Code/Framework/AzCore/AzCore/Component/TransformBus.h @@ -26,7 +26,7 @@ namespace AZ { class Transform; - using TransformChangedEvent = Event; + using TransformChangedEvent = Event; using ParentChangedEvent = Event; diff --git a/Code/Framework/AzCore/AzCore/Math/Vector2.cpp b/Code/Framework/AzCore/AzCore/Math/Vector2.cpp index bc5f6ecdad..c2a3a934b0 100644 --- a/Code/Framework/AzCore/AzCore/Math/Vector2.cpp +++ b/Code/Framework/AzCore/AzCore/Math/Vector2.cpp @@ -167,14 +167,14 @@ namespace AZ } } - AZ_MATH_INLINE Vector2::Vector2(const Vector3& source) + Vector2::Vector2(const Vector3& source) : m_x(source.GetX()) , m_y(source.GetY()) { } - AZ_MATH_INLINE Vector2::Vector2(const Vector4& source) + Vector2::Vector2(const Vector4& source) : m_x(source.GetX()) , m_y(source.GetY()) { diff --git a/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.cpp b/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.cpp new file mode 100644 index 0000000000..63aad1ecf4 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.cpp @@ -0,0 +1,340 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include + +#include + +namespace AZ +{ + inline namespace PlatformDefaults + { + static const char* PlatformNames[PlatformId::NumPlatformIds] = { PlatformPC, PlatformES3, PlatformIOS, PlatformOSX, PlatformProvo, PlatformSalem, PlatformJasper, PlatformServer, PlatformAll, PlatformAllClient }; + + const char* PlatformIdToPalFolder(AZ::PlatformId platform) + { +#ifdef IOS +#define AZ_REDEFINE_IOS_AT_END IOS +#undef IOS +#endif + switch (platform) + { + case AZ::PC: + return "PC"; + case AZ::ES3: + return "Android"; + case AZ::IOS: + return "iOS"; + case AZ::OSX: + return "Mac"; + case AZ::PROVO: + return "Provo"; + case AZ::SALEM: + return "Salem"; + case AZ::JASPER: + return "Jasper"; + case AZ::SERVER: + return "Server"; + case AZ::ALL: + case AZ::ALL_CLIENT: + case AZ::NumPlatformIds: + case AZ::Invalid: + default: + return ""; + } + +#ifdef AZ_REDEFINE_IOS_AT_END +#define IOS AZ_REDEFINE_IOS_AT_END +#endif + } + + const char* OSPlatformToDefaultAssetPlatform(AZStd::string_view osPlatform) + { + if (osPlatform == PlatformCodeNameWindows || osPlatform == PlatformCodeNameLinux) + { + return PlatformPC; + } + else if (osPlatform == PlatformCodeNameMac) + { + return PlatformOSX; + } + else if (osPlatform == PlatformCodeNameAndroid) + { + return PlatformES3; + } + else if (osPlatform == PlatformCodeNameiOS) + { + return PlatformIOS; + } + else if (osPlatform == PlatformCodeNameProvo) + { + return PlatformProvo; + } + else if (osPlatform == PlatformCodeNameSalem) + { + return PlatformSalem; + } + else if (osPlatform == PlatformCodeNameJasper) + { + return PlatformJasper; + } + + AZ_Error("PlatformDefault", false, R"(Supplied OS platform "%.*s" does not have a corresponding default asset platform)", + aznumeric_cast(osPlatform.size()), osPlatform.data()); + return ""; + } + + PlatformFlags PlatformHelper::GetPlatformFlagFromPlatformIndex(PlatformId platformIndex) + { + if (platformIndex < 0 || platformIndex > PlatformId::NumPlatformIds) + { + return PlatformFlags::Platform_NONE; + } + if (platformIndex == PlatformId::ALL) + { + return PlatformFlags::Platform_ALL; + } + if (platformIndex == PlatformId::ALL_CLIENT) + { + return PlatformFlags::Platform_ALL_CLIENT; + } + return static_cast(1 << platformIndex); + } + + AZStd::fixed_vector PlatformHelper::GetPlatforms(PlatformFlags platformFlags) + { + AZStd::fixed_vector platforms; + for (int platformNum = 0; platformNum < PlatformId::NumPlatformIds; ++platformNum) + { + const bool isAllPlatforms = PlatformId::ALL == static_cast(platformNum) + && ((platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE); + + const bool isAllClientPlatforms = PlatformId::ALL_CLIENT == static_cast(platformNum) + && ((platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE); + + if (isAllPlatforms || isAllClientPlatforms + || (platformFlags & static_cast(1 << platformNum)) != PlatformFlags::Platform_NONE) + { + platforms.push_back(PlatformNames[platformNum]); + } + } + + return platforms; + } + + AZStd::fixed_vector PlatformHelper::GetPlatformsInterpreted(PlatformFlags platformFlags) + { + return GetPlatforms(GetPlatformFlagsInterpreted(platformFlags)); + } + + AZStd::fixed_vector PlatformHelper::GetPlatformIndices(PlatformFlags platformFlags) + { + AZStd::fixed_vector platformIndices; + for (int i = 0; i < PlatformId::NumPlatformIds; i++) + { + PlatformId index = static_cast(i); + if ((GetPlatformFlagFromPlatformIndex(index) & platformFlags) != PlatformFlags::Platform_NONE) + { + platformIndices.emplace_back(index); + } + } + return platformIndices; + } + + AZStd::fixed_vector PlatformHelper::GetPlatformIndicesInterpreted(PlatformFlags platformFlags) + { + return GetPlatformIndices(GetPlatformFlagsInterpreted(platformFlags)); + } + + PlatformFlags PlatformHelper::GetPlatformFlag(AZStd::string_view platform) + { + int platformIndex = GetPlatformIndexFromName(platform); + if (platformIndex == PlatformId::Invalid) + { + AZ_Error("PlatformDefault", false, "Invalid Platform ( %.*s ).\n", static_cast(platform.length()), platform.data()); + return PlatformFlags::Platform_NONE; + } + + if (platformIndex == PlatformId::ALL) + { + return PlatformFlags::Platform_ALL; + } + + if (platformIndex == PlatformId::ALL_CLIENT) + { + return PlatformFlags::Platform_ALL_CLIENT; + } + + return static_cast(1 << platformIndex); + } + + const char* PlatformHelper::GetPlatformName(PlatformId platform) + { + if (platform < 0 || platform > PlatformId::NumPlatformIds) + { + return "invalid"; + } + return PlatformNames[platform]; + } + + void PlatformHelper::AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, AZStd::string_view platformId) + { + PlatformId platform = GetPlatformIdFromName(platformId); + AZ_Assert(platform != PlatformId::Invalid, "Unsupported Platform ID: %.*s", static_cast(platformId.length()), platformId.data()); + AppendPlatformCodeNames(platformCodes, platform); + } + + void PlatformHelper::AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, PlatformId platformId) + { + // The IOS SDK has a macro that defines IOS as 1 which causes the enum below to be incorrectly converted to "PlatformId::1". +#pragma push_macro("IOS") +#undef IOS + // To reduce work the Asset Processor groups assets that can be shared between hardware platforms together. For this + // reason "PC" can for instance cover both the Windows and Linux platforms and "IOS" can cover AppleTV and iOS. + switch (platformId) + { + case PlatformId::PC: + platformCodes.emplace_back(PlatformCodeNameWindows); + platformCodes.emplace_back(PlatformCodeNameLinux); + break; + case PlatformId::ES3: + platformCodes.emplace_back(PlatformCodeNameAndroid); + break; + case PlatformId::IOS: + platformCodes.emplace_back(PlatformCodeNameiOS); + break; + case PlatformId::OSX: + platformCodes.emplace_back(PlatformCodeNameMac); + break; + case PlatformId::PROVO: + platformCodes.emplace_back(PlatformCodeNameProvo); + break; + case PlatformId::SALEM: + platformCodes.emplace_back(PlatformCodeNameSalem); + break; + case PlatformId::JASPER: + platformCodes.emplace_back(PlatformCodeNameJasper); + break; + case PlatformId::SERVER: + // Server is not a hardware platform + break; + default: + AZ_Assert(false, "Unsupported Platform ID: %i", platformId); + break; + } +#pragma pop_macro("IOS") + } + + int PlatformHelper::GetPlatformIndexFromName(AZStd::string_view platformName) + { + for (int idx = 0; idx < PlatformId::NumPlatformIds; idx++) + { + if (platformName == PlatformNames[idx]) + { + return idx; + } + } + + return PlatformId::Invalid; + } + + PlatformId PlatformHelper::GetPlatformIdFromName(AZStd::string_view platformName) + { + return aznumeric_caster(GetPlatformIndexFromName(platformName)); + } + + AssetPlatformCombinedString PlatformHelper::GetCommaSeparatedPlatformList(PlatformFlags platformFlags) + { + AZStd::fixed_vector platformNames = GetPlatforms(platformFlags); + AssetPlatformCombinedString platformsString; + AZ::StringFunc::Join(platformsString, platformNames.begin(), platformNames.end(), ", "); + return platformsString; + } + + PlatformFlags PlatformHelper::GetPlatformFlagsInterpreted(PlatformFlags platformFlags) + { + PlatformFlags returnFlags = PlatformFlags::Platform_NONE; + + if ((platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE) + { + for (int i = 0; i < NumPlatforms; ++i) + { + auto platformId = static_cast(i); + + if (platformId != PlatformId::ALL && platformId != PlatformId::ALL_CLIENT) + { + returnFlags |= GetPlatformFlagFromPlatformIndex(platformId); + } + } + } + else if ((platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE) + { + for (int i = 0; i < NumPlatforms; ++i) + { + auto platformId = static_cast(i); + + if (platformId != PlatformId::ALL && platformId != PlatformId::ALL_CLIENT && platformId != PlatformId::SERVER) + { + returnFlags |= GetPlatformFlagFromPlatformIndex(platformId); + } + } + } + else + { + returnFlags = platformFlags; + } + + return returnFlags; + } + + bool PlatformHelper::IsSpecialPlatform(PlatformFlags platformFlags) + { + return (platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE + || (platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE; + } + + bool HasFlagHelper(PlatformFlags flags, PlatformFlags checkPlatform) + { + return (flags & checkPlatform) == checkPlatform; + } + + + bool PlatformHelper::HasPlatformFlag(PlatformFlags flags, PlatformId checkPlatform) + { + // If checkPlatform contains any kind of invalid id, just exit out here + if (checkPlatform == PlatformId::Invalid || checkPlatform == NumPlatforms) + { + return false; + } + + // ALL_CLIENT + SERVER = ALL + if (HasFlagHelper(flags, PlatformFlags::Platform_ALL_CLIENT | PlatformFlags::Platform_SERVER)) + { + flags = PlatformFlags::Platform_ALL; + } + + if (HasFlagHelper(flags, PlatformFlags::Platform_ALL)) + { + // It doesn't matter what checkPlatform is set to in this case, just return true + return true; + } + + if (HasFlagHelper(flags, PlatformFlags::Platform_ALL_CLIENT)) + { + return checkPlatform != PlatformId::SERVER; + } + + return HasFlagHelper(flags, GetPlatformFlagFromPlatformIndex(checkPlatform)); + } + } +} diff --git a/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.h b/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.h new file mode 100644 index 0000000000..2d67c860cd --- /dev/null +++ b/Code/Framework/AzCore/AzCore/PlatformId/PlatformDefaults.h @@ -0,0 +1,157 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include +#include +#include +#include + +// On IOS builds IOS will be defined and interfere with the below enums +#pragma push_macro("IOS") +#undef IOS + +namespace AZ +{ + inline namespace PlatformDefaults + { + constexpr char PlatformPC[] = "pc"; + constexpr char PlatformES3[] = "es3"; + constexpr char PlatformIOS[] = "ios"; + constexpr char PlatformOSX[] = "osx_gl"; + constexpr char PlatformProvo[] = "provo"; + constexpr char PlatformSalem[] = "salem"; + constexpr char PlatformJasper[] = "jasper"; + constexpr char PlatformServer[] = "server"; + + constexpr char PlatformCodeNameWindows[] = "Windows"; + constexpr char PlatformCodeNameLinux[] = "Linux"; + constexpr char PlatformCodeNameAndroid[] = "Android"; + constexpr char PlatformCodeNameiOS[] = "iOS"; + constexpr char PlatformCodeNameMac[] = "Mac"; + constexpr char PlatformCodeNameProvo[] = "Provo"; + constexpr char PlatformCodeNameSalem[] = "Salem"; + constexpr char PlatformCodeNameJasper[] = "Jasper"; + constexpr char PlatformAll[] = "all"; + constexpr char PlatformAllClient[] = "all_client"; + + // Used for the capacity of a fixed vector to store the code names of platforms + // The value needs to be higher than the number of unique OS platforms that are supported(at this time 8) + constexpr size_t MaxPlatformCodeNames = 16; + + //! This platform enum have platform values in sequence and can also be used to get the platform count. + AZ_ENUM_WITH_UNDERLYING_TYPE(PlatformId, int, + (Invalid, -1), + PC, + ES3, + IOS, + OSX, + PROVO, + SALEM, + JASPER, + SERVER, // Corresponds to the customer's flavor of "server" which could be windows, ubuntu, etc + ALL, + ALL_CLIENT, + + // Add new platforms above this + NumPlatformIds + ); + constexpr int NumClientPlatforms = 7; + constexpr int NumPlatforms = NumClientPlatforms + 1; // 1 "Server" platform currently + enum class PlatformFlags : AZ::u32 + { + Platform_NONE = 0x00, + Platform_PC = 1 << PlatformId::PC, + Platform_ES3 = 1 << PlatformId::ES3, + Platform_IOS = 1 << PlatformId::IOS, + Platform_OSX = 1 << PlatformId::OSX, + Platform_PROVO = 1 << PlatformId::PROVO, + Platform_SALEM = 1 << PlatformId::SALEM, + Platform_JASPER = 1 << PlatformId::JASPER, + Platform_SERVER = 1 << PlatformId::SERVER, + + // A special platform that will always correspond to all platforms, even if new ones are added + Platform_ALL = 1ULL << 30, + + // A special platform that will always correspond to all non-server platforms, even if new ones are added + Platform_ALL_CLIENT = 1ULL << 31, + + AllNamedPlatforms = Platform_PC | Platform_ES3 | Platform_IOS | Platform_OSX | Platform_PROVO | Platform_SALEM | Platform_JASPER | Platform_SERVER, + }; + + AZ_DEFINE_ENUM_BITWISE_OPERATORS(PlatformFlags); + + // 32 characters should be more than enough to store a platform name + using AssetPlatformFixedString = AZStd::fixed_string<32>; + // Fixed string which can store a comma separated list of platforms names + // Additional byte is added to take into account the comma + using AssetPlatformCombinedString = AZStd::fixed_string < (AssetPlatformFixedString{}.max_size() + 1)* PlatformId::NumPlatformIds > ; + + const char* PlatformIdToPalFolder(PlatformId platform); + + const char* OSPlatformToDefaultAssetPlatform(AZStd::string_view osPlatform); + + //! Platform Helper is an utility class that can be used to retrieve platform related information + class PlatformHelper + { + public: + + //! Given a platformIndex returns the platform name + static const char* GetPlatformName(PlatformId platform); + + //! Converts the platform name to the platform code names as defined in AZ_TRAIT_OS_PLATFORM_CODENAME. + static void AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, AZStd::string_view platformName); + + //! Converts the platform name to the platform code names as defined in AZ_TRAIT_OS_PLATFORM_CODENAME. + static void AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, PlatformId platformId); + + //! Given a platform name returns a platform index. + //! If the platform is not found, the method returns -1. + static int GetPlatformIndexFromName(AZStd::string_view platformName); + + //! Given a platform name returns a platform id. + //! If the platform is not found, the method returns -1. + static PlatformId GetPlatformIdFromName(AZStd::string_view platformName); + + //! Given a platformIndex returns the platformFlags + static PlatformFlags GetPlatformFlagFromPlatformIndex(PlatformId platform); + + //! Given a platformFlags returns all the platform identifiers that are set. + static AZStd::fixed_vector GetPlatforms(PlatformFlags platformFlags); + //! Given a platformFlags returns all the platform identifiers that are set, with special flags interpreted. Do not use the result for saving + static AZStd::fixed_vector GetPlatformsInterpreted(PlatformFlags platformFlags); + + //! Given a platformFlags return a list of PlatformId indices + static AZStd::fixed_vector GetPlatformIndices(PlatformFlags platformFlags); + //! Given a platformFlags return a list of PlatformId indices, with special flags interpreted. Do not use the result for saving + static AZStd::fixed_vector GetPlatformIndicesInterpreted(PlatformFlags platformFlags); + + //! Given a platform identifier returns its corresponding platform flag. + static PlatformFlags GetPlatformFlag(AZStd::string_view platform); + + //! Given any platformFlags returns a string listing the input platforms + static AssetPlatformCombinedString GetCommaSeparatedPlatformList(PlatformFlags platformFlags); + + //! If platformFlags contains any special flags, they are removed and replaced with the normal flags they represent + static PlatformFlags GetPlatformFlagsInterpreted(PlatformFlags platformFlags); + + //! Returns true if platformFlags contains any special flags + static bool IsSpecialPlatform(PlatformFlags platformFlags); + + //! Returns true if platformFlags has checkPlatform flag set. + static bool HasPlatformFlag(PlatformFlags platformFlags, PlatformId checkPlatform); + }; + } +} +#pragma pop_macro("IOS") diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/ByteStreamSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/ByteStreamSerializer.cpp new file mode 100644 index 0000000000..6077a66682 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/ByteStreamSerializer.cpp @@ -0,0 +1,100 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include "ByteStreamSerializer.h" + +#include +#include +#include +#include + +namespace AZ +{ + namespace ByteSerializerInternal + { + static JsonSerializationResult::Result Load(void* outputValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context) + { + using JsonSerializationResult::Outcomes; + using JsonSerializationResult::Tasks; + + AZ_Assert(outputValue, "Expected a valid pointer to load from json value."); + + switch (inputValue.GetType()) + { + case rapidjson::kStringType: { + JsonByteStream buffer; + if (AZ::StringFunc::Base64::Decode(buffer, inputValue.GetString(), inputValue.GetStringLength())) + { + JsonByteStream* valAsByteStream = static_cast(outputValue); + *valAsByteStream = AZStd::move(buffer); + return context.Report(Tasks::ReadField, Outcomes::Success, "Successfully read ByteStream."); + } + return context.Report(Tasks::ReadField, Outcomes::Invalid, "Decode of Base64 encoded ByteStream failed."); + } + case rapidjson::kArrayType: + case rapidjson::kObjectType: + case rapidjson::kNullType: + case rapidjson::kFalseType: + case rapidjson::kTrueType: + case rapidjson::kNumberType: + return context.Report( + Tasks::ReadField, Outcomes::Unsupported, + "Unsupported type. ByteStream values cannot be read from arrays, objects, nulls, booleans or numbers."); + default: + return context.Report(Tasks::ReadField, Outcomes::Unknown, "Unknown json type encountered for ByteStream value."); + } + } + + static JsonSerializationResult::Result StoreWithDefault( + rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, JsonSerializerContext& context) + { + using JsonSerializationResult::Outcomes; + using JsonSerializationResult::Tasks; + + const JsonByteStream& valAsByteStream = *static_cast(inputValue); + if (context.ShouldKeepDefaults() || !defaultValue || (valAsByteStream != *static_cast(defaultValue))) + { + const auto base64ByteStream = AZ::StringFunc::Base64::Encode(valAsByteStream.data(), valAsByteStream.size()); + outputValue.SetString(base64ByteStream.c_str(), base64ByteStream.size(), context.GetJsonAllocator()); + return context.Report(Tasks::WriteValue, Outcomes::Success, "ByteStream successfully stored."); + } + + return context.Report(Tasks::WriteValue, Outcomes::DefaultsUsed, "Default ByteStream used."); + } + } // namespace ByteSerializerInternal + + AZ_CLASS_ALLOCATOR_IMPL(JsonByteStreamSerializer, SystemAllocator, 0); + + JsonSerializationResult::Result JsonByteStreamSerializer::Load( + void* outputValue, [[maybe_unused]] const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + JsonDeserializerContext& context) + { + AZ_Assert( + azrtti_typeid() == outputValueTypeId, + "Unable to deserialize AZStd::vector> to json because the provided type is %s", + outputValueTypeId.ToString().c_str()); + + return ByteSerializerInternal::Load(outputValue, inputValue, context); + } + + JsonSerializationResult::Result JsonByteStreamSerializer::Store( + rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, [[maybe_unused]] const Uuid& valueTypeId, + JsonSerializerContext& context) + { + AZ_Assert( + azrtti_typeid() == valueTypeId, + "Unable to serialize AZStd::vector to json because the provided type is %s", + valueTypeId.ToString().c_str()); + + return ByteSerializerInternal::StoreWithDefault(outputValue, inputValue, defaultValue, context); + } +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/ByteStreamSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/ByteStreamSerializer.h new file mode 100644 index 0000000000..4f01e28319 --- /dev/null +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/ByteStreamSerializer.h @@ -0,0 +1,38 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#pragma once + +#include +#include + +namespace AZ +{ + using JsonByteStream = AZStd::vector; //!< Alias for AZStd::vector. + + //! Serialize a stream of bytes (usually binary data) as a json string value. + //! @note Related to GenericClassByteStream (part of SerializeGenericTypeInfo> - see AZStdContainers.inl for more + //! details). + class JsonByteStreamSerializer : public BaseJsonSerializer + { + public: + AZ_RTTI(JsonByteStreamSerializer, "{30F0EA5A-CD13-4BA7-BAE1-D50D851CAC45}", BaseJsonSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + JsonSerializationResult::Result Load( + void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, + JsonDeserializerContext& context) override; + JsonSerializationResult::Result Store( + rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, const Uuid& valueTypeId, + JsonSerializerContext& context) override; + }; +} // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp index e33466d8dc..6e3c8cec60 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,8 @@ namespace AZ jsonContext->Serializer()->HandlesType(); jsonContext->Serializer()->HandlesType(); + jsonContext->Serializer()->HandlesType(); + jsonContext->Serializer() ->HandlesType() ->HandlesType() diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp index 392e95bf6e..27f6f222dd 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -132,23 +133,14 @@ namespace AZ::Internal AZ::IO::FixedMaxPath ScanUpRootLocator(AZStd::string_view rootFileToLocate) { - - AZStd::fixed_string executableDir; - if (AZ::Utils::GetExecutableDirectory(executableDir.data(), executableDir.capacity()) == Utils::ExecutablePathResult::Success) - { - // Update the size value of the executable directory fixed string to correctly be the length of the null-terminated string - // stored within it - executableDir.resize_no_construct(AZStd::char_traits::length(executableDir.data())); - } - - AZ::IO::FixedMaxPath engineRootCandidate{ executableDir }; + AZ::IO::FixedMaxPath rootCandidate{ AZ::Utils::GetExecutableDirectory() }; bool rootPathVisited = false; do { - if (AZ::IO::SystemFile::Exists((engineRootCandidate / rootFileToLocate).c_str())) + if (AZ::IO::SystemFile::Exists((rootCandidate / rootFileToLocate).c_str())) { - return engineRootCandidate; + return rootCandidate; } // Note for posix filesystems the parent directory of '/' is '/' and for windows @@ -156,38 +148,69 @@ namespace AZ::Internal // Validate that the parent directory isn't itself, that would imply // that it is the filesystem root path - AZ::IO::PathView parentPath = engineRootCandidate.ParentPath(); - rootPathVisited = (engineRootCandidate == parentPath); + AZ::IO::PathView parentPath = rootCandidate.ParentPath(); + rootPathVisited = (rootCandidate == parentPath); // Recurse upwards one directory - engineRootCandidate = AZStd::move(parentPath); + rootCandidate = AZStd::move(parentPath); } while (!rootPathVisited); return {}; } + void InjectSettingToCommandLineFront(AZ::SettingsRegistryInterface& settingsRegistry, + AZStd::string_view path, AZStd::string_view value) + { + AZ::CommandLine commandLine; + AZ::SettingsRegistryMergeUtils::GetCommandLineFromRegistry(settingsRegistry, commandLine); + AZ::CommandLine::ParamContainer paramContainer; + commandLine.Dump(paramContainer); + + auto projectPathOverride = AZStd::string::format(R"(--regset="%.*s=%.*s")", + aznumeric_cast(path.size()), path.data(), aznumeric_cast(value.size()), value.data()); + paramContainer.emplace(paramContainer.begin(), AZStd::move(projectPathOverride)); + commandLine.Parse(paramContainer); + AZ::SettingsRegistryMergeUtils::StoreCommandLineToRegistry(settingsRegistry, commandLine); + } } // namespace AZ::Internal namespace AZ::SettingsRegistryMergeUtils { + constexpr AZStd::string_view InternalScanUpEngineRootKey{ "/O3DE/Settings/Internal/engine_root_scan_up_path" }; + constexpr AZStd::string_view InternalScanUpProjectRootKey{ "/O3DE/Settings/Internal/project_root_scan_up_path" }; + AZ::IO::FixedMaxPath FindEngineRoot(SettingsRegistryInterface& settingsRegistry) { AZ::IO::FixedMaxPath engineRoot; - // This is the 'external' engine root key, as in passed from command-line or .setreg files. auto engineRootKey = SettingsRegistryInterface::FixedValueString::format("%s/engine_path", BootstrapSettingsRootKey); + + // Step 1 Run the scan upwards logic once to find the location of the engine.json if it exist + // Once this step is run the {InternalScanUpEngineRootKey} is set in the Settings Registry + // to have this scan logic only run once InternalScanUpEngineRootKey the supplied registry + if (settingsRegistry.GetType(InternalScanUpEngineRootKey) == SettingsRegistryInterface::Type::NoType) + { + // We can scan up from exe directory to find engine.json, use that for engine root if it exists. + engineRoot = Internal::ScanUpRootLocator("engine.json"); + // Set the {InternalScanUpEngineRootKey} to make sure this code path isn't called again for this settings registry + settingsRegistry.Set(InternalScanUpEngineRootKey, engineRoot.Native()); + if (!engineRoot.empty()) + { + settingsRegistry.Set(engineRootKey, engineRoot.Native()); + // Inject the engine root into the front of the command line settings + Internal::InjectSettingToCommandLineFront(settingsRegistry, engineRootKey, engineRoot.Native()); + return engineRoot; + } + } + + // Step 2 check if the engine_path key has been supplied if (settingsRegistry.Get(engineRoot.Native(), engineRootKey); !engineRoot.empty()) { return engineRoot; } - // We can scan up from exe directory to find engine.json, use that for engine root if it exists. - if (engineRoot = Internal::ScanUpRootLocator("engine.json"); !engineRoot.empty()) - { - settingsRegistry.Set(engineRootKey, engineRoot.c_str()); - return engineRoot; - } - + // Step 3 locate the project root and attempt to find the engine root using the registered engine + // for the project in the project.json file AZ::IO::FixedMaxPath projectRoot = FindProjectRoot(settingsRegistry); if (projectRoot.empty()) { @@ -207,16 +230,30 @@ namespace AZ::SettingsRegistryMergeUtils AZ::IO::FixedMaxPath FindProjectRoot(SettingsRegistryInterface& settingsRegistry) { AZ::IO::FixedMaxPath projectRoot; - // This is the 'external' project root key, as in passed from command-line or .setreg files. - auto projectRootKey = SettingsRegistryInterface::FixedValueString::format("%s/project_path", BootstrapSettingsRootKey); - if (settingsRegistry.Get(projectRoot.Native(), projectRootKey)) + const auto projectRootKey = SettingsRegistryInterface::FixedValueString::format("%s/project_path", BootstrapSettingsRootKey); + + // Step 1 Run the scan upwards logic once to find the location of the project.json if it exist + // Once this step is run the {InternalScanUpProjectRootKey} is set in the Settings Registry + // to have this scan logic only run once for the supplied registry + // SettingsRegistryInterface::GetType is used to check if a key is set + if (settingsRegistry.GetType(InternalScanUpProjectRootKey) == SettingsRegistryInterface::Type::NoType) { - return projectRoot; + projectRoot = Internal::ScanUpRootLocator("project.json"); + // Set the {InternalScanUpProjectRootKey} to make sure this code path isn't called again for this settings registry + settingsRegistry.Set(InternalScanUpProjectRootKey, projectRoot.Native()); + if (!projectRoot.empty()) + { + settingsRegistry.Set(projectRootKey, projectRoot.c_str()); + // Inject the project root into the front of the command line settings + Internal::InjectSettingToCommandLineFront(settingsRegistry, projectRootKey, projectRoot.Native()); + return projectRoot; + } } - if (projectRoot = Internal::ScanUpRootLocator("project.json"); !projectRoot.empty()) + // Step 2 Check the project-path key + // This is the project path root key, as in passed from command-line or .setreg files. + if (settingsRegistry.Get(projectRoot.Native(), projectRootKey)) { - settingsRegistry.Set(projectRootKey, projectRoot.c_str()); return projectRoot; } @@ -463,24 +500,13 @@ namespace AZ::SettingsRegistryMergeUtils void MergeSettingsToRegistry_Bootstrap(SettingsRegistryInterface& registry) { ConfigParserSettings parserSettings; - parserSettings.m_commentPrefixFunc = [](AZStd::string_view line) -> AZStd::string_view - { - constexpr AZStd::string_view commentPrefixes[]{ "--", ";","#" }; - for (AZStd::string_view commentPrefix : commentPrefixes) - { - if (size_t commentOffset = line.find(commentPrefix); commentOffset != AZStd::string_view::npos) - { - return line.substr(0, commentOffset); - } - } - return line; - }; parserSettings.m_registryRootPointerPath = BootstrapSettingsRootKey; MergeSettingsToRegistry_ConfigFile(registry, "bootstrap.cfg", parserSettings); } void MergeSettingsToRegistry_AddRuntimeFilePaths(SettingsRegistryInterface& registry) { + using FixedValueString = AZ::SettingsRegistryInterface::FixedValueString; // Binary folder AZ::IO::FixedMaxPath path = AZ::Utils::GetExecutableDirectory(); registry.Set(FilePathKey_BinaryFolder, path.LexicallyNormal().Native()); @@ -489,27 +515,25 @@ namespace AZ::SettingsRegistryMergeUtils AZ::IO::FixedMaxPath engineRoot = FindEngineRoot(registry); registry.Set(FilePathKey_EngineRootFolder, engineRoot.LexicallyNormal().Native()); - constexpr size_t bufferSize = 64; - auto buffer = AZStd::fixed_string::format("%s/project_path", BootstrapSettingsRootKey); - - AZ::SettingsRegistryInterface::FixedValueString projectPathKey(buffer); + auto projectPathKey = FixedValueString::format("%s/project_path", BootstrapSettingsRootKey); SettingsRegistryInterface::FixedValueString projectPathValue; if (registry.Get(projectPathValue, projectPathKey)) { // Cache folder // Get the name of the asset platform assigned by the bootstrap. First check for platform version such as "windows_assets" // and if that's missing just get "assets". - constexpr char platformName[] = AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER; - - SettingsRegistryInterface::FixedValueString assetPlatform; - buffer = AZStd::fixed_string::format("%s/%s_assets", BootstrapSettingsRootKey, platformName); - AZStd::string_view assetPlatformKey(buffer); - if (!registry.Get(assetPlatform, assetPlatformKey)) + FixedValueString assetPlatform; + if (auto assetPlatformKey = FixedValueString::format("%s/%s_assets", BootstrapSettingsRootKey, AZ_TRAIT_OS_PLATFORM_CODENAME_LOWER); + !registry.Get(assetPlatform, assetPlatformKey)) { - buffer = AZStd::fixed_string::format("%s/assets", BootstrapSettingsRootKey); - assetPlatformKey = AZStd::string_view(buffer); + assetPlatformKey = FixedValueString::format("%s/assets", BootstrapSettingsRootKey); registry.Get(assetPlatform, assetPlatformKey); } + if (assetPlatform.empty()) + { + // Use the platform codename to retrieve the default asset platform value + assetPlatform = AZ::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME); + } // Project path - corresponds to the @devassets@ alias // NOTE: Here we append to engineRoot, but if projectPathValue is absolute then engineRoot is discarded. @@ -549,8 +573,7 @@ namespace AZ::SettingsRegistryMergeUtils { // Cache: project root - no corresponding fileIO alias, but this is where the asset database lives. // A registry override is accepted using the "project_cache_path" key. - buffer = AZStd::fixed_string::format("%s/project_cache_path", BootstrapSettingsRootKey); - AZStd::string_view projectCacheRootOverrideKey(buffer); + auto projectCacheRootOverrideKey = FixedValueString::format("%s/project_cache_path", BootstrapSettingsRootKey); // Clear path to make sure that the `project_cache_path` value isn't concatenated to the project path path.clear(); if (registry.Get(path.Native(), projectCacheRootOverrideKey)) @@ -807,6 +830,11 @@ namespace AZ::SettingsRegistryMergeUtils ++argumentIndex; commandLinePath.resize(commandLineRootSize); } + + // This key is used allow Notification Handlers to know when the command line has been updated within the + // registry. The value itself is meaningless. The JSON path of {CommandLineValueChangedKey} + // being passed to the Notification Event Handler indicates that the command line has be updated + registry.Set(CommandLineValueChangedKey, true); } bool GetCommandLineFromRegistry(SettingsRegistryInterface& registry, AZ::CommandLine& commandLine) @@ -823,10 +851,16 @@ namespace AZ::SettingsRegistryMergeUtils } else if (valueName == "Value" && !value.empty()) { - m_arguments.push_back(value); + // Make sure value types are in quotes in case they start with a command option prefix + m_arguments.push_back(QuoteArgument(value)); } } + AZStd::string QuoteArgument(AZStd::string_view arg) + { + return !arg.empty() ? AZStd::string::format(R"("%.*s")", aznumeric_cast(arg.size()), arg.data()) : AZStd::string{ arg }; + } + // The first parameter is skipped by the ComamndLine::Parse function so initialize // the container with one empty element AZ::CommandLine::ParamContainer m_arguments{ 1 }; diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h index dad6c36d0f..10b3c2f18b 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistryMergeUtils.h @@ -57,6 +57,9 @@ namespace AZ::SettingsRegistryMergeUtils //! Root key for where command line are stored at within the settings registry inline static constexpr char CommandLineRootKey[] = "/Amazon/AzCore/Runtime/CommandLine"; + //! Key set to trigger a notification that the CommandLine has been stored within the settings registry + //! The value of the key has no meaning. Notification Handlers only need to check if the key was supplied + inline static constexpr char CommandLineValueChangedKey[] = "/Amazon/AzCore/Runtime/CommandLineChanged"; //! Root key where raw project settings (project.json) file is merged to settings registry inline static constexpr char ProjectSettingsRootKey[] = "/Amazon/Project/Settings"; @@ -74,6 +77,20 @@ namespace AZ::SettingsRegistryMergeUtils //! If it's still not found, attempt to find the project (by similar means) then reconcile the //! engine root by inspecting project.json and the engine manifest file. AZ::IO::FixedMaxPath FindEngineRoot(SettingsRegistryInterface& settingsRegistry); + + //! The algorithm that is used to find the project root is as follows + //! 1. The first time this function is it performs a upward scan for a project.json file from + //! the executable directory and if found stores that path to an internal key. + //! In the same step it injects the path into the front of list of command line parameters + //! using the --regset="{BootstrapSettingsRootKey}/project_path=" value + //! 2. Next the "{BootstrapSettingsRootKey}/project_path" is checked to see if it has a project path set + //! + //! The order in which the project path settings are overridden proceeds in the following order + //! 1. project_path set in the /bootstrap.cfg file + //! 2. project_path set in a *.setreg/*.setregpatch file + //! 3. project_path found by scanning upwards from the executable directory to the project.json path + //! 4. project_path set on the Command line via either --regset="{BootstrapSettingsRootKey}/project_path=" + //! or --project_path= AZ::IO::FixedMaxPath FindProjectRoot(SettingsRegistryInterface& settingsRegistry); //! Query the specializations that will be used when loading the Settings Registry. diff --git a/Code/Framework/AzCore/AzCore/azcore_files.cmake b/Code/Framework/AzCore/AzCore/azcore_files.cmake index 97b86f2432..5357ed66a6 100644 --- a/Code/Framework/AzCore/AzCore/azcore_files.cmake +++ b/Code/Framework/AzCore/AzCore/azcore_files.cmake @@ -505,6 +505,8 @@ set(FILES Serialization/Json/BasicContainerSerializer.cpp Serialization/Json/BoolSerializer.h Serialization/Json/BoolSerializer.cpp + Serialization/Json/ByteStreamSerializer.h + Serialization/Json/ByteStreamSerializer.cpp Serialization/Json/CastingHelpers.h Serialization/Json/DoubleSerializer.h Serialization/Json/DoubleSerializer.cpp @@ -605,6 +607,8 @@ set(FILES Utils/Utils.h Script/lua/lua.h Memory/HeapSchema.cpp + PlatformId/PlatformDefaults.h + PlatformId/PlatformDefaults.cpp PlatformId/PlatformId.h PlatformId/PlatformId.cpp Socket/AzSocket_fwd.h diff --git a/Code/Framework/AzCore/Tests/Serialization/Json/ByteStreamSerializerTests.cpp b/Code/Framework/AzCore/Tests/Serialization/Json/ByteStreamSerializerTests.cpp new file mode 100644 index 0000000000..110466d1a0 --- /dev/null +++ b/Code/Framework/AzCore/Tests/Serialization/Json/ByteStreamSerializerTests.cpp @@ -0,0 +1,59 @@ +/* + * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or + * its licensors. + * + * For complete copyright and license terms please see the LICENSE at the root of this + * distribution (the "License"). All use of this software is governed by the License, + * or, if provided, by the license below or the license accompanying this file. Do not + * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + */ + +#include +#include +#include + +namespace JsonSerializationTests +{ + class ByteStreamSerializerTestDescription : public JsonSerializerConformityTestDescriptor + { + public: + AZStd::shared_ptr CreateSerializer() override + { + return AZStd::make_shared(); + } + + AZStd::shared_ptr CreateDefaultInstance() override + { + return AZStd::make_shared(); + } + + AZStd::shared_ptr CreateFullySetInstance() override + { + // create a JsonByteStream (AZStd::vector) with ten 'a's + return AZStd::make_shared(10, 'a'); + } + + AZStd::string_view GetJsonForFullySetInstance() override + { + // Base64 encoded version of 'aaaaaaaaaa' (see CreateFullySetInstance) + return R"("YWFhYWFhYWFhYQ==")"; + } + + void ConfigureFeatures(JsonSerializerConformityTestDescriptorFeatures& features) override + { + features.EnableJsonType(rapidjson::kStringType); + features.m_supportsPartialInitialization = false; + features.m_supportsInjection = false; + } + + bool AreEqual(const AZ::JsonByteStream& lhs, const AZ::JsonByteStream& rhs) override + { + return lhs == rhs; + } + }; + + using ByteStreamConformityTestTypes = ::testing::Types; + INSTANTIATE_TYPED_TEST_CASE_P(JsonByteStreamSerialzier, JsonSerializerConformityTests, ByteStreamConformityTestTypes); +} // namespace JsonSerializationTests diff --git a/Code/Framework/AzCore/Tests/azcoretests_files.cmake b/Code/Framework/AzCore/Tests/azcoretests_files.cmake index c51cf46a37..2129761bfe 100644 --- a/Code/Framework/AzCore/Tests/azcoretests_files.cmake +++ b/Code/Framework/AzCore/Tests/azcoretests_files.cmake @@ -98,6 +98,7 @@ set(FILES Serialization/Json/BaseJsonSerializerTests.cpp Serialization/Json/BasicContainerSerializerTests.cpp Serialization/Json/BoolSerializerTests.cpp + Serialization/Json/ByteStreamSerializerTests.cpp Serialization/Json/ColorSerializerTests.cpp Serialization/Json/DoubleSerializerTests.cpp Serialization/Json/IntSerializerTests.cpp diff --git a/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h b/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h index a5d3e657f5..f84f0276e1 100644 --- a/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h +++ b/Code/Framework/AzFramework/AzFramework/Entity/EntityDebugDisplayBus.h @@ -105,8 +105,6 @@ namespace AzFramework virtual bool SetDrawInFrontMode(bool bOn) { (void)bOn; return false; } virtual AZ::u32 GetState() { return 0; } virtual AZ::u32 SetState(AZ::u32 state) { (void)state; return 0; } - virtual AZ::u32 SetStateFlag(AZ::u32 state) { (void)state; return 0; } - virtual AZ::u32 ClearStateFlag(AZ::u32 state) { (void)state; return 0; } virtual void PushMatrix(const AZ::Transform& tm) { (void)tm; } virtual void PopMatrix() {} diff --git a/Code/Framework/AzFramework/AzFramework/Font/FontInterface.h b/Code/Framework/AzFramework/AzFramework/Font/FontInterface.h new file mode 100644 index 0000000000..7c5bcce6d6 --- /dev/null +++ b/Code/Framework/AzFramework/AzFramework/Font/FontInterface.h @@ -0,0 +1,85 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include +#include +#include +#include + +namespace AzFramework +{ + using FontId = uint32_t; + static constexpr FontId InvalidFontId = 0xffffffffu; + + enum class TextHorizontalAlignment : uint16_t + { + Left, + Right, + Center + }; + + enum class TextVerticalAlignment : uint16_t + { + Top, + Bottom, + Center, + }; + + //! Standard parameters for drawing text on screen + struct TextDrawParameters + { + ViewportId m_drawViewportId = InvalidViewportId; //! Viewport to draw into + AZ::Vector3 m_position; //! world space position for 3d draws, screen space x,y,depth for 2d. + AZ::Color m_color = AZ::Colors::White; //! Color to draw the text + AZ::Vector2 m_scale = AZ::Vector2(1.0f); //! font scale + TextHorizontalAlignment m_hAlign = TextHorizontalAlignment::Left; //! Horizontal text alignment + TextVerticalAlignment m_vAlign = TextVerticalAlignment::Top; //! Vertical text alignment + bool m_monospace = false; //! disable character proportional spacing + bool m_depthTest = false; //! Test character against the depth buffer + bool m_virtual800x600ScreenSize = true; //! Text placement and size are scaled relative to a virtual 800x600 resolution + bool m_scaleWithWindow = false; //! Font gets bigger as the window gets bigger + bool m_multiline = true; //! text respects ascii newline characters + }; + + class FontDrawInterface + { + public: + AZ_RTTI(FontDrawInterface, "{545A7C14-CB3E-4A5B-B435-13EA606708EE}"); + + FontDrawInterface() = default; + virtual ~FontDrawInterface() = default; + + virtual void DrawScreenAlignedText2d( + const TextDrawParameters& params, + const AZStd::string_view& string) = 0; + virtual void DrawScreenAlignedText3d( + const TextDrawParameters& params, + const AZStd::string_view& string) = 0; + }; + + class FontQueryInterface + { + public: + AZ_RTTI(FontQueryInterface, "{4BDD8520-EBC1-4680-B25E-421BDF31750F}"); + + FontQueryInterface() = default; + virtual ~FontQueryInterface() = default; + + FontId GetFontId(const AZStd::string_view& fontName) const {return FontId(AZ::Crc32(fontName));} + virtual FontDrawInterface* GetFontDrawInterface(FontId) const = 0; + virtual FontDrawInterface* GetDefaultFontDrawInterface() const = 0; + + }; +} // namespace AzFramework diff --git a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp index 44c24758f3..f01e42a443 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.cpp @@ -142,6 +142,7 @@ namespace Physics ->Field("PhysicsAsset", &PhysicsAssetShapeConfiguration::m_asset) ->Field("AssetScale", &PhysicsAssetShapeConfiguration::m_assetScale) ->Field("UseMaterialsFromAsset", &PhysicsAssetShapeConfiguration::m_useMaterialsFromAsset) + ->Field("SubdivisionLevel", &PhysicsAssetShapeConfiguration::m_subdivisionLevel) ; if (auto editContext = serializeContext->GetEditContext()) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h index 8afe6851b7..b3d04a10c9 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/ShapeConfiguration.h @@ -141,6 +141,7 @@ namespace Physics AZ::Data::Asset m_asset{ AZ::Data::AssetLoadBehavior::PreLoad }; AZ::Vector3 m_assetScale = AZ::Vector3::CreateOne(); bool m_useMaterialsFromAsset = true; + AZ::u8 m_subdivisionLevel = 4; ///< The level of subdivision if a primitive shape is replaced with a convex mesh due to scaling. }; class NativeShapeConfiguration : public ShapeConfiguration diff --git a/Code/Framework/AzFramework/AzFramework/Physics/SystemBus.h b/Code/Framework/AzFramework/AzFramework/Physics/SystemBus.h index c303e14636..717f9e023c 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/SystemBus.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/SystemBus.h @@ -142,13 +142,6 @@ namespace Physics virtual AZStd::shared_ptr CreateShape(const ColliderConfiguration& colliderConfiguration, const ShapeConfiguration& configuration) = 0; - /// Adds an appropriate collider component to the entity based on the provided shape configuration. - /// @param entity Entity where the component should be added to. - /// @param colliderConfiguration Configuration of the collider. - /// @param shapeConfiguration Configuration of the shape of the collider. - /// @param addEditorComponents Tells whether to add the Editor version of the collider component or the Game one. - virtual void AddColliderComponentToEntity(AZ::Entity* entity, const Physics::ColliderConfiguration& colliderConfiguration, const Physics::ShapeConfiguration& shapeConfiguration, bool addEditorComponents = false) = 0; - /// Releases the mesh object created by the physics backend. /// @param nativeMeshObject Pointer to the mesh object. virtual void ReleaseNativeMeshObject(void* nativeMeshObject) = 0; diff --git a/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.cpp b/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.cpp deleted file mode 100644 index 81154bae35..0000000000 --- a/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/* -* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or -* its licensors. -* -* For complete copyright and license terms please see the LICENSE at the root of this -* distribution (the "License"). All use of this software is governed by the License, -* or, if provided, by the license below or the license accompanying this file. Do not -* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* -*/ - -#include -#include - -#include - -namespace AzFramework -{ - static const char* PlatformNames[PlatformId::NumPlatformIds] = { PlatformPC, PlatformES3, PlatformIOS, PlatformOSX, PlatformProvo, PlatformSalem, PlatformJasper, PlatformServer, PlatformAll, PlatformAllClient }; - - const char* PlatformIdToPalFolder(AzFramework::PlatformId platform) - { -#ifdef IOS -#define AZ_REDEFINE_IOS_AT_END IOS -#undef IOS -#endif - switch (platform) - { - case AzFramework::PC: - return "PC"; - case AzFramework::ES3: - return "Android"; - case AzFramework::IOS: - return "iOS"; - case AzFramework::OSX: - return "Mac"; - case AzFramework::PROVO: - return "Provo"; - case AzFramework::SALEM: - return "Salem"; - case AzFramework::JASPER: - return "Jasper"; - case AzFramework::SERVER: - return "Server"; - case AzFramework::ALL: - case AzFramework::ALL_CLIENT: - case AzFramework::NumPlatformIds: - case AzFramework::Invalid: - default: - return ""; - } - -#ifdef AZ_REDEFINE_IOS_AT_END -#define IOS AZ_REDEFINE_IOS_AT_END -#endif - } - - const char* OSPlatformToDefaultAssetPlatform(AZStd::string_view osPlatform) - { - if (osPlatform == PlatformCodeNameWindows || osPlatform == PlatformCodeNameLinux) - { - return PlatformPC; - } - else if (osPlatform == PlatformCodeNameMac) - { - return PlatformOSX; - } - else if (osPlatform == PlatformCodeNameAndroid) - { - return PlatformES3; - } - else if (osPlatform == PlatformCodeNameiOS) - { - return PlatformIOS; - } - else if (osPlatform == PlatformCodeNameProvo) - { - return PlatformProvo; - } - else if (osPlatform == PlatformCodeNameSalem) - { - return PlatformSalem; - } - else if (osPlatform == PlatformCodeNameJasper) - { - return PlatformJasper; - } - - AZ_Error("PlatformDefault", false, R"(Supplied OS platform "%.*s" does not have a corresponding default asset platform)", - aznumeric_cast(osPlatform.size()), osPlatform.data()); - return ""; - } - - PlatformFlags PlatformHelper::GetPlatformFlagFromPlatformIndex(PlatformId platformIndex) - { - if (platformIndex < 0 || platformIndex > PlatformId::NumPlatformIds) - { - return PlatformFlags::Platform_NONE; - } - if (platformIndex == PlatformId::ALL) - { - return PlatformFlags::Platform_ALL; - } - if (platformIndex == PlatformId::ALL_CLIENT) - { - return PlatformFlags::Platform_ALL_CLIENT; - } - return static_cast(1 << platformIndex); - } - - AZStd::fixed_vector PlatformHelper::GetPlatforms(PlatformFlags platformFlags) - { - AZStd::fixed_vector platforms; - for (int platformNum = 0; platformNum < PlatformId::NumPlatformIds; ++platformNum) - { - const bool isAllPlatforms = PlatformId::ALL == static_cast(platformNum) - && ((platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE); - - const bool isAllClientPlatforms = PlatformId::ALL_CLIENT == static_cast(platformNum) - && ((platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE); - - if (isAllPlatforms || isAllClientPlatforms - || (platformFlags & static_cast(1 << platformNum)) != PlatformFlags::Platform_NONE) - { - platforms.push_back(PlatformNames[platformNum]); - } - } - - return platforms; - } - - AZStd::fixed_vector PlatformHelper::GetPlatformsInterpreted(PlatformFlags platformFlags) - { - return GetPlatforms(GetPlatformFlagsInterpreted(platformFlags)); - } - - AZStd::fixed_vector PlatformHelper::GetPlatformIndices(PlatformFlags platformFlags) - { - AZStd::fixed_vector platformIndices; - for (int i = 0; i < PlatformId::NumPlatformIds; i++) - { - PlatformId index = static_cast(i); - if ((GetPlatformFlagFromPlatformIndex(index) & platformFlags) != PlatformFlags::Platform_NONE) - { - platformIndices.emplace_back(index); - } - } - return platformIndices; - } - - AZStd::fixed_vector PlatformHelper::GetPlatformIndicesInterpreted(PlatformFlags platformFlags) - { - return GetPlatformIndices(GetPlatformFlagsInterpreted(platformFlags)); - } - - PlatformFlags PlatformHelper::GetPlatformFlag(AZStd::string_view platform) - { - int platformIndex = GetPlatformIndexFromName(platform); - if (platformIndex == PlatformId::Invalid) - { - AZ_Error("PlatformDefault", false, "Invalid Platform ( %.*s ).\n", static_cast(platform.length()), platform.data()); - return PlatformFlags::Platform_NONE; - } - - if(platformIndex == PlatformId::ALL) - { - return PlatformFlags::Platform_ALL; - } - - if (platformIndex == PlatformId::ALL_CLIENT) - { - return PlatformFlags::Platform_ALL_CLIENT; - } - - return static_cast(1 << platformIndex); - } - - const char* PlatformHelper::GetPlatformName(PlatformId platform) - { - if (platform < 0 || platform > PlatformId::NumPlatformIds) - { - return "invalid"; - } - return PlatformNames[platform]; - } - - void PlatformHelper::AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, AZStd::string_view platformId) - { - PlatformId platform = GetPlatformIdFromName(platformId); - AZ_Assert(platform != PlatformId::Invalid, "Unsupported Platform ID: %.*s", static_cast(platformId.length()), platformId.data()); - AppendPlatformCodeNames(platformCodes, platform); - } - - void PlatformHelper::AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, PlatformId platformId) - { -// The IOS SDK has a macro that defines IOS as 1 which causes the enum below to be incorrectly converted to "PlatformId::1". -#pragma push_macro("IOS") -#undef IOS - // To reduce work the Asset Processor groups assets that can be shared between hardware platforms together. For this - // reason "PC" can for instance cover both the Windows and Linux platforms and "IOS" can cover AppleTV and iOS. - switch (platformId) - { - case PlatformId::PC: - platformCodes.emplace_back(PlatformCodeNameWindows); - platformCodes.emplace_back(PlatformCodeNameLinux); - break; - case PlatformId::ES3: - platformCodes.emplace_back(PlatformCodeNameAndroid); - break; - case PlatformId::IOS: - platformCodes.emplace_back(PlatformCodeNameiOS); - break; - case PlatformId::OSX: - platformCodes.emplace_back(PlatformCodeNameMac); - break; - case PlatformId::PROVO: - platformCodes.emplace_back(PlatformCodeNameProvo); - break; - case PlatformId::SALEM: - platformCodes.emplace_back(PlatformCodeNameSalem); - break; - case PlatformId::JASPER: - platformCodes.emplace_back(PlatformCodeNameJasper); - break; - case PlatformId::SERVER: - // Server is not a hardware platform - break; - default: - AZ_Assert(false, "Unsupported Platform ID: %i", platformId); - break; - } -#pragma pop_macro("IOS") - } - - int PlatformHelper::GetPlatformIndexFromName(AZStd::string_view platformName) - { - for (int idx = 0; idx < PlatformId::NumPlatformIds; idx++) - { - if (platformName == PlatformNames[idx]) - { - return idx; - } - } - - return PlatformId::Invalid; - } - - PlatformId PlatformHelper::GetPlatformIdFromName(AZStd::string_view platformName) - { - return aznumeric_caster(GetPlatformIndexFromName(platformName)); - } - - AssetPlatformCombinedString PlatformHelper::GetCommaSeparatedPlatformList(PlatformFlags platformFlags) - { - AZStd::fixed_vector platformNames = GetPlatforms(platformFlags); - AssetPlatformCombinedString platformsString; - AZ::StringFunc::Join(platformsString, platformNames.begin(), platformNames.end(), ", "); - return platformsString; - } - - PlatformFlags PlatformHelper::GetPlatformFlagsInterpreted(PlatformFlags platformFlags) - { - PlatformFlags returnFlags = PlatformFlags::Platform_NONE; - - if((platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE) - { - for (int i = 0; i < NumPlatforms; ++i) - { - auto platformId = static_cast(i); - - if (platformId != PlatformId::ALL && platformId != PlatformId::ALL_CLIENT) - { - returnFlags |= GetPlatformFlagFromPlatformIndex(platformId); - } - } - } - else if((platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE) - { - for (int i = 0; i < NumPlatforms; ++i) - { - auto platformId = static_cast(i); - - if (platformId != PlatformId::ALL && platformId != PlatformId::ALL_CLIENT && platformId != PlatformId::SERVER) - { - returnFlags |= GetPlatformFlagFromPlatformIndex(platformId); - } - } - } - else - { - returnFlags = platformFlags; - } - - return returnFlags; - } - - bool PlatformHelper::IsSpecialPlatform(PlatformFlags platformFlags) - { - return (platformFlags & PlatformFlags::Platform_ALL) != PlatformFlags::Platform_NONE - || (platformFlags & PlatformFlags::Platform_ALL_CLIENT) != PlatformFlags::Platform_NONE; - } - - bool HasFlagHelper(PlatformFlags flags, PlatformFlags checkPlatform) - { - return (flags & checkPlatform) == checkPlatform; - } - - - bool PlatformHelper::HasPlatformFlag(PlatformFlags flags, PlatformId checkPlatform) - { - // If checkPlatform contains any kind of invalid id, just exit out here - if(checkPlatform == PlatformId::Invalid || checkPlatform == NumPlatforms) - { - return false; - } - - // ALL_CLIENT + SERVER = ALL - if(HasFlagHelper(flags, PlatformFlags::Platform_ALL_CLIENT | PlatformFlags::Platform_SERVER)) - { - flags = PlatformFlags::Platform_ALL; - } - - if(HasFlagHelper(flags, PlatformFlags::Platform_ALL)) - { - // It doesn't matter what checkPlatform is set to in this case, just return true - return true; - } - - if(HasFlagHelper(flags, PlatformFlags::Platform_ALL_CLIENT)) - { - return checkPlatform != PlatformId::SERVER; - } - - return HasFlagHelper(flags, GetPlatformFlagFromPlatformIndex(checkPlatform)); - } - -} diff --git a/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.h b/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.h index d7f467ec0f..13f7fa20e5 100644 --- a/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.h +++ b/Code/Framework/AzFramework/AzFramework/Platform/PlatformDefaults.h @@ -12,144 +12,12 @@ #pragma once -#include -#include -#include -#include -#include - -// On IOS builds IOS will be defined and interfere with the below enums -#pragma push_macro("IOS") -#undef IOS +#include +// As the Platform defaults is needed within AzCore, +// those structures have been moved to AzCore and brought into +// The AzFramework namespace for backwards compatibility namespace AzFramework { - constexpr char PlatformPC[] = "pc"; - constexpr char PlatformES3[] = "es3"; - constexpr char PlatformIOS[] = "ios"; - constexpr char PlatformOSX[] = "osx_gl"; - constexpr char PlatformProvo[] = "provo"; - constexpr char PlatformSalem[] = "salem"; - constexpr char PlatformJasper[] = "jasper"; - constexpr char PlatformServer[] = "server"; - - constexpr char PlatformCodeNameWindows[] = "Windows"; - constexpr char PlatformCodeNameLinux[] = "Linux"; - constexpr char PlatformCodeNameAndroid[] = "Android"; - constexpr char PlatformCodeNameiOS[] = "iOS"; - constexpr char PlatformCodeNameMac[] = "Mac"; - constexpr char PlatformCodeNameProvo[] = "Provo"; - constexpr char PlatformCodeNameSalem[] = "Salem"; - constexpr char PlatformCodeNameJasper[] = "Jasper"; - constexpr char PlatformAll[] = "all"; - constexpr char PlatformAllClient[] = "all_client"; - - // Used for the capacity of a fixed vector to store the code names of platforms - // The value needs to be higher than the number of unique OS platforms that are supported(at this time 8) - constexpr size_t MaxPlatformCodeNames = 16; - - //! This platform enum have platform values in sequence and can also be used to get the platform count. - AZ_ENUM_WITH_UNDERLYING_TYPE(PlatformId, int, - (Invalid, -1), - PC, - ES3, - IOS, - OSX, - PROVO, - SALEM, - JASPER, - SERVER, // Corresponds to the customer's flavor of "server" which could be windows, ubuntu, etc - ALL, - ALL_CLIENT, - - // Add new platforms above this - NumPlatformIds - ); - constexpr int NumClientPlatforms = 7; - constexpr int NumPlatforms = NumClientPlatforms + 1; // 1 "Server" platform currently - enum class PlatformFlags : AZ::u32 - { - Platform_NONE = 0x00, - Platform_PC = 1 << PlatformId::PC, - Platform_ES3 = 1 << PlatformId::ES3, - Platform_IOS = 1 << PlatformId::IOS, - Platform_OSX = 1 << PlatformId::OSX, - Platform_PROVO = 1 << PlatformId::PROVO, - Platform_SALEM = 1 << PlatformId::SALEM, - Platform_JASPER = 1 << PlatformId::JASPER, - Platform_SERVER = 1 << PlatformId::SERVER, - - // A special platform that will always correspond to all platforms, even if new ones are added - Platform_ALL = 1ULL << 30, - - // A special platform that will always correspond to all non-server platforms, even if new ones are added - Platform_ALL_CLIENT = 1ULL << 31, - - AllNamedPlatforms = Platform_PC | Platform_ES3 | Platform_IOS | Platform_OSX | Platform_PROVO | Platform_SALEM | Platform_JASPER | Platform_SERVER, - }; - - AZ_DEFINE_ENUM_BITWISE_OPERATORS(PlatformFlags); - - // 32 characters should be more than enough to store a platform name - using AssetPlatformFixedString = AZStd::fixed_string<32>; - // Fixed string which can store a comma separated list of platforms names - // Additional byte is added to take into account the comma - using AssetPlatformCombinedString = AZStd::fixed_string<(AssetPlatformFixedString{}.max_size() + 1) * PlatformId::NumPlatformIds>; - - const char* PlatformIdToPalFolder(AzFramework::PlatformId platform); - - const char* OSPlatformToDefaultAssetPlatform(AZStd::string_view osPlatform); - - //! Platform Helper is an utility class that can be used to retrieve platform related information - class PlatformHelper - { - public: - - //! Given a platformIndex returns the platform name - static const char* GetPlatformName(PlatformId platform); - - //! Converts the platform name to the platform code names as defined in AZ_TRAIT_OS_PLATFORM_CODENAME. - static void AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, AZStd::string_view platformName); - - //! Converts the platform name to the platform code names as defined in AZ_TRAIT_OS_PLATFORM_CODENAME. - static void AppendPlatformCodeNames(AZStd::fixed_vector& platformCodes, PlatformId platformId); - - //! Given a platform name returns a platform index. - //! If the platform is not found, the method returns -1. - static int GetPlatformIndexFromName(AZStd::string_view platformName); - - //! Given a platform name returns a platform id. - //! If the platform is not found, the method returns -1. - static PlatformId GetPlatformIdFromName(AZStd::string_view platformName); - - //! Given a platformIndex returns the platformFlags - static PlatformFlags GetPlatformFlagFromPlatformIndex(PlatformId platform); - - //! Given a platformFlags returns all the platform identifiers that are set. - static AZStd::fixed_vector GetPlatforms(PlatformFlags platformFlags); - //! Given a platformFlags returns all the platform identifiers that are set, with special flags interpreted. Do not use the result for saving - static AZStd::fixed_vector GetPlatformsInterpreted(PlatformFlags platformFlags); - - //! Given a platformFlags return a list of PlatformId indices - static AZStd::fixed_vector GetPlatformIndices(PlatformFlags platformFlags); - //! Given a platformFlags return a list of PlatformId indices, with special flags interpreted. Do not use the result for saving - static AZStd::fixed_vector GetPlatformIndicesInterpreted(PlatformFlags platformFlags); - - //! Given a platform identifier returns its corresponding platform flag. - static PlatformFlags GetPlatformFlag(AZStd::string_view platform); - - //! Given any platformFlags returns a string listing the input platforms - static AssetPlatformCombinedString GetCommaSeparatedPlatformList(PlatformFlags platformFlags); - - //! If platformFlags contains any special flags, they are removed and replaced with the normal flags they represent - static PlatformFlags GetPlatformFlagsInterpreted(PlatformFlags platformFlags); - - //! Returns true if platformFlags contains any special flags - static bool IsSpecialPlatform(PlatformFlags platformFlags); - - //! Returns true if platformFlags has checkPlatform flag set. - static bool HasPlatformFlag(PlatformFlags platformFlags, PlatformId checkPlatform); - }; + using namespace AZ::PlatformDefaults; } - -#pragma pop_macro("IOS") diff --git a/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.cpp b/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.cpp index 5acf4e75d1..7e968ffcd8 100644 --- a/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.cpp +++ b/Code/Framework/AzFramework/AzFramework/ProjectManager/ProjectManager.cpp @@ -42,8 +42,14 @@ namespace AzFramework::ProjectManager AZ::CommandLine commandLine; commandLine.Parse(argc, argv); AZ::SettingsRegistryImpl settingsRegistry; + // Store the Command line to the Setting Registry + + AZ::SettingsRegistryMergeUtils::StoreCommandLineToRegistry(settingsRegistry, commandLine); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_Bootstrap(settingsRegistry); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_O3deUserRegistry(settingsRegistry, AZ_TRAIT_OS_PLATFORM_CODENAME, {}); + // Retrieve Command Line from Settings Registry, it may have been updated by the call to FindEngineRoot() + // in MergeSettingstoRegistry_ConfigFile + AZ::SettingsRegistryMergeUtils::GetCommandLineFromRegistry(settingsRegistry, commandLine); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(settingsRegistry, commandLine, false); engineRootPath = AZ::SettingsRegistryMergeUtils::FindEngineRoot(settingsRegistry); projectRootPath = AZ::SettingsRegistryMergeUtils::FindProjectRoot(settingsRegistry); diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h b/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h index 1b570ebb8e..d3ae4e16f3 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ScreenGeometry.h @@ -14,6 +14,7 @@ #include #include +#include #include namespace AZ @@ -133,6 +134,18 @@ namespace AzFramework return !operator==(lhs, rhs); } + inline ScreenPoint ScreenPointFromNDC(const AZ::Vector3& screenNDC, const AZ::Vector2& viewportSize) + { + return ScreenPoint( + aznumeric_caster(std::round(screenNDC.GetX() * viewportSize.GetX())), + aznumeric_caster(std::round((1.0f - screenNDC.GetY()) * viewportSize.GetY()))); + } + + inline AZ::Vector2 NDCFromScreenPoint(const ScreenPoint& screenPoint, const AZ::Vector2& viewportSize) + { + return AZ::Vector2(aznumeric_cast(screenPoint.m_x), viewportSize.GetY() - aznumeric_cast(screenPoint.m_y)) / viewportSize; + } + //! Return an AZ::Vector2 from a ScreenPoint. inline AZ::Vector2 Vector2FromScreenPoint(const ScreenPoint& screenPoint) { diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp index 3ca16897ba..5d2d02a398 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.cpp @@ -101,20 +101,25 @@ namespace AzFramework cameraState.m_nearClip, cameraState.m_farClip); } - ScreenPoint WorldToScreen( - const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection, - const AZ::Vector2& viewportSize) + AZ::Vector3 WorldToScreenNDC( + const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection) { // transform the world space position to clip space const auto clipSpacePosition = cameraProjection * cameraView * AZ::Vector3ToVector4(worldPosition, 1.0f); // transform the clip space position to ndc space (perspective divide) const auto ndcPosition = clipSpacePosition / clipSpacePosition.GetW(); // transform ndc space from <-1,1> to <0, 1> range - const auto ndcNormalizedPosition = (AZ::Vector4ToVector2(ndcPosition) + AZ::Vector2::CreateOne()) * 0.5f; + return (AZ::Vector4ToVector3(ndcPosition) + AZ::Vector3::CreateOne()) * 0.5f; + } + + + ScreenPoint WorldToScreen( + const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection, + const AZ::Vector2& viewportSize) + { + const auto ndcNormalizedPosition = WorldToScreenNDC(worldPosition, cameraView, cameraProjection); // scale ndc position by screen dimensions to return screen position - return ScreenPoint( - aznumeric_caster(std::round(ndcNormalizedPosition.GetX() * viewportSize.GetX())), - aznumeric_caster(std::round(viewportSize.GetY() - (ndcNormalizedPosition.GetY() * viewportSize.GetY())))); + return ScreenPointFromNDC(ndcNormalizedPosition, viewportSize); } ScreenPoint WorldToScreen(const AZ::Vector3& worldPosition, const CameraState& cameraState) @@ -127,12 +132,8 @@ namespace AzFramework const ScreenPoint& screenPosition, const AZ::Matrix4x4& inverseCameraView, const AZ::Matrix4x4& inverseCameraProjection, const AZ::Vector2& viewportSize) { - const auto screenHeight = viewportSize.GetY(); - const auto flippedScreenPosition = - AZ::Vector2(aznumeric_caster(screenPosition.m_x), aznumeric_caster(screenHeight - screenPosition.m_y)); - - // convert screen space coordinates to <-1,1> range - const auto ndcPosition = (flippedScreenPosition / viewportSize) * 2.0f - AZ::Vector2::CreateOne(); + // convert screen space coordinates from <0, 1> to <-1,1> range + const auto ndcPosition = NDCFromScreenPoint(screenPosition, viewportSize) * 2.0f - AZ::Vector2::CreateOne(); // transform ndc space position to clip space const auto clipSpacePosition = inverseCameraProjection * Vector2ToVector4(ndcPosition, -1.0f, 1.0f); diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h index 582e051bbb..a2c650465f 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/ViewportScreen.h @@ -28,6 +28,11 @@ namespace AzFramework struct ScreenPoint; struct ViewportInfo; + //! Projects a position in world space to screen space normalized device coordinates for the given camera. + AZ::Vector3 WorldToScreenNDC( + const AZ::Vector3& worldPosition, const AZ::Matrix4x4& cameraView, const AZ::Matrix4x4& cameraProjection); + + //! Projects a position in world space to screen space for the given camera. ScreenPoint WorldToScreen(const AZ::Vector3& worldPosition, const CameraState& cameraState); diff --git a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake index b37c1b259f..312a3766ac 100644 --- a/Code/Framework/AzFramework/AzFramework/azframework_files.cmake +++ b/Code/Framework/AzFramework/AzFramework/azframework_files.cmake @@ -145,6 +145,7 @@ set(FILES Components/NonUniformScaleComponent.cpp FileFunc/FileFunc.h FileFunc/FileFunc.cpp + Font/FontInterface.h Gem/GemInfo.cpp Gem/GemInfo.h StringFunc/StringFunc.h @@ -316,7 +317,6 @@ set(FILES Terrain/TerrainDataRequestBus.h Terrain/TerrainDataRequestBus.cpp Platform/PlatformDefaults.h - Platform/PlatformDefaults.cpp Windowing/WindowBus.h Windowing/NativeWindow.cpp Windowing/NativeWindow.h diff --git a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp index f4fc9364f7..edd4af293d 100644 --- a/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp +++ b/Code/Framework/AzGameFramework/AzGameFramework/Application/GameApplication.cpp @@ -80,6 +80,8 @@ namespace AzGameFramework AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_ProjectUserRegistry(registry, AZ_TRAIT_OS_PLATFORM_CODENAME, specializations, &scratchBuffer); AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(registry, m_commandLine, true); #endif + // Update the Runtime file paths in case the "{BootstrapSettingsRootKey}/assets" key was overriden by a setting registry + AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddRuntimeFilePaths(registry); } AZ::ComponentTypeList GameApplication::GetRequiredSystemComponents() const diff --git a/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitset.h b/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitset.h index 21e12cd305..3d064b5ecc 100644 --- a/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitset.h +++ b/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeBitset.h @@ -114,6 +114,9 @@ namespace AzNetworking void ClearUnusedBits(); ContainerType m_container; + + template + friend class FixedSizeVectorBitset; }; } diff --git a/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeVectorBitset.inl b/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeVectorBitset.inl index a8aceb4dd5..038e68d1d0 100644 --- a/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeVectorBitset.inl +++ b/Code/Framework/AzNetworking/AzNetworking/DataStructures/FixedSizeVectorBitset.inl @@ -192,19 +192,11 @@ namespace AzNetworking template inline void FixedSizeVectorBitset::ClearUnusedBits() { - constexpr ElementType AllOnes = static_cast(~0); - const ElementType LastUsedBits = (GetSize() % BitsetType::ElementTypeBits); -#pragma warning(push) -#pragma warning(disable : 4293) // shift count negative or too big, undefined behaviour -#pragma warning(disable : 6326) // constant constant comparison - const ElementType ShiftAmount = (LastUsedBits == 0) ? 0 : BitsetType::ElementTypeBits - LastUsedBits; - const ElementType ClearBitMask = AllOnes >> ShiftAmount; -#pragma warning(pop) uint32_t usedElementSize = (GetSize() + BitsetType::ElementTypeBits - 1) / BitsetType::ElementTypeBits; - for (uint32_t i = usedElementSize + 1; i < CAPACITY; ++i) + for (uint32_t i = usedElementSize + 1; i < BitsetType::ElementCount; ++i) { m_bitset.GetContainer()[i] = 0; } - m_bitset.GetContainer()[m_bitset.GetContainer().size() - 1] &= ClearBitMask; + m_bitset.ClearUnusedBits(); } } diff --git a/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h b/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h index 70dc7847d2..a43a09165c 100644 --- a/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h +++ b/Code/Framework/AzNetworking/AzNetworking/Serialization/AzContainerSerializers.h @@ -270,7 +270,7 @@ namespace AzNetworking value.StoreToFloat3(values); serializer.Serialize(values[0], "xValue"); serializer.Serialize(values[1], "yValue"); - serializer.Serialize(values[1], "zValue"); + serializer.Serialize(values[2], "zValue"); value = AZ::Vector3::CreateFromFloat3(values); return serializer.IsValid(); } @@ -285,8 +285,8 @@ namespace AzNetworking value.StoreToFloat4(values); serializer.Serialize(values[0], "xValue"); serializer.Serialize(values[1], "yValue"); - serializer.Serialize(values[1], "zValue"); - serializer.Serialize(values[1], "wValue"); + serializer.Serialize(values[2], "zValue"); + serializer.Serialize(values[3], "wValue"); value = AZ::Vector4::CreateFromFloat4(values); return serializer.IsValid(); } @@ -301,8 +301,8 @@ namespace AzNetworking value.StoreToFloat4(values); serializer.Serialize(values[0], "xValue"); serializer.Serialize(values[1], "yValue"); - serializer.Serialize(values[1], "zValue"); - serializer.Serialize(values[1], "wValue"); + serializer.Serialize(values[2], "zValue"); + serializer.Serialize(values[3], "wValue"); value = AZ::Quaternion::CreateFromFloat4(values); return serializer.IsValid(); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h index 0c631cf09e..f12ab71936 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h @@ -578,16 +578,6 @@ namespace AzToolsFramework */ virtual bool IsEditorInIsolationMode() = 0; - /*! - * Get the engine root path that the current tool is running under. - */ - virtual const char* GetEngineRootPath() const = 0; - - /** - * Get the version of the engine the current tools application is running under - */ - virtual const char* GetEngineVersion() const = 0; - /** * Creates and adds a new entity to the tools application from components which match at least one of the requiredTags * The tag matching occurs on AZ::Edit::SystemComponentTags attribute from the reflected class data in the serialization context diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index 352048f5f0..22c1390828 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -224,112 +224,6 @@ namespace AzToolsFramework } // Internal -#define AZ_MAX_ENGINE_VERSION_LEN 64 - // Private Implementation class to manage the engine root and version - // Note: We are not using any AzCore classes because the ToolsApplication - // initialization happens early on, before the Allocators get instantiated, - // so we are using Qt privately instead - class ToolsApplication::EngineConfigImpl - { - private: - friend class ToolsApplication; - - typedef QMap EngineJsonMap; - - EngineConfigImpl(const char* logWindow, const char* fileName) - : m_logWindow(logWindow) - , m_fileName(fileName) - { - m_engineRoot[0] = '\0'; - m_engineVersion[0] = '\0'; - } - - char m_engineRoot[AZ_MAX_PATH_LEN]; - char m_engineVersion[AZ_MAX_ENGINE_VERSION_LEN]; - EngineJsonMap m_engineConfigMap; - const char* m_logWindow; - const char* m_fileName; - - - // Read an engine configuration into a map of key/value pairs - bool ReadEngineConfigIntoMap(QString engineJsonPath, EngineJsonMap& engineJsonMap) - { - QFile engineJsonFile(engineJsonPath); - if (!engineJsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) - { - AZ_Warning(m_logWindow, false, "Unable to open file '%s' in the current root directory", engineJsonPath.toUtf8().data()); - return false; - } - - QByteArray engineJsonData = engineJsonFile.readAll(); - engineJsonFile.close(); - QJsonDocument engineJsonDoc(QJsonDocument::fromJson(engineJsonData)); - if (engineJsonDoc.isNull()) - { - AZ_Warning(m_logWindow, false, "Unable to read file '%s' in the current root directory", engineJsonPath.toUtf8().data()); - return false; - } - - QJsonObject engineJsonRoot = engineJsonDoc.object(); - for (const QString& configKey : engineJsonRoot.keys()) - { - QJsonValue configValue = engineJsonRoot[configKey]; - if (configValue.isString() || configValue.isDouble()) - { - // Only map strings and numbers, ignore every other type - engineJsonMap[configKey] = configValue.toString(); - } - else - { - AZ_Warning(m_logWindow, false, "Ignoring key '%s' from '%s', unsupported type.", configKey.toUtf8().data(), engineJsonPath.toUtf8().data()); - } - } - return true; - } - - // Initialize the engine config object based on the current - bool Initialize(const char* currentEngineRoot) - { - // Start with the app root as the engine root (legacy), but check to see if the engine root - // is external to the app root - azstrncpy(m_engineRoot, AZ_ARRAY_SIZE(m_engineRoot), currentEngineRoot, strlen(currentEngineRoot) + 1); - - // From the appRoot, check and see if we can read any external engine reference in engine.json - QString engineJsonFileName = QString(m_fileName); - QString engineJsonFilePath = QDir(currentEngineRoot).absoluteFilePath(engineJsonFileName); - - // From the appRoot, check and see if we can read any external engine reference in engine.json - if (!QFile::exists(engineJsonFilePath)) - { - AZ_Warning(m_logWindow, false, "Unable to find '%s' in the current app root directory.", m_fileName); - return false; - } - if (!ReadEngineConfigIntoMap(engineJsonFilePath, m_engineConfigMap)) - { - AZ_Warning(m_logWindow, false, "Defaulting root engine path to '%s'", currentEngineRoot); - return false; - } - - // Read in the local engine version value - auto localEngineVersionValue = m_engineConfigMap.find(QString(AzToolsFramework::Internal::s_engineConfigEngineVersionKey)); - QString localEngineVersion(localEngineVersionValue.value()); - azstrncpy(m_engineVersion, AZ_ARRAY_SIZE(m_engineVersion), localEngineVersion.toUtf8().data(), localEngineVersion.length() + 1); - - return true; - } - - const char* GetEngineRoot() const - { - return m_engineRoot; - } - - const char* GetEngineVersion() const - { - return m_engineVersion; - } - }; - - ToolsApplication::ToolsApplication(int* argc, char*** argv) : AzFramework::Application(argc, argv) , m_selectionBounds(AZ::Aabb()) @@ -339,7 +233,6 @@ namespace AzToolsFramework , m_isInIsolationMode(false) { ToolsApplicationRequests::Bus::Handler::BusConnect(); - m_engineConfigImpl.reset(new ToolsApplication::EngineConfigImpl(AzToolsFramework::Internal::s_startupLogWindow, AzToolsFramework::Internal::s_engineConfigFileName)); m_undoCache.RegisterToUndoCacheInterface(); } @@ -391,7 +284,6 @@ namespace AzToolsFramework void ToolsApplication::Start(const Descriptor& descriptor, const StartupParameters& startupParameters/* = StartupParameters()*/) { Application::Start(descriptor, startupParameters); - InitializeEngineConfig(); m_editorEntityManager.Start(); @@ -399,14 +291,6 @@ namespace AzToolsFramework AZ_Assert(m_editorEntityAPI, "ToolsApplication - Could not retrieve instance of EditorEntityAPI"); } - void ToolsApplication::InitializeEngineConfig() - { - if (!m_engineConfigImpl->Initialize(GetEngineRoot())) - { - AZ_Warning(AzToolsFramework::Internal::s_startupLogWindow, false, "Defaulting engine root path to '%s'", GetEngineRoot()); - } - } - void ToolsApplication::StartCommon(AZ::Entity* systemEntity) { Application::StartCommon(systemEntity); @@ -1832,16 +1716,6 @@ namespace AzToolsFramework return m_isInIsolationMode; } - const char* ToolsApplication::GetEngineRootPath() const - { - return m_engineConfigImpl->GetEngineRoot(); - } - - const char* ToolsApplication::GetEngineVersion() const - { - return m_engineConfigImpl->GetEngineVersion(); - } - void ToolsApplication::CreateAndAddEntityFromComponentTags(const AZStd::vector& requiredTags, const char* entityName) { if (!entityName || !entityName[0]) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.h index ef9f190309..0f038422ce 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.h @@ -150,8 +150,6 @@ namespace AzToolsFramework void EnterEditorIsolationMode() override; void ExitEditorIsolationMode() override; bool IsEditorInIsolationMode() override; - const char* GetEngineRootPath() const override; - const char* GetEngineVersion() const override; void CreateAndAddEntityFromComponentTags(const AZStd::vector& requiredTags, const char* entityName) override; @@ -174,7 +172,6 @@ namespace AzToolsFramework void CreateUndosForDirtyEntities(); void ConsistencyCheckUndoCache(); - void InitializeEngineConfig(); AZ::Aabb m_selectionBounds; EntityIdList m_selectedEntities; EntityIdList m_highlightedEntities; @@ -186,9 +183,6 @@ namespace AzToolsFramework bool m_isInIsolationMode; EntityIdSet m_isolatedEntityIdSet; - class EngineConfigImpl; - AZStd::unique_ptr m_engineConfigImpl; - EditorEntityAPI* m_editorEntityAPI = nullptr; EditorEntityManager m_editorEntityManager; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp index 6ab3625dd2..629dcd639d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.cpp @@ -136,6 +136,48 @@ namespace AzToolsFramework return entity->GetName(); } + EntityList EntityIdListToEntityList(const EntityIdList& inputEntityIds) + { + EntityList entities; + entities.reserve(inputEntityIds.size()); + + for (AZ::EntityId entityId : inputEntityIds) + { + if (!entityId.IsValid()) + { + continue; + } + + if (auto entity = GetEntityById(entityId)) + { + entities.emplace_back(entity); + } + } + + return entities; + } + + EntityList EntityIdSetToEntityList(const EntityIdSet& inputEntityIds) + { + EntityList entities; + entities.reserve(inputEntityIds.size()); + + for (AZ::EntityId entityId : inputEntityIds) + { + if (!entityId.IsValid()) + { + continue; + } + + if (auto entity = GetEntityById(entityId)) + { + entities.emplace_back(entity); + } + } + + return entities; + } + void GetAllComponentsForEntity(const AZ::Entity* entity, AZ::Entity::ComponentArrayType& componentsOnEntity) { if (entity) @@ -1068,6 +1110,45 @@ namespace AzToolsFramework return !allEntityClonesContainer.m_entities.empty(); } + EntityIdSet GetCulledEntityHierarchy(const EntityIdList& entities) + { + EntityIdSet culledEntities; + + for (const AZ::EntityId& entityId : entities) + { + bool selectionIncludesTransformHeritage = false; + AZ::EntityId parentEntityId = entityId; + do + { + AZ::EntityId nextParentId; + AZ::TransformBus::EventResult( + /*result*/ nextParentId, + /*address*/ parentEntityId, + &AZ::TransformBus::Events::GetParentId); + parentEntityId = nextParentId; + if (!parentEntityId.IsValid()) + { + break; + } + for (const AZ::EntityId& parentCheck : entities) + { + if (parentCheck == parentEntityId) + { + selectionIncludesTransformHeritage = true; + break; + } + } + } while (parentEntityId.IsValid() && !selectionIncludesTransformHeritage); + + if (!selectionIncludesTransformHeritage) + { + culledEntities.insert(entityId); + } + } + + return culledEntities; + } + namespace Internal { void CloneSliceEntitiesAndChildren( diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.h index 39f4c37c29..5454b19f7a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/EditorEntityHelpers.h @@ -47,6 +47,9 @@ namespace AzToolsFramework AZStd::string GetEntityName(const AZ::EntityId& entityId, const AZStd::string_view& nameOverride = {}); + EntityList EntityIdListToEntityList(const EntityIdList& inputEntityIds); + EntityList EntityIdSetToEntityList(const EntityIdSet& inputEntityIds); + template struct AddComponents { @@ -202,4 +205,8 @@ namespace AzToolsFramework /// Wrap EBus SetSelectedEntities call. void SelectEntities(const AzToolsFramework::EntityIdList& entities); + /// Return a set of entities, culling any that have an ancestor in the list. + /// e.g. This is useful for getting a concise set of entities that need to be duplicated. + EntityIdSet GetCulledEntityHierarchy(const EntityIdList& entities); + }; // namespace AzToolsFramework diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 26191c97af..c64a9491c5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -61,8 +61,7 @@ namespace AzToolsFramework PrefabOperationResult PrefabPublicHandler::CreatePrefab(const AZStd::vector& entityIds, AZ::IO::PathView filePath) { // Retrieve entityList from entityIds - EntityList inputEntityList; - EntityIdListToEntityList(entityIds, inputEntityList); + EntityList inputEntityList = EntityIdListToEntityList(entityIds); // Find common root and top level entities bool entitiesHaveCommonRoot = false; @@ -419,8 +418,7 @@ namespace AzToolsFramework InstanceOptionalReference instance = GetOwnerInstanceByEntityId(entityIds[0]); // Retrieve entityList from entityIds - EntityList inputEntityList; - EntityIdListToEntityList(entityIds, inputEntityList); + EntityList inputEntityList = EntityIdListToEntityList(entityIds); AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); @@ -767,18 +765,5 @@ namespace AzToolsFramework return true; } - - void PrefabPublicHandler::EntityIdListToEntityList(const EntityIdList& inputEntityIds, EntityList& outEntities) - { - outEntities.reserve(inputEntityIds.size()); - - for (AZ::EntityId entityId : inputEntityIds) - { - if (entityId.IsValid()) - { - outEntities.emplace_back(GetEntityById(entityId)); - } - } - } } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h index 80f28d7edb..d9dba2a32e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.h @@ -70,7 +70,6 @@ namespace AzToolsFramework static Instance* GetParentInstance(Instance* instance); static Instance* GetAncestorOfInstanceThatIsChildOfRoot(const Instance* ancestor, Instance* descendant); static void GenerateContainerEntityTransform(const EntityList& topLevelEntities, AZ::Vector3& translation, AZ::Quaternion& rotation); - static void EntityIdListToEntityList(const EntityIdList& inputEntityIds, EntityList& outEntities); InstanceEntityMapperInterface* m_instanceEntityMapperInterface = nullptr; InstanceToTemplateInterface* m_instanceToTemplateInterface = nullptr; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp index bc27ffa5e1..261645e79a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp @@ -38,6 +38,7 @@ AZ_POP_DISABLE_WARNING #include #include #include +#include #include #include #include @@ -1212,9 +1213,8 @@ namespace AzToolsFramework if (!QFile::exists(path)) { - const char* engineRoot = nullptr; - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(engineRoot, &AzToolsFramework::ToolsApplicationRequests::GetEngineRootPath); - QDir engineDir = engineRoot ? QDir(engineRoot) : QDir::current(); + AZ::IO::FixedMaxPathString engineRoot = AZ::Utils::GetEnginePath(); + QDir engineDir = !engineRoot.empty() ? QDir(QString(engineRoot.c_str())) : QDir::current(); path = engineDir.absoluteFilePath(iconPath.c_str()); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp index 83632708d9..433602e6d8 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/ViewportSelection/EditorTransformComponentSelection.cpp @@ -53,7 +53,7 @@ namespace AzToolsFramework float, cl_viewportGizmoAxisLabelOffset, 1.15f, nullptr, AZ::ConsoleFunctorFlags::Null, "The offset of the label for the viewport axis gizmo"); AZ_CVAR( - float, cl_viewportGizmoAxisLabelSize, 2.0f, nullptr, AZ::ConsoleFunctorFlags::Null, + float, cl_viewportGizmoAxisLabelSize, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "The size of each label for the viewport axis gizmo"); AZ_CVAR( AZ::Vector2, cl_viewportGizmoAxisScreenPosition, AZ::Vector2(0.045f, 0.9f), nullptr, @@ -3434,19 +3434,22 @@ namespace AzToolsFramework const auto cameraProjection = AzFramework::CameraProjection(gizmoCameraState); // screen space offset to move the 2d gizmo around - const AZ::Vector3 screenPosition = - (AZ::Vector2ToVector3(cl_viewportGizmoAxisScreenPosition) - AZ::Vector3(0.5f, 0.5f, 0.0f)) * - AZ::Vector2ToVector3(gizmoCameraState.m_viewportSize); + const AZ::Vector2 screenOffset = AZ::Vector2(cl_viewportGizmoAxisScreenPosition) - AZ::Vector2(0.5f, 0.5f); // map from a position in world space (relative to the the gizmo camera near the origin) to a position in // screen space const auto calculateGizmoAxis = - [&cameraView, &cameraProjection, &gizmoCameraState, &screenPosition] - (const AZ::Vector3& position) + [&cameraView, &cameraProjection, &screenOffset] + (const AZ::Vector3& axis) { - return AZ::Vector2ToVector3(AzFramework::Vector2FromScreenPoint( - AzFramework::WorldToScreen( - position, cameraView, cameraProjection, gizmoCameraState.m_viewportSize))) + screenPosition; + auto result = AZ::Vector2( + AzFramework::WorldToScreenNDC( + axis, + cameraView, + cameraProjection) + ); + result.SetY(1.0f - result.GetY()); + return result + screenOffset; }; // get all important axis positions in screen space @@ -3456,31 +3459,31 @@ namespace AzToolsFramework const auto gizmoEndAxisY = calculateGizmoAxis(-AZ::Vector3::CreateAxisY() * lineLength); const auto gizmoEndAxisZ = calculateGizmoAxis(-AZ::Vector3::CreateAxisZ() * lineLength); - const AZ::Vector3 gizmoAxisX = gizmoEndAxisX - gizmoStart; - const AZ::Vector3 gizmoAxisY = gizmoEndAxisY - gizmoStart; - const AZ::Vector3 gizmoAxisZ = gizmoEndAxisZ - gizmoStart; + const AZ::Vector2 gizmoAxisX = gizmoEndAxisX - gizmoStart; + const AZ::Vector2 gizmoAxisY = gizmoEndAxisY - gizmoStart; + const AZ::Vector2 gizmoAxisZ = gizmoEndAxisZ - gizmoStart; // draw the axes of the gizmo debugDisplay.SetLineWidth(cl_viewportGizmoAxisLineWidth); debugDisplay.SetColor(AZ::Colors::Red); - debugDisplay.DrawLine(gizmoStart, gizmoEndAxisX); + debugDisplay.DrawLine2d(gizmoStart, gizmoEndAxisX, 1.0f); debugDisplay.SetColor(AZ::Colors::Lime); - debugDisplay.DrawLine(gizmoStart, gizmoEndAxisY); + debugDisplay.DrawLine2d(gizmoStart, gizmoEndAxisY, 1.0f); debugDisplay.SetColor(AZ::Colors::Blue); - debugDisplay.DrawLine(gizmoStart, gizmoEndAxisZ); + debugDisplay.DrawLine2d(gizmoStart, gizmoEndAxisZ, 1.0f); debugDisplay.SetLineWidth(1.0f); const float labelOffset = cl_viewportGizmoAxisLabelOffset; - const auto labelOffsetX = gizmoStart + gizmoAxisX * labelOffset; - const auto labelOffsetY = gizmoStart + gizmoAxisY * labelOffset; - const auto labelOffsetZ = gizmoStart + gizmoAxisZ * labelOffset; + const auto labelXScreenPosition = (gizmoStart + (gizmoAxisX * labelOffset)) * editorCameraState.m_viewportSize; + const auto labelYScreenPosition = (gizmoStart + (gizmoAxisY * labelOffset)) * editorCameraState.m_viewportSize; + const auto labelZScreenPosition = (gizmoStart + (gizmoAxisZ * labelOffset)) * editorCameraState.m_viewportSize; // draw the label of of each axis for the gizmo const float labelSize = cl_viewportGizmoAxisLabelSize; debugDisplay.SetColor(AZ::Colors::White); - debugDisplay.Draw2dTextLabel(labelOffsetX.GetX(), labelOffsetX.GetY(), labelSize, "X", true); - debugDisplay.Draw2dTextLabel(labelOffsetY.GetX(), labelOffsetY.GetY(), labelSize, "Y", true); - debugDisplay.Draw2dTextLabel(labelOffsetZ.GetX(), labelOffsetZ.GetY(), labelSize, "Z", true); + debugDisplay.Draw2dTextLabel(labelXScreenPosition.GetX(), labelXScreenPosition.GetY(), labelSize, "X", true); + debugDisplay.Draw2dTextLabel(labelYScreenPosition.GetX(), labelYScreenPosition.GetY(), labelSize, "Y", true); + debugDisplay.Draw2dTextLabel(labelZScreenPosition.GetX(), labelZScreenPosition.GetY(), labelSize, "Z", true); } void EditorTransformComponentSelection::DisplayViewportSelection2d( diff --git a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp index 2003f8eafd..5ccbd95f09 100644 --- a/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp +++ b/Code/Framework/AzToolsFramework/Tests/AssetSeedManager.cpp @@ -68,7 +68,7 @@ namespace UnitTest { assets[idx] = AssetId(AZ::Uuid::CreateRandom(), 0); AZ::Data::AssetInfo info; - info.m_relativePath = AZStd::string::format("Asset%d.txt", idx); + info.m_relativePath = AZStd::string::format("asset%d.txt", idx); m_assetsPath[idx] = info.m_relativePath; info.m_assetId = assets[idx]; m_assetRegistry->RegisterAsset(assets[idx], info); @@ -623,7 +623,7 @@ namespace UnitTest EXPECT_TRUE(Search(assetList1, assets[fileIndex])); if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { - AZStd::string fileContent = AZStd::string::format("Asset%d.txt", fileIndex); + AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex); m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str()); m_fileStreams[0][fileIndex].Close(); } @@ -654,7 +654,7 @@ namespace UnitTest EXPECT_TRUE(Search(assetList1, assets[fileIndex])); if (m_fileStreams[0][fileIndex].Open(m_assetsPathFull[0][fileIndex].c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary | AZ::IO::OpenMode::ModeCreatePath)) { - AZStd::string fileContent = AZStd::string::format("Asset%d.txt", fileIndex + 1);// changing file content + AZStd::string fileContent = AZStd::string::format("asset%d.txt", fileIndex + 1);// changing file content m_fileStreams[0][fileIndex].Write(fileContent.size(), fileContent.c_str()); m_fileStreams[0][fileIndex].Close(); } @@ -987,7 +987,7 @@ namespace UnitTest m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); - m_assetSeedManager->RemoveSeedAsset("Asset0.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); + m_assetSeedManager->RemoveSeedAsset("asset0.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList(); EXPECT_EQ(secondSeedList.size(), 0); } @@ -1003,7 +1003,7 @@ namespace UnitTest m_assetSeedManager->AddSeedAsset(assets[0], AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); - m_assetSeedManager->RemoveSeedAsset("Asset0.txt", AzFramework::PlatformFlags::Platform_PC); + m_assetSeedManager->RemoveSeedAsset("asset0.txt", AzFramework::PlatformFlags::Platform_PC); const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList(); EXPECT_EQ(secondSeedList.size(), 1); } @@ -1017,7 +1017,7 @@ namespace UnitTest EXPECT_EQ(seedList.size(), 1); - m_assetSeedManager->RemoveSeedAsset("Asset1.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); + m_assetSeedManager->RemoveSeedAsset("asset1.txt", AzFramework::PlatformFlags::Platform_PC | AzFramework::PlatformFlags::Platform_OSX); const AzFramework::AssetSeedList& secondSeedList = m_assetSeedManager->GetAssetSeedList(); EXPECT_EQ(secondSeedList.size(), 1); } diff --git a/Code/Framework/AzToolsFramework/Tests/Entity/EditorEntityHelpersTests.cpp b/Code/Framework/AzToolsFramework/Tests/Entity/EditorEntityHelpersTests.cpp new file mode 100644 index 0000000000..51feacfa2b --- /dev/null +++ b/Code/Framework/AzToolsFramework/Tests/Entity/EditorEntityHelpersTests.cpp @@ -0,0 +1,57 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include + +#include +#include +#include + +namespace UnitTest +{ + class EditorEntityHelpersTest + : public ToolsApplicationFixture + { + void SetUpEditorFixtureImpl() override + { + m_parent1 = CreateDefaultEditorEntity("Parent1"); + m_child1 = CreateDefaultEditorEntity("Child1"); + m_child2 = CreateDefaultEditorEntity("Child2"); + m_grandChild1 = CreateDefaultEditorEntity("GrandChild1"); + m_parent2 = CreateDefaultEditorEntity("Parent2"); + + AZ::TransformBus::Event(m_child1, &AZ::TransformBus::Events::SetParent, m_parent1); + AZ::TransformBus::Event(m_child2, &AZ::TransformBus::Events::SetParent, m_parent1); + AZ::TransformBus::Event(m_grandChild1, &AZ::TransformBus::Events::SetParent, m_child1); + } + + public: + AZ::EntityId m_parent1; + AZ::EntityId m_child1; + AZ::EntityId m_child2; + AZ::EntityId m_grandChild1; + AZ::EntityId m_parent2; + }; + + TEST_F(EditorEntityHelpersTest, EditorEntityHelpersTests_GetCulledEntityHierarchy) + { + AzToolsFramework::EntityIdList testEntityIds{ m_parent1, m_child1, m_child2, m_grandChild1, m_parent2 }; + + AzToolsFramework::EntityIdSet culledSet = AzToolsFramework::GetCulledEntityHierarchy(testEntityIds); + + // There should only be two EntityIds returned (m_parent1, and m_parent2), + // since all the others should be culled out since they have a common ancestor + // in the list already + using ::testing::UnorderedElementsAre; + EXPECT_THAT(culledSet, UnorderedElementsAre(m_parent1, m_parent2)); + } +} diff --git a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake index 7a2cd373a2..e54aa187e4 100644 --- a/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake +++ b/Code/Framework/AzToolsFramework/Tests/aztoolsframeworktests_files.cmake @@ -85,7 +85,9 @@ set(FILES Prefab/SpawnableSortEntitiesTestFixture.cpp Prefab/SpawnableSortEntitiesTestFixture.h Entity/EditorEntityContextComponentTests.cpp + Entity/EditorEntityHelpersTests.cpp Entity/EditorEntitySearchComponentTests.cpp + Entity/EditorEntitySelectionTests.cpp SliceStabilityTests/SliceStabilityTestFramework.h SliceStabilityTests/SliceStabilityTestFramework.cpp SliceStabilityTests/SliceStabilityCreateTests.cpp diff --git a/Code/Sandbox/Editor/AboutDialog.cpp b/Code/Sandbox/Editor/AboutDialog.cpp index e1cd4c7bb0..d9cf722d1f 100644 --- a/Code/Sandbox/Editor/AboutDialog.cpp +++ b/Code/Sandbox/Editor/AboutDialog.cpp @@ -56,7 +56,7 @@ CAboutDialog::CAboutDialog(QString versionText, QString richTextCopyrightNotice, m_backgroundImage = QPixmap::fromImage(backgroundImage.scaled(m_enforcedWidth, m_enforcedHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); // Draw the Open 3D Engine logo from svg - m_ui->m_logo->load(QStringLiteral(":/StartupLogoDialog/lumberyard_logo.svg")); + m_ui->m_logo->load(QStringLiteral(":/StartupLogoDialog/o3de_logo.svg")); // Prevent re-sizing setFixedSize(m_enforcedWidth, m_enforcedHeight); diff --git a/Code/Sandbox/Editor/AboutDialog.ui b/Code/Sandbox/Editor/AboutDialog.ui index 0eb2881600..67767c0de1 100644 --- a/Code/Sandbox/Editor/AboutDialog.ui +++ b/Code/Sandbox/Editor/AboutDialog.ui @@ -60,35 +60,35 @@ 5 - - - - 4 - - - 12 - - - 9 - - - - - - 250 - 60 - - - - - 250 - 60 - - - - - - + + + + 4 + + + 12 + + + 9 + + + + + + 161 + 49 + + + + + 161 + 49 + + + + + + @@ -251,6 +251,11 @@ + + QSvgWidget + QWidget +
qsvgwidget.h
+
ClickableLabel QLabel diff --git a/Code/Sandbox/Editor/AssetEditor/AssetEditorWindow.cpp b/Code/Sandbox/Editor/AssetEditor/AssetEditorWindow.cpp index 4645019261..53e2884943 100644 --- a/Code/Sandbox/Editor/AssetEditor/AssetEditorWindow.cpp +++ b/Code/Sandbox/Editor/AssetEditor/AssetEditorWindow.cpp @@ -20,6 +20,7 @@ // AzCore #include #include +#include // AzToolsFramework #include @@ -104,13 +105,9 @@ void AssetEditorWindow::SaveAssetAs(const AZStd::string_view assetPath) return; } - const char* engineRoot; - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(engineRoot, &AzToolsFramework::ToolsApplicationRequests::GetEngineRootPath); + auto absoluteAssetPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / assetPath; - AZStd::string absoluteAssetPath; - AzFramework::StringFunc::Path::Join(engineRoot, assetPath.data(), absoluteAssetPath); - - if (!m_ui->m_assetEditorWidget->SaveAssetToPath(absoluteAssetPath)) + if (!m_ui->m_assetEditorWidget->SaveAssetToPath(absoluteAssetPath.Native())) { AZ_Warning("Asset Editor", false, "File was not saved correctly via SaveAssetAs."); } diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index a3b2542418..695a0fa5f1 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -1617,11 +1617,6 @@ void EditorViewportWidget::keyPressEvent(QKeyEvent* event) // because we want the movement to be butter smooth. if (!event->isAutoRepeat()) { - if (m_keyDown.isEmpty()) - { - grabKeyboard(); - } - m_keyDown.insert(event->key()); } diff --git a/Code/Sandbox/Editor/Objects/DisplayContextShared.inl b/Code/Sandbox/Editor/Objects/DisplayContextShared.inl index a4baf1fe89..dd5c248357 100644 --- a/Code/Sandbox/Editor/Objects/DisplayContextShared.inl +++ b/Code/Sandbox/Editor/Objects/DisplayContextShared.inl @@ -1245,28 +1245,6 @@ uint32 DisplayContext::SetState(uint32 state) return old; } -//! Set a new render state flags. -//! @param returns previous render state. -uint32 DisplayContext::SetStateFlag(uint32 state) -{ - uint32 old = m_renderState; - m_renderState |= state; - m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags; - pRenderAuxGeom->SetRenderFlags(m_renderState); - return old; -} - -//! Clear specified flags in render state. -//! @param returns previous render state. -uint32 DisplayContext::ClearStateFlag(uint32 state) -{ - uint32 old = m_renderState; - m_renderState &= ~state; - m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags; - pRenderAuxGeom->SetRenderFlags(m_renderState); - return old; -} - ////////////////////////////////////////////////////////////////////////// void DisplayContext::DepthTestOff() { diff --git a/Code/Sandbox/Editor/PythonEditorFuncs.cpp b/Code/Sandbox/Editor/PythonEditorFuncs.cpp index 5c74a950c2..f5de22387c 100644 --- a/Code/Sandbox/Editor/PythonEditorFuncs.cpp +++ b/Code/Sandbox/Editor/PythonEditorFuncs.cpp @@ -19,6 +19,8 @@ #include #include +#include + // AzToolsFramework #include #include @@ -293,9 +295,8 @@ namespace // If not found try editor folder if (!CFileUtil::FileExists(path)) { - const char* engineRoot = nullptr; - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(engineRoot, &AzToolsFramework::ToolsApplicationRequests::GetEngineRootPath); - QDir engineDir = engineRoot ? QDir(engineRoot) : QDir::current(); + AZ::IO::FixedMaxPathString engineRoot = AZ::Utils::GetEnginePath(); + QDir engineDir = !engineRoot.empty() ? QDir(QString(engineRoot.c_str())) : QDir::current(); QString scriptFolder = engineDir.absoluteFilePath("Editor/Scripts/"); Path::ConvertBackSlashToSlash(scriptFolder); diff --git a/Code/Sandbox/Editor/StartupLogoDialog.cpp b/Code/Sandbox/Editor/StartupLogoDialog.cpp index 38cf1bc5f6..c3d584b030 100644 --- a/Code/Sandbox/Editor/StartupLogoDialog.cpp +++ b/Code/Sandbox/Editor/StartupLogoDialog.cpp @@ -49,7 +49,7 @@ CStartupLogoDialog::CStartupLogoDialog(QString versionText, QString richTextCopy m_backgroundImage = QPixmap::fromImage(backgroundImage.scaled(m_enforcedWidth, m_enforcedHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); // Draw the Open 3D Engine logo from svg - m_ui->m_logo->load(QStringLiteral(":/StartupLogoDialog/lumberyard_logo.svg")); + m_ui->m_logo->load(QStringLiteral(":/StartupLogoDialog/o3de_logo.svg")); m_ui->m_TransparentConfidential->setObjectName("copyrightNotice"); m_ui->m_TransparentConfidential->setTextFormat(Qt::RichText); diff --git a/Code/Sandbox/Editor/StartupLogoDialog.qrc b/Code/Sandbox/Editor/StartupLogoDialog.qrc index 55c93b427c..29730ef9c7 100644 --- a/Code/Sandbox/Editor/StartupLogoDialog.qrc +++ b/Code/Sandbox/Editor/StartupLogoDialog.qrc @@ -1,6 +1,6 @@ - lumberyard_logo.svg + o3de_logo.svg splashscreen_1_27.png diff --git a/Code/Sandbox/Editor/StartupLogoDialog.ui b/Code/Sandbox/Editor/StartupLogoDialog.ui index f14355de8c..6e01808a84 100644 --- a/Code/Sandbox/Editor/StartupLogoDialog.ui +++ b/Code/Sandbox/Editor/StartupLogoDialog.ui @@ -42,14 +42,14 @@ - 250 - 60 + 161 + 49 - 250 - 60 + 161 + 50 diff --git a/Code/Sandbox/Editor/ToolBox.cpp b/Code/Sandbox/Editor/ToolBox.cpp index def7329e83..46c01ce864 100644 --- a/Code/Sandbox/Editor/ToolBox.cpp +++ b/Code/Sandbox/Editor/ToolBox.cpp @@ -18,6 +18,8 @@ #include "ToolBox.h" +#include + // AzToolsFramework #include #include @@ -419,9 +421,8 @@ void CToolBoxManager::Load(QString xmlpath, AmazonToolbar* pToolbar, bool bToolb } } - const char* engineRoot = nullptr; - AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(engineRoot, &AzToolsFramework::ToolsApplicationRequests::GetEngineRootPath); - QDir engineDir = engineRoot ? QDir(engineRoot) : QDir::current(); + AZ::IO::FixedMaxPathString engineRoot = AZ::Utils::GetEnginePath(); + QDir engineDir = !engineRoot.empty() ? QDir(QString(engineRoot.c_str())) : QDir::current(); string enginePath = PathUtil::AddSlash(engineDir.absolutePath().toUtf8().data()); diff --git a/Code/Sandbox/Editor/lumberyard_logo.svg b/Code/Sandbox/Editor/lumberyard_logo.svg deleted file mode 100644 index fe5f2fbdcd..0000000000 --- a/Code/Sandbox/Editor/lumberyard_logo.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - background - - - - Layer 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Code/Sandbox/Editor/o3de_logo.svg b/Code/Sandbox/Editor/o3de_logo.svg new file mode 100644 index 0000000000..ac746c07a5 --- /dev/null +++ b/Code/Sandbox/Editor/o3de_logo.svg @@ -0,0 +1,22 @@ + + + Group 12 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index e5311dbea9..9c917b25c0 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -670,9 +670,13 @@ void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, con action = menu->addAction(QObject::tr("Create layer")); QObject::connect(action, &QAction::triggered, [this] { ContextMenu_NewLayer(); }); + AzToolsFramework::EntityIdList entities; + AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult( + entities, + &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); + SetupLayerContextMenu(menu); - AzToolsFramework::EntityIdSet flattenedSelection; - GetSelectedEntitiesSetWithFlattenedHierarchy(flattenedSelection); + AzToolsFramework::EntityIdSet flattenedSelection = AzToolsFramework::GetCulledEntityHierarchy(entities); AzToolsFramework::SetupAddToLayerMenu(menu, flattenedSelection, [this] { return ContextMenu_NewLayer(); }); SetupSliceContextMenu(menu); @@ -1220,10 +1224,14 @@ void SandboxIntegrationManager::CloneSelection(bool& handled) { AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework); - AzToolsFramework::EntityIdSet duplicationSet; - GetSelectedEntitiesSetWithFlattenedHierarchy(duplicationSet); + AzToolsFramework::EntityIdList entities; + AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult( + entities, + &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities); - if (duplicationSet.size() > 0) + AzToolsFramework::EntityIdSet duplicationSet = AzToolsFramework::GetCulledEntityHierarchy(entities); + + if (!duplicationSet.empty()) { AZStd::unordered_set clonedEntities; handled = AzToolsFramework::CloneInstantiatedEntities(duplicationSet, clonedEntities); @@ -2777,26 +2785,6 @@ AZ::u32 SandboxIntegrationManager::SetState(AZ::u32 state) return 0; } -AZ::u32 SandboxIntegrationManager::SetStateFlag(AZ::u32 state) -{ - if (m_dc) - { - return m_dc->SetStateFlag(state); - } - - return 0; -} - -AZ::u32 SandboxIntegrationManager::ClearStateFlag(AZ::u32 state) -{ - if (m_dc) - { - return m_dc->ClearStateFlag(state); - } - - return 0; -} - void SandboxIntegrationManager::PushMatrix(const AZ::Transform& tm) { if (m_dc) diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h index e35fb5087a..36767605b2 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h @@ -268,8 +268,6 @@ private: bool SetDrawInFrontMode(bool bOn) override; AZ::u32 GetState() override; AZ::u32 SetState(AZ::u32 state) override; - AZ::u32 SetStateFlag(AZ::u32 state) override; - AZ::u32 ClearStateFlag(AZ::u32 state) override; void PushMatrix(const AZ::Transform& tm) override; void PopMatrix() override; diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index 2f71ebcb78..9522512619 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp @@ -42,7 +42,108 @@ namespace AZ // Downstream only supports 30 frames per second sample rate. Adjusting to 60 doubles the // length of the animations, they still play back at 30 frames per second. - const double AssImpAnimationImporter::s_defaultTimeStepSampleRate = 1.0 / 30.0; + const double AssImpAnimationImporter::s_defaultTimeStepBetweenFrames = 1.0 / 30.0; + + AZ::u32 GetNumKeyFrames(AZ::u32 keysSize, double duration, double ticksPerSecond) + { + if (AZ::IsClose(ticksPerSecond, 0)) + { + AZ_Warning("AnimationImporter", false, "Animation ticks per second should not be zero, defaulting to %d keyframes for animation.", keysSize); + return keysSize; + } + const double totalTicks = duration / ticksPerSecond; + AZ::u32 numKeys = keysSize; + // +1 because the animation is from [0, duration] - we have a keyframe at the end of the duration which needs to be included + double totalFramesAtDefaultTimeStep = totalTicks / AssImpAnimationImporter::s_defaultTimeStepBetweenFrames + 1; + if (!AZ::IsClose(totalFramesAtDefaultTimeStep, numKeys, 1)) + { + numKeys = AZStd::ceilf(totalFramesAtDefaultTimeStep); + } + return numKeys; + } + + double GetTimeForFrame(AZ::u32 frame, double ticksPerSecond) + { + return frame * AssImpAnimationImporter::s_defaultTimeStepBetweenFrames * ticksPerSecond; + } + + // Helper class to store key data, when translating from AssImp layout to the engine's scene format. + struct KeyData + { + KeyData(float value, float time) : + mValue(value), + mTime(time) + { + + } + + bool operator<(const KeyData& other) const + { + return mTime < other.mTime; + } + + float mValue = 0; + float mTime = 0; + }; + + template + void LerpTemplate(T& start, const T& end, float t) + { + start = start * (1.0f - t) + end * t; + } + + template<> + void LerpTemplate(aiQuaternion& start, const aiQuaternion& end, float t) + { + aiQuaternion::Interpolate(start, start, end, t); + } + + template<> + void LerpTemplate(float& start, const float& end, float t) + { + start = AZ::Lerp(start, end, t); + } + + template + bool SampleKeyFrame(FrameValueType& result, const KeyContainerType& keys, AZ::u32 numKeys, double time, AZ::u32& lastIndex) + { + if (numKeys == 0) + { + AZ_Error("AnimationImporter", numKeys > 0, "Animation key set must have at least 1 key"); + return false; + } + if (numKeys == 1) + { + result = keys[0].mValue; + return true; + } + + while (lastIndex < numKeys - 1 && time >= keys[lastIndex + 1].mTime) + { + ++lastIndex; + } + result = keys[lastIndex].mValue; + if (lastIndex < numKeys - 1) + { + auto nextValue = keys[lastIndex + 1].mValue; + float normalizedTimeBetweenFrames = 0; + if (keys[lastIndex + 1].mTime != keys[lastIndex].mTime) + { + normalizedTimeBetweenFrames = + (time - keys[lastIndex].mTime) / (keys[lastIndex + 1].mTime - keys[lastIndex].mTime); + } + else + { + AZ_Warning("AnimationImporter", false, + "Animation has keys with duplicate time %5.5f, at indices %d and %d. The second will be ignored.", + keys[lastIndex].mTime, + lastIndex, + lastIndex + 1); + } + LerpTemplate(result, nextValue, normalizedTimeBetweenFrames); + } + return true; + } AssImpAnimationImporter::AssImpAnimationImporter() { @@ -199,6 +300,14 @@ namespace AZ for (AZ::u32 animIndex = 0; animIndex < scene->mNumAnimations; ++animIndex) { const aiAnimation* animation = scene->mAnimations[animIndex]; + if (animation->mTicksPerSecond == 0) + { + AZ_Error( + "AnimationImporter", false, + "Animation name %s has a sample rate of 0 ticks per second and cannot be processed.", + animation->mName.C_Str()); + return Events::ProcessingResult::Failure; + } mapAnimationsFunc(animation->mNumChannels, animation->mChannels, animation, boneAnimations); @@ -410,70 +519,38 @@ namespace AZ anim->mNumPositionKeys, anim->mNumRotationKeys, anim->mNumScalingKeys); return Events::ProcessingResult::Failure; } - - auto sampleKeyFrame = [](const auto& keys, AZ::u32 numKeys, double time, AZ::u32& lastIndex) - { - AZ_Error("AnimationImporter", numKeys > 0, "Animation key set must have at least 1 key"); - - if (numKeys == 1) - { - return keys[0].mValue; - } - - auto returnValue = keys[0].mValue; - - for (AZ::u32 keyIndex = lastIndex; keyIndex < numKeys; ++keyIndex) - { - const auto& key = keys[keyIndex]; - lastIndex = keyIndex; - - // We want to return the key that exactly matches the time if possible, otherwise we'll keep track of the previous time - // If we don't find an exact match and end up going past the desired time (or run out of keyframes) then we return the previous key - if (key.mTime < time) - { - returnValue = key.mValue; - } - else if (AZ::IsClose(key.mTime, time)) - { - return key.mValue; - } - else - { - return returnValue; - } - } - - return returnValue; - }; // Resample the animations at a fixed time step. This matches the behaviour of // the previous SDK used. Longer term, this could be data driven, or based on the // smallest time step between key frames. // AssImp has an animation->mTicksPerSecond and animation->mDuration, but those // are less predictable than just using a fixed time step. - const double duration = animation->mDuration / animation->mTicksPerSecond; + // AssImp documentation claims animation->mDuration is the duration of the animation in ticks, but + // not all animations we've tested follow that pattern. Sometimes duration is in seconds. + const AZ::u32 numKeyFrames = GetNumKeyFrames( + AZStd::max(AZStd::max(anim->mNumScalingKeys, anim->mNumPositionKeys), anim->mNumRotationKeys), + animation->mDuration, + animation->mTicksPerSecond); - AZ::u32 numKeyFrames = AZStd::max(AZStd::max(anim->mNumScalingKeys, anim->mNumPositionKeys), anim->mNumRotationKeys); - if (!AZ::IsClose(duration / s_defaultTimeStepSampleRate, numKeyFrames, 1)) - { - double dT = duration / s_defaultTimeStepSampleRate; - numKeyFrames = AZStd::ceilf(dT) + 1; // +1 because the animation is from [0, duration] - we have a keyframe at the end of the duration which needs to be included - } - AZStd::shared_ptr createdAnimationData = AZStd::make_shared(); createdAnimationData->ReserveKeyFrames(numKeyFrames); - createdAnimationData->SetTimeStepBetweenFrames(s_defaultTimeStepSampleRate); + createdAnimationData->SetTimeStepBetweenFrames(s_defaultTimeStepBetweenFrames); AZ::u32 lastScaleIndex = 0; AZ::u32 lastPositionIndex = 0; AZ::u32 lastRotationIndex = 0; for (AZ::u32 frame = 0; frame < numKeyFrames; ++frame) { - double time = frame * s_defaultTimeStepSampleRate * animation->mTicksPerSecond; - aiVector3D scale = sampleKeyFrame(anim->mScalingKeys, anim->mNumScalingKeys, time, lastScaleIndex); - aiVector3D position = sampleKeyFrame(anim->mPositionKeys, anim->mNumPositionKeys, time, lastPositionIndex); - aiQuaternion rotation = sampleKeyFrame(anim->mRotationKeys, anim->mNumRotationKeys, time, lastRotationIndex); + const double time = GetTimeForFrame(frame, animation->mTicksPerSecond); + aiVector3D scale = aiVector3D(1.f, 1.f, 1.f), position = aiVector3D(0.f, 0.f, 0.f); + aiQuaternion rotation(1.f, 0.f, 0.f, 0.f); + if (!SampleKeyFrame(scale, anim->mScalingKeys, anim->mNumScalingKeys, time, lastScaleIndex) || + !SampleKeyFrame(position, anim->mPositionKeys, anim->mNumPositionKeys, time, lastPositionIndex) || + !SampleKeyFrame(rotation, anim->mRotationKeys, anim->mNumRotationKeys, time, lastRotationIndex)) + { + return Events::ProcessingResult::Failure; + } aiMatrix4x4 transform(scale, rotation, position); @@ -520,28 +597,6 @@ namespace AZ // SetTimeStepBetweenFrames set on the animation data // Keyframes. Weights (Values in FBX SDK) per key time. // Keyframes generated for every single frame of the animation. - - // Helper class to store key data, when translating from AssImp layout to the engine's scene format. - struct KeyData - { - KeyData(float weight, float time) : - m_weight(weight), - m_time(time) - { - - } - - bool operator<(const KeyData& other) const - { - return m_time < other.m_time; - } - - // Naming in the previous SDK (FBX SDK) and in the engine's scene format - // doesn't match AssImp's naming convention. - // weight here is the AssImp's name for the data, it was named value in FBX SDK. - float m_weight = 0; - float m_time = 0; - }; typedef AZStd::map> ValueToKeyDataMap; ValueToKeyDataMap valueToKeyDataMap; @@ -562,44 +617,27 @@ namespace AZ { AZStd::shared_ptr morphAnimNode = AZStd::make_shared(); - morphAnimNode->ReserveKeyFrames(animation->mDuration + 1); - morphAnimNode->SetTimeStepBetweenFrames(1.0 / animation->mTicksPerSecond); + + const AZ::u32 numKeyFrames = GetNumKeyFrames(keys.size(), animation->mDuration, animation->mTicksPerSecond); + morphAnimNode->ReserveKeyFrames(numKeyFrames); + morphAnimNode->SetTimeStepBetweenFrames(s_defaultTimeStepBetweenFrames); aiAnimMesh* aiAnimMesh = mesh->mAnimMeshes[meshIdx]; AZStd::string_view nodeName(aiAnimMesh->mName.C_Str()); const AZ::u32 maxKeys = keys.size(); AZ::u32 keyIdx = 0; - for (AZ::u32 time = 0; time <= animation->mDuration; ++time) + for (AZ::u32 frame = 0; frame <= numKeyFrames; ++frame) { - if (keyIdx < maxKeys - 1 && time >= keys[keyIdx+1].m_time) - { - ++keyIdx; - } - float weight_value = keys[keyIdx].m_weight; - if (keyIdx < maxKeys - 1) - { - float nextWeight = keys[keyIdx+1].m_weight; - float normalizedTimeBetweenFrames = 0; + const double time = GetTimeForFrame(frame, animation->mTicksPerSecond); - if (keys[keyIdx + 1].m_time != keys[keyIdx].m_time) - { - normalizedTimeBetweenFrames = - (time - keys[keyIdx].m_time) / (keys[keyIdx + 1].m_time - keys[keyIdx].m_time); - } - else - { - AZ_Warning("AnimationImporter", false, - "Morph target mesh %s has keys with duplicate time, at indices %d and %d. The second will be ignored.", - nodeName.data(), - keyIdx, - keyIdx+1); - } - - // AssImp and FBX both only support linear interpolation for blend shapes. - weight_value = AZ::Lerp(weight_value, nextWeight, normalizedTimeBetweenFrames); + float weight = 0; + if (!SampleKeyFrame(weight, keys, keys.size(), time, keyIdx)) + { + return Events::ProcessingResult::Failure; } - morphAnimNode->AddKeyFrame(weight_value); + + morphAnimNode->AddKeyFrame(weight); } diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.h b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.h index 72180dea1a..3c06153d04 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.h +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.h @@ -45,7 +45,7 @@ namespace AZ const aiMeshMorphAnim* meshMorphAnim, const aiMesh* mesh); - static const double s_defaultTimeStepSampleRate; + static const double s_defaultTimeStepBetweenFrames; protected: static const char* s_animationNodeName; diff --git a/Code/Tools/SceneAPI/SceneCore/Containers/SceneGraph.cpp b/Code/Tools/SceneAPI/SceneCore/Containers/SceneGraph.cpp index 934b0154c9..87c265481f 100644 --- a/Code/Tools/SceneAPI/SceneCore/Containers/SceneGraph.cpp +++ b/Code/Tools/SceneAPI/SceneCore/Containers/SceneGraph.cpp @@ -43,7 +43,7 @@ namespace AZ AZ::BehaviorContext* behaviorContext = azrtti_cast(context); if (behaviorContext) { - behaviorContext->Class() + behaviorContext->Class("NodeIndex") ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Module, "scene.graph") ->Constructor<>() @@ -57,7 +57,7 @@ namespace AZ ->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString) ; - behaviorContext->Class() + behaviorContext->Class("SceneGraphName") ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) ->Attribute(AZ::Script::Attributes::Module, "scene.graph") ->Constructor() diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h index c5e3c46cd4..c44327a5f2 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h @@ -12,6 +12,7 @@ #pragma once #include +#include namespace AWSClientAuth { @@ -28,74 +29,104 @@ namespace AWSClientAuth OnPasswordGrantMultiFactorConfirmSignInSuccess, OnPasswordGrantMultiFactorConfirmSignInFail, OnDeviceCodeGrantSignInSuccess, OnDeviceCodeGrantSignInFail, OnDeviceCodeGrantConfirmSignInSuccess, OnDeviceCodeGrantConfirmSignInFail, - OnRefreshTokensSuccess, OnRefreshTokensFail, - OnSignOut + OnRefreshTokensSuccess, OnRefreshTokensFail ); void OnPasswordGrantSingleFactorSignInSuccess(const AuthenticationTokens& authenticationToken) override { - Call(FN_OnPasswordGrantSingleFactorSignInSuccess, authenticationToken); + AZ::TickBus::QueueFunction([authenticationToken, this]() + { + Call(FN_OnPasswordGrantSingleFactorSignInSuccess, authenticationToken); + }); } void OnPasswordGrantSingleFactorSignInFail(const AZStd::string& error) override { - Call(FN_OnPasswordGrantSingleFactorSignInFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnPasswordGrantSingleFactorSignInFail, error); + }); } void OnPasswordGrantMultiFactorSignInSuccess() override { - Call(FN_OnPasswordGrantMultiFactorSignInSuccess); + AZ::TickBus::QueueFunction([this]() + { + Call(FN_OnPasswordGrantMultiFactorSignInSuccess); + }); } void OnPasswordGrantMultiFactorSignInFail(const AZStd::string& error) override { - Call(FN_OnPasswordGrantMultiFactorSignInFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnPasswordGrantMultiFactorSignInFail, error); + }); } void OnPasswordGrantMultiFactorConfirmSignInSuccess(const AuthenticationTokens& authenticationToken) override { - Call(FN_OnPasswordGrantMultiFactorConfirmSignInSuccess, authenticationToken); + AZ::TickBus::QueueFunction([authenticationToken, this]() + { + Call(FN_OnPasswordGrantMultiFactorConfirmSignInSuccess, authenticationToken); + }); } void OnPasswordGrantMultiFactorConfirmSignInFail(const AZStd::string& error) override { - Call(FN_OnPasswordGrantMultiFactorConfirmSignInFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnPasswordGrantMultiFactorConfirmSignInFail, error); + }); } void OnDeviceCodeGrantSignInSuccess( const AZStd::string& userCode, const AZStd::string& verificationUrl, const int codeExpiresInSeconds) override { - Call(FN_OnDeviceCodeGrantSignInSuccess, userCode, verificationUrl, codeExpiresInSeconds); + AZ::TickBus::QueueFunction([userCode, verificationUrl, codeExpiresInSeconds, this]() + { + Call(FN_OnDeviceCodeGrantSignInSuccess, userCode, verificationUrl, codeExpiresInSeconds); + }); } void OnDeviceCodeGrantSignInFail(const AZStd::string& error) override { - Call(FN_OnDeviceCodeGrantSignInFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnDeviceCodeGrantSignInFail, error); + }); } void OnDeviceCodeGrantConfirmSignInSuccess(const AuthenticationTokens& authenticationToken) override { - Call(FN_OnDeviceCodeGrantConfirmSignInSuccess, authenticationToken); + AZ::TickBus::QueueFunction([authenticationToken, this]() + { + Call(FN_OnDeviceCodeGrantConfirmSignInSuccess, authenticationToken); + }); } void OnDeviceCodeGrantConfirmSignInFail(const AZStd::string& error) override { - Call(FN_OnDeviceCodeGrantConfirmSignInFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnDeviceCodeGrantConfirmSignInFail, error); + }); } void OnRefreshTokensSuccess(const AuthenticationTokens& authenticationToken) override { - Call(FN_OnRefreshTokensSuccess, authenticationToken); + AZ::TickBus::QueueFunction([authenticationToken, this]() + { + Call(FN_OnRefreshTokensSuccess, authenticationToken); + }); } void OnRefreshTokensFail(const AZStd::string& error) override { - Call(FN_OnRefreshTokensFail, error); - } - - void OnSignOut(const ProviderNameEnum& provideName) override - { - Call(FN_OnSignOut, provideName); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnRefreshTokensFail, error); + }); } }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderManager.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderManager.h index a9a2f2ad6e..a09a96ba5c 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderManager.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderManager.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -23,7 +24,8 @@ namespace AWSClientAuth { //! Manages various authentication provider implementations and implements AuthenticationProvider Request bus. class AuthenticationProviderManager - : AuthenticationProviderRequestBus::Handler + : public AuthenticationProviderRequestBus::Handler + , public AuthenticationProviderScriptCanvasRequestBus::Handler { public: AZ_RTTI(AuthenticationProviderManager, "{45813BA5-9A46-4A2A-A923-C79CFBA0E63D}", IAuthenticationProviderRequests); @@ -43,6 +45,22 @@ namespace AWSClientAuth bool IsSignedIn(const ProviderNameEnum& providerName) override; bool SignOut(const ProviderNameEnum& providerName) override; AuthenticationTokens GetAuthenticationTokens(const ProviderNameEnum& providerName) override; + + // AuthenticationProviderScriptCanvasRequest interface + bool Initialize(const AZStd::vector& providerNames, const AZStd::string& settingsRegistryPath) override; + void PasswordGrantSingleFactorSignInAsync( + const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) override; + void PasswordGrantMultiFactorSignInAsync( + const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) override; + void PasswordGrantMultiFactorConfirmSignInAsync( + const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& confirmationCode) override; + void DeviceCodeGrantSignInAsync(const AZStd::string& providerName) override; + void DeviceCodeGrantConfirmSignInAsync(const AZStd::string& providerName) override; + void RefreshTokensAsync(const AZStd::string& providerName) override; + void GetTokensWithRefreshAsync(const AZStd::string& providerName) override; + bool IsSignedIn(const AZStd::string& providerName) override; + bool SignOut(const AZStd::string& providerName) override; + AuthenticationTokens GetAuthenticationTokens(const AZStd::string& providerName) override; virtual AZStd::unique_ptr CreateAuthenticationProviderObject(const ProviderNameEnum& providerName); AZStd::map> m_authenticationProvidersMap; @@ -50,9 +68,9 @@ namespace AWSClientAuth private: bool IsProviderInitialized(const ProviderNameEnum& providerName); void ResetProviders(); + ProviderNameEnum GetProviderNameEnum(AZStd::string name); AZStd::shared_ptr m_settingsRegistry; - }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderScriptCanvasBus.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderScriptCanvasBus.h new file mode 100644 index 0000000000..9ce508b497 --- /dev/null +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderScriptCanvasBus.h @@ -0,0 +1,103 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ +#pragma once + +#include +#include + +namespace AWSClientAuth +{ + //! Abstract class for authentication provider script canvas requests. + //! Private class to allow provide names to be string type instead of an enum as behavior context does not work well with enum's. + class IAuthenticationProviderScriptCanvasRequests + { + public: + AZ_TYPE_INFO(IAuthenticationProviderRequests, "{A8FD915F-9FF2-4BA3-8AA0-8CF7A94A323B}"); + + //! Parse the settings file for required settings for authentication providers. Instantiate and initialize authentication providers + //! @param providerNames List of provider names to instantiate and initialize for Authentication. + //! @param settingsRegistryPath Path for the settings registry file to use to configure providers. + //! @return bool True: if all providers initialized successfully. False: If any provider fails initialization. + virtual bool Initialize(const AZStd::vector& providerNames, const AZStd::string& settingsRegistryPath) = 0; + + //! Checks if user is signed in. + //! If access tokens are available and not expired. + //! @param providerName Provider to check signed in for + //! @return bool True if valid access token available, else False + virtual bool IsSignedIn(const AZStd::string& providerName) = 0; + + //! Get cached tokens from last last successful sign-in for the provider. + //! @param providerName Provider to get authentication tokens + //! @return AuthenticationTokens tokens from successful authentication. + virtual AuthenticationTokens GetAuthenticationTokens(const AZStd::string& providerName) = 0; + + // Below methods have corresponding notifications for success and failures. + + //! Call sign in endpoint for provider password grant flow. + //! @param providerName Provider to call sign in. + //! @param username Username to use to for sign in. + //! @param password Password to use to for sign in. + virtual void PasswordGrantSingleFactorSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) = 0; + + //! Call sign in endpoint for provider password grant multi factor authentication flow. + //! @param providerName Provider to call MFA sign in. + //! @param username Username to use for MFA sign in. + //! @param password Password to use for MFA sign in. + virtual void PasswordGrantMultiFactorSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) = 0; + + //! Call confirm endpoint for provider password grant multi factor authentication flow . + //! @param providerName Provider to call MFA confirm sign in. + //! @param username Username to use for MFA confirm. + //! @param confirmationCode Confirmation code (sent to email/text) to use for MFA confirm. + virtual void PasswordGrantMultiFactorConfirmSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& confirmationCode) = 0; + + //! Call code-pair endpoint for provider device grant flow. + //! @param providerName Provider to call device sign in. + virtual void DeviceCodeGrantSignInAsync(const AZStd::string& providerName) = 0; + + //! Call tokens endpoint for provider device grant flow. + //! @param providerName Provider to call device confirm sign in. + virtual void DeviceCodeGrantConfirmSignInAsync(const AZStd::string& providerName) = 0; + + //! Call refresh endpoint for provider refresh grant flow. + //! @param providerName Provider to call refresh tokens. + virtual void RefreshTokensAsync(const AZStd::string& providerName) = 0; + + //! Call refresh token if token not valid. If token valid, fires corresponding event. + //! @param providerName Provider to get access token for. + //! events: OnRefreshTokensSuccess, OnRefreshTokensFail + virtual void GetTokensWithRefreshAsync(const AZStd::string& providerName) = 0; + + //! Signs user out. + //! Clears all cached tokens. + //! @param providerName Provider to sign out. + //! @return bool True: Successfully sign out. + virtual bool SignOut(const AZStd::string& providerName) = 0; + + ////////////////////////////////////////////////////////////////////////// + }; + + //! Authentication Request bus for different supported providers. + class AuthenticationProviderScriptCanvasRequests + : public AZ::EBusTraits + { + public: + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + using MutexType = AZ::NullMutex; + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + ////////////////////////////////////////////////////////////////////////// + }; + using AuthenticationProviderScriptCanvasRequestBus = AZ::EBus; + +} // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h index 1e10e66307..8bd31d6aeb 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authentication/AuthenticationProviderTypes.h @@ -15,6 +15,14 @@ namespace AWSClientAuth { + constexpr char ProvideNameEnumStringNone[] = "None"; + constexpr char ProvideNameEnumStringAWSCognitoIDP[] = "AWSCognitoIDP"; + constexpr char ProvideNameEnumStringLoginWithAmazon[] = "LoginWithAmazon"; + constexpr char ProvideNameEnumStringGoogle[] = "Google"; + constexpr char ProvideNameEnumStringApple[] = "Apple"; + constexpr char ProvideNameEnumStringFacebook[] = "Facebook"; + constexpr char ProvideNameEnumStringTwitch[] = "Twitch"; + //! Holds Login with Amazon provider serialized settings class LWAProviderSetting { diff --git a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h index f690445c26..e26896fa06 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h +++ b/Gems/AWSClientAuth/Code/Include/Private/Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h @@ -12,6 +12,7 @@ #pragma once #include +#include #include namespace AWSClientAuth @@ -28,12 +29,18 @@ namespace AWSClientAuth void OnRequestAWSCredentialsSuccess(const ClientAuthAWSCredentials& awsCredentials) override { - Call(FN_OnRequestAWSCredentialsSuccess, awsCredentials); + AZ::TickBus::QueueFunction([awsCredentials, this]() + { + Call(FN_OnRequestAWSCredentialsSuccess, awsCredentials); + }); } void OnRequestAWSCredentialsFail(const AZStd::string& error) override { - Call(FN_OnRequestAWSCredentialsFail, error); + AZ::TickBus::QueueFunction([error, this]() + { + Call(FN_OnRequestAWSCredentialsFail, error); + }); } }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h b/Gems/AWSClientAuth/Code/Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h index 06f2ae6e58..f5c2ca7ed1 100644 --- a/Gems/AWSClientAuth/Code/Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h +++ b/Gems/AWSClientAuth/Code/Include/Private/UserManagement/UserManagementNotificationBusBehaviorHandler.h @@ -12,6 +12,7 @@ #pragma once #include +#include namespace AWSClientAuth { @@ -32,62 +33,86 @@ namespace AWSClientAuth void OnEmailSignUpSuccess(const AZStd::string& uuid) override { - Call(FN_OnEmailSignUpSuccess, uuid); + AZ::TickBus::QueueFunction([uuid, this]() { + Call(FN_OnEmailSignUpSuccess, uuid); + }); } void OnEmailSignUpFail(const AZStd::string& error) override { - Call(FN_OnEmailSignUpFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnEmailSignUpFail, error); + }); } void OnPhoneSignUpSuccess(const AZStd::string& uuid) override { - Call(FN_OnPhoneSignUpSuccess, uuid); + AZ::TickBus::QueueFunction([uuid, this]() { + Call(FN_OnPhoneSignUpSuccess, uuid); + }); } void OnPhoneSignUpFail(const AZStd::string& error) override { - Call(FN_OnPhoneSignUpFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnPhoneSignUpFail, error); + }); } void OnConfirmSignUpSuccess() override { - Call(FN_OnConfirmSignUpSuccess); + AZ::TickBus::QueueFunction([this]() { + Call(FN_OnConfirmSignUpSuccess); + }); } void OnConfirmSignUpFail(const AZStd::string& error) override { - Call(FN_OnConfirmSignUpFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnConfirmSignUpFail, error); + }); } void OnForgotPasswordSuccess() override { - Call(FN_OnForgotPasswordSuccess); + AZ::TickBus::QueueFunction([this]() { + Call(FN_OnForgotPasswordSuccess); + }); } void OnForgotPasswordFail(const AZStd::string& error) override { - Call(FN_OnForgotPasswordFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnForgotPasswordFail, error); + }); } void OnConfirmForgotPasswordSuccess() override { - Call(FN_OnConfirmForgotPasswordSuccess); + AZ::TickBus::QueueFunction([this]() { + Call(FN_OnConfirmForgotPasswordSuccess); + }); } void OnConfirmForgotPasswordFail(const AZStd::string& error) override { - Call(FN_OnConfirmForgotPasswordFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnConfirmForgotPasswordFail, error); + }); } void OnEnableMFASuccess() override { - Call(FN_OnEnableMFASuccess); + AZ::TickBus::QueueFunction([this]() { + Call(FN_OnEnableMFASuccess); + }); } void OnEnableMFAFail(const AZStd::string& error) override { - Call(FN_OnEnableMFAFail, error); + AZ::TickBus::QueueFunction([error, this]() { + Call(FN_OnEnableMFAFail, error); + }); } }; } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationProviderBus.h b/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationProviderBus.h index 693adf1e65..9e822849bc 100644 --- a/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationProviderBus.h +++ b/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationProviderBus.h @@ -16,7 +16,7 @@ namespace AWSClientAuth { - //@ Abstract class for authentication provider requests. + //! Abstract class for authentication provider requests. class IAuthenticationProviderRequests { public: @@ -35,32 +35,40 @@ namespace AWSClientAuth virtual bool IsSignedIn(const ProviderNameEnum& providerName) = 0; //! Get cached tokens from last last successful sign-in for the provider. + //! @param providerName Provider to get authentication tokens. + //! @return AuthenticationTokens tokens from successful authentication. virtual AuthenticationTokens GetAuthenticationTokens(const ProviderNameEnum& providerName) = 0; // Below methods have corresponding notifications for success and failures. //! Call sign in endpoint for provider password grant flow. + //! @param providerName Provider to call sign in. //! @param username Username to use to for sign in. //! @param password Password to use to for sign in. virtual void PasswordGrantSingleFactorSignInAsync(const ProviderNameEnum& providerName, const AZStd::string& username, const AZStd::string& password) = 0; //! Call sign in endpoint for provider password grant multi factor authentication flow. + //! @param providerName Provider to call MFA sign in. //! @param username Username to use for MFA sign in. //! @param password Password to use for MFA sign in. virtual void PasswordGrantMultiFactorSignInAsync(const ProviderNameEnum& providerName, const AZStd::string& username, const AZStd::string& password) = 0; //! Call confirm endpoint for provider password grant multi factor authentication flow . + //! @param providerName Provider to call MFA confirm sign in. //! @param username Username to use for MFA confirm. //! @param confirmationCode Confirmation code (sent to email/text) to use for MFA confirm. virtual void PasswordGrantMultiFactorConfirmSignInAsync(const ProviderNameEnum& providerName, const AZStd::string& username, const AZStd::string& confirmationCode) = 0; //! Call code-pair endpoint for provider device grant flow. + //! @param providerName Provider to call device sign in. virtual void DeviceCodeGrantSignInAsync(const ProviderNameEnum& providerName) = 0; //! Call tokens endpoint for provider device grant flow. + //! @param providerName Provider to call device confirm sign in. virtual void DeviceCodeGrantConfirmSignInAsync(const ProviderNameEnum& providerName) = 0; //! Call refresh endpoint for provider refresh grant flow. + //! @param providerName Provider to call refresh tokens. virtual void RefreshTokensAsync(const ProviderNameEnum& providerName) = 0; //! Call refresh token if token not valid. If token valid, fires corresponding event. diff --git a/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationTokens.h b/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationTokens.h index 80138efd1b..3bb781f262 100644 --- a/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationTokens.h +++ b/Gems/AWSClientAuth/Code/Include/Public/Authentication/AuthenticationTokens.h @@ -11,20 +11,15 @@ */ #pragma once +#include #include #include +#include +#include namespace AWSClientAuth { - enum class ProviderNameEnum - { - None, - AWSCognitoIDP, - LoginWithAmazon, - Google, - Apple, - Facebook - }; + AZ_ENUM_CLASS(ProviderNameEnum, None, AWSCognitoIDP, LoginWithAmazon, Twitch, Google, Apple, Facebook); //! Used to share authentication tokens to caller and to AWSCognitoAuthorizationController. class AuthenticationTokens @@ -55,6 +50,8 @@ namespace AWSClientAuth //! @return Expiration time in seconds. int GetTokensExpireTimeSeconds() const; + static void Reflect(AZ::ReflectContext* context); + private: int m_tokensExpireTimeSeconds = 0; AZStd::string m_accessToken; diff --git a/Gems/AWSClientAuth/Code/Include/Public/Authorization/ClientAuthAWSCredentials.h b/Gems/AWSClientAuth/Code/Include/Public/Authorization/ClientAuthAWSCredentials.h index 71a5703efd..2daac42a49 100644 --- a/Gems/AWSClientAuth/Code/Include/Public/Authorization/ClientAuthAWSCredentials.h +++ b/Gems/AWSClientAuth/Code/Include/Public/Authorization/ClientAuthAWSCredentials.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include #include @@ -24,6 +24,14 @@ namespace AWSClientAuth { public: AZ_TYPE_INFO(ClientAuthAWSCredentials, "{02FB32C4-B94E-4084-9049-3DF32F87BD76}"); + ClientAuthAWSCredentials() = default; + ClientAuthAWSCredentials(const ClientAuthAWSCredentials& other) + : m_accessKeyId(other.m_accessKeyId) + , m_secretKey(other.m_secretKey) + , m_sessionToken(other.m_sessionToken) + + { + } ClientAuthAWSCredentials(const AZStd::string& accessKeyId, const AZStd::string& secretKey, const AZStd::string& sessionToken) { @@ -50,6 +58,32 @@ namespace AWSClientAuth return m_sessionToken; } + static void Reflect(AZ::ReflectContext* context) + { + auto serializeContext = azrtti_cast(context); + if (serializeContext) + { + serializeContext->Class() + ->Field("AWSAccessKeyId", &ClientAuthAWSCredentials::m_accessKeyId) + ->Field("AWSSecretKey", &ClientAuthAWSCredentials::m_secretKey) + ->Field("AWSSessionToken", &ClientAuthAWSCredentials::m_sessionToken); + } + + AZ::BehaviorContext* behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Category, "AWSClientAuth") + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Constructor() + ->Constructor() + ->Property("AWSAccessKeyId", BehaviorValueGetter(&ClientAuthAWSCredentials::m_accessKeyId), BehaviorValueSetter(&ClientAuthAWSCredentials::m_accessKeyId)) + ->Property("AWSSecretKey", BehaviorValueGetter(&ClientAuthAWSCredentials::m_secretKey), BehaviorValueSetter(&ClientAuthAWSCredentials::m_secretKey)) + ->Property("AWSSessionToken", BehaviorValueGetter(&ClientAuthAWSCredentials::m_sessionToken), BehaviorValueSetter(&ClientAuthAWSCredentials::m_sessionToken)); + } + } + private: AZStd::string m_accessKeyId; AZStd::string m_secretKey; diff --git a/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h b/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h index 89ddf0a999..aff68db365 100644 --- a/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h +++ b/Gems/AWSClientAuth/Code/Include/Public/UserManagement/AWSCognitoUserManagementBus.h @@ -22,11 +22,12 @@ namespace AWSClientAuth public: AZ_TYPE_INFO(IAWSCognitoUserManagementRequests, "{A4C90F21-7056-4827-8C6B-401E6945697D}"); - //! Initialize Cognito User pool. + //! Initialize Cognito User pool using settings from resource mappings. //! @param settingsRegistryPath settingsRegistryPath Path for the settings registry file to use. virtual bool Initialize() = 0; // Requests interface + //! Cognito user pool email sign up start. //! @param username User name to use for sign up. //! @param password Password to use for sign up. @@ -59,7 +60,7 @@ namespace AWSClientAuth virtual void EnableMFAAsync(const AZStd::string& accessToken) = 0; }; - //! Manages various authentication provider implementations and implements AuthenticationProvider Request bus. + //! Implements AWS Cognito user pool user management requests. class AWSCognitoUserManagementRequests : public AZ::EBusTraits { diff --git a/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp b/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp index 20efa354cc..008d56da0b 100644 --- a/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp +++ b/Gems/AWSClientAuth/Code/Source/AWSClientAuthSystemComponent.cpp @@ -22,6 +22,11 @@ #include #include +namespace AZ +{ + AZ_TYPE_INFO_SPECIALIZE(AWSClientAuth::ProviderNameEnum, "{FB34B23A-B249-47A2-B1F1-C05284B50CCC}"); +} + namespace AWSClientAuth { constexpr char SerializeComponentName[] = "AWSClientAuth"; @@ -44,20 +49,35 @@ namespace AWSClientAuth AWSClientAuth::GoogleProviderSetting::Reflect(*serialize); } + AWSClientAuth::AuthenticationTokens::Reflect(context); + AWSClientAuth::ClientAuthAWSCredentials::Reflect(context); + if (AZ::BehaviorContext* behaviorContext = azrtti_cast(context)) { - behaviorContext->EBus("AuthenticationProviderRequestBus") + behaviorContext->Enum<(int)ProviderNameEnum::None>("ProviderNameEnum_None") + ->Enum<(int)ProviderNameEnum::AWSCognitoIDP>("ProviderNameEnum_AWSCognitoIDP") + ->Enum<(int)ProviderNameEnum::LoginWithAmazon>("ProviderNameEnum_LoginWithAmazon") + ->Enum<(int)ProviderNameEnum::Google>("ProviderNameEnum_Google"); + + behaviorContext->EBus("AuthenticationProviderRequestBus") ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) - ->Event("Initialize", &AuthenticationProviderRequestBus::Events::Initialize) - ->Event("IsSignedIn", &AuthenticationProviderRequestBus::Events::IsSignedIn) - ->Event("GetAuthenticationTokens", &AuthenticationProviderRequestBus::Events::GetAuthenticationTokens) + ->Event("Initialize", &AuthenticationProviderScriptCanvasRequestBus::Events::Initialize) + ->Event("IsSignedIn", &AuthenticationProviderScriptCanvasRequestBus::Events::IsSignedIn) + ->Event("GetAuthenticationTokens", &AuthenticationProviderScriptCanvasRequestBus::Events::GetAuthenticationTokens) ->Event( - "PasswordGrantSingleFactorSignInAsync", &AuthenticationProviderRequestBus::Events::PasswordGrantSingleFactorSignInAsync) - ->Event("DeviceCodeGrantSignInAsync", &AuthenticationProviderRequestBus::Events::DeviceCodeGrantSignInAsync) - ->Event("DeviceCodeGrantConfirmSignInAsync", &AuthenticationProviderRequestBus::Events::DeviceCodeGrantConfirmSignInAsync) - ->Event("RefreshTokensAsync", &AuthenticationProviderRequestBus::Events::RefreshTokensAsync) - ->Event("GetTokensWithRefreshAsync", &AuthenticationProviderRequestBus::Events::GetTokensWithRefreshAsync) - ->Event("SignOut", &AuthenticationProviderRequestBus::Events::SignOut); + "PasswordGrantSingleFactorSignInAsync", + &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantSingleFactorSignInAsync) + ->Event( + "PasswordGrantMultiFactorSignInAsync", + &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantMultiFactorSignInAsync) + ->Event( + "PasswordGrantMultiFactorConfirmSignInAsync", + &AuthenticationProviderScriptCanvasRequestBus::Events::PasswordGrantMultiFactorConfirmSignInAsync) + ->Event("DeviceCodeGrantSignInAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::DeviceCodeGrantSignInAsync) + ->Event("DeviceCodeGrantConfirmSignInAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::DeviceCodeGrantConfirmSignInAsync) + ->Event("RefreshTokensAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::RefreshTokensAsync) + ->Event("GetTokensWithRefreshAsync", &AuthenticationProviderScriptCanvasRequestBus::Events::GetTokensWithRefreshAsync) + ->Event("SignOut", &AuthenticationProviderScriptCanvasRequestBus::Events::SignOut); behaviorContext->EBus("AWSCognitoAuthorizationRequestBus") ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) @@ -77,11 +97,15 @@ namespace AWSClientAuth ->Event("ConfirmForgotPasswordAsync", &AWSCognitoUserManagementRequestBus::Events::ConfirmForgotPasswordAsync) ->Event("EnableMFAAsync", &AWSCognitoUserManagementRequestBus::Events::EnableMFAAsync); + behaviorContext->EBus("AuthenticationProviderNotificationBus") + ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Handler(); behaviorContext->EBus("AWSCognitoUserManagementNotificationBus") + ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Handler(); behaviorContext->EBus("AWSCognitoAuthorizationNotificationBus") + ->Attribute(AZ::Script::Attributes::Category, SerializeComponentName) ->Handler(); } } diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp index eca5ba22c2..74865c0044 100644 --- a/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authentication/AWSCognitoAuthenticationProvider.cpp @@ -40,7 +40,7 @@ namespace AWSClientAuth AZ_UNUSED(settingsRegistry); AWSCore::AWSResourceMappingRequestBus::BroadcastResult( m_cognitoAppClientId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoAppClientIdResourceMappingKey); - AZ_Warning("AWSCognitoAuthenticationProvider", m_cognitoAppClientId.empty(), "Missing Cognito App Client Id from resource mappings. Calls to Cognito will fail."); + AZ_Warning("AWSCognitoAuthenticationProvider", !m_cognitoAppClientId.empty(), "Missing Cognito App Client Id from resource mappings. Calls to Cognito will fail."); return !m_cognitoAppClientId.empty(); } diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp index 76d7c45c71..d4d2d0d67b 100644 --- a/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationProviderManager.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -25,12 +26,14 @@ namespace AWSClientAuth { AZ::Interface::Register(this); AuthenticationProviderRequestBus::Handler::BusConnect(); + AuthenticationProviderScriptCanvasRequestBus::Handler::BusConnect(); } AuthenticationProviderManager::~AuthenticationProviderManager() { ResetProviders(); m_settingsRegistry.reset(); + AuthenticationProviderScriptCanvasRequestBus::Handler::BusDisconnect(); AuthenticationProviderRequestBus::Handler::BusDisconnect(); AZ::Interface::Unregister(this); } @@ -38,12 +41,19 @@ namespace AWSClientAuth bool AuthenticationProviderManager::Initialize(const AZStd::vector& providerNames, const AZStd::string& settingsRegistryPath) { ResetProviders(); + AZ::IO::FileIOBase* fileIO = AZ::IO::FileIOBase::GetInstance(); + AZ_Assert(fileIO, "File IO is not initialized."); + m_settingsRegistry.reset(); m_settingsRegistry = AZStd::make_shared(); - if (!m_settingsRegistry->MergeSettingsFile(settingsRegistryPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch)) + AZStd::array resolvedPath{}; + fileIO->ResolvePath(settingsRegistryPath.data(), resolvedPath.data(), resolvedPath.size()); + + + if (!m_settingsRegistry->MergeSettingsFile(resolvedPath.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch)) { - AZ_Error("AuthenticationProviderManager", true, "Error merging settings registry for path: %s", settingsRegistryPath.c_str()); + AZ_Error("AuthenticationProviderManager", true, "Error merging settings registry for path: %s", resolvedPath.data()); return false; } @@ -112,6 +122,7 @@ namespace AWSClientAuth { AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensFail , "Provider is not initialized"); + return; } AuthenticationTokens tokens = m_authenticationProvidersMap[providerName]->GetAuthenticationTokens(); @@ -181,5 +192,77 @@ namespace AWSClientAuth } } + ProviderNameEnum AuthenticationProviderManager::GetProviderNameEnum(AZStd::string name) + { + auto enumValue = ProviderNameEnumNamespace::FromStringToProviderNameEnum(name); + if (enumValue.has_value()) + { + return enumValue.value(); + } + AZ_Warning("AuthenticationProviderManager", true, "Incorrect string value for enum: %s", name.c_str()); + return ProviderNameEnum::None; + } + + bool AuthenticationProviderManager::Initialize( + const AZStd::vector& providerNames, const AZStd::string& settingsRegistryPath) + { + AZStd::vector providerNamesEnum; + for (auto name : providerNames) + { + providerNamesEnum.push_back(GetProviderNameEnum(name)); + } + return Initialize(providerNamesEnum, settingsRegistryPath); + } + + void AuthenticationProviderManager::PasswordGrantSingleFactorSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) + { + PasswordGrantSingleFactorSignInAsync(GetProviderNameEnum(providerName), username, password); + } + + void AuthenticationProviderManager::PasswordGrantMultiFactorSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& password) + { + PasswordGrantMultiFactorSignInAsync(GetProviderNameEnum(providerName), username, password); + } + + void AuthenticationProviderManager::PasswordGrantMultiFactorConfirmSignInAsync(const AZStd::string& providerName, const AZStd::string& username, const AZStd::string& confirmationCode) + { + PasswordGrantMultiFactorConfirmSignInAsync(GetProviderNameEnum(providerName), username, confirmationCode); + } + + void AuthenticationProviderManager::DeviceCodeGrantSignInAsync(const AZStd::string& providerName) + { + DeviceCodeGrantSignInAsync(GetProviderNameEnum(providerName)); + } + + void AuthenticationProviderManager::DeviceCodeGrantConfirmSignInAsync(const AZStd::string& providerName) + { + DeviceCodeGrantConfirmSignInAsync(GetProviderNameEnum(providerName)); + } + + void AuthenticationProviderManager::RefreshTokensAsync(const AZStd::string& providerName) + { + RefreshTokensAsync(GetProviderNameEnum(providerName)); + } + + void AuthenticationProviderManager::GetTokensWithRefreshAsync(const AZStd::string& providerName) + { + GetTokensWithRefreshAsync(GetProviderNameEnum(providerName)); + } + + bool AuthenticationProviderManager::IsSignedIn(const AZStd::string& providerName) + { + return IsSignedIn(GetProviderNameEnum(providerName)); + } + + bool AuthenticationProviderManager::SignOut(const AZStd::string& providerName) + { + return SignOut(GetProviderNameEnum(providerName)); + } + + AuthenticationTokens AuthenticationProviderManager::GetAuthenticationTokens(const AZStd::string& providerName) + { + return GetAuthenticationTokens(GetProviderNameEnum(providerName)); + } + } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationTokens.cpp b/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationTokens.cpp index 9c078ad99c..737d6ae929 100644 --- a/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationTokens.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authentication/AuthenticationTokens.cpp @@ -79,4 +79,30 @@ namespace AWSClientAuth { return m_tokensExpireTimeSeconds; } + + void AuthenticationTokens::Reflect(AZ::ReflectContext* context) + { + auto serializeContext = azrtti_cast(context); + if (serializeContext) + { + serializeContext->Class() + ->Field("AccessToken", &AuthenticationTokens::m_accessToken) + ->Field("OpenIdToken", &AuthenticationTokens::m_openIdToken) + ->Field("RefreshToken", &AuthenticationTokens::m_refreshToken); + } + + AZ::BehaviorContext* behaviorContext = azrtti_cast(context); + if (behaviorContext) + { + behaviorContext->Class() + ->Attribute(AZ::Script::Attributes::Category, "AWSClientAuth") + ->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value) + ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common) + ->Constructor() + ->Constructor() + ->Property("AccessToken", BehaviorValueGetter(&AuthenticationTokens::m_accessToken), BehaviorValueSetter(&AuthenticationTokens::m_accessToken)) + ->Property("OpenIdToken", BehaviorValueGetter(&AuthenticationTokens::m_openIdToken), BehaviorValueSetter(&AuthenticationTokens::m_accessToken)) + ->Property("RefreshToken", BehaviorValueGetter(&AuthenticationTokens::m_refreshToken), BehaviorValueSetter(&AuthenticationTokens::m_accessToken)); + } + } } // namespace AWSClientAuth diff --git a/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp b/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp index 4c10d968fc..5e2c07bdbb 100644 --- a/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp +++ b/Gems/AWSClientAuth/Code/Source/Authorization/AWSCognitoAuthorizationController.cpp @@ -71,15 +71,15 @@ namespace AWSClientAuth if (m_awsAccountId.empty() || m_cognitoIdentityPoolId.empty()) { - AZ_Warning("AWSCognitoUserManagementController", m_awsAccountId.empty(), "Missing AWS account id in resource mappings."); - AZ_Warning("AWSCognitoUserManagementController", m_cognitoIdentityPoolId.empty(), "Missing Cognito Identity pool id in resource mappings."); + AZ_Warning("AWSCognitoAuthorizationController", !m_awsAccountId.empty(), "Missing AWS account id not configured."); + AZ_Warning("AWSCognitoAuthorizationController", !m_cognitoIdentityPoolId.empty(), "Missing Cognito Identity pool id in resource mappings."); return false; } AZStd::string userPoolId; AWSCore::AWSResourceMappingRequestBus::BroadcastResult( userPoolId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoUserPoolIdResourceMappingKey); - AZ_Warning("AWSCognitoUserManagementController", userPoolId.empty(), "Missing Cognito USer pool id in resource mappings. Cognito IDP authenticated identities will no work."); + AZ_Warning("AWSCognitoAuthorizationController", !userPoolId.empty(), "Missing Cognito User pool id in resource mappings. Cognito IDP authenticated identities will no work."); AZStd::string defaultRegion; AWSCore::AWSResourceMappingRequestBus::BroadcastResult( diff --git a/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp b/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp index 19d5d47d33..755b0e1f15 100644 --- a/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp +++ b/Gems/AWSClientAuth/Code/Source/UserManagement/AWSCognitoUserManagementController.cpp @@ -54,7 +54,7 @@ namespace AWSClientAuth AWSCore::AWSResourceMappingRequestBus::BroadcastResult( m_cognitoAppClientId, &AWSCore::AWSResourceMappingRequests::GetResourceNameId, CognitoAppClientIdResourceMappingKey); AZ_Warning( - "AWSCognitoUserManagementController", m_cognitoAppClientId.empty(), "Missing Cognito App Client Id from resource mappings. Calls to Cognito will fail."); + "AWSCognitoUserManagementController", !m_cognitoAppClientId.empty(), "Missing Cognito App Client Id from resource mappings. Calls to Cognito will fail."); return !m_cognitoAppClientId.empty(); } diff --git a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerMock.h b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerMock.h new file mode 100644 index 0000000000..e7b233c786 --- /dev/null +++ b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerMock.h @@ -0,0 +1,55 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#include +#include + +namespace AWSClientAuthUnitTest +{ + class AuthenticationProviderManagerLocalMock + : public AWSClientAuth::AuthenticationProviderManager + { + public: + using AWSClientAuth::AuthenticationProviderManager::DeviceCodeGrantConfirmSignInAsync; + using AWSClientAuth::AuthenticationProviderManager::DeviceCodeGrantSignInAsync; + using AWSClientAuth::AuthenticationProviderManager::GetAuthenticationTokens; + using AWSClientAuth::AuthenticationProviderManager::GetTokensWithRefreshAsync; + using AWSClientAuth::AuthenticationProviderManager::Initialize; + using AWSClientAuth::AuthenticationProviderManager::IsSignedIn; + using AWSClientAuth::AuthenticationProviderManager::m_authenticationProvidersMap; + using AWSClientAuth::AuthenticationProviderManager::PasswordGrantMultiFactorConfirmSignInAsync; + using AWSClientAuth::AuthenticationProviderManager::PasswordGrantMultiFactorSignInAsync; + using AWSClientAuth::AuthenticationProviderManager::PasswordGrantSingleFactorSignInAsync; + using AWSClientAuth::AuthenticationProviderManager::RefreshTokensAsync; + using AWSClientAuth::AuthenticationProviderManager::SignOut; + + AZStd::unique_ptr CreateAuthenticationProviderObjectMock( + const AWSClientAuth::ProviderNameEnum& providerName) + { + auto providerObject = AWSClientAuth::AuthenticationProviderManager::CreateAuthenticationProviderObject(providerName); + providerObject.reset(); + return AZStd::make_unique>(); + } + + AuthenticationProviderManagerLocalMock() + { + ON_CALL(*this, CreateAuthenticationProviderObject(testing::_)) + .WillByDefault(testing::Invoke(this, &AuthenticationProviderManagerLocalMock::CreateAuthenticationProviderObjectMock)); + } + + MOCK_METHOD1( + CreateAuthenticationProviderObject, + AZStd::unique_ptr(const AWSClientAuth::ProviderNameEnum&)); + }; +} // namespace AWSClientAuthUnitTest diff --git a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp new file mode 100644 index 0000000000..7673840299 --- /dev/null +++ b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp @@ -0,0 +1,261 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class AuthenticationProviderManagerScriptCanvasTest + : public AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture +{ +protected: + void SetUp() override + { + AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture::SetUp(); + + AWSClientAuth::LWAProviderSetting::Reflect(*m_serializeContext); + AWSClientAuth::GoogleProviderSetting::Reflect(*m_serializeContext); + + m_settingspath = AZStd::string::format("%s/%s/authenticationProvider.setreg", + m_testFolder->c_str(), AZ::SettingsRegistryInterface::RegistryFolder); + CreateTestFile("authenticationProvider.setreg" + , R"({ + "AWS": + { + "LoginWithAmazon": + { + "AppClientId": "TestLWAClientId", + "GrantType": "device_code", + "Scope": "profile", + "ResponseType": "device_code", + "OAuthCodeURL": "https://api.amazon.com/auth/o2/create/codepair", + "OAuthTokensURL": "https://oauth2.googleapis.com/token" + }, + "Google": + { + "AppClientId": "TestGoogleClientId", + "ClientSecret": "123", + "GrantType": "urn:ietf:params:oauth:grant-type:device_code", + "Scope": "profile", + "OAuthCodeURL": "https://oauth2.googleapis.com/device/code", + "OAuthTokensURL": "https://oauth2.googleapis.com/token" + } + } + })"); + + m_mockController = AZStd::make_unique>(); + } + + void TearDown() override + { + m_mockController.reset(); + AWSClientAuthUnitTest::AWSClientAuthGemAllocatorFixture::TearDown(); + } + +public: + AZStd::unique_ptr> m_mockController; + AZStd::string m_settingspath; + AZStd::vector m_enabledProviderNames { AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP, + AWSClientAuth::ProvideNameEnumStringLoginWithAmazon, AWSClientAuth::ProvideNameEnumStringGoogle}; +}; + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, Initialize_Success) +{ + ASSERT_TRUE(m_mockController->Initialize(m_enabledProviderNames, m_settingspath)); + ASSERT_TRUE(m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP] != nullptr); +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, PasswordGrantSingleFactorSignInAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock *cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + + EXPECT_CALL(*cognitoProviderMock, PasswordGrantSingleFactorSignInAsync(testing::_, testing::_)).Times(1); + m_mockController->PasswordGrantSingleFactorSignInAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, PasswordGrantSingleFactorSignInAsync_Fail_NonConfiguredProviderError) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + m_mockController->PasswordGrantSingleFactorSignInAsync(AWSClientAuth::ProvideNameEnumStringApple, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, PasswordGrantMultiFactorSignInAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + testing::NiceMock* lwaProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::LoginWithAmazon].get(); + + EXPECT_CALL(*cognitoProviderMock, PasswordGrantMultiFactorSignInAsync(testing::_, testing::_)).Times(1); + m_mockController->PasswordGrantMultiFactorSignInAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + + EXPECT_CALL(*lwaProviderMock, PasswordGrantMultiFactorSignInAsync(testing::_, testing::_)).Times(1); + m_mockController->PasswordGrantMultiFactorSignInAsync(AWSClientAuth::ProvideNameEnumStringLoginWithAmazon, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, PasswordGrantMultiFactorConfirmSignInAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock *cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + testing::NiceMock *lwaProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::LoginWithAmazon].get(); + + EXPECT_CALL(*cognitoProviderMock, PasswordGrantMultiFactorConfirmSignInAsync(testing::_, testing::_)).Times(1); + m_mockController->PasswordGrantMultiFactorConfirmSignInAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + + EXPECT_CALL(*lwaProviderMock, PasswordGrantMultiFactorConfirmSignInAsync(testing::_, testing::_)).Times(1); + m_mockController->PasswordGrantMultiFactorConfirmSignInAsync(AWSClientAuth::ProvideNameEnumStringLoginWithAmazon, AWSClientAuthUnitTest::TEST_USERNAME, AWSClientAuthUnitTest::TEST_PASSWORD); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, DeviceCodeGrantSignInAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + testing::NiceMock* lwaProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::LoginWithAmazon].get(); + + EXPECT_CALL(*cognitoProviderMock, DeviceCodeGrantSignInAsync()).Times(1); + m_mockController->DeviceCodeGrantSignInAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + EXPECT_CALL(*lwaProviderMock, DeviceCodeGrantSignInAsync()).Times(1); + m_mockController->DeviceCodeGrantSignInAsync(AWSClientAuth::ProvideNameEnumStringLoginWithAmazon); + + cognitoProviderMock = nullptr; +} + + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, DeviceCodeGrantConfirmSignInAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + testing::NiceMock* lwaProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::LoginWithAmazon].get(); + + EXPECT_CALL(*cognitoProviderMock, DeviceCodeGrantConfirmSignInAsync()).Times(1); + m_mockController->DeviceCodeGrantConfirmSignInAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + EXPECT_CALL(*lwaProviderMock, DeviceCodeGrantConfirmSignInAsync()).Times(1); + m_mockController->DeviceCodeGrantConfirmSignInAsync(AWSClientAuth::ProvideNameEnumStringLoginWithAmazon); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, RefreshTokenAsync_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock *cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + testing::NiceMock *lwaProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::LoginWithAmazon].get(); + + EXPECT_CALL(*cognitoProviderMock, RefreshTokensAsync()).Times(1); + m_mockController->RefreshTokensAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + EXPECT_CALL(*lwaProviderMock, RefreshTokensAsync()).Times(1); + m_mockController->RefreshTokensAsync(AWSClientAuth::ProvideNameEnumStringLoginWithAmazon); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, GetTokensWithRefreshAsync_ValidToken_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + + AWSClientAuth::AuthenticationTokens tokens( + AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, + AWSClientAuth::ProviderNameEnum::AWSCognitoIDP, 600); + EXPECT_CALL(*cognitoProviderMock, GetAuthenticationTokens()).Times(1).WillOnce(testing::Return(tokens)); + EXPECT_CALL(*cognitoProviderMock, RefreshTokensAsync()).Times(0); + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnRefreshTokensSuccess(testing::_)).Times(1); + m_mockController->GetTokensWithRefreshAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, GetTokensWithRefreshAsync_InvalidToken_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + AWSClientAuth::AuthenticationTokens tokens; + EXPECT_CALL(*cognitoProviderMock, GetAuthenticationTokens()).Times(1).WillOnce(testing::Return(tokens)); + EXPECT_CALL(*cognitoProviderMock, RefreshTokensAsync()).Times(1); + m_mockController->GetTokensWithRefreshAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, GetTokensWithRefreshAsync_NotInitializedProvider_Fail) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnRefreshTokensSuccess(testing::_)).Times(0); + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnRefreshTokensFail(testing::_)).Times(1); + m_mockController->GetTokensWithRefreshAsync(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, GetTokens_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + + AWSClientAuth::AuthenticationTokens tokens( + AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, + AWSClientAuth::ProviderNameEnum::AWSCognitoIDP, 60); + + EXPECT_CALL(*cognitoProviderMock, GetAuthenticationTokens()).Times(1).WillOnce(testing::Return(tokens)); + m_mockController->GetAuthenticationTokens(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, IsSignedIn_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* cognitoProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::AWSCognitoIDP].get(); + + AWSClientAuth::AuthenticationTokens tokens( + AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, AWSClientAuthUnitTest::TEST_TOKEN, + AWSClientAuth::ProviderNameEnum::AWSCognitoIDP, 60); + EXPECT_CALL(*cognitoProviderMock, GetAuthenticationTokens()).Times(1).WillOnce(testing::Return(tokens)); + m_mockController->IsSignedIn(AWSClientAuth::ProvideNameEnumStringAWSCognitoIDP); + + cognitoProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, SignOut_Success) +{ + m_mockController->Initialize(m_enabledProviderNames, m_settingspath); + testing::NiceMock* googleProviderMock = (testing::NiceMock*)m_mockController->m_authenticationProvidersMap[AWSClientAuth::ProviderNameEnum::Google].get(); + + EXPECT_CALL(*googleProviderMock, SignOut()).Times(1); + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnSignOut(testing::_)).Times(1); + m_mockController->SignOut(AWSClientAuth::ProvideNameEnumStringGoogle); + + googleProviderMock = nullptr; +} + +TEST_F(AuthenticationProviderManagerScriptCanvasTest, Initialize_Fail_InvalidPath) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + ASSERT_FALSE(m_mockController->Initialize(m_enabledProviderNames, "")); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); +} diff --git a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp index 9e7d189f5d..4b5bdfb841 100644 --- a/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp +++ b/Gems/AWSClientAuth/Code/Tests/Authentication/AuthenticationProviderManagerTest.cpp @@ -10,8 +10,6 @@ * */ -#include -#include #include #include #include @@ -20,42 +18,7 @@ #include #include #include - -namespace AWSClientAuthUnitTest -{ - class AuthenticationProviderManagerLocalMock - : public AWSClientAuth::AuthenticationProviderManager - { - public: - using AWSClientAuth::AuthenticationProviderManager::m_authenticationProvidersMap; - using AWSClientAuth::AuthenticationProviderManager::Initialize; - using AWSClientAuth::AuthenticationProviderManager::PasswordGrantSingleFactorSignInAsync; - using AWSClientAuth::AuthenticationProviderManager::PasswordGrantMultiFactorSignInAsync; - using AWSClientAuth::AuthenticationProviderManager::PasswordGrantMultiFactorConfirmSignInAsync; - using AWSClientAuth::AuthenticationProviderManager::DeviceCodeGrantSignInAsync; - using AWSClientAuth::AuthenticationProviderManager::DeviceCodeGrantConfirmSignInAsync; - using AWSClientAuth::AuthenticationProviderManager::RefreshTokensAsync; - using AWSClientAuth::AuthenticationProviderManager::GetTokensWithRefreshAsync; - using AWSClientAuth::AuthenticationProviderManager::GetAuthenticationTokens; - using AWSClientAuth::AuthenticationProviderManager::SignOut; - using AWSClientAuth::AuthenticationProviderManager::IsSignedIn; - - AZStd::unique_ptr CreateAuthenticationProviderObjectMock(const AWSClientAuth::ProviderNameEnum& providerName) - { - auto providerObject = AWSClientAuth::AuthenticationProviderManager::CreateAuthenticationProviderObject(providerName); - providerObject.reset(); - return AZStd::make_unique>(); - } - - AuthenticationProviderManagerLocalMock() - { - ON_CALL(*this, CreateAuthenticationProviderObject(testing::_)).WillByDefault( - testing::Invoke(this, &AuthenticationProviderManagerLocalMock::CreateAuthenticationProviderObjectMock)); - } - - MOCK_METHOD1(CreateAuthenticationProviderObject, AZStd::unique_ptr(const AWSClientAuth::ProviderNameEnum&)); - }; -} +#include class AuthenticationProviderManagerTest @@ -239,6 +202,15 @@ TEST_F(AuthenticationProviderManagerTest, GetTokensWithRefreshAsync_InvalidToken cognitoProviderMock = nullptr; } +TEST_F(AuthenticationProviderManagerTest, GetTokensWithRefreshAsync_NotInitializedProvider_Fail) +{ + AZ_TEST_START_TRACE_SUPPRESSION; + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnRefreshTokensSuccess(testing::_)).Times(0); + EXPECT_CALL(m_authenticationProviderNotificationsBusMock, OnRefreshTokensFail(testing::_)).Times(1); + m_mockController->GetTokensWithRefreshAsync(AWSClientAuth::ProviderNameEnum::AWSCognitoIDP); + AZ_TEST_STOP_TRACE_SUPPRESSION(1); +} + TEST_F(AuthenticationProviderManagerTest, GetTokens_Success) { m_mockController->Initialize(m_enabledProviderNames, m_settingspath); diff --git a/Gems/AWSClientAuth/Code/awsclientauth_files.cmake b/Gems/AWSClientAuth/Code/awsclientauth_files.cmake index 79da00076c..7e4734992f 100644 --- a/Gems/AWSClientAuth/Code/awsclientauth_files.cmake +++ b/Gems/AWSClientAuth/Code/awsclientauth_files.cmake @@ -20,6 +20,7 @@ set(FILES Include/Private/AWSClientAuthBus.h Include/Private/AWSClientAuthResourceMappingConstants.h Include/Private/Authentication/AuthenticationProviderTypes.h + Include/Private/Authentication/AuthenticationProviderScriptCanvasBus.h Include/Private/Authentication/AuthenticationProviderManager.h Include/Private/Authentication/AuthenticationNotificationBusBehaviorHandler.h diff --git a/Gems/AWSClientAuth/Code/awsclientauth_test_files.cmake b/Gems/AWSClientAuth/Code/awsclientauth_test_files.cmake index 6d3de7cc54..18aaa697dd 100644 --- a/Gems/AWSClientAuth/Code/awsclientauth_test_files.cmake +++ b/Gems/AWSClientAuth/Code/awsclientauth_test_files.cmake @@ -14,7 +14,9 @@ set(FILES Tests/AWSClientAuthGemTest.cpp Tests/AWSClientAuthSystemComponentTest.cpp + Tests/Authentication/AuthenticationProviderManagerMock.h Tests/Authentication/AuthenticationProviderManagerTest.cpp + Tests/Authentication/AuthenticationProviderManagerScriptCanvasBusTest.cpp Tests/Authentication/AWSCognitoAuthenticationProviderTest.cpp Tests/Authentication/LWAAuthenticationProviderTest.cpp Tests/Authentication/GoogleAuthenticationProviderTest.cpp diff --git a/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py b/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py index 0ebef83eba..3a2e413617 100755 --- a/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py +++ b/Gems/AWSClientAuth/cdk/auth/cognito_identity_pool_role.py @@ -56,8 +56,7 @@ class CognitoIdentityPoolRole: # basic permissions stack_statement = iam.PolicyStatement( actions=[ - 's3:Get*', - 's3:List*' + 's3:ListBuckets' ], effect=iam.Effect.ALLOW, resources=[ diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index 034d0c7cf2..1e3c7b6759 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -162,7 +162,7 @@ namespace AZ AZStd::string expectedHigherPrecedenceFileFullPath; AzFramework::StringFunc::Path::Join(gameProjectPath, RPI::ShaderVariantTreeAsset::CommonSubFolder, expectedHigherPrecedenceFileFullPath, false /* handle directory overlap? */, false /* be case insensitive? */); AzFramework::StringFunc::Path::Join(expectedHigherPrecedenceFileFullPath.c_str(), shaderProductFileRelativePath.c_str(), expectedHigherPrecedenceFileFullPath, false /* handle directory overlap? */, false /* be case insensitive? */); - AzFramework::StringFunc::Path::ReplaceExtension(expectedHigherPrecedenceFileFullPath, AZ::RPI::ShaderVariantAsset::Extension); + AzFramework::StringFunc::Path::ReplaceExtension(expectedHigherPrecedenceFileFullPath, AZ::RPI::ShaderVariantListSourceData::Extension); AzFramework::StringFunc::Path::Normalize(expectedHigherPrecedenceFileFullPath); AZStd::string normalizedShaderVariantListFileFullPath = shaderVariantListFileFullPath; diff --git a/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/Materials/basic_grey.material b/Gems/Atom/Feature/Common/Assets/Materials/basic_grey.material similarity index 100% rename from Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/Materials/basic_grey.material rename to Gems/Atom/Feature/Common/Assets/Materials/basic_grey.material diff --git a/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapForwardMSAA.pass b/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapForwardMSAA.pass index 60de5e10b9..aa422aa227 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapForwardMSAA.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapForwardMSAA.pass @@ -49,11 +49,6 @@ "IsArray": 1 } }, - { - "Name": "DepthStencilInputOutput", - "SlotType": "InputOutput", - "ScopeAttachmentUsage": "DepthStencil" - }, { "Name": "TileLightData", "SlotType": "Input", @@ -66,6 +61,13 @@ "ShaderInputName": "m_lightListRemapped", "ScopeAttachmentUsage": "Shader" }, + // Input/Outputs... + { + "Name": "DepthStencilInputOutput", + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "DepthStencil" + }, + // Outputs... { "Name": "DiffuseOutput", "SlotType": "Output", @@ -222,11 +224,12 @@ "Attachment": "Output" } }, + "MultisampleSource": { + "Pass": "This", + "Attachment": "DepthStencilInputOutput" + }, "ImageDescriptor": { "Format": "R8G8B8A8_UNORM", - "MultisampleState": { - "samples": 4 - }, "SharedQueueMask": "Graphics" } }, diff --git a/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapPipeline.pass b/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapPipeline.pass index 79a42b11f7..0e2fb93359 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapPipeline.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapPipeline.pass @@ -9,7 +9,8 @@ "Slots": [ { "Name": "Output", - "SlotType": 2 + "SlotType": "InputOutput", + "ScopeAttachmentUsage": "RenderTarget" } ], "PassRequests": [ @@ -101,13 +102,8 @@ ] }, { - "Name": "DepthMSAAPass", - "TemplateName": "EnvironmentCubeMapDepthMSAAPassTemplate", - "PassData": { - "$type": "RasterPassData", - "DrawListTag": "depth", - "PipelineViewTag": "MainCamera" - }, + "Name": "DepthPrePass", + "TemplateName": "DepthMSAAParentTemplate", "Connections": [ { "LocalSlot": "SkinnedMeshes", @@ -115,70 +111,11 @@ "Pass": "SkinningPass", "Attachment": "SkinnedMeshOutputStream" } - } - ] - }, - // The light culling system can do highly accurate culling of transparent objects but it needs - // more depth information than the opaque geometry pass can provide - // Specifically the minimum and maximum depth of transparent objects - { - "Name": "DepthTransparentMinPass", - "TemplateName": "DepthPassTemplate", - "PassData": { - "$type": "RasterPassData", - "DrawListTag": "depthTransparentMin", - "PipelineViewTag": "MainCamera" - }, - "Connections": [ - { - "LocalSlot": "SkinnedMeshes", - "AttachmentRef": { - "Pass": "SkinningPass", - "Attachment": "SkinnedMeshOutputStream" - } - } - ] - }, - { - "Name": "DepthTransparentMaxPass", - "TemplateName": "DepthMaxPassTemplate", - "PassData": { - "$type": "RasterPassData", - "DrawListTag": "depthTransparentMax", - "PipelineViewTag": "MainCamera" - }, - "Connections": [ - { - "LocalSlot": "SkinnedMeshes", - "AttachmentRef": { - "Pass": "SkinningPass", - "Attachment": "SkinnedMeshOutputStream" - } - } - ] - }, - { - "Name": "LightCullingTilePreparePass", - "TemplateName": "LightCullingTilePrepareMSAATemplate", - "Connections": [ - { - "LocalSlot": "Depth", - "AttachmentRef": { - "Pass": "DepthMSAAPass", - "Attachment": "Output" - } }, { - "LocalSlot": "DepthTransparentMin", + "LocalSlot": "SwapChainOutput", "AttachmentRef": { - "Pass": "DepthTransparentMinPass", - "Attachment": "Output" - } - }, - { - "LocalSlot": "DepthTransparentMax", - "AttachmentRef": { - "Pass": "DepthTransparentMaxPass", + "Pass": "Parent", "Attachment": "Output" } } @@ -186,40 +123,27 @@ }, { "Name": "LightCullingPass", - "TemplateName": "LightCullingTemplate", + "TemplateName": "LightCullingParentTemplate", "Connections": [ { - "LocalSlot": "TileLightData", + "LocalSlot": "SkinnedMeshes", "AttachmentRef": { - "Pass": "LightCullingTilePreparePass", - "Attachment": "TileLightData" - } - } - ] - }, - { - "Name": "LightCullingRemapPass", - "TemplateName": "LightCullingRemapTemplate", - "Connections": [ - { - "LocalSlot": "TileLightData", - "AttachmentRef": { - "Pass": "LightCullingTilePreparePass", - "Attachment": "TileLightData" + "Pass": "SkinningPass", + "Attachment": "SkinnedMeshOutputStream" } }, { - "LocalSlot": "LightCount", + "LocalSlot": "DepthMSAA", "AttachmentRef": { - "Pass": "LightCullingPass", - "Attachment": "LightCount" + "Pass": "DepthPrePass", + "Attachment": "DepthMSAA" } }, { - "LocalSlot": "LightList", + "LocalSlot": "SwapChainOutput", "AttachmentRef": { - "Pass": "LightCullingPass", - "Attachment": "LightList" + "Pass": "Parent", + "Attachment": "Output" } } ] @@ -259,21 +183,21 @@ { "LocalSlot": "DepthStencilInputOutput", "AttachmentRef": { - "Pass": "DepthMSAAPass", - "Attachment": "Output" + "Pass": "DepthPrePass", + "Attachment": "DepthMSAA" } }, { "LocalSlot": "TileLightData", "AttachmentRef": { - "Pass": "LightCullingRemapPass", + "Pass": "LightCullingPass", "Attachment": "TileLightData" } }, { "LocalSlot": "LightListRemapped", "AttachmentRef": { - "Pass": "LightCullingRemapPass", + "Pass": "LightCullingPass", "Attachment": "LightListRemapped" } } diff --git a/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapSkyBox.pass b/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapSkyBox.pass index b16cd1cbcc..4c74f9e967 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapSkyBox.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/EnvironmentCubeMapSkyBox.pass @@ -32,11 +32,12 @@ "Attachment": "SpecularInputOutput" } }, + "MultisampleSource": { + "Pass": "This", + "Attachment": "SpecularInputOutput" + }, "ImageDescriptor": { "Format": "R16G16B16A16_FLOAT", - "MultisampleState": { - "samples": 4 - }, "SharedQueueMask": "Graphics" } } diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h index a595471813..7ad8bd8283 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Mesh/MeshFeatureProcessor.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace AZ { @@ -160,8 +161,14 @@ namespace AZ // called when reflection probes are modified in the editor so that meshes can re-evaluate their probes void UpdateMeshReflectionProbes(); - private: + void ForceRebuildDrawPackets(const AZ::ConsoleCommandContainer& arguments); + AZ_CONSOLEFUNC(MeshFeatureProcessor, + ForceRebuildDrawPackets, + AZ::ConsoleFunctorFlags::Null, + "(For Testing) Invalidates all mesh draw packets, causing them to rebuild on the next frame." + ); + MeshFeatureProcessor(const MeshFeatureProcessor&) = delete; // RPI::SceneNotificationBus::Handler overrides... diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/LightingPreset.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/LightingPreset.h index 1c220e0d8d..f1d8337a35 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/LightingPreset.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/LightingPreset.h @@ -78,7 +78,6 @@ namespace AZ AZ_CLASS_ALLOCATOR(LightingPreset, AZ::SystemAllocator, 0); static void Reflect(AZ::ReflectContext* context); - bool m_autoSelect = false; AZStd::string m_displayName; AZ::Data::Asset m_iblDiffuseImageAsset; AZ::Data::Asset m_iblSpecularImageAsset; diff --git a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/ModelPreset.h b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/ModelPreset.h index 896d6fb78f..9ca8c13859 100644 --- a/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/ModelPreset.h +++ b/Gems/Atom/Feature/Common/Code/Include/Atom/Feature/Utils/ModelPreset.h @@ -32,7 +32,6 @@ namespace AZ AZ_CLASS_ALLOCATOR(ModelPreset, AZ::SystemAllocator, 0); static void Reflect(AZ::ReflectContext* context); - bool m_autoSelect = false; AZStd::string m_displayName; AZ::Data::Asset m_modelAsset; AZ::Data::Asset m_previewImageAsset; diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp index fd4b5b28d1..dc53498c8b 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.cpp @@ -289,7 +289,7 @@ namespace AZ void AuxGeomDrawQueue::DrawQuad( float width, float height, - const AZ::Transform& transform, + const AZ::Matrix3x4& transform, const AZ::Color& color, DrawStyle style, DepthTest depthTest, @@ -302,8 +302,8 @@ namespace AZ return; } - Transform noScaleTransform = transform; - noScaleTransform.ExtractScale(); + AZ::Matrix3x4 noScaleTransform = transform; + AZ::Vector3 scale = noScaleTransform.ExtractScale(); ShapeBufferEntry shape; shape.m_shapeType = ShapeType_Quad; @@ -311,9 +311,9 @@ namespace AZ shape.m_depthWrite = ConvertRPIDepthWriteFlag(depthWrite); shape.m_faceCullMode = ConvertRPIFaceCullFlag(faceCull); shape.m_color = color; - shape.m_rotationMatrix = Matrix3x3::CreateFromTransform(noScaleTransform); + shape.m_rotationMatrix = Matrix3x3::CreateFromMatrix3x4(noScaleTransform); shape.m_position = transform.GetTranslation(); - shape.m_scale = transform.GetScale() * Vector3(width, 1.0f, height); + shape.m_scale = scale * Vector3(width, 1.0f, height); shape.m_pointSize = m_pointSize; shape.m_viewProjOverrideIndex = viewProjOverrideIndex; diff --git a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h index b959173ed1..53220c031d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h +++ b/Gems/Atom/Feature/Common/Code/Source/AuxGeom/AuxGeomDrawQueue.h @@ -62,7 +62,7 @@ namespace AZ void DrawTriangles(const AuxGeomDynamicIndexedDrawArguments& args, FaceCullMode faceCull = FaceCullMode::None) override; // Fixed shape draws - void DrawQuad(float width, float height, const AZ::Transform& transform, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; + void DrawQuad(float width, float height, const AZ::Matrix3x4& transform, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawSphere(const AZ::Vector3& center, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawDisk(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; void DrawCone(const AZ::Vector3& center, const AZ::Vector3& direction, float radius, float height, const AZ::Color& color, DrawStyle style, DepthTest depthTest, DepthWrite depthWrite, FaceCullMode faceCull, int32_t viewProjOverrideIndex) override; diff --git a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp index 95bbe13586..5f39c6bc38 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Mesh/MeshFeatureProcessor.cpp @@ -387,6 +387,11 @@ namespace AZ } } + void MeshFeatureProcessor::ForceRebuildDrawPackets([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + { + m_forceRebuildDrawPackets = true; + } + void MeshFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline) { m_forceRebuildDrawPackets = true;; diff --git a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp index 206e58d5e6..e0ff253301 100644 --- a/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/PostProcessing/BlendColorGradingLutsPass.cpp @@ -131,8 +131,13 @@ namespace AZ AZ_Assert(m_blendedLut.m_lutImage != nullptr, "BlendColorGradingLutsPass unable to acquire LUT image"); AZ::RHI::AttachmentId imageAttachmentId = AZ::RHI::AttachmentId("BlendColorGradingLutImageAttachmentId"); - [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportImage(imageAttachmentId, m_blendedLut.m_lutImage); - AZ_Error("BlendColorGradingLutsPass", result == RHI::ResultCode::Success, "Failed to import compute buffer with error %d", result); + + // import this attachment if it wasn't imported + if (!frameGraph.GetAttachmentDatabase().IsAttachmentValid(imageAttachmentId)) + { + [[maybe_unused]] RHI::ResultCode result = frameGraph.GetAttachmentDatabase().ImportImage(imageAttachmentId, m_blendedLut.m_lutImage); + AZ_Error("BlendColorGradingLutsPass", result == RHI::ResultCode::Success, "Failed to import BlendColorGradingLutImageAttachmentId with error %d", result); + } RHI::ImageScopeAttachmentDescriptor desc; desc.m_attachmentId = imageAttachmentId; diff --git a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp index 38c30d67a6..9cc98a15ec 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ProfilingCaptureSystemComponent.cpp @@ -186,7 +186,7 @@ namespace AZ { for (const RPI::Pass* pass : passes) { - m_timestampEntries.push_back({ pass->GetName(), pass->GetTimestampResult().GetTimestampInNanoseconds() }); + m_timestampEntries.push_back({pass->GetName(), pass->GetLatestTimestampResult().GetDurationInNanoseconds()}); } } @@ -223,7 +223,7 @@ namespace AZ { for (const RPI::Pass* pass : passes) { - m_pipelineStatisticsEntries.push_back({ pass->GetName(), pass->GetPipelineStatisticsResult() }); + m_pipelineStatisticsEntries.push_back({pass->GetName(), pass->GetLatestPipelineStatisticsResult()}); } } diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp index 86c012731c..0826739119 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbe.cpp @@ -248,6 +248,9 @@ namespace AZ AZ::RPI::RenderPipelineDescriptor environmentCubeMapPipelineDesc; environmentCubeMapPipelineDesc.m_mainViewTagName = "MainCamera"; + environmentCubeMapPipelineDesc.m_renderSettings.m_multisampleState.m_samples = 4; + environmentCubeMapPipelineDesc.m_renderSettings.m_size.m_width = RPI::EnvironmentCubeMapPass::CubeMapFaceSize; + environmentCubeMapPipelineDesc.m_renderSettings.m_size.m_height = RPI::EnvironmentCubeMapPass::CubeMapFaceSize; // create a unique name for the pipeline AZ::Uuid uuid = AZ::Uuid::CreateRandom(); diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/EditorLightingPreset.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/EditorLightingPreset.cpp index e7f9c8b09f..1da9463bd8 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/EditorLightingPreset.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/EditorLightingPreset.cpp @@ -112,7 +112,6 @@ namespace AZ ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_displayName, "Display Name", "Identifier used for display and selection") - ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_autoSelect, "Auto Select", "When true, the configuration is automatically selected when loaded") ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_iblDiffuseImageAsset, "IBL Diffuse Image Asset", "IBL diffuse image asset reference") ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_iblSpecularImageAsset, "IBL Specular Image Asset", "IBL specular image asset reference") ->DataElement(AZ::Edit::UIHandlers::Default, &LightingPreset::m_skyboxImageAsset, "Skybox Image Asset", "Skybox image asset reference") diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/EditorModelPreset.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/EditorModelPreset.cpp index b8b0b610f3..bed320c45d 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/EditorModelPreset.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/EditorModelPreset.cpp @@ -32,7 +32,6 @@ namespace AZ ->ClassElement(AZ::Edit::ClassElements::EditorData, "") ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(AZ::Edit::UIHandlers::Default, &ModelPreset::m_displayName, "Display Name", "Identifier used for display and selection") - ->DataElement(AZ::Edit::UIHandlers::Default, &ModelPreset::m_autoSelect, "Auto Select", "When true, the configuration is automatically selected when loaded") ->DataElement(AZ::Edit::UIHandlers::Default, &ModelPreset::m_modelAsset, "Model Asset", "Model asset reference") ->DataElement(AZ::Edit::UIHandlers::Default, &ModelPreset::m_previewImageAsset, "Preview Image Asset", "Preview image asset reference") ; diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp index 837a725a9f..77924b87a3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/LightingPreset.cpp @@ -105,8 +105,7 @@ namespace AZ serializeContext->RegisterGenericType>(); serializeContext->Class() - ->Version(4) - ->Field("autoSelect", &LightingPreset::m_autoSelect) + ->Version(5) ->Field("displayName", &LightingPreset::m_displayName) ->Field("iblDiffuseImageAsset", &LightingPreset::m_iblDiffuseImageAsset) ->Field("iblSpecularImageAsset", &LightingPreset::m_iblSpecularImageAsset) @@ -128,7 +127,6 @@ namespace AZ ->Attribute(AZ::Script::Attributes::Module, "render") ->Constructor() ->Constructor() - ->Property("autoSelect", BehaviorValueProperty(&LightingPreset::m_autoSelect)) ->Property("displayName", BehaviorValueProperty(&LightingPreset::m_displayName)) ->Property("alternateSkyboxImageAsset", BehaviorValueProperty(&LightingPreset::m_alternateSkyboxImageAsset)) ->Property("skyboxImageAsset", BehaviorValueProperty(&LightingPreset::m_skyboxImageAsset)) diff --git a/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp b/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp index e93bfa527a..2795617c18 100644 --- a/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/Utils/ModelPreset.cpp @@ -25,8 +25,7 @@ namespace AZ if (auto serializeContext = azrtti_cast(context)) { serializeContext->Class() - ->Version(2) - ->Field("autoSelect", &ModelPreset::m_autoSelect) + ->Version(3) ->Field("displayName", &ModelPreset::m_displayName) ->Field("modelAsset", &ModelPreset::m_modelAsset) ->Field("previewImageAsset", &ModelPreset::m_previewImageAsset) @@ -41,7 +40,6 @@ namespace AZ ->Attribute(AZ::Script::Attributes::Module, "render") ->Constructor() ->Constructor() - ->Property("autoSelect", BehaviorValueProperty(&ModelPreset::m_autoSelect)) ->Property("displayName", BehaviorValueProperty(&ModelPreset::m_displayName)) ->Property("modelAsset", BehaviorValueProperty(&ModelPreset::m_modelAsset)) ->Property("previewImageAsset", BehaviorValueProperty(&ModelPreset::m_previewImageAsset)) diff --git a/Gems/Atom/RHI/Code/Source/RHI.Reflect/Base.cpp b/Gems/Atom/RHI/Code/Source/RHI.Reflect/Base.cpp index 4d35411e09..21eb634159 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Reflect/Base.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Reflect/Base.cpp @@ -16,6 +16,6 @@ namespace AZ { namespace RHI { - bool Validation::s_isEnabled = BuildOptions::IsDebugBuild; + bool Validation::s_isEnabled = BuildOptions::IsDebugBuild || BuildOptions::IsProfileBuild; } } diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp index 1ae8a4ae96..7fc1db179a 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/FrameGraphCompiler.cpp @@ -404,6 +404,12 @@ namespace AZ Buffer& buffer = static_cast(*bufferFrameAttachment.GetBuffer()); RHI::BufferScopeAttachment* scopeAttachment = bufferFrameAttachment.GetFirstScopeAttachment(); + if (scopeAttachment == nullptr) + { + AZ_WarningOnce("RHI", false, "Imported BufferFrameAttachment isn't used in any Scope"); + return; + } + D3D12_RESOURCE_TRANSITION_BARRIER transition; transition.pResource = buffer.GetMemoryView().GetMemory(); transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; @@ -471,6 +477,12 @@ namespace AZ Image& image = static_cast(*imageFrameAttachment.GetImage()); RHI::ImageScopeAttachment* scopeAttachment = imageFrameAttachment.GetFirstScopeAttachment(); + if (scopeAttachment == nullptr) + { + AZ_WarningOnce("RHI", false, "Imported ImageFrameAttachment isn't used in any Scope"); + return; + } + D3D12_RESOURCE_TRANSITION_BARRIER transition; transition.pResource = image.GetMemoryView().GetMemory(); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h index afba71a457..0e7f11e46e 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/AuxGeom/AuxGeomDraw.h @@ -138,7 +138,7 @@ namespace AZ //! @param depthWrite If depth writing should be enabled //! @param faceCull Which (if any) facing triangles should be culled //! @param viewProjOverrideIndex Which view projection override entry to use, -1 if unused - virtual void DrawQuad(float width, float height, const AZ::Transform& transform, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0; + virtual void DrawQuad(float width, float height, const AZ::Matrix3x4& transform, const AZ::Color& color, DrawStyle style = DrawStyle::Shaded, DepthTest depthTest = DepthTest::On, DepthWrite depthWrite = DepthWrite::On, FaceCullMode faceCull = FaceCullMode::Back, int32_t viewProjOverrideIndex = -1) = 0; //! Draw a sphere. //! @param center The center of the sphere. diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/GpuQuery/GpuQueryTypes.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/GpuQuery/GpuQueryTypes.h index 80a72aaf55..ae86557170 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/GpuQuery/GpuQueryTypes.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/GpuQuery/GpuQueryTypes.h @@ -11,6 +11,7 @@ */ #pragma once +#include #include #include @@ -43,15 +44,19 @@ namespace AZ { public: TimestampResult() = default; - TimestampResult(uint64_t timestampInTicks); - TimestampResult(uint64_t timestampQueryResultLow, uint64_t timestampQueryResultHigh); - TimestampResult(AZStd::array_view&& timestampResultArray); + TimestampResult(uint64_t beginTick, uint64_t endTick, RHI::HardwareQueueClass hardwareQueueClass); - uint64_t GetTimestampInNanoseconds() const; - uint64_t GetTimestampInTicks() const; + uint64_t GetDurationInNanoseconds() const; + uint64_t GetDurationInTicks() const; + uint64_t GetTimestampBeginInTicks() const; + + void Add(const TimestampResult& extent); private: - uint64_t m_timestampInTicks = 0u; + // the timestamp of begin and duration in ticks. + uint64_t m_begin = 0; + uint64_t m_duration = 0; + RHI::HardwareQueueClass m_hardwareQueueClass = RHI::HardwareQueueClass::Graphics; }; //! The structure that is used to read back the results form the PipelineStatistics queries diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h index 9317158437..b4f63a7099 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/ParentPass.h @@ -122,7 +122,6 @@ namespace AZ private: // RPI::Pass overrides... - TimestampResult GetTimestampResultInternal() const override; PipelineStatisticsResult GetPipelineStatisticsResultInternal() const override; // --- Hierarchy related functions --- diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h index ae249a5f45..b0d6bd4117 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Pass/Pass.h @@ -211,11 +211,11 @@ namespace AZ //! Prints the pass virtual void DebugPrint() const; - //! Return the Timestamp result of this pass - TimestampResult GetTimestampResult() const; + //! Return the latest Timestamp result of this pass + TimestampResult GetLatestTimestampResult() const; - //! Return the PipelineStatistic result of this pass - PipelineStatisticsResult GetPipelineStatisticsResult() const; + //! Return the latest PipelineStatistic result of this pass + PipelineStatisticsResult GetLatestPipelineStatisticsResult() const; //! Enables/Disables Timestamp queries for this pass virtual void SetTimestampQueryEnabled(bool enable); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Builders/ResourcePool/ResourcePoolBuilder.cpp b/Gems/Atom/RPI/Code/Source/RPI.Builders/ResourcePool/ResourcePoolBuilder.cpp index 7f617f4c6c..92c30c28b1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Builders/ResourcePool/ResourcePoolBuilder.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Builders/ResourcePool/ResourcePoolBuilder.cpp @@ -45,7 +45,7 @@ namespace AZ AssetBuilderSDK::AssetBuilderDesc builderDescriptor; builderDescriptor.m_name = "Atom Resource Pool Asset Builder"; - builderDescriptor.m_version = 1; + builderDescriptor.m_version = 2; //ATOM-15196 builderDescriptor.m_patterns.emplace_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string("*.") + s_sourcePoolAssetExt, AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); builderDescriptor.m_busId = azrtti_typeid(); diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQueryTypes.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQueryTypes.cpp index a1b2ece4dc..715964651f 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQueryTypes.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/GpuQueryTypes.cpp @@ -21,41 +21,39 @@ namespace AZ namespace RPI { // --- TimestampResult --- - - TimestampResult::TimestampResult(uint64_t timestampInTicks) + TimestampResult::TimestampResult(uint64_t beginTick, uint64_t endTick, RHI::HardwareQueueClass hardwareQueueClass) { - m_timestampInTicks = timestampInTicks; + AZ_Assert(endTick >= beginTick, "TimestampResult: bad inputs"); + m_begin = beginTick; + m_duration = endTick - beginTick; + m_hardwareQueueClass = hardwareQueueClass; } - TimestampResult::TimestampResult(uint64_t timestampQueryResultLow, uint64_t timestampQueryResultHigh) - { - const uint64_t low = AZStd::min(timestampQueryResultLow, timestampQueryResultHigh); - const uint64_t high = AZStd::max(timestampQueryResultLow, timestampQueryResultHigh); - - m_timestampInTicks = high - low; - } - - TimestampResult::TimestampResult(AZStd::array_view&& timestampResultArray) - { - // Loop through all the child passes, and accumulate all the timestampTicks - for (const TimestampResult& timestampResult : timestampResultArray) - { - m_timestampInTicks += timestampResult.m_timestampInTicks; - } - } - - uint64_t TimestampResult::GetTimestampInNanoseconds() const + uint64_t TimestampResult::GetDurationInNanoseconds() const { const RHI::Ptr device = RHI::GetRHIDevice(); - const AZStd::chrono::microseconds timeInMicroseconds = device->GpuTimestampToMicroseconds(m_timestampInTicks, RHI::HardwareQueueClass::Graphics); + const AZStd::chrono::microseconds timeInMicroseconds = device->GpuTimestampToMicroseconds(m_duration, m_hardwareQueueClass); const auto timeInNanoseconds = AZStd::chrono::nanoseconds(timeInMicroseconds); return static_cast(timeInNanoseconds.count()); } - uint64_t TimestampResult::GetTimestampInTicks() const + uint64_t TimestampResult::GetDurationInTicks() const { - return m_timestampInTicks; + return m_duration; + } + + uint64_t TimestampResult::GetTimestampBeginInTicks() const + { + return m_begin; + } + + void TimestampResult::Add(const TimestampResult& extent) + { + uint64_t end1 = m_begin + m_duration; + uint64_t end2 = extent.m_begin + extent.m_duration; + m_begin = m_begin < extent.m_begin ? m_begin : extent.m_begin; + m_duration = (end1 > end2 ? end1 : end2) - m_begin; } // --- PipelineStatisticsResult --- diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/MeshDrawPacket.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/MeshDrawPacket.cpp index 1e5eaab20c..d0a277304e 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/MeshDrawPacket.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/MeshDrawPacket.cpp @@ -17,11 +17,20 @@ #include #include #include +#include namespace AZ { namespace RPI { + AZ_CVAR(bool, + r_forceRootShaderVariantUsage, + false, + [](const bool&) { AZ::Interface::Get()->PerformCommand("MeshFeatureProcessor.ForceRebuildDrawPackets"); }, + ConsoleFunctorFlags::Null, + "(For Testing) Forces usage of root shader variant in the mesh draw packet level, ignoring any other shader variants that may exist." + ); + MeshDrawPacket::MeshDrawPacket( ModelLod& modelLod, size_t modelLodMeshIndex, @@ -187,7 +196,7 @@ namespace AZ } const ShaderVariantId finalVariantId = shaderOptions.GetShaderVariantId(); - const ShaderVariant& variant = shader->GetVariant(finalVariantId); + const ShaderVariant& variant = r_forceRootShaderVariantUsage ? shader->GetRootVariant() : shader->GetVariant(finalVariantId); Data::Instance drawSrg; if (drawSrgAsset) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp index 6314ae376e..106ef82bf1 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp @@ -393,19 +393,6 @@ namespace AZ } } - TimestampResult ParentPass::GetTimestampResultInternal() const - { - AZStd::vector timestampResultArray; - timestampResultArray.reserve(m_children.size()); - - // Calculate the Timestamp result by summing all of its child's TimestampResults - for (const Ptr& childPass : m_children) - { - timestampResultArray.emplace_back(childPass->GetTimestampResult()); - } - return TimestampResult(timestampResultArray); - } - PipelineStatisticsResult ParentPass::GetPipelineStatisticsResultInternal() const { AZStd::vector pipelineStatisticsResultArray; @@ -414,7 +401,7 @@ namespace AZ // Calculate the PipelineStatistics result by summing all of its child's PipelineStatistics for (const Ptr& childPass : m_children) { - pipelineStatisticsResultArray.emplace_back(childPass->GetPipelineStatisticsResult()); + pipelineStatisticsResultArray.emplace_back(childPass->GetLatestPipelineStatisticsResult()); } return PipelineStatisticsResult(pipelineStatisticsResultArray); } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp index 5ecf293efe..9401d1a9e0 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Pass.cpp @@ -1273,24 +1273,14 @@ namespace AZ } } - TimestampResult Pass::GetTimestampResult() const + TimestampResult Pass::GetLatestTimestampResult() const { - if (IsEnabled() && IsTimestampQueryEnabled()) - { - return GetTimestampResultInternal(); - } - - return TimestampResult(); + return GetTimestampResultInternal(); } - PipelineStatisticsResult Pass::GetPipelineStatisticsResult() const + PipelineStatisticsResult Pass::GetLatestPipelineStatisticsResult() const { - if (IsEnabled() && IsPipelineStatisticsQueryEnabled()) - { - return GetPipelineStatisticsResultInternal(); - } - - return PipelineStatisticsResult(); + return GetPipelineStatisticsResultInternal(); } TimestampResult Pass::GetTimestampResultInternal() const diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp index 19a4f3d302..1fad385fa6 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -539,7 +539,7 @@ namespace AZ const uint32_t TimestampResultQueryCount = 2u; uint64_t timestampResult[TimestampResultQueryCount] = {0}; query->GetLatestResult(×tampResult, sizeof(uint64_t) * TimestampResultQueryCount); - m_timestampResult = TimestampResult(timestampResult[0], timestampResult[1]); + m_timestampResult = TimestampResult(timestampResult[0], timestampResult[1], RHI::HardwareQueueClass::Graphics); }); ExecuteOnPipelineStatisticsQuery([this](RHI::Ptr query) diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp index 5ba43f9f7e..c72712bce5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/Specific/EnvironmentCubeMapPass.cpp @@ -57,7 +57,7 @@ namespace AZ PassConnection childInputConnection; childInputConnection.m_localSlot = "Output"; childInputConnection.m_attachmentRef.m_pass = "Parent"; - childInputConnection.m_attachmentRef.m_attachment = "CubeMapOutput"; + childInputConnection.m_attachmentRef.m_attachment = "Output"; childRequest.m_connections.emplace_back(childInputConnection); PassSystemInterface* passSystem = PassSystemInterface::Get(); @@ -120,15 +120,16 @@ namespace AZ // create output PassAttachment m_passAttachment = aznew PassAttachment(); - m_passAttachment->m_name = "CubeMapOutput"; - m_passAttachment->m_path = "CubeMapOutput"; + m_passAttachment->m_name = "Output"; + AZ::Name attachmentPath(AZStd::string::format("%s.%s", GetPathName().GetCStr(), m_passAttachment->m_name.GetCStr())); + m_passAttachment->m_path = attachmentPath; m_passAttachment->m_lifetime = RHI::AttachmentLifetimeType::Transient; m_passAttachment->m_descriptor = m_outputImageDesc; // create pass attachment binding PassAttachmentBinding outputAttachment; - outputAttachment.m_name = "CubeMapOutput"; - outputAttachment.m_slotType = PassSlotType::Output; + outputAttachment.m_name = "Output"; + outputAttachment.m_slotType = PassSlotType::InputOutput; outputAttachment.m_attachment = m_passAttachment; outputAttachment.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::RenderTarget; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Base.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Base.cpp index 7012a7cf88..8addb16a23 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Base.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Base.cpp @@ -16,6 +16,6 @@ namespace AZ { namespace RPI { - bool Validation::s_isEnabled = RHI::BuildOptions::IsDebugBuild; + bool Validation::s_isEnabled = RHI::BuildOptions::IsDebugBuild || RHI::BuildOptions::IsProfileBuild; } } diff --git a/Gems/Atom/TestData/TestData/LightingPresets/urban_street_02.lightingpreset.azasset b/Gems/Atom/TestData/TestData/LightingPresets/urban_street_02.lightingpreset.azasset index d0a290649b..a676d5fba6 100644 --- a/Gems/Atom/TestData/TestData/LightingPresets/urban_street_02.lightingpreset.azasset +++ b/Gems/Atom/TestData/TestData/LightingPresets/urban_street_02.lightingpreset.azasset @@ -3,7 +3,6 @@ "Version": 1, "ClassName": "AZ::Render::LightingPreset", "ClassData": { - "autoSelect": false, "displayName": "Urban Street 02", "skyboxImageAsset": { "assetId": { diff --git a/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/LightingPresets/_TEMPLATE_.lightingconfig.json.template b/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/LightingPresets/_TEMPLATE_.lightingconfig.json.template index 7cfa7edbc3..6d87c5eb7b 100644 --- a/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/LightingPresets/_TEMPLATE_.lightingconfig.json.template +++ b/Gems/Atom/Tools/MaterialEditor/Assets/MaterialEditor/LightingPresets/_TEMPLATE_.lightingconfig.json.template @@ -2,7 +2,6 @@ "configurations": [ { "displayName": "Substance: