diff --git a/.clang-format b/.clang-format index 565f28130e..04e0284f97 100644 --- a/.clang-format +++ b/.clang-format @@ -46,7 +46,7 @@ SortIncludes: true SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: false SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: true +SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements diff --git a/Assets/Engine/SeedAssetList.seed b/Assets/Engine/SeedAssetList.seed index 45a02f7682..77ec509721 100644 --- a/Assets/Engine/SeedAssetList.seed +++ b/Assets/Engine/SeedAssetList.seed @@ -67,106 +67,98 @@ - + - + - + - + - + - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -264,109 +256,101 @@ - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -387,498 +371,474 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -896,14 +856,6 @@ - - - - - - - - @@ -928,29 +880,13 @@ - - - - - - - - - - - - - - - - - + - + @@ -1451,146 +1387,146 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1699,42 +1635,42 @@ - + - + - + - + - + - + - + - + - + - + diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py index 7a85cb1813..34af4d9115 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py @@ -162,7 +162,7 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) -> else: cmd.append(f"--{key}") if append_defaults: - cmd.append(f"--project={workspace.project}") + cmd.append(f"--project-path={workspace.project}") return cmd # ****** @@ -300,9 +300,9 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) -> workspace.paths.engine_root(), "Code", "Framework", - "AzFramework", - "AzFramework", - "Platform", + "AzCore", + "AzCore", + "PlatformId", "PlatformDefaults.h", ) @@ -318,7 +318,7 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) -> if start_gathering: result = get_platform.match(line) # Try the regex if result: - platform_values[result.group(1).lower()] = counter + platform_values[result.group(1).replace("_ID", "").lower()] = counter counter = counter << 1 elif "(Invalid, -1)" in line: # The line right before the first platform start_gathering = True diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py index 8738e8acdf..1043bbaefa 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py @@ -302,7 +302,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): that generating debug information does not affect asset list creation """ helper = bundler_batch_helper - seed_list = os.path.join(workspace.paths.engine_root(), "Engine", "SeedAssetList.seed") # Engine seed list + seed_list = os.path.join(workspace.paths.engine_root(), "Assets", "Engine", "SeedAssetList.seed") # Engine seed list asset = r"levels\testdependencieslevel\level.pak" # Create Asset list @@ -377,7 +377,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): subcommands. """ helper = bundler_batch_helper - seed_list = os.path.join(workspace.paths.engine_root(), "Engine", "SeedAssetList.seed") # Engine seed list + seed_list = os.path.join(workspace.paths.engine_root(), "Assets", "Engine", "SeedAssetList.seed") # Engine seed list asset = r"levels\testdependencieslevel\level.pak" # Useful bundle locations / names (2 for comparing contents) @@ -465,7 +465,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): "Please rerun with commandline option: '--bundle_platforms=pc,mac'" # fmt:on - seed_list = os.path.join(workspace.paths.engine_root(), "Engine", "SeedAssetList.seed") # Engine seed list + seed_list = os.path.join(workspace.paths.engine_root(), "Assets", "Engine", "SeedAssetList.seed") # Engine seed list # Useful bundle / asset list locations bundle_dir = os.path.dirname(helper["bundle_file"]) @@ -502,13 +502,13 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): for bundle_file in bundle_files.values(): assert os.path.isfile(bundle_file) - # This asset is created on mac platform but not on windows - file_to_check = b"engineassets/shading/defaultprobe_cm.dds.5" # [use byte str because file is in binary] + # This asset is created both on mac and windows platform + file_to_check = b"engineassets/shading/defaultprobe_cm_ibldiffuse.tif.streamingimage" # [use byte str because file is in binary] # Extract the delta catalog file from pc archive. {file_to_check} SHOULD NOT be present for PC file_contents = helper.extract_file_content(bundle_files["pc"], "DeltaCatalog.xml") # fmt:off - assert file_to_check not in file_contents, \ + assert file_to_check in file_contents, \ f"{file_to_check} was found in DeltaCatalog.xml in pc bundle file {bundle_files['pc']}" # fmt:on @@ -619,7 +619,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): # Validate both mac and pc are activated for seed # fmt:off check_seed_platform(helper["seed_list_file"], test_asset, - helper["platform_values"]["pc"] + helper["platform_values"]["osx"]) + helper["platform_values"]["pc"] + helper["platform_values"]["mac"]) # fmt:on # Remove MAC platform @@ -651,7 +651,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): # Validate Mac platform was added back on. Save file contents # fmt:off all_lines = check_seed_platform(helper["seed_list_file"], test_asset, - helper["platform_values"]["pc"] + helper["platform_values"]["osx"]) + helper["platform_values"]["pc"] + helper["platform_values"]["mac"]) # fmt:on # Try to remove platform without specifying a platform to remove (should fail) @@ -1046,7 +1046,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): "--addDefaultSeedListFiles", "--platform=pc", "--print", - f"--project={workspace.project}" + f"--project-path={workspace.project}" ], universal_newlines=True, ) @@ -1115,7 +1115,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): bundle_result_path = os.path.join(bundles_folder, helper.platform_file_name("bundle.pak", workspace.asset_processor_platform)) - bundle_cache_path = os.path.join(workspace.paths.platform_cache(), workspace.project, + bundle_cache_path = os.path.join(workspace.paths.platform_cache(), "Bundles", helper.platform_file_name("bundle.pak", workspace.asset_processor_platform)) @@ -1156,13 +1156,15 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): # fmt:off def test_WindowsAndMac_FilesMarkedSkip_FilesAreSkipped(self, workspace, bundler_batch_helper): expected_assets = [ - "libs/particles/milestone2particles.xml", - "textures/milestone2/particles/fx_sparkstreak_01.dds" + "ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas", + "ui/textures/prefab/button_normal.sprite" ] bundler_batch_helper.call_assetLists( assetListFile=bundler_batch_helper['asset_info_file_request'], - addSeed="libs/particles/milestone2particles.xml", - skip="textures/milestone2/particles/fx_launchermuzzlering_01.dds,textures/milestone2/particles/fx_launchermuzzlefront_01.dds" + addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas", + skip="ui/textures/prefab/button_disabled.sprite,ui/scripts/lyshineexamples/animation/multiplesequences.luac," + "ui/textures/prefab/tooltip_sliced.sprite,ui/scripts/lyshineexamples/unloadthiscanvasbutton.luac,fonts/vera.fontfamily,fonts/vera-italic.font," + "fonts/vera.font,fonts/vera-bold.font,fonts/vera-bold-italic.font,fonts/vera-italic.ttf,fonts/vera.ttf,fonts/vera-bold.ttf,fonts/vera-bold-italic.ttf" ) assert os.path.isfile(bundler_batch_helper["asset_info_file_result"]) assets_in_list = [] diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py index 4f58a23a19..730a557a9e 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/SurfaceMaskFilter_BasicSurfaceTagCreation.py @@ -23,6 +23,25 @@ class TestSurfaceMaskFilter_BasicSurfaceTagCreation(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="TestSurfaceMaskFilter_BasicSurfaceTagCreation", args=["level"]) def run_test(self): + """ + Summary: + Verifies basic surface tag value equality + + Expected Behavior: + Surface tags of the same name are equal, and different names aren't. + + Test Steps: + 1) Open level + 2) Create 2 new surface tags of identical names and verify they resolve as equal. + 3) Create another new tag of a different name and verify they resolve as different. + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ self.log("SurfaceTag test started") # Create a level diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py index c25761d655..46c5483988 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/VegetationInstances_DespawnWhenOutOfRange.py @@ -33,6 +33,25 @@ class TestVegetationInstances_DespawnWhenOutOfRange(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix='VegetationInstances_DespawnWhenOutOfRange', args=['level']) def run_test(self): + """ + Summary: + Verifies that vegetation instances properly spawn/despawn based on camera range. + + Expected Behavior: + Vegetation instances despawn when out of camera range. + + Test Steps: + 1) Create a new level + 2) Create a simple vegetation area, and set the view position near the spawner. Verify instances plant. + 3) Move the view position away from the spawner. Verify instances despawn. + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ # Create a new level self.test_success = self.create_level( diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py index cc9a15bba0..c37bc9780f 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientGenerators_Incompatibilities.py @@ -28,8 +28,21 @@ class TestGradientGeneratorIncompatibilities(EditorTestHelper): def run_test(self): """ Summary: - Verify that Entities are not active when a Gradient Generator and incompatible component are both present - on the same Entity. + This test verifies that components are disabled when conflicting components are present on the same entity. + + Expected Behavior: + Gradient Generator components are incompatible with Vegetation area components. + + Test Steps: + 1) Create a new level + 2) Create a new entity in the level + 3) Add each Gradient Generator component to an entity, and add a Vegetation Area component to the same entity + 4) Verify that components are only enabled when entity is free of a conflicting component + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. :return: None """ diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py index b7d12d074a..f2edc2924e 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientModifiers_Incompatibilities.py @@ -28,8 +28,21 @@ class TestGradientModifiersIncompatibilities(EditorTestHelper): def run_test(self): """ Summary: - Verify that Entities are not active when a Gradient Modifier and incompatible component are both present - on the same Entity. + This test verifies that components are disabled when conflicting components are present on the same entity. + + Expected Behavior: + Gradient Modifier components are incompatible with Vegetation area components. + + Test Steps: + 1) Create a new level + 2) Create a new entity in the level + 3) Add each Gradient Modifier component to an entity, and add a Vegetation Area component to the same entity + 4) Verify that components are only enabled when entity is free of a conflicting component + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. :return: None """ diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py index c37ee36265..45da74d6cd 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_ClearingPinnedEntitySetsPreviewToOrigin.py @@ -9,19 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ -""" -The below cases are combined in this script -C2676829 -C3961326 -C3980659 -C3980664 -C3980669 -C3416548 -C2676823 -C3961321 -C2676826 -""" - import os import sys diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py index 5a758b9d89..b8f4114d30 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientPreviewSettings_DefaultPinnedEntityIsSelf.py @@ -44,7 +44,21 @@ class TestGradientPreviewSettings(EditorTestHelper): def run_test(self): """ Summary: - Verify if the current entity is set to the pin preview to shape entity by default for several components. + This test verifies default values for the pinned entity for Gradient Preview settings. + + Expected Behavior: + Pinned entity is self for all gradient generator/modifiers. + + Test Steps: + 1) Create a new level + 2) Create a new entity in the level + 3) Add each Gradient Generator component to an entity, and verify the Pin Preview to Shape property is set to + self + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. :return: None """ diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py index a16e37e0fc..8e2d0611af 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientSurfaceTagEmitter_ComponentDependencies.py @@ -31,11 +31,21 @@ class TestGradientSurfaceTagEmitterDependencies(EditorTestHelper): def run_test(self): """ Summary: - Component has a dependency on a Gradient component + This test verifies that the Gradient Surface Tag Emitter component is dependent on a gradient component. Expected Result: - Component is disabled until a Gradient Generator, Modifier or Gradient Reference component - (and any sub-dependencies) is added to the entity. + Gradient Surface Tag Emitter component is disabled until a Gradient Generator, Modifier or Gradient Reference + component (and any sub-dependencies) is added to the entity. + + Test Steps: + 1) Open level + 2) Create a new entity with a Gradient Surface Tag Emitter component + 3) Verify the component is disabled until a dependent component is also added to the entity + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. :return: None """ diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py index e1e901f2f7..2311363db9 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/GradientTransform_RequiresShape.py @@ -28,8 +28,20 @@ class TestGradientTransformRequiresShape(EditorTestHelper): def run_test(self): """ Summary: - Verify that Gradient Transform Modifier component requires a - Shape component before the Entity can become active. + This test verifies that the Gradient Transform Modifier component is dependent on a shape component. + + Expected Result: + Gradient Transform Modifier component is disabled until a shape component is added to the entity. + + Test Steps: + 1) Open level + 2) Create a new entity with a Gradient Transform Modifier component + 3) Verify the component is disabled until a shape component is also added to the entity + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. :return: None """ diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py index dab8e6928a..a5d9632fd6 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/EditorScripts/ImageGradient_RequiresShape.py @@ -28,8 +28,20 @@ class TestImageGradientRequiresShape(EditorTestHelper): def run_test(self): """ Summary: - Verify that Image Gradient component requires a - Shape component before the Entity can become active. + This test verifies that the Image Gradient component is dependent on a shape component. + + Expected Result: + Gradient Transform Modifier component is disabled until a shape component is added to the entity. + + Test Steps: + 1) Open level + 2) Create a new entity with a Image Gradient component + 3) Verify the component is disabled until a shape component is also added to the entity + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. :return: None """ diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py index d1e0b68ef4..c41d153cfa 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_DependentComponentsAdded.py @@ -33,6 +33,26 @@ class TestAreaNodeComponentDependency(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="AreaNodeComponentDependency", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with + proper dependent components. + + Expected Behavior: + All expected component dependencies are met when adding an area node to a graph. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the area nodes to the graph area, and ensure the proper dependent components are added + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newEntityId diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py index 4e429a192b..fb977b4987 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityCreatedOnNodeAdd.py @@ -33,7 +33,25 @@ class TestGradientNodeEntityCreate(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="AreaNodeEntityCreate", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + Expected Behavior: + New entities are created when dragging area nodes to graph area. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the area nodes to the graph area, and ensure a new entity is created + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newEntityId newEntityId = parameters[0] diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py index 38f8641b4c..57ba8fc006 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/AreaNodes_EntityRemovedOnNodeDelete.py @@ -34,7 +34,26 @@ class TestAreaNodeEntityDelete(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="AreaNodeEntityDelete", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + Expected Behavior: + Entities are removed when area nodes are deleted from a graph. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the area nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global createdEntityId createdEntityId = parameters[0] diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py index 26062c01f8..60527b64d2 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ComponentUpdates_UpdateGraph.py @@ -9,24 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ - -""" -C22602072 - Graph is updated when underlying components are added/removed - -1. Open Level. -2. Find LandscapeCanvas named entity. -3. Ensure Vegetation Distribution Component is present on the BushSpawner entity. -4. Open graph and ensure Distribution Filter wrapped node is present. -5. Delete the Vegetation Distribution Filter component from the BushSpawner entity via Entity Inspector. -6. Ensure the Vegetation Distribution Filter component was deleted from the BushSpawner entity and node is no longer -present in the graph. -7. Add Vegetation Altitude Filter to the BushSpawner entity through Entity Inspector. -8. Ensure Altitude Filter was added to the BushSpawner node in the open graph. -9. Add a new entity with unique name as a child of the Landscape Canvas entity. -10. Add a Box Shape component to the new child entity. -11. Ensure Box Shape node is present on the open graph. -""" - import os import sys @@ -50,6 +32,36 @@ class TestComponentUpdatesUpdateGraph(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="ComponentUpdatesUpdateGraph", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas graphs update properly when components are added/removed outside of + Landscape Canvas. + + Expected Behavior: + Graphs properly reflect component changes made to entities outside of Landscape Canvas. + + Test Steps: + 1. Open Level + 2. Find LandscapeCanvas named entity + 3. Ensure Vegetation Distribution Component is present on the BushSpawner entity + 4. Open graph and ensure Distribution Filter wrapped node is present + 5. Delete the Vegetation Distribution Filter component from the BushSpawner entity via Entity Inspector + 6. Ensure the Vegetation Distribution Filter component was deleted from the BushSpawner entity and node is + no longer present in the graph + 7. Add Vegetation Altitude Filter to the BushSpawner entity through Entity Inspector + 8. Ensure Altitude Filter was added to the BushSpawner node in the open graph + 9. Add a new entity with unique name as a child of the Landscape Canvas entity + 10. Add a Box Shape component to the new child entity + 11. Ensure Box Shape node is present on the open graph + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + # Create a new empty level and instantiate LC_BushFlowerBlender.slice self.test_success = self.create_level( self.args["level"], diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py index 5fed13985d..4b5e03abbc 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/CreateNewGraph.py @@ -37,6 +37,25 @@ class TestCreateNewGraph(EditorTestHelper): print("New root entity created") def run_test(self): + """ + Summary: + This test verifies that new graphs can be created in Landscape Canvas. + + Expected Behavior: + New graphs can be created, and proper entity is created to hold graph data with a Landscape Canvas component. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Ensures the root entity created contains a Landscape Canvas component + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ self.test_success = self.create_level( self.args["level"], heightmap_resolution=128, diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py index 7fd3f075e0..81e24b20e1 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_DisabledNodeDuplication.py @@ -33,7 +33,25 @@ class TestDisabledNodeDuplication(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="DisabledNodeDuplication", args=["level"]) def run_test(self): + """ + Summary: + This test verifies Editor stability after duplicating disabled Landscape Canvas nodes. + Expected Behavior: + Editor remains stable and free of crashes. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Create several new nodes, disable the nodes via disabling/deleting components, and duplicate the nodes + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newEntityId newEntityId = parameters[0] diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py index 27ab6fded3..61c4cf9ac2 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/Edit_UndoNodeDelete_SliceEntity.py @@ -9,17 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ - -""" -C30813586 - Editor remains stable after Undoing deletion of a node on a slice entity - -1. Open level with instantiated slice. -2. Open the graph. -3. Find the BushSpawner's Vegetation Layer Spawner node. -4. Delete the node. -5. Undo to restore the node. -""" - import os import sys @@ -44,7 +33,26 @@ class TestUndoNodeDeleteSlice(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="UndoNodeDeleteSlice", args=["level"]) def run_test(self): + """ + Summary: + This test verifies Editor stability after undoing the deletion of nodes on a slice entity. + Expected Behavior: + Editor remains stable and free of crashes. + + Test Steps: + 1) Create a new level + 2) Instantiate a slice with a Landscape Canvas setup + 3) Find a specific node on the graph, and delete it + 4) Restore the node with Undo + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ # Create a new empty level and instantiate LC_BushFlowerBlender.slice self.test_success = self.create_level( self.args["level"], diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py index ca3bc04f47..124baf9d2e 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientMixer_NodeConstruction.py @@ -34,6 +34,27 @@ class TestGradientMixerNodeConstruction(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="GradientMixerNodeConstruction", args=["level"]) def run_test(self): + """ + Summary: + This test verifies a Gradient Mixer vegetation setup can be constructed through Landscape Canvas. + + Expected Behavior: + Entities contain all required components and component references after creating nodes and setting connections + on a Landscape Canvas graph. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Add all necessary nodes to the graph and set connections to form a Gradient Mixer setup + 4) Verify all components and component references were properly set during graph construction + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newEntityId diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py index d40b19e7db..aa98eb3dc3 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityCreatedOnNodeAdd.py @@ -33,6 +33,25 @@ class TestGradientModifierNodeEntityCreate(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="GradientModifierNodeEntityCreate", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + + Expected Behavior: + New entities are created when dragging Gradient Modifier nodes to graph area. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newEntityId diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py index dc263924d1..6a82b05039 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientModifierNodes_EntityRemovedOnNodeDelete.py @@ -34,7 +34,26 @@ class TestGradientModifierNodeEntityDelete(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="GradientModifierNodeEntityDelete", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + Expected Behavior: + Entities are removed when Gradient Modifier nodes are deleted from a graph. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global createdEntityId createdEntityId = parameters[0] diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py index 5e203e1892..f9360fe356 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_DependentComponentsAdded.py @@ -33,6 +33,27 @@ class TestGradientNodeComponentDependency(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="GradientNodeComponentDependency", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities with + proper dependent components. + + Expected Behavior: + All expected component dependencies are met when adding a Gradient Modifier node to a graph. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient Modifier nodes to the graph area, and ensure the proper dependent components are + added + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newEntityId diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py index 6d4a2f58a7..8aaad9b81d 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityCreatedOnNodeAdd.py @@ -32,6 +32,25 @@ class TestGradientNodeEntityCreate(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="GradientNodeEntityCreate", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + + Expected Behavior: + New entities are created when dragging Gradient nodes to graph area. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newEntityId diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py index 2b49e3a911..d74b86d0bf 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GradientNodes_EntityRemovedOnNodeDelete.py @@ -34,6 +34,26 @@ class TestGradientNodeEntityDelete(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="GradientNodeEntityDelete", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + + Expected Behavior: + Entities are removed when Gradient nodes are deleted from a graph. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the Gradient nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global createdEntityId diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py index d3ad5c1c1e..6aa539b554 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnEntityDelete.py @@ -31,6 +31,26 @@ class TestGraphClosedOnEntityDelete(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="GraphClosedOnEntityDelete", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that Landscape Canvas graphs are auto-closed when the corresponding entity is deleted. + + Expected Behavior: + When a Landscape Canvas root entity is deleted, the corresponding graph automatically closes. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Delete the automatically created entity + 4) Verify the open graph is closed + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newRootEntityId diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py index b7b0008eb2..ebc75ab621 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_OnLevelChange.py @@ -29,7 +29,26 @@ class TestGraphClosedOnLevelChange(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="GraphClosedOnLevelChange", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that Landscape Canvas graphs are auto-closed when the currently open level changes. + Expected Behavior: + When a new level is loaded in the Editor, open Landscape Canvas graphs are automatically closed. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Open a different level + 4) Verify the open graph is closed + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ # Create a new empty level self.test_success = self.create_level( self.args["level"], diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py index efd1cc5a55..4b018aeb45 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphClosed_TabbedGraph.py @@ -29,6 +29,26 @@ class TestGraphClosedTabbedGraph(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="GraphClosedTabbedGraph", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that Landscape Canvas tabbed graphs can be independently closed. + + Expected Behavior: + Closing a tabbed graph only closes the appropriate graph. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create several new graphs + 3) Close one of the open graphs + 4) Ensure the graph properly closed, and other open graphs remain open + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ # Create a new empty level self.test_success = self.create_level( diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py index f350d37178..f94a6c2e3a 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/GraphUpdates_UpdateComponents.py @@ -9,21 +9,6 @@ remove or modify any license notices. This file is distributed on an "AS IS" BAS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ - -""" -C22715182 - Components are updated when nodes are added/removed/updated - -1. Open Level. -2. Open the graph on LC_BushFlowerBlender.slice -3. Find the Rotation Modifier node on the BushSpawner entity -4. Delete the Rotation Modifier node -5. Ensure the Vegetation Rotation Modifier component is removed from the BushSpawner entity -6. Delete the Vegetation Layer Spawner node from the graph -7. Ensure BushSpawner entity is deleted -8. Change connection from second Rotation Modifier node to a different Gradient -9. Ensure Gradient reference on component is updated -""" - import os import sys @@ -50,6 +35,31 @@ class TestGraphUpdatesUpdateComponents(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="GraphUpdatesUpdateComponents", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that components are properly updated as nodes are added/removed/updated. + + Expected Behavior: + Landscape Canvas node CRUD properly updates component entities. + + Test Steps: + 1. Open Level. + 2. Open the graph on LC_BushFlowerBlender.slice + 3. Find the Rotation Modifier node on the BushSpawner entity + 4. Delete the Rotation Modifier node + 5. Ensure the Vegetation Rotation Modifier component is removed from the BushSpawner entity + 6. Delete the Vegetation Layer Spawner node from the graph + 7. Ensure BushSpawner entity is deleted + 8. Change connection from second Rotation Modifier node to a different Gradient + 9. Ensure Gradient reference on component is updated + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ # Create a new empty level and instantiate LC_BushFlowerBlender.slice self.test_success = self.create_level( self.args["level"], diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py index 176429885f..c3857e1393 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvasComponent_AddedRemoved.py @@ -30,6 +30,26 @@ class TestLandscapeCanvasComponentAddedRemoved(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="LandscapeCanvasComponentAddedRemoved", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas component can be added to/removed from an entity. + + Expected Behavior: + Closing a tabbed graph only closes the appropriate graph. + + Test Steps: + 1) Create a new level + 2) Create a new entity + 3) Add a Landscape Canvas component to the entity + 4) Remove the Landscape Canvas component from the entity + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ # Create a new empty level self.test_success = self.create_level( diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py index e0f13adaa9..f174a52610 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LandscapeCanvas_SliceCreateInstantiate.py @@ -30,12 +30,21 @@ class TestLandscapeCanvasSliceCreateInstantiate(EditorTestHelper): def run_test(self): """ Summary: - C22602016 A slice containing the LandscapeCanvas component can be created/instantiated. + A slice containing the LandscapeCanvas component can be created/instantiated. Expected Result: - Slice is created and processed successfully and free of errors/warnings. - Another copy of the slice is instantiated. + Slice is created/processed/instantiated successfully and free of errors/warnings. + Test Steps: + 1) Create a new level + 2) Create a new entity with a Landscape Canvas component + 3) Create a slice of the new entity + 4) Instantiate a new copy of the slice + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. :return: None """ diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py index ecc529b9b4..82a2abf5ea 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerBlender_NodeConstruction.py @@ -34,6 +34,27 @@ class TestLayerBlenderNodeConstruction(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="LayerBlenderNodeConstruction", args=["level"]) def run_test(self): + """ + Summary: + This test verifies a Layer Blender vegetation setup can be constructed through Landscape Canvas. + + Expected Behavior: + Entities contain all required components and component references after creating nodes and setting connections + on a Landscape Canvas graph. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Add all necessary nodes to the graph and set connections to form a Layer Blender setup + 4) Verify all components and component references were properly set during graph construction + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newEntityId diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py index 00fcb5170c..df3c549fff 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/LayerExtenderNodes_ComponentEntitySync.py @@ -34,6 +34,25 @@ class TestLayerExtenderNodeComponentEntitySync(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="LayerExtenderNodeComponentEntitySync", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that all wrapped nodes can be successfully added to/removed from parent nodes. + + Expected Behavior: + All wrapped extender nodes can be added to/removed from appropriate parent nodes. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Add Area Blender and Layer Spawner nodes to the graph, and add/remove each extender node to/from each + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newEntityId diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py index bd10e5f4c6..cd4915ea24 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityCreatedOnNodeAdd.py @@ -33,6 +33,25 @@ class TestShapeNodeEntityCreate(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="ShapeNodeEntityCreate", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas nodes can be added to a graph, and correctly create entities. + + Expected Behavior: + New entities are created when dragging shape nodes to graph area. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the shape nodes to the graph area, and ensure a new entity is created + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ def onEntityCreated(parameters): global newEntityId diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py index f71f5ae906..fcfbe03576 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/ShapeNodes_EntityRemovedOnNodeDelete.py @@ -34,7 +34,27 @@ class TestShapeNodeEntityDelete(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="ShapeNodeEntityDelete", args=["level"]) def run_test(self): - + """ + Summary: + This test verifies that the Landscape Canvas node deletion properly cleans up entities in the Editor. + + Expected Behavior: + Entities are removed when shape nodes are deleted from a graph. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Drag each of the shape nodes to the graph area, and ensure a new entity is created + 4) Delete the nodes, and ensure the newly created entities are removed + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + def onEntityCreated(parameters): global createdEntityId createdEntityId = parameters[0] diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py index 968f39c64d..183c3f7ccb 100755 --- a/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py +++ b/AutomatedTesting/Gem/PythonTests/largeworlds/landscape_canvas/EditorScripts/SlotConnections_UpdateComponentReferences.py @@ -33,6 +33,27 @@ class TestSlotConnectionsUpdateComponents(EditorTestHelper): EditorTestHelper.__init__(self, log_prefix="SlotConnectionsUpdateComponents", args=["level"]) def run_test(self): + """ + Summary: + This test verifies that the Landscape Canvas slot connections properly update component references. + + Expected Behavior: + A reference created through slot connections in Landscape Canvas is reflected in the Entity Inspector. + + Test Steps: + 1) Create a new level + 2) Open Landscape Canvas and create a new graph + 3) Several nodes are added to a graph, and connections are set between the nodes + 4) Component references are verified via Entity Inspector + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + # Retrieve the proper component TypeIds per component name componentNames = [ 'Random Noise Gradient', diff --git a/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_AllParamDatatypes_CreationSuccess.py b/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_AllParamDatatypes_CreationSuccess.py new file mode 100644 index 0000000000..4beedec7cf --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvents_AllParamDatatypes_CreationSuccess.py @@ -0,0 +1,210 @@ +""" +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. +""" + + +# fmt: off +class Tests(): + new_event_created = ("New Script Event created", "New Script Event not created") + child_event_created = ("Child Event created", "Child Event not created") + params_added = ("New parameters added", "New parameters are not added") + file_saved = ("Script event file saved", "Script event file did not save") + node_found = ("Node found in Script Canvas", "Node not found in Script Canvas") +# fmt: on + + +def ScriptEvents_AllParamDatatypes_CreationSuccess(): + """ + Summary: + Parameters of all types can be created. + + Expected Behavior: + The Method handles the large number of Parameters gracefully. + Parameters of all data types can be successfully created. + Updated ScriptEvent toast appears in Script Canvas. + + Test Steps: + 1) Open Asset Editor + 2) Initially create new Script Event file with one method + 3) Add new method and set name to it + 4) Add new parameters of each type + 5) Verify if parameters are added + 6) Expand the parameter rows + 7) Set different names and datatypes for each parameter + 8) Save file and verify node in SC Node Palette + 9) Close Asset Editor + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + import os + from utils import TestHelper as helper + import pyside_utils + + # Open 3D Engine imports + import azlmbr.legacy.general as general + import azlmbr.editor as editor + import azlmbr.bus as bus + + # Pyside imports + from PySide2 import QtWidgets, QtTest, QtCore + + GENERAL_WAIT = 1.0 # seconds + + FILE_PATH = os.path.join("AutomatedTesting", "TestAssets", "test_file.scriptevents") + N_VAR_TYPES = 10 # Top 10 variable types + TEST_METHOD_NAME = "test_method_name" + + editor_window = pyside_utils.get_editor_main_window() + asset_editor = asset_editor_widget = container = menu_bar = None + sc = node_palette = tree = search_frame = search_box = None + + def initialize_asset_editor_qt_objects(): + nonlocal asset_editor, asset_editor_widget, container, menu_bar + asset_editor = editor_window.findChild(QtWidgets.QDockWidget, "Asset Editor") + asset_editor_widget = asset_editor.findChild(QtWidgets.QWidget, "AssetEditorWindowClass") + container = asset_editor_widget.findChild(QtWidgets.QWidget, "ContainerForRows") + menu_bar = asset_editor_widget.findChild(QtWidgets.QMenuBar) + + def initialize_sc_qt_objects(): + nonlocal sc, node_palette, tree, search_frame, search_box + sc = editor_window.findChild(QtWidgets.QDockWidget, "Script Canvas") + if sc.findChild(QtWidgets.QDockWidget, "NodePalette") is None: + action = pyside_utils.find_child_by_pattern(sc, {"text": "Node Palette", "type": QtWidgets.QAction}) + action.trigger() + node_palette = sc.findChild(QtWidgets.QDockWidget, "NodePalette") + tree = node_palette.findChild(QtWidgets.QTreeView, "treeView") + search_frame = node_palette.findChild(QtWidgets.QFrame, "searchFrame") + search_box = search_frame.findChild(QtWidgets.QLineEdit, "searchFilter") + + def save_file(): + editor.AssetEditorWidgetRequestsBus(bus.Broadcast, "SaveAssetAs", FILE_PATH) + action = pyside_utils.find_child_by_pattern(menu_bar, {"type": QtWidgets.QAction, "iconText": "Save"}) + action.trigger() + # wait till file is saved, to validate that check the text of QLabel at the bottom of the AssetEditor, + # if there are no unsaved changes we will not have any * in the text + label = asset_editor.findChild(QtWidgets.QLabel, "textEdit") + return helper.wait_for_condition(lambda: "*" not in label.text(), 3.0) + + def expand_container_rows(object_name): + children = container.findChildren(QtWidgets.QFrame, object_name) + for child in children: + check_box = child.findChild(QtWidgets.QCheckBox) + if check_box and not check_box.isChecked(): + QtTest.QTest.mouseClick(check_box, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier) + + def node_palette_search(node_name): + search_box.setText(node_name) + helper.wait_for_condition(lambda: search_box.text() == node_name, 1.0) + # Try clicking ENTER in search box multiple times + for _ in range(20): + QtTest.QTest.keyClick(search_box, QtCore.Qt.Key_Enter, QtCore.Qt.NoModifier) + if pyside_utils.find_child_by_pattern(tree, {"text": node_name}) is not None: + break + + def verify_added_params(): + for index in range(N_VAR_TYPES): + if container.findChild(QtWidgets.QFrame, f"[{index}]") is None: + return False + return True + + # 1) Open Asset Editor + general.idle_enable(True) + # Initially close the Asset Editor and then reopen to ensure we don't have any existing assets open + general.close_pane("Asset Editor") + general.open_pane("Asset Editor") + helper.wait_for_condition(lambda: general.is_pane_visible("Asset Editor"), 5.0) + + # 2) Initially create new Script Event file with one method + initialize_asset_editor_qt_objects() + action = pyside_utils.find_child_by_pattern(menu_bar, {"type": QtWidgets.QAction, "text": "Script Events"}) + action.trigger() + result = helper.wait_for_condition( + lambda: container.findChild(QtWidgets.QFrame, "Events") is not None + and container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "") is not None, + 3 * GENERAL_WAIT, + ) + Report.result(Tests.new_event_created, result) + + # 3) Add new method and set name to it + add_event = container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "") + add_event.click() + result = helper.wait_for_condition( + lambda: asset_editor_widget.findChild(QtWidgets.QFrame, "EventName") is not None, GENERAL_WAIT + ) + Report.result(Tests.child_event_created, result) + expand_container_rows("EventName") + expand_container_rows("Name") + initialize_asset_editor_qt_objects() + children = container.findChildren(QtWidgets.QFrame, "Name") + for child in children: + line_edit = child.findChild(QtWidgets.QLineEdit) + if line_edit is not None and line_edit.text() == "MethodName": + line_edit.setText(TEST_METHOD_NAME) + + # 4) Add new parameters of each type + helper.wait_for_condition(lambda: container.findChild(QtWidgets.QFrame, "Parameters") is not None, 2.0) + parameters = container.findChild(QtWidgets.QFrame, "Parameters") + add_param = parameters.findChild(QtWidgets.QToolButton, "") + for _ in range(N_VAR_TYPES): + add_param.click() + + # 5) Verify if parameters are added + result = helper.wait_for_condition(verify_added_params, 3.0) + Report.result(Tests.params_added, result) + + # 6) Expand the parameter rows (to render QFrame 'Type' for each param) + for index in range(N_VAR_TYPES): + expand_container_rows(f"[{index}]") + + # 7) Set different names and datatypes for each parameter + expand_container_rows("Name") + children = container.findChildren(QtWidgets.QFrame, "Name") + index = 0 + for child in children: + line_edit = child.findChild(QtWidgets.QLineEdit) + if line_edit is not None and line_edit.text() == "ParameterName": + line_edit.setText(f"param_{index}") + index += 1 + + children = container.findChildren(QtWidgets.QFrame, "Type") + index = 0 + for child in children: + combo_box = child.findChild(QtWidgets.QComboBox) + if combo_box is not None and index < N_VAR_TYPES: + combo_box.setCurrentIndex(index) + index += 1 + + # 8) Save file and verify node in SC Node Palette + Report.result(Tests.file_saved, save_file()) + general.open_pane("Script Canvas") + helper.wait_for_condition(lambda: general.is_pane_visible("Script Canvas"), 5.0) + initialize_sc_qt_objects() + node_palette_search(TEST_METHOD_NAME) + get_node_index = lambda: pyside_utils.find_child_by_pattern(tree, {"text": TEST_METHOD_NAME}) is not None + result = helper.wait_for_condition(get_node_index, 2.0) + Report.result(Tests.node_found, result) + + # 9) Close Asset Editor + general.close_pane("Asset Editor") + general.close_pane("Script Canvas") + + +if __name__ == "__main__": + import ImportPathHelper as imports + + imports.init() + from utils import Report + + Report.start_test(ScriptEvents_AllParamDatatypes_CreationSuccess) diff --git a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py index 85d0b4523f..91d6b3e53e 100755 --- a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py @@ -113,10 +113,6 @@ class TestAutomation(TestAutomationBase): from . import Debugger_HappyPath_TargetMultipleGraphs as test_module self._run_test(request, workspace, editor, test_module) - def test_Debugging_TargetMultipleGraphs(self, request, workspace, editor, launcher_platform, project): - from . import Debugging_TargetMultipleGraphs as test_module - self._run_test(request, workspace, editor, test_module) - @pytest.mark.parametrize("level", ["tmp_level"]) def test_Debugger_HappyPath_TargetMultipleEntities(self, request, workspace, editor, launcher_platform, project, level): def teardown(): @@ -317,4 +313,30 @@ class TestScriptCanvasTests(object): auto_test_mode=False, timeout=60, ) + + def test_ScriptEvents_AllParamDatatypes_CreationSuccess(self, request, workspace, editor, launcher_platform): + def teardown(): + file_system.delete( + [os.path.join(workspace.paths.project(), "TestAssets", "test_file.scriptevents")], True, True + ) + request.addfinalizer(teardown) + file_system.delete( + [os.path.join(workspace.paths.project(), "TestAssets", "test_file.scriptevents")], True, True + ) + expected_lines = [ + "Success: New Script Event created", + "Success: Child Event created", + "Success: New parameters added", + "Success: Script event file saved", + "Success: Node found in Script Canvas", + ] + hydra.launch_and_validate_results( + request, + TEST_DIRECTORY, + editor, + "ScriptEvents_AllParamDatatypes_CreationSuccess.py", + expected_lines, + auto_test_mode=False, + timeout=60, + ) \ No newline at end of file diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.h b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.h index ed8a68dc24..9d45a17edc 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Common/PhysicsSimulatedBody.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,22 @@ namespace AzPhysics return m_customUserData; } + //! Helper functions for setting frame ID. + //! @param frameId Optionally set frame ID for the systems moving the actors back in time. + void SetFrameId(uint32_t frameId) + { + m_frameId = frameId; + } + + //! Helper functions for getting the set frame ID. + //! @return Will return the frame ID. + uint32_t GetFrameId() const + { + return m_frameId; + } + + static constexpr uint32_t UndefinedFrameId = AZStd::numeric_limits::max(); + //! Perform a ray cast on this Simulated Body. //! @param request The request to make. //! @return Returns the closest hit, if any, against this simulated body. @@ -126,6 +143,7 @@ namespace AzPhysics SimulatedBodyEvents::OnTriggerExit m_triggerExitEvent; void* m_customUserData = nullptr; + uint32_t m_frameId = UndefinedFrameId; // helpers for reflecting to behavior context SimulatedBodyEvents::OnCollisionBegin* GetOnCollisionBeginEvent(); diff --git a/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionBus.h b/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionBus.h index ba1d2d1e06..749f457286 100644 --- a/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionBus.h +++ b/Code/Framework/AzFramework/AzFramework/Render/GeometryIntersectionBus.h @@ -12,6 +12,7 @@ #pragma once #include +#include #include namespace AzFramework @@ -35,12 +36,12 @@ namespace AzFramework AzFramework::EntityContextId m_contextId; }; - //! Interface for intersection requests, implement this interface for making your component - //! render geometry intersectable. + //! Interface for intersection requests. + //! Implement this interface to make your component 'intersectable'. class IntersectionRequests : public AZ::EBusTraits { - //! Policy for notifying the Intersector bus of entities connected/disconnected to this ebus + //! Policy for notifying the Intersector bus of entities connected/disconnected to this EBus //! so it updates the internal data of the entities template struct IntersectionRequestsConnectionPolicy diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp index e4833ccb3c..d5f02c957c 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.cpp @@ -144,7 +144,7 @@ namespace AzFramework z = AZStd::atan2(-orientation.GetElement(1, 2), orientation.GetElement(1, 1)); } - return {x, y, z}; + return { x, y, z }; } void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform) @@ -179,7 +179,7 @@ namespace AzFramework { const auto nextCamera = m_cameras.StepCamera(targetCamera, m_motionDelta, m_scrollDelta, deltaTime); - m_motionDelta = ScreenVector{0, 0}; + m_motionDelta = ScreenVector{ 0, 0 }; m_scrollDelta = 0.0f; return nextCamera; @@ -213,7 +213,10 @@ namespace AzFramework auto& cameraInput = m_idleCameraInputs[i]; const bool canBegin = cameraInput->Beginning() && AZStd::all_of(m_activeCameraInputs.cbegin(), m_activeCameraInputs.cend(), - [](const auto& input) { return !input->Exclusive(); }) && + [](const auto& input) + { + return !input->Exclusive(); + }) && (!cameraInput->Exclusive() || (cameraInput->Exclusive() && m_activeCameraInputs.empty())); if (canBegin) @@ -231,7 +234,8 @@ namespace AzFramework const Camera nextCamera = AZStd::accumulate( AZStd::begin(m_activeCameraInputs), AZStd::end(m_activeCameraInputs), targetCamera, - [cursorDelta, scrollDelta, deltaTime](Camera acc, auto& camera) { + [cursorDelta, scrollDelta, deltaTime](Camera acc, auto& camera) + { acc = camera->StepCamera(acc, cursorDelta, scrollDelta, deltaTime); return acc; }); @@ -284,7 +288,8 @@ namespace AzFramework bool RotateCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta) { - const ClickDetector::ClickEvent clickEvent = [&event, this] { + const ClickDetector::ClickEvent clickEvent = [&event, this] + { if (const auto& input = AZStd::get_if(&event)) { if (input->m_channelId == m_rotateChannelId) @@ -330,7 +335,10 @@ namespace AzFramework nextCamera.m_pitch -= float(cursorDelta.m_y) * ed_cameraSystemRotateSpeed; nextCamera.m_yaw -= float(cursorDelta.m_x) * ed_cameraSystemRotateSpeed; - const auto clampRotation = [](const float angle) { return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); }; + const auto clampRotation = [](const float angle) + { + return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); + }; nextCamera.m_yaw = clampRotation(nextCamera.m_yaw); // clamp pitch to be +-90 degrees @@ -377,9 +385,10 @@ namespace AzFramework const auto deltaPanX = float(cursorDelta.m_x) * panAxes.m_horizontalAxis * ed_cameraSystemPanSpeed; const auto deltaPanY = float(cursorDelta.m_y) * panAxes.m_verticalAxis * ed_cameraSystemPanSpeed; - const auto inv = [](const bool invert) { - constexpr float Dir[] = {1.0f, -1.0f}; - return Dir[static_cast(invert)]; + const auto inv = [](const bool invert) + { + constexpr float Dir[] = { 1.0f, -1.0f }; + return Dir[aznumeric_cast(invert)]; }; nextCamera.m_lookAt += deltaPanX * inv(ed_cameraSystemPanInvertX); @@ -475,7 +484,8 @@ namespace AzFramework const auto axisY = translationBasis.GetBasisY(); const auto axisZ = translationBasis.GetBasisZ(); - const float speed = [boost = m_boost]() { + const float speed = [boost = m_boost]() + { return ed_cameraSystemTranslateSpeed * (boost ? ed_cameraSystemBoostMultiplier : 1.0f); }(); @@ -555,10 +565,12 @@ namespace AzFramework if (Beginning()) { - const auto hasLookAt = [&nextCamera, &targetCamera, &lookAtFn = m_lookAtFn] { + const auto hasLookAt = [&nextCamera, &targetCamera, &lookAtFn = m_lookAtFn] + { if (lookAtFn) { - if (const auto lookAt = lookAtFn()) + // pass through the camera's position and look vector for use in the lookAt function + if (const auto lookAt = lookAtFn(targetCamera.Translation(), targetCamera.Rotation().GetBasisY())) { auto transform = AZ::Transform::CreateLookAt(targetCamera.m_lookAt, *lookAt); nextCamera.m_lookDist = -lookAt->GetDistance(targetCamera.m_lookAt); @@ -692,14 +704,20 @@ namespace AzFramework Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const float deltaTime) { - const auto clamp_rotation = [](const float angle) { return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); }; + const auto clamp_rotation = [](const float angle) + { + return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi); + }; // keep yaw in 0 - 360 range float targetYaw = clamp_rotation(targetCamera.m_yaw); const float currentYaw = clamp_rotation(currentCamera.m_yaw); // return the sign of the float input (-1, 0, 1) - const auto sign = [](const float value) { return aznumeric_cast((0.0f < value) - (value < 0.0f)); }; + const auto sign = [](const float value) + { + return aznumeric_cast((0.0f < value) - (value < 0.0f)); + }; // ensure smooth transition when moving across 0 - 360 boundary const float yawDelta = targetYaw - currentYaw; @@ -727,26 +745,28 @@ namespace AzFramework const auto& inputChannelId = inputChannel.GetInputChannelId(); const auto& inputDeviceId = inputChannel.GetInputDevice().GetInputDeviceId(); - const bool wasMouseButton = - AZStd::any_of(InputDeviceMouse::Button::All.begin(), InputDeviceMouse::Button::All.end(), [inputChannelId](const auto& button) { + const bool wasMouseButton = AZStd::any_of( + InputDeviceMouse::Button::All.begin(), InputDeviceMouse::Button::All.end(), + [inputChannelId](const auto& button) + { return button == inputChannelId; }); if (inputChannelId == InputDeviceMouse::Movement::X) { - return HorizontalMotionEvent{(int)inputChannel.GetValue()}; + return HorizontalMotionEvent{ aznumeric_cast(inputChannel.GetValue()) }; } else if (inputChannelId == InputDeviceMouse::Movement::Y) { - return VerticalMotionEvent{(int)inputChannel.GetValue()}; + return VerticalMotionEvent{ aznumeric_cast(inputChannel.GetValue()) }; } else if (inputChannelId == InputDeviceMouse::Movement::Z) { - return ScrollEvent{inputChannel.GetValue()}; + return ScrollEvent{ inputChannel.GetValue() }; } else if (wasMouseButton || InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId)) { - return DiscreteInputEvent{inputChannelId, inputChannel.GetState()}; + return DiscreteInputEvent{ inputChannelId, inputChannel.GetState() }; } return AZStd::monostate{}; diff --git a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h index ec70fc00de..a02f796899 100644 --- a/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h +++ b/Code/Framework/AzFramework/AzFramework/Viewport/CameraInput.h @@ -34,9 +34,9 @@ namespace AzFramework AZ::Vector3 m_lookAt = AZ::Vector3::CreateZero(); //!< Position of camera when m_lookDist is zero, //!< or position of m_lookAt when m_lookDist is greater //!< than zero. - float m_yaw{0.0}; - float m_pitch{0.0}; - float m_lookDist{0.0}; //!< Zero gives first person free look, otherwise orbit about m_lookAt + float m_yaw{ 0.0 }; + float m_pitch{ 0.0 }; + float m_lookDist{ 0.0 }; //!< Zero gives first person free look, otherwise orbit about m_lookAt //! View camera transform (v in MVP). AZ::Transform View() const; @@ -195,7 +195,11 @@ namespace AzFramework inline bool Cameras::Exclusive() const { return AZStd::any_of( - m_activeCameraInputs.begin(), m_activeCameraInputs.end(), [](const auto& cameraInput) { return cameraInput->Exclusive(); }); + m_activeCameraInputs.begin(), m_activeCameraInputs.end(), + [](const auto& cameraInput) + { + return cameraInput->Exclusive(); + }); } //! Responsible for updating a series of cameras given various inputs. @@ -209,7 +213,7 @@ namespace AzFramework private: ScreenVector m_motionDelta; //!< The delta used for look/orbit/pan (rotation + translation) - two dimensional. - float m_scrollDelta = 0.0f; //!< The delta used for dolly/movement (translation) - one dimensional. + float m_scrollDelta = 0.0f; //!< The delta used for dolly/movement (translation) - one dimensional. }; class RotateCameraInput : public CameraInput @@ -237,7 +241,7 @@ namespace AzFramework inline PanAxes LookPan(const Camera& camera) { const AZ::Matrix3x3 orientation = camera.Rotation(); - return {orientation.GetBasisX(), orientation.GetBasisZ()}; + return { orientation.GetBasisX(), orientation.GetBasisZ() }; } inline PanAxes OrbitPan(const Camera& camera) @@ -245,12 +249,13 @@ namespace AzFramework const AZ::Matrix3x3 orientation = camera.Rotation(); const auto basisX = orientation.GetBasisX(); - const auto basisY = [&orientation] { + const auto basisY = [&orientation] + { const auto forward = orientation.GetBasisY(); return AZ::Vector3(forward.GetX(), forward.GetY(), 0.0f).GetNormalized(); }(); - return {basisX, basisY}; + return { basisX, basisY }; } class PanCameraInput : public CameraInput @@ -285,7 +290,8 @@ namespace AzFramework const AZ::Matrix3x3 orientation = camera.Rotation(); const auto basisX = orientation.GetBasisX(); - const auto basisY = [&orientation] { + const auto basisY = [&orientation] + { const auto forward = orientation.GetBasisY(); return AZ::Vector3(forward.GetX(), forward.GetY(), 0.0f).GetNormalized(); }(); @@ -398,7 +404,7 @@ namespace AzFramework class OrbitCameraInput : public CameraInput { public: - using LookAtFn = AZStd::function()>; + using LookAtFn = AZStd::function(const AZ::Vector3& position, const AZ::Vector3& direction)>; // CameraInput overrides ... bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override; diff --git a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h index 884562d7e8..28971dc779 100644 --- a/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h +++ b/Code/Framework/AzManipulatorTestFramework/Include/AzManipulatorTestFramework/ViewportInteraction.h @@ -41,6 +41,7 @@ namespace AzManipulatorTestFramework AZStd::optional ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) override; AZStd::optional ViewportScreenToWorldRay( const AzFramework::ScreenPoint& screenPosition) override; + float DeviceScalingFactor() override; private: // ViewportInteractionRequestBus ... bool GridSnappingEnabled(); diff --git a/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp b/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp index ebef9dea30..7d32187a74 100644 --- a/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp +++ b/Code/Framework/AzManipulatorTestFramework/Source/ViewportInteraction.cpp @@ -127,4 +127,9 @@ namespace AzManipulatorTestFramework { return {}; } -} // namespace AzManipulatorTestFramework + + float ViewportInteraction::DeviceScalingFactor() + { + return 1.0f; + } +}// namespace AzManipulatorTestFramework diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/Menu.qss b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/Menu.qss index af9c675f23..7f48637cc8 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/Menu.qss +++ b/Code/Framework/AzQtComponents/AzQtComponents/Components/Widgets/Menu.qss @@ -49,7 +49,7 @@ QMenu::right-arrow QMenu::icon { - right: 8px; + right: 20px; } QMenu::indicator:checked diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/Notifications/link.svg b/Code/Framework/AzQtComponents/AzQtComponents/Images/Notifications/link.svg new file mode 100644 index 0000000000..dfd21d157f --- /dev/null +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/Notifications/link.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc index dbbf0e78e2..7b0c6530ab 100644 --- a/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc +++ b/Code/Framework/AzQtComponents/AzQtComponents/Images/resources.qrc @@ -13,5 +13,6 @@ Notifications/checkmark.svg Notifications/download.svg + Notifications/link.svg diff --git a/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h b/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h index 0090ce066b..855b4fe416 100644 --- a/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h +++ b/Code/Framework/AzTest/AzTest/Platform/Linux/AzTest_Traits_Linux.h @@ -39,4 +39,3 @@ #define AZ_TRAIT_DISABLE_FAILED_EMOTION_FX_EDITOR_TESTS true #define AZ_TRAIT_DISABLE_FAILED_METRICS_TESTS true -#define AZ_TRAIT_DISABLE_ASSET_JOB_PARALLEL_TESTS true diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp index 439789f11b..7fd11ff9bf 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Entity/PrefabEditorEntityOwnershipService.cpp @@ -57,7 +57,6 @@ namespace AzToolsFramework "Couldn't get prefab loader interface, it's a requirement for PrefabEntityOwnership system to work"); m_rootInstance = AZStd::unique_ptr(m_prefabSystemComponent->CreatePrefab({}, {}, "NewLevel.prefab")); - m_sliceOwnershipService.BusConnect(m_entityContextId); m_sliceOwnershipService.m_shouldAssertForLegacySlicesUsage = m_shouldAssertForLegacySlicesUsage; m_editorSliceOwnershipService.BusConnect(); @@ -91,14 +90,17 @@ namespace AzToolsFramework void PrefabEditorEntityOwnershipService::Reset() { - Prefab::TemplateId templateId = m_rootInstance->GetTemplateId(); - if (templateId != Prefab::InvalidTemplateId) + if (m_rootInstance) { - m_rootInstance->SetTemplateId(Prefab::InvalidTemplateId); - m_prefabSystemComponent->RemoveTemplate(templateId); + Prefab::TemplateId templateId = m_rootInstance->GetTemplateId(); + if (templateId != Prefab::InvalidTemplateId) + { + m_rootInstance->SetTemplateId(Prefab::InvalidTemplateId); + m_prefabSystemComponent->RemoveTemplate(templateId); + } + m_rootInstance->Reset(); + m_rootInstance->SetContainerEntityName("Level"); } - m_rootInstance->Reset(); - m_rootInstance->SetContainerEntityName("Level"); AzFramework::EntityOwnershipServiceNotificationBus::Event( m_entityContextId, &AzFramework::EntityOwnershipServiceNotificationBus::Events::OnEntityOwnershipServiceReset); @@ -202,7 +204,7 @@ namespace AzToolsFramework } m_rootInstance->SetTemplateId(templateId); - m_rootInstance->SetTemplateSourcePath(m_loaderInterface->GetRelativePathToProject(filename)); + m_rootInstance->SetTemplateSourcePath(m_loaderInterface->GenerateRelativePath(filename)); m_rootInstance->SetContainerEntityName("Level"); m_prefabSystemComponent->PropagateTemplateChanges(templateId); @@ -220,7 +222,7 @@ namespace AzToolsFramework bool PrefabEditorEntityOwnershipService::SaveToStream(AZ::IO::GenericStream& stream, AZStd::string_view filename) { - AZ::IO::Path relativePath = m_loaderInterface->GetRelativePathToProject(filename); + AZ::IO::Path relativePath = m_loaderInterface->GenerateRelativePath(filename); AzToolsFramework::Prefab::TemplateId templateId = m_prefabSystemComponent->GetTemplateIdFromFilePath(relativePath); m_rootInstance->SetTemplateSourcePath(relativePath); @@ -267,7 +269,7 @@ namespace AzToolsFramework void PrefabEditorEntityOwnershipService::CreateNewLevelPrefab(AZStd::string_view filename, const AZStd::string& templateFilename) { - AZ::IO::Path relativePath = m_loaderInterface->GetRelativePathToProject(filename); + AZ::IO::Path relativePath = m_loaderInterface->GenerateRelativePath(filename); AzToolsFramework::Prefab::TemplateId templateId = m_prefabSystemComponent->GetTemplateIdFromFilePath(relativePath); m_rootInstance->SetTemplateSourcePath(relativePath); @@ -378,7 +380,12 @@ namespace AzToolsFramework Prefab::InstanceOptionalReference PrefabEditorEntityOwnershipService::GetRootPrefabInstance() { AZ_Assert(m_rootInstance, "A valid root prefab instance couldn't be found in PrefabEditorEntityOwnershipService."); - return *m_rootInstance; + if (m_rootInstance) + { + return *m_rootInstance; + } + + return AZStd::nullopt; } const AZStd::vector>& PrefabEditorEntityOwnershipService::GetPlayInEditorAssetData() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceSerializer.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceSerializer.cpp index 836140eb74..39351df486 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceSerializer.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/Instance/InstanceSerializer.cpp @@ -124,7 +124,7 @@ namespace AzToolsFramework "PrefabLoaderInterface could not be found. It is required to load Prefab Instances"); // Make sure we have a relative path - instance->m_templateSourcePath = loaderInterface->GetRelativePathToProject(instance->m_templateSourcePath); + instance->m_templateSourcePath = loaderInterface->GenerateRelativePath(instance->m_templateSourcePath); TemplateId templateId = prefabSystemComponentInterface->GetTemplateIdFromFilePath(instance->GetTemplateSourcePath()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.cpp index 2965148172..e4507227b5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.cpp @@ -18,7 +18,9 @@ #include #include +#include #include +#include #include #include #include @@ -112,7 +114,7 @@ namespace AzToolsFramework return InvalidTemplateId; } - AZ::IO::Path relativePath = GetRelativePathToProject(originPath); + AZ::IO::Path relativePath = GenerateRelativePath(originPath); // Cyclical dependency detected if the prefab file is already part of the progressed // file path set. @@ -385,21 +387,100 @@ namespace AzToolsFramework AZ::IO::Path pathWithOSSeparator = AZ::IO::Path(path).MakePreferred(); if (pathWithOSSeparator.IsAbsolute()) { + // If an absolute path was passed in, just return it as-is. return path; } - return AZ::IO::Path(m_projectPathWithOsSeparator).Append(pathWithOSSeparator); + // A relative path was passed in, so try to turn it back into an absolute path. + + AZ::IO::Path fullPath; + + bool pathFound = false; + AZ::Data::AssetInfo assetInfo; + AZStd::string rootFolder; + AZStd::string inputPath(path.Native()); + + // Given an input path that's expected to exist, try to look it up. + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + pathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, + inputPath.c_str(), assetInfo, rootFolder); + + if (pathFound) + { + // The asset system provided us with a valid root folder and relative path, so return it. + fullPath = AZ::IO::Path(rootFolder) / assetInfo.m_relativePath; + } + else + { + // If for some reason the Asset system couldn't provide a relative path, provide some fallback logic. + + // Check to see if the AssetProcessor is ready. If it *is* and we didn't get a path, print an error then follow + // the fallback logic. If it's *not* ready, we're probably either extremely early in a tool startup flow or inside + // a unit test, so just execute the fallback logic without an error. + [[maybe_unused]] bool assetProcessorReady = false; + AzFramework::AssetSystemRequestBus::BroadcastResult( + assetProcessorReady, &AzFramework::AssetSystemRequestBus::Events::AssetProcessorIsReady); + + AZ_Error( + "Prefab", !assetProcessorReady, "Full source path for '%.*s' could not be determined. Using fallback logic.", + AZ_STRING_ARG(path.Native())); + + // If a relative path was passed in, make it relative to the project root. + fullPath = AZ::IO::Path(m_projectPathWithOsSeparator).Append(pathWithOSSeparator); + } + + return fullPath; } - AZ::IO::Path PrefabLoader::GetRelativePathToProject(AZ::IO::PathView path) + AZ::IO::Path PrefabLoader::GenerateRelativePath(AZ::IO::PathView path) { - AZ::IO::Path pathWithOSSeparator = AZ::IO::Path(path.Native()).MakePreferred(); - if (!pathWithOSSeparator.IsAbsolute()) + bool pathFound = false; + + AZStd::string relativePath; + AZStd::string rootFolder; + AZ::IO::Path finalPath; + + // The asset system allows for paths to be relative to multiple root folders, using a priority system. + // This request will make the input path relative to the most appropriate, highest-priority root folder. + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + pathFound, &AzToolsFramework::AssetSystemRequestBus::Events::GenerateRelativeSourcePath, path.Native(), + relativePath, rootFolder); + + if (pathFound && !relativePath.empty()) { - return path; + // A relative path was generated successfully, so return it. + finalPath = relativePath; + } + else + { + // If for some reason the Asset system couldn't provide a relative path, provide some fallback logic. + + // Check to see if the AssetProcessor is ready. If it *is* and we didn't get a path, print an error then follow + // the fallback logic. If it's *not* ready, we're probably either extremely early in a tool startup flow or inside + // a unit test, so just execute the fallback logic without an error. + [[maybe_unused]] bool assetProcessorReady = false; + AzFramework::AssetSystemRequestBus::BroadcastResult( + assetProcessorReady, &AzFramework::AssetSystemRequestBus::Events::AssetProcessorIsReady); + + AZ_Error("Prefab", !assetProcessorReady, + "Relative source path for '%.*s' could not be determined. Using project path as relative root.", + AZ_STRING_ARG(path.Native())); + + AZ::IO::Path pathWithOSSeparator = AZ::IO::Path(path.Native()).MakePreferred(); + + if (pathWithOSSeparator.IsAbsolute()) + { + // If an absolute path was passed in, make it relative to the project path. + finalPath = AZ::IO::Path(path.Native(), '/').MakePreferred().LexicallyRelative(m_projectPathWithSlashSeparator); + } + else + { + // If a relative path was passed in, just return it. + finalPath = path; + } } - return AZ::IO::Path(path.Native(), '/').MakePreferred().LexicallyRelative(m_projectPathWithSlashSeparator); + return finalPath; } AZ::IO::Path PrefabLoaderInterface::GeneratePath() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.h index d11cb62ca3..aed24e153e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoader.h @@ -91,9 +91,11 @@ namespace AzToolsFramework //! The path will always have the correct separator for the current OS AZ::IO::Path GetFullPath(AZ::IO::PathView path) override; - //! Converts path into a relative path to the project, this will be the paths in .prefab file. - //! The path will always have '/' separator. - AZ::IO::Path GetRelativePathToProject(AZ::IO::PathView path) override; + //! Converts path into a path that's relative to the highest-priority containing folder of all the folders registered + //! with the engine. + //! This path will be the path that appears in the .prefab file. + //! The path will always use the '/' separator. + AZ::IO::Path GenerateRelativePath(AZ::IO::PathView path) override; //! Returns if the path is a valid path for a prefab static bool IsValidPrefabPath(AZ::IO::PathView path); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderInterface.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderInterface.h index a4055fb15a..d71fbff80f 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderInterface.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabLoaderInterface.h @@ -74,9 +74,11 @@ namespace AzToolsFramework //! The path will always have the correct separator for the current OS virtual AZ::IO::Path GetFullPath(AZ::IO::PathView path) = 0; - //! Converts path into a relative path to the current project, this will be the paths in .prefab file. - //! The path will always have '/' separator. - virtual AZ::IO::Path GetRelativePathToProject(AZ::IO::PathView path) = 0; + //! Converts path into a path that's relative to the highest-priority containing folder of all the folders registered + //! with the engine. + //! This path will be the path that appears in the .prefab file. + //! The path will always use the '/' separator. + virtual AZ::IO::Path GenerateRelativePath(AZ::IO::PathView path) = 0; protected: diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp index 0181050a32..9dd5199ea2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabPublicHandler.cpp @@ -318,7 +318,7 @@ namespace AzToolsFramework } //Detect whether this instantiation would produce a cyclical dependency - auto relativePath = m_prefabLoaderInterface->GetRelativePathToProject(filePath); + auto relativePath = m_prefabLoaderInterface->GenerateRelativePath(filePath); Prefab::TemplateId templateId = m_prefabSystemComponentInterface->GetTemplateIdFromFilePath(relativePath); if (templateId == InvalidTemplateId) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp index c4e6415b02..0136f791b3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Prefab/PrefabSystemComponent.cpp @@ -95,7 +95,7 @@ namespace AzToolsFramework const AZStd::vector& entities, AZStd::vector>&& instancesToConsume, AZ::IO::PathView filePath, AZStd::unique_ptr containerEntity, bool shouldCreateLinks) { - AZ::IO::Path relativeFilePath = m_prefabLoader.GetRelativePathToProject(filePath); + AZ::IO::Path relativeFilePath = m_prefabLoader.GenerateRelativePath(filePath); if (GetTemplateIdFromFilePath(relativeFilePath) != InvalidTemplateId) { AZ_Error("Prefab", false, diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index cc65b61908..8293614525 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -172,7 +172,7 @@ namespace AzToolsFramework const int autoExpandDelayMilliseconds = 2500; m_gui->m_objectTree->setSelectionMode(QAbstractItemView::ExtendedSelection); - m_gui->m_objectTree->setEditTriggers(QAbstractItemView::EditKeyPressed); + SetDefaultTreeViewEditTriggers(); m_gui->m_objectTree->setAutoExpandDelay(autoExpandDelayMilliseconds); m_gui->m_objectTree->setDragEnabled(true); m_gui->m_objectTree->setDropIndicatorShown(true); @@ -850,6 +850,11 @@ namespace AzToolsFramework addAction(m_actionGoToEntitiesInViewport); } + void EntityOutlinerWidget::SetDefaultTreeViewEditTriggers() + { + m_gui->m_objectTree->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::EditKeyPressed); + } + void EntityOutlinerWidget::OnEntityPickModeStarted() { m_gui->m_objectTree->setDragEnabled(false); @@ -862,7 +867,7 @@ namespace AzToolsFramework { m_gui->m_objectTree->setDragEnabled(true); m_gui->m_objectTree->setSelectionMode(QAbstractItemView::ExtendedSelection); - m_gui->m_objectTree->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); + SetDefaultTreeViewEditTriggers(); m_inObjectPickMode = false; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx index 9a02febab2..6e3979a21e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx @@ -166,6 +166,8 @@ namespace AzToolsFramework // to a given entity void QueueScrollToNewContent(const AZ::EntityId& entityId) override; + void SetDefaultTreeViewEditTriggers(); + void ScrollToNewContent(); bool m_scrollToNewContentQueued; bool m_scrollToSelectedEntity; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp index 3edc190fb7..61d4433c0e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabIntegrationManager.cpp @@ -333,7 +333,8 @@ namespace AzToolsFramework } } - auto createPrefabOutcome = s_prefabPublicInterface->CreatePrefab(selectedEntities, s_prefabLoaderInterface->GetRelativePathToProject(prefabFilePath.data())); + auto createPrefabOutcome = s_prefabPublicInterface->CreatePrefab( + selectedEntities, s_prefabLoaderInterface->GenerateRelativePath(prefabFilePath.data())); if (!createPrefabOutcome.IsSuccess()) { diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h index 8e91dc945d..91eee18cb7 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Viewport/ViewportMessages.h @@ -165,15 +165,18 @@ namespace AzToolsFramework virtual bool AngleSnappingEnabled() = 0; /// Return the angle snapping/step size. virtual float AngleStep() = 0; - /// Transform a point in world space to screen space coordinates. + /// Transform a point in world space to screen space coordinates in Qt Widget space. + /// Multiply by DeviceScalingFactor to get the position in viewport pixel space. virtual AzFramework::ScreenPoint ViewportWorldToScreen(const AZ::Vector3& worldPosition) = 0; - /// Transform a point in screen space coordinates to a vector in world space based on clip space depth. + /// Transform a point from Qt widget screen space to world space based on the given clip space depth. /// Depth specifies a relative camera depth to project in the range of [0.f, 1.f]. /// Returns the world space position if successful. virtual AZStd::optional ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) = 0; /// Casts a point in screen space to a ray in world space originating from the viewport camera frustum's near plane. /// Returns a ray containing the ray's origin and a direction normal, if successful. virtual AZStd::optional ViewportScreenToWorldRay(const AzFramework::ScreenPoint& screenPosition) = 0; + /// Gets the DPI scaling factor that translates Qt widget space into viewport pixel space. + virtual float DeviceScalingFactor() = 0; protected: ~ViewportInteractionRequests() = default; diff --git a/Code/LauncherUnified/launcher_generator.cmake b/Code/LauncherUnified/launcher_generator.cmake index edb6655411..c5d60eb29e 100644 --- a/Code/LauncherUnified/launcher_generator.cmake +++ b/Code/LauncherUnified/launcher_generator.cmake @@ -179,6 +179,7 @@ function(ly_delayed_generate_static_modules_inl) ${launcher_unified_binary_dir}/${project_name}.GameLauncher/Includes/StaticModules.inl ) + ly_target_link_libraries(${project_name}.GameLauncher PRIVATE ${all_game_gem_dependencies}) if(PAL_TRAIT_BUILD_SERVER_SUPPORTED) get_property(server_gem_dependencies GLOBAL PROPERTY LY_STATIC_MODULE_PROJECTS_DEPENDENCIES_${project_name}.ServerLauncher) @@ -204,6 +205,7 @@ function(ly_delayed_generate_static_modules_inl) ${launcher_unified_binary_dir}/${project_name}.ServerLauncher/Includes/StaticModules.inl ) + ly_target_link_libraries(${project_name}.ServerLauncher PRIVATE ${all_server_gem_dependencies}) endif() endforeach() endif() diff --git a/Code/Sandbox/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp b/Code/Sandbox/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp index c8bd157b65..e0ba106875 100644 --- a/Code/Sandbox/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp +++ b/Code/Sandbox/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp @@ -137,8 +137,20 @@ namespace AzAssetBrowserRequestHandlerPrivate entityName = AZStd::string::format("Entity%d", GetIEditor()->GetObjectManager()->GetObjectCount()); } - AZ::Entity* newEntity = aznew AZ::Entity(entityName.c_str()); - EditorEntityContextRequestBus::Broadcast(&EditorEntityContextRequests::AddRequiredComponents, *newEntity); + AZ::EntityId targetEntityId; + EditorRequests::Bus::BroadcastResult(targetEntityId, &EditorRequests::CreateNewEntityAtPosition, worldTransform.GetTranslation(), AZ::EntityId()); + + AZ::Entity* newEntity = nullptr; + AZ::ComponentApplicationBus::BroadcastResult(newEntity, &AZ::ComponentApplicationRequests::FindEntity, targetEntityId); + + if (newEntity == nullptr) + { + return; + } + + newEntity->SetName(entityName); + + newEntity->Deactivate(); // Create component. AZ::Component* newComponent = newEntity->CreateComponent(componentTypeId); @@ -151,15 +163,7 @@ namespace AzAssetBrowserRequestHandlerPrivate newEntity->AddComponent(newComponent); } - // Set entity position. - auto* transformComponent = newEntity->FindComponent(); - if (transformComponent) - { - transformComponent->SetWorldTM(worldTransform); - } - - // Add the entity to the editor context, which activates it and creates the sandbox object. - EditorEntityContextRequestBus::Broadcast(&EditorEntityContextRequests::AddEditorEntity, newEntity); + newEntity->Activate(); // set asset after components have been activated in AddEditorEntity method if (newComponent) diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index ecd11da817..989d6e407d 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -1221,50 +1221,73 @@ void EditorViewportWidget::SetViewportId(int id) AzFramework::ReloadCameraKeyBindings(); auto controller = AZStd::make_shared(); - controller->SetCameraListBuilderCallback([](AzFramework::Cameras& cameras) - { - auto firstPersonRotateCamera = AZStd::make_shared(AzFramework::CameraFreeLookButton); - auto firstPersonPanCamera = - AZStd::make_shared(AzFramework::CameraFreePanButton, AzFramework::LookPan); - auto firstPersonTranslateCamera = AZStd::make_shared(AzFramework::LookTranslation); - auto firstPersonWheelCamera = AZStd::make_shared(); + controller->SetCameraListBuilderCallback( + [](AzFramework::Cameras& cameras) + { + auto firstPersonRotateCamera = AZStd::make_shared(AzFramework::CameraFreeLookButton); + auto firstPersonPanCamera = + AZStd::make_shared(AzFramework::CameraFreePanButton, AzFramework::LookPan); + auto firstPersonTranslateCamera = AZStd::make_shared(AzFramework::LookTranslation); + auto firstPersonWheelCamera = AZStd::make_shared(); - auto orbitCamera = AZStd::make_shared(); - orbitCamera->SetLookAtFn([]() -> AZStd::optional { - AZStd::optional manipulatorTransform; - AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( - manipulatorTransform, AzToolsFramework::GetEntityContextId(), - &AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform); + auto orbitCamera = AZStd::make_shared(); + orbitCamera->SetLookAtFn( + [](const AZ::Vector3& position, const AZ::Vector3& direction) -> AZStd::optional + { + AZStd::optional manipulatorTransform; + AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult( + manipulatorTransform, AzToolsFramework::GetEntityContextId(), + &AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform); - if (manipulatorTransform) - { - return manipulatorTransform->GetTranslation(); - } + // initially attempt to use manipulator transform if one exists (there is a selection) + if (manipulatorTransform) + { + return manipulatorTransform->GetTranslation(); + } - return {}; + const float RayDistance = 1000.0f; + AzFramework::RenderGeometry::RayRequest ray; + ray.m_startWorldPosition = position; + ray.m_endWorldPosition = position + direction * RayDistance; + ray.m_onlyVisible = true; + + AzFramework::RenderGeometry::RayResult renderGeometryIntersectionResult; + AzFramework::RenderGeometry::IntersectorBus::EventResult( + renderGeometryIntersectionResult, AzToolsFramework::GetEntityContextId(), + &AzFramework::RenderGeometry::IntersectorInterface::RayIntersect, ray); + + // attempt a ray intersection with any visible mesh and return the intersection position if successful + if (renderGeometryIntersectionResult) + { + return renderGeometryIntersectionResult.m_worldPosition; + } + + // if there is no selection or no intersection, fallback to default camera orbit behavior (ground plane + // intersection) + return {}; + }); + + auto orbitRotateCamera = AZStd::make_shared(AzFramework::CameraOrbitLookButton); + auto orbitTranslateCamera = AZStd::make_shared(AzFramework::OrbitTranslation); + auto orbitDollyWheelCamera = AZStd::make_shared(); + auto orbitDollyMoveCamera = + AZStd::make_shared(AzFramework::CameraOrbitDollyButton); + auto orbitPanCamera = + AZStd::make_shared(AzFramework::CameraOrbitPanButton, AzFramework::OrbitPan); + + orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera); + orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera); + orbitCamera->m_orbitCameras.AddCamera(orbitDollyWheelCamera); + orbitCamera->m_orbitCameras.AddCamera(orbitDollyMoveCamera); + orbitCamera->m_orbitCameras.AddCamera(orbitPanCamera); + + cameras.AddCamera(firstPersonRotateCamera); + cameras.AddCamera(firstPersonPanCamera); + cameras.AddCamera(firstPersonTranslateCamera); + cameras.AddCamera(firstPersonWheelCamera); + cameras.AddCamera(orbitCamera); }); - auto orbitRotateCamera = AZStd::make_shared(AzFramework::CameraOrbitLookButton); - auto orbitTranslateCamera = AZStd::make_shared(AzFramework::OrbitTranslation); - auto orbitDollyWheelCamera = AZStd::make_shared(); - auto orbitDollyMoveCamera = - AZStd::make_shared(AzFramework::CameraOrbitDollyButton); - auto orbitPanCamera = - AZStd::make_shared(AzFramework::CameraOrbitPanButton, AzFramework::OrbitPan); - - orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera); - orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera); - orbitCamera->m_orbitCameras.AddCamera(orbitDollyWheelCamera); - orbitCamera->m_orbitCameras.AddCamera(orbitDollyMoveCamera); - orbitCamera->m_orbitCameras.AddCamera(orbitPanCamera); - - cameras.AddCamera(firstPersonRotateCamera); - cameras.AddCamera(firstPersonPanCamera); - cameras.AddCamera(firstPersonTranslateCamera); - cameras.AddCamera(firstPersonWheelCamera); - cameras.AddCamera(orbitCamera); - }); - m_renderViewport->GetControllerList()->Add(controller); } else diff --git a/Code/Sandbox/Editor/RenderViewport.h b/Code/Sandbox/Editor/RenderViewport.h index d70dd59b98..b45c92b1c8 100644 --- a/Code/Sandbox/Editor/RenderViewport.h +++ b/Code/Sandbox/Editor/RenderViewport.h @@ -200,6 +200,7 @@ public: { return {}; } + float DeviceScalingFactor() override { return 1.0f; } // AzToolsFramework::ViewportFreezeRequestBus bool IsViewportInputFrozen() override; diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index 5eb92964dd..a85b911c15 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -336,4 +336,31 @@ QTabBar::tab:pressed max-width:210px;; min-height:278px; max-height:278px; -} \ No newline at end of file +} + +/************** Gem Catalog **************/ + +#GemCatalogTitle { + font-size: 18px; +} + +/************** Gem Catalog (Inspector) **************/ + +#GemCatalogInspector { + background-color: #444444; +} + +/************** Gem Catalog (Filter/left pane) **************/ + +#GemCatalogFilterWidget { + background-color: #444444; +} + +#GemCatalogHeaderWidget { + background-color: #1E252F; +} + +#GemCatalogFilterCategoryTitle { + font-size: 12px; + font-weight: 600; +} diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp index 6e9ad42017..6402121e4a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogHeaderWidget.cpp @@ -25,10 +25,12 @@ namespace O3DE::ProjectManager hLayout->setMargin(0); setLayout(hLayout); - setStyleSheet("background-color: #1E252F;"); + setObjectName("GemCatalogHeaderWidget"); + + hLayout->addSpacing(7); QLabel* titleLabel = new QLabel(tr("Gem Catalog")); - titleLabel->setStyleSheet("font-size: 21px;"); + titleLabel->setObjectName("GemCatalogTitle"); hLayout->addWidget(titleLabel); hLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); @@ -42,7 +44,7 @@ namespace O3DE::ProjectManager hLayout->addWidget(filterLineEdit); hLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); - hLayout->addSpacerItem(new QSpacerItem(220, 0, QSizePolicy::Fixed)); + hLayout->addSpacerItem(new QSpacerItem(140, 0, QSizePolicy::Fixed)); setFixedHeight(60); } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp index 3ece7760cf..a6a4e95ff9 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp @@ -43,7 +43,6 @@ namespace O3DE::ProjectManager m_collapseButton->setFlat(true); m_collapseButton->setFocusPolicy(Qt::NoFocus); m_collapseButton->setFixedWidth(s_collapseButtonSize); - m_collapseButton->setStyleSheet("border: 0px; border-radius: 0px;"); connect(m_collapseButton, &QPushButton::clicked, this, [=]() { UpdateCollapseState(); @@ -52,7 +51,7 @@ namespace O3DE::ProjectManager // Category title QLabel* headerLabel = new QLabel(header); - headerLabel->setStyleSheet("font-size: 11pt;"); + headerLabel->setObjectName("GemCatalogFilterCategoryTitle"); collapseLayout->addWidget(headerLabel); vLayout->addLayout(collapseLayout); @@ -79,14 +78,14 @@ namespace O3DE::ProjectManager elementWidget->setLayout(elementLayout); QCheckBox* checkbox = new QCheckBox(elementNames[i]); - checkbox->setStyleSheet("font-size: 11pt;"); + checkbox->setStyleSheet("font-size: 12px;"); m_buttonGroup->addButton(checkbox); elementLayout->addWidget(checkbox); elementLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); QLabel* countLabel = new QLabel(QString::number(elementCounts[i])); - countLabel->setStyleSheet("font-size: 11pt; background-color: #333333; border-radius: 3px; color: #94D2FF;"); + countLabel->setStyleSheet("font-size: 12px; background-color: #333333; border-radius: 3px; color: #94D2FF;"); elementLayout->addWidget(countLabel); m_elementWidgets.push_back(elementWidget); @@ -110,6 +109,8 @@ namespace O3DE::ProjectManager } } + vLayout->addSpacing(5); + // Separating line QFrame* hLine = new QFrame(); hLine->setFrameShape(QFrame::HLine); @@ -181,6 +182,8 @@ namespace O3DE::ProjectManager : QScrollArea(parent) , m_filterProxyModel(filterProxyModel) { + setObjectName("GemCatalogFilterWidget"); + m_gemModel = m_filterProxyModel->GetSourceModel(); setWidgetResizable(true); @@ -195,7 +198,7 @@ namespace O3DE::ProjectManager mainWidget->setLayout(m_mainLayout); QLabel* filterByLabel = new QLabel("Filter by"); - filterByLabel->setStyleSheet("font-size: 15pt;"); + filterByLabel->setStyleSheet("font-size: 16px;"); m_mainLayout->addWidget(filterByLabel); AddGemOriginFilter(); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp index 6276ddc996..3ecc18231e 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp @@ -23,6 +23,7 @@ namespace O3DE::ProjectManager : QScrollArea(parent) , m_model(model) { + setObjectName("GemCatalogInspector"); setWidgetResizable(true); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); @@ -85,7 +86,7 @@ namespace O3DE::ProjectManager QLabel* GemInspector::CreateStyledLabel(QLayout* layout, int fontSize, const QString& colorCodeString) { QLabel* result = new QLabel(); - result->setStyleSheet(QString("font-size: %1pt; color: %2;").arg(QString::number(fontSize), colorCodeString)); + result->setStyleSheet(QString("font-size: %1px; color: %2;").arg(QString::number(fontSize), colorCodeString)); layout->addWidget(result); return result; } @@ -93,13 +94,13 @@ namespace O3DE::ProjectManager void GemInspector::InitMainWidget() { // Gem name, creator and summary - m_nameLabel = CreateStyledLabel(m_mainLayout, 17, s_headerColor); + m_nameLabel = CreateStyledLabel(m_mainLayout, 18, s_headerColor); m_creatorLabel = CreateStyledLabel(m_mainLayout, 12, s_creatorColor); m_mainLayout->addSpacing(5); // TODO: QLabel seems to have issues determining the right sizeHint() for our font with the given font size. // This results into squeezed elements in the layout in case the text is a little longer than a sentence. - m_summaryLabel = new QLabel();//CreateLabel(m_mainLayout, 12, s_textColor); + m_summaryLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor); m_mainLayout->addWidget(m_summaryLabel); m_summaryLabel->setWordWrap(true); m_mainLayout->addSpacing(5); @@ -146,9 +147,9 @@ namespace O3DE::ProjectManager QLabel* additionalInfoLabel = CreateStyledLabel(m_mainLayout, 14, s_headerColor); additionalInfoLabel->setText("Additional Information"); - m_versionLabel = CreateStyledLabel(m_mainLayout, 11, s_textColor); - m_lastUpdatedLabel = CreateStyledLabel(m_mainLayout, 11, s_textColor); - m_binarySizeLabel = CreateStyledLabel(m_mainLayout, 11, s_textColor); + m_versionLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor); + m_lastUpdatedLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor); + m_binarySizeLabel = CreateStyledLabel(m_mainLayout, 12, s_textColor); } GemInspector::GemsSubWidget::GemsSubWidget(QWidget* parent) @@ -159,8 +160,8 @@ namespace O3DE::ProjectManager m_layout->setMargin(0); setLayout(m_layout); - m_titleLabel = GemInspector::CreateStyledLabel(m_layout, 15, s_headerColor); - m_textLabel = GemInspector::CreateStyledLabel(m_layout, 9, s_textColor); + m_titleLabel = GemInspector::CreateStyledLabel(m_layout, 16, s_headerColor); + m_textLabel = GemInspector::CreateStyledLabel(m_layout, 10, s_textColor); m_textLabel->setWordWrap(true); m_tagWidget = new TagContainerWidget(); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index a40e5eb447..57200e3b36 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -49,7 +49,7 @@ namespace O3DE::ProjectManager painter->setRenderHint(QPainter::Antialiasing); QRect fullRect, itemRect, contentRect; - CalcRects(options, modelIndex, fullRect, itemRect, contentRect); + CalcRects(options, fullRect, itemRect, contentRect); QFont standardFont(options.font); standardFont.setPixelSize(s_fontSize); @@ -99,7 +99,7 @@ namespace O3DE::ProjectManager painter->drawText(gemCreatorRect, Qt::TextSingleLine, gemCreator); // Gem summary - const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - s_itemMargins.right() * 4, contentRect.height()); + const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - s_itemMargins.right() * 3, contentRect.height()); const QRect summaryRect = QRect(/*topLeft=*/QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), summarySize); painter->setFont(standardFont); @@ -134,12 +134,10 @@ namespace O3DE::ProjectManager return QStyledItemDelegate::editorEvent(event, model, option, modelIndex); } - void GemItemDelegate::CalcRects(const QStyleOptionViewItem& option, const QModelIndex& modelIndex, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const + void GemItemDelegate::CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const { - const bool isFirst = modelIndex.row() == 0; - outFullRect = QRect(option.rect); - outItemRect = QRect(outFullRect.adjusted(s_itemMargins.left(), isFirst ? s_itemMargins.top() * 2 : s_itemMargins.top(), -s_itemMargins.right(), -s_itemMargins.bottom())); + outItemRect = QRect(outFullRect.adjusted(s_itemMargins.left(), s_itemMargins.top(), -s_itemMargins.right(), -s_itemMargins.bottom())); outContentRect = QRect(outItemRect.adjusted(s_contentMargins.left(), s_contentMargins.top(), -s_contentMargins.right(), -s_contentMargins.bottom())); } @@ -194,12 +192,12 @@ namespace O3DE::ProjectManager painter->setBrush(m_buttonEnabledColor); painter->setPen(m_buttonEnabledColor); - circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius, 1); + circleCenter = buttonRect.center() + QPoint(buttonRect.width() / 2 - s_buttonBorderRadius + 1, 1); buttonText = "Added"; } else { - circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius + 1, 1); + circleCenter = buttonRect.center() + QPoint(-buttonRect.width() / 2 + s_buttonBorderRadius, 1); buttonText = "Get"; } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h index d43b5d15f6..48f173ec3f 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h @@ -45,25 +45,25 @@ namespace O3DE::ProjectManager const QColor m_buttonEnabledColor = QColor("#00B931"); // Item - inline constexpr static int s_height = 135; // Gem item total height - inline constexpr static qreal s_gemNameFontSize = 16.0; - inline constexpr static qreal s_fontSize = 15.0; - inline constexpr static int s_summaryStartX = 200; + inline constexpr static int s_height = 105; // Gem item total height + inline constexpr static qreal s_gemNameFontSize = 13.0; + inline constexpr static qreal s_fontSize = 12.0; + inline constexpr static int s_summaryStartX = 150; // Margin and borders - inline constexpr static QMargins s_itemMargins = QMargins(/*left=*/20, /*top=*/10, /*right=*/20, /*bottom=*/10); // Item border distances - inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/15, /*top=*/12, /*right=*/12, /*bottom=*/12); // Distances of the elements within an item to the item borders + inline constexpr static QMargins s_itemMargins = QMargins(/*left=*/16, /*top=*/8, /*right=*/16, /*bottom=*/8); // Item border distances + inline constexpr static QMargins s_contentMargins = QMargins(/*left=*/20, /*top=*/12, /*right=*/15, /*bottom=*/12); // Distances of the elements within an item to the item borders inline constexpr static int s_borderWidth = 4; // Button - inline constexpr static int s_buttonWidth = 70; - inline constexpr static int s_buttonHeight = 24; - inline constexpr static int s_buttonBorderRadius = 12; - inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 3; - inline constexpr static qreal s_buttonFontSize = 12.0; + inline constexpr static int s_buttonWidth = 55; + inline constexpr static int s_buttonHeight = 18; + inline constexpr static int s_buttonBorderRadius = 9; + inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 2; + inline constexpr static qreal s_buttonFontSize = 10.0; private: - void CalcRects(const QStyleOptionViewItem& option, const QModelIndex& modelIndex, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const; + void CalcRects(const QStyleOptionViewItem& option, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const; QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const; QRect CalcButtonRect(const QRect& contentRect) const; void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; @@ -73,7 +73,7 @@ namespace O3DE::ProjectManager // Platform icons void AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath); - inline constexpr static int s_platformIconSize = 16; + inline constexpr static int s_platformIconSize = 12; QHash m_platformIcons; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp index 128fb93345..bc287e3c61 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp @@ -35,7 +35,7 @@ namespace O3DE::ProjectManager topLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); QLabel* showCountLabel = new QLabel(); - showCountLabel->setStyleSheet("font-size: 11pt; font: italic;"); + showCountLabel->setStyleSheet("font-size: 12px; font: italic;"); topLayout->addWidget(showCountLabel); connect(proxyModel, &GemSortFilterProxyModel::OnInvalidated, this, [=] { @@ -61,16 +61,17 @@ namespace O3DE::ProjectManager QHBoxLayout* columnHeaderLayout = new QHBoxLayout(); columnHeaderLayout->setAlignment(Qt::AlignLeft); - columnHeaderLayout->addSpacing(31); + const int gemNameStartX = GemItemDelegate::s_itemMargins.left() + GemItemDelegate::s_contentMargins.left() - 3; + columnHeaderLayout->addSpacing(gemNameStartX); QLabel* gemNameLabel = new QLabel(tr("Gem Name")); - gemNameLabel->setStyleSheet("font-size: 11pt;"); + gemNameLabel->setStyleSheet("font-size: 12px;"); columnHeaderLayout->addWidget(gemNameLabel); - columnHeaderLayout->addSpacing(111); + columnHeaderLayout->addSpacing(77); QLabel* gemSummaryLabel = new QLabel(tr("Gem Summary")); - gemSummaryLabel->setStyleSheet("font-size: 11pt;"); + gemSummaryLabel->setStyleSheet("font-size: 12px;"); columnHeaderLayout->addWidget(gemSummaryLabel); vLayout->addLayout(columnHeaderLayout); diff --git a/Code/Tools/ProjectManager/Source/LinkWidget.cpp b/Code/Tools/ProjectManager/Source/LinkWidget.cpp index a6308f6c62..160d9cf7c7 100644 --- a/Code/Tools/ProjectManager/Source/LinkWidget.cpp +++ b/Code/Tools/ProjectManager/Source/LinkWidget.cpp @@ -37,7 +37,7 @@ namespace O3DE::ProjectManager void LinkLabel::enterEvent([[maybe_unused]] QEvent* event) { - setStyleSheet("font-size: 9pt; color: #94D2FF; text-decoration: underline;"); + setStyleSheet("font-size: 10px; color: #94D2FF; text-decoration: underline;"); } void LinkLabel::leaveEvent([[maybe_unused]] QEvent* event) @@ -52,6 +52,6 @@ namespace O3DE::ProjectManager void LinkLabel::SetDefaultStyle() { - setStyleSheet("font-size: 9pt; color: #94D2FF;"); + setStyleSheet("font-size: 10px; color: #94D2FF;"); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp index 4be876e79f..72ffa686c1 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp @@ -12,6 +12,7 @@ #include + #include #include #include @@ -58,19 +59,15 @@ namespace O3DE::ProjectManager m_overlayLabel->setText(text); } - ProjectButton::ProjectButton(const QString& projectName, QWidget* parent) + ProjectButton::ProjectButton(const ProjectInfo& projectInfo, QWidget* parent) : QFrame(parent) - , m_projectName(projectName) - , m_projectImagePath(":/Resources/DefaultProjectImage.png") + , m_projectInfo(projectInfo) { - Setup(); - } + if (m_projectInfo.m_imagePath.isEmpty()) + { + m_projectInfo.m_imagePath = ":/DefaultProjectImage.png"; + } - ProjectButton::ProjectButton(const QString& projectName, const QString& projectImage, QWidget* parent) - : QFrame(parent) - , m_projectName(projectName) - , m_projectImagePath(projectImage) - { Setup(); } @@ -85,20 +82,22 @@ namespace O3DE::ProjectManager m_projectImageLabel = new LabelButton(this); m_projectImageLabel->setFixedSize(s_projectImageWidth, s_projectImageHeight); + m_projectImageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); vLayout->addWidget(m_projectImageLabel); - m_projectImageLabel->setPixmap(QPixmap(m_projectImagePath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding)); + m_projectImageLabel->setPixmap( + QPixmap(m_projectInfo.m_imagePath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding)); QMenu* newProjectMenu = new QMenu(this); m_editProjectAction = newProjectMenu->addAction(tr("Edit Project Settings...")); - -#ifdef SHOW_ALL_PROJECT_ACTIONS - m_editProjectGemsAction = newProjectMenu->addAction(tr("Cutomize Gems...")); newProjectMenu->addSeparator(); m_copyProjectAction = newProjectMenu->addAction(tr("Duplicate")); newProjectMenu->addSeparator(); m_removeProjectAction = newProjectMenu->addAction(tr("Remove from O3DE")); - m_deleteProjectAction = newProjectMenu->addAction(tr("Delete the Project")); + m_deleteProjectAction = newProjectMenu->addAction(tr("Delete this Project")); + +#ifdef SHOW_ALL_PROJECT_ACTIONS + m_editProjectGemsAction = newProjectMenu->addAction(tr("Cutomize Gems...")); #endif QFrame* footer = new QFrame(this); @@ -106,7 +105,7 @@ namespace O3DE::ProjectManager hLayout->setContentsMargins(0, 0, 0, 0); footer->setLayout(hLayout); { - QLabel* projectNameLabel = new QLabel(m_projectName, this); + QLabel* projectNameLabel = new QLabel(m_projectInfo.m_displayName, this); hLayout->addWidget(projectNameLabel); QPushButton* projectMenuButton = new QPushButton(this); @@ -117,14 +116,14 @@ namespace O3DE::ProjectManager vLayout->addWidget(footer); - connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectName); }); - connect(m_editProjectAction, &QAction::triggered, [this]() { emit EditProject(m_projectName); }); + connect(m_projectImageLabel, &LabelButton::triggered, [this]() { emit OpenProject(m_projectInfo.m_path); }); + connect(m_editProjectAction, &QAction::triggered, [this]() { emit EditProject(m_projectInfo.m_path); }); + connect(m_copyProjectAction, &QAction::triggered, [this]() { emit CopyProject(m_projectInfo.m_path); }); + connect(m_removeProjectAction, &QAction::triggered, [this]() { emit RemoveProject(m_projectInfo.m_path); }); + connect(m_deleteProjectAction, &QAction::triggered, [this]() { emit DeleteProject(m_projectInfo.m_path); }); #ifdef SHOW_ALL_PROJECT_ACTIONS - connect(m_editProjectGemsAction, &QAction::triggered, [this]() { emit EditProjectGems(m_projectName); }); - connect(m_copyProjectAction, &QAction::triggered, [this]() { emit CopyProject(m_projectName); }); - connect(m_removeProjectAction, &QAction::triggered, [this]() { emit RemoveProject(m_projectName); }); - connect(m_deleteProjectAction, &QAction::triggered, [this]() { emit DeleteProject(m_projectName); }); + connect(m_editProjectGemsAction, &QAction::triggered, [this]() { emit EditProjectGems(m_projectInfo.m_path); }); #endif } diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h index 671debf6d0..e82b56b3fa 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.h @@ -13,7 +13,8 @@ #pragma once #if !defined(Q_MOC_RUN) -#include +#include + #include #endif @@ -52,8 +53,7 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - explicit ProjectButton(const QString& projectName, QWidget* parent = nullptr); - explicit ProjectButton(const QString& projectName, const QString& projectImage, QWidget* parent = nullptr); + explicit ProjectButton(const ProjectInfo& m_projectInfo, QWidget* parent = nullptr); ~ProjectButton() = default; void SetButtonEnabled(bool enabled); @@ -70,8 +70,7 @@ namespace O3DE::ProjectManager private: void Setup(); - QString m_projectName; - QString m_projectImagePath; + ProjectInfo m_projectInfo; LabelButton* m_projectImageLabel; QAction* m_editProjectAction; QAction* m_editProjectGemsAction; diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp new file mode 100644 index 0000000000..526e745d82 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -0,0 +1,196 @@ +/* + * 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 + +namespace O3DE::ProjectManager +{ + namespace ProjectUtils + { + static bool WarnDirectoryOverwrite(const QString& path, QWidget* parent) + { + if (!QDir(path).isEmpty()) + { + QMessageBox::StandardButton warningResult = QMessageBox::warning( + parent, + QObject::tr("Overwrite Directory"), + QObject::tr("Directory is not empty! Are you sure you want to overwrite it?"), + QMessageBox::No | QMessageBox::Yes + ); + + if (warningResult != QMessageBox::Yes) + { + return false; + } + } + + return true; + } + + static bool IsDirectoryDescedent(const QString& possibleAncestorPath, const QString& possibleDecedentPath) + { + QDir ancestor(possibleAncestorPath); + QDir descendent(possibleDecedentPath); + + do + { + if (ancestor == descendent) + { + return false; + } + + descendent.cdUp(); + } + while (!descendent.isRoot()); + + return true; + } + + static bool CopyDirectory(const QString& origPath, const QString& newPath) + { + QDir original(origPath); + if (!original.exists()) + { + return false; + } + + for (QString directory : original.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) + { + QString newDirectoryPath = newPath + QDir::separator() + directory; + original.mkpath(newDirectoryPath); + + if (!CopyDirectory(origPath + QDir::separator() + directory, newDirectoryPath)) + { + return false; + } + } + + for (QString file : original.entryList(QDir::Files)) + { + if (!QFile::copy(origPath + QDir::separator() + file, newPath + QDir::separator() + file)) + return false; + } + + return true; + } + + bool AddProjectDialog(QWidget* parent) + { + QString path = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(parent, QObject::tr("Select Project Directory"))); + if (!path.isEmpty()) + { + return RegisterProject(path); + } + + return false; + } + + bool RegisterProject(const QString& path) + { + return PythonBindingsInterface::Get()->AddProject(path); + } + + bool UnregisterProject(const QString& path) + { + return PythonBindingsInterface::Get()->RemoveProject(path); + } + + bool CopyProjectDialog(const QString& origPath, QWidget* parent) + { + bool copyResult = false; + + QDir parentOrigDir(origPath); + parentOrigDir.cdUp(); + QString newPath = QDir::toNativeSeparators( + QFileDialog::getExistingDirectory(parent, QObject::tr("Select New Project Directory"), parentOrigDir.path())); + if (!newPath.isEmpty()) + { + if (!WarnDirectoryOverwrite(newPath, parent)) + { + return false; + } + + // TODO: Block UX and Notify User they need to wait + + copyResult = CopyProject(origPath, newPath); + } + + return copyResult; + } + + bool CopyProject(const QString& origPath, const QString& newPath) + { + // Disallow copying from or into subdirectory + if (!IsDirectoryDescedent(origPath, newPath) || !IsDirectoryDescedent(newPath, origPath)) + { + return false; + } + + if (!CopyDirectory(origPath, newPath)) + { + // Cleanup whatever mess was made + DeleteProjectFiles(newPath, true); + return false; + } + + if (!RegisterProject(newPath)) + { + DeleteProjectFiles(newPath, true); + } + + return true; + } + + bool DeleteProjectFiles(const QString& path, bool force) + { + QDir projectDirectory(path); + if (projectDirectory.exists()) + { + // Check if there is an actual project hereor just force it + if (force || PythonBindingsInterface::Get()->GetProject(path).IsSuccess()) + { + return projectDirectory.removeRecursively(); + } + } + + return false; + } + + bool MoveProject(const QString& origPath, const QString& newPath, QWidget* parent) + { + if (!WarnDirectoryOverwrite(newPath, parent) || !UnregisterProject(origPath)) + { + return false; + } + + QDir directory; + if (directory.rename(origPath, newPath)) + { + return directory.rename(origPath, newPath); + } + + if (!RegisterProject(newPath)) + { + return false; + } + + return true; + } + + } // namespace ProjectUtils +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h new file mode 100644 index 0000000000..5982bff634 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -0,0 +1,28 @@ +/* + * 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 + +namespace O3DE::ProjectManager +{ + namespace ProjectUtils + { + bool AddProjectDialog(QWidget* parent = nullptr); + bool RegisterProject(const QString& path); + bool UnregisterProject(const QString& path); + bool CopyProjectDialog(const QString& origPath, QWidget* parent = nullptr); + bool CopyProject(const QString& origPath, const QString& newPath); + bool DeleteProjectFiles(const QString& path, bool force = false); + bool MoveProject(const QString& origPath, const QString& newPath, QWidget* parent = nullptr); + } // namespace ProjectUtils +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp index 5f1c0e2b36..dd2e411ec5 100644 --- a/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectsScreen.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -65,9 +66,6 @@ namespace O3DE::ProjectManager m_stack->addWidget(m_projectsContent); vLayout->addWidget(m_stack); - - connect(m_createNewProjectAction, &QAction::triggered, this, &ProjectsScreen::HandleNewProjectButton); - connect(m_addExistingProjectAction, &QAction::triggered, this, &ProjectsScreen::HandleAddProjectButton); } QFrame* ProjectsScreen::CreateFirstTimeContent() @@ -167,28 +165,27 @@ namespace O3DE::ProjectManager #endif { ProjectButton* projectButton; + QString projectPreviewPath = project.m_path + m_projectPreviewImagePath; QFileInfo doesPreviewExist(projectPreviewPath); if (doesPreviewExist.exists() && doesPreviewExist.isFile()) { - projectButton = new ProjectButton(project.m_projectName, projectPreviewPath, this); - } - else - { - projectButton = new ProjectButton(project.m_projectName, this); + project.m_imagePath = projectPreviewPath; } + projectButton = new ProjectButton(project, this); + flowLayout->addWidget(projectButton); connect(projectButton, &ProjectButton::OpenProject, this, &ProjectsScreen::HandleOpenProject); connect(projectButton, &ProjectButton::EditProject, this, &ProjectsScreen::HandleEditProject); - - #ifdef DISPLAY_PROJECT_DEV_DATA - connect(projectButton, &ProjectButton::EditProjectGems, this, &ProjectsScreen::HandleEditProjectGems); connect(projectButton, &ProjectButton::CopyProject, this, &ProjectsScreen::HandleCopyProject); connect(projectButton, &ProjectButton::RemoveProject, this, &ProjectsScreen::HandleRemoveProject); connect(projectButton, &ProjectButton::DeleteProject, this, &ProjectsScreen::HandleDeleteProject); - #endif + +#ifdef SHOW_ALL_PROJECT_ACTIONS + connect(projectButton, &ProjectButton::EditProjectGems, this, &ProjectsScreen::HandleEditProjectGems); +#endif } layout->addWidget(projectsScrollArea); @@ -242,7 +239,11 @@ namespace O3DE::ProjectManager } void ProjectsScreen::HandleAddProjectButton() { - // Do nothing for now + if (ProjectUtils::AddProjectDialog(this)) + { + emit ResetScreenRequest(ProjectManagerScreen::Projects); + emit ChangeScreenRequest(ProjectManagerScreen::Projects); + } } void ProjectsScreen::HandleOpenProject(const QString& projectPath) { @@ -300,18 +301,36 @@ namespace O3DE::ProjectManager emit NotifyCurrentProject(projectPath); emit ChangeScreenRequest(ProjectManagerScreen::GemCatalog); } - void ProjectsScreen::HandleCopyProject([[maybe_unused]] const QString& projectPath) + void ProjectsScreen::HandleCopyProject(const QString& projectPath) { // Open file dialog and choose location for copied project then register copy with O3DE + if (ProjectUtils::CopyProjectDialog(projectPath, this)) + { + emit ResetScreenRequest(ProjectManagerScreen::Projects); + emit ChangeScreenRequest(ProjectManagerScreen::Projects); + } } - void ProjectsScreen::HandleRemoveProject([[maybe_unused]] const QString& projectPath) + void ProjectsScreen::HandleRemoveProject(const QString& projectPath) { - // Unregister Project from O3DE + // Unregister Project from O3DE and reload projects + if (ProjectUtils::UnregisterProject(projectPath)) + { + emit ResetScreenRequest(ProjectManagerScreen::Projects); + emit ChangeScreenRequest(ProjectManagerScreen::Projects); + } } - void ProjectsScreen::HandleDeleteProject([[maybe_unused]] const QString& projectPath) + void ProjectsScreen::HandleDeleteProject(const QString& projectPath) { - // Remove project from 03DE and delete from disk - ProjectsScreen::HandleRemoveProject(projectPath); + QMessageBox::StandardButton warningResult = QMessageBox::warning( + this, tr("Delete Project"), tr("Are you sure?\nProject will be removed from O3DE and directory will be deleted!"), + QMessageBox::No | QMessageBox::Yes); + + if (warningResult == QMessageBox::Yes) + { + // Remove project from O3DE and delete from disk + HandleRemoveProject(projectPath); + ProjectUtils::DeleteProjectFiles(projectPath); + } } void ProjectsScreen::NotifyCurrentScreen() diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 8c79a153c8..9279ad1291 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -379,13 +379,13 @@ namespace O3DE::ProjectManager pybind11::str defaultTemplatesFolder = engineInfo.m_defaultTemplatesFolder.toStdString(); auto registrationResult = m_registration.attr("register")( - enginePath, // engine_path - pybind11::none(), // project_path - pybind11::none(), // gem_path - pybind11::none(), // template_path - pybind11::none(), // restricted_path - pybind11::none(), // repo_uri - pybind11::none(), // default_engines_folder + enginePath, // engine_path + pybind11::none(), // project_path + pybind11::none(), // gem_path + pybind11::none(), // template_path + pybind11::none(), // restricted_path + pybind11::none(), // repo_uri + pybind11::none(), // default_engines_folder defaultProjectsFolder, defaultGemsFolder, defaultTemplatesFolder @@ -456,6 +456,51 @@ namespace O3DE::ProjectManager } } + bool PythonBindings::AddProject(const QString& path) + { + bool registrationResult = false; + bool result = ExecuteWithLock( + [&] + { + pybind11::str projectPath = path.toStdString(); + auto pythonRegistrationResult = m_registration.attr("register")(pybind11::none(), projectPath); + + // Returns an exit code so boolify it then invert result + registrationResult = !pythonRegistrationResult.cast(); + }); + + return result && registrationResult; + } + + bool PythonBindings::RemoveProject(const QString& path) + { + bool registrationResult = false; + bool result = ExecuteWithLock( + [&] + { + pybind11::str projectPath = path.toStdString(); + auto pythonRegistrationResult = m_registration.attr("register")( + pybind11::none(), // engine_path + projectPath, // project_path + pybind11::none(), // gem_path + pybind11::none(), // template_path + pybind11::none(), // restricted_path + pybind11::none(), // repo_uri + pybind11::none(), // default_engines_folder + pybind11::none(), // default_gems_folder + pybind11::none(), // default_templates_folder + pybind11::none(), // default_restricted_folder + pybind11::none(), // default_restricted_folder + true // remove + ); + + // Returns an exit code so boolify it then invert result + registrationResult = !pythonRegistrationResult.cast(); + }); + + return result && registrationResult; + } + AZ::Outcome PythonBindings::CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) { ProjectInfo createdProjectInfo; @@ -600,7 +645,7 @@ namespace O3DE::ProjectManager pybind11::none(), // gem_target pybind11::none(), // project_name pyProjectPath - ); + ); }); return result; @@ -618,7 +663,7 @@ namespace O3DE::ProjectManager pybind11::none(), // gem_target pybind11::none(), // project_name pyProjectPath - ); + ); }); return result; diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.h b/Code/Tools/ProjectManager/Source/PythonBindings.h index 892e13a65b..fb2303c495 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.h +++ b/Code/Tools/ProjectManager/Source/PythonBindings.h @@ -46,6 +46,8 @@ namespace O3DE::ProjectManager AZ::Outcome CreateProject(const QString& projectTemplatePath, const ProjectInfo& projectInfo) override; AZ::Outcome GetProject(const QString& path) override; AZ::Outcome> GetProjects() override; + bool AddProject(const QString& path) override; + bool RemoveProject(const QString& path) override; bool UpdateProject(const ProjectInfo& projectInfo) override; bool AddGemToProject(const QString& gemPath, const QString& projectPath) override; bool RemoveGemFromProject(const QString& gemPath, const QString& projectPath) override; diff --git a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h index b5c8f1a76a..a58eea0fe6 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h +++ b/Code/Tools/ProjectManager/Source/PythonBindingsInterface.h @@ -88,6 +88,20 @@ namespace O3DE::ProjectManager * @return an outcome with ProjectInfos on success */ virtual AZ::Outcome> GetProjects() = 0; + + /** + * Adds existing project on disk + * @param path the absolute path to the project + * @return true on success, false on failure + */ + virtual bool AddProject(const QString& path) = 0; + + /** + * Adds existing project on disk + * @param path the absolute path to the project + * @return true on success, false on failure + */ + virtual bool RemoveProject(const QString& path) = 0; /** * Update a project diff --git a/Code/Tools/ProjectManager/Source/TagWidget.cpp b/Code/Tools/ProjectManager/Source/TagWidget.cpp index 3e80944204..628b682b95 100644 --- a/Code/Tools/ProjectManager/Source/TagWidget.cpp +++ b/Code/Tools/ProjectManager/Source/TagWidget.cpp @@ -18,9 +18,9 @@ namespace O3DE::ProjectManager TagWidget::TagWidget(const QString& text, QWidget* parent) : QLabel(text, parent) { - setFixedHeight(35); + setFixedHeight(24); setMargin(5); - setStyleSheet("font-size: 12pt; background-color: #333333; border-radius: 4px;"); + setStyleSheet("font-size: 12px; background-color: #333333; border-radius: 3px;"); } TagContainerWidget::TagContainerWidget(QWidget* parent) @@ -35,7 +35,7 @@ namespace O3DE::ProjectManager void TagContainerWidget::Update(const QStringList& tags) { QWidget* parentWidget = qobject_cast(parent()); - int width = 250; + int width = 200; if (parentWidget) { width = parentWidget->width(); diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 223465f3c8..feaea4c172 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -36,6 +36,8 @@ set(FILES Source/PythonBindingsInterface.h Source/ProjectInfo.h Source/ProjectInfo.cpp + Source/ProjectUtils.h + Source/ProjectUtils.cpp Source/NewProjectSettingsScreen.h Source/NewProjectSettingsScreen.cpp Source/CreateProjectCtrl.h diff --git a/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp b/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp index 2cda1e68ae..791af4bf68 100644 --- a/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp +++ b/Code/Tools/SceneAPI/SDKWrapper/AssImpSceneWrapper.cpp @@ -17,6 +17,13 @@ #include #include +#if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL +#include +#include +#include +#include +#endif // AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL + namespace AZ { namespace AssImpSDKWrapper @@ -34,10 +41,31 @@ namespace AZ { } +#if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL + void signal_handler(int signal) + { + AZ_TracePrintf( + SceneAPI::Utilities::ErrorWindow, + "Failed to import scene with Asset Importer library. An %s has occured in the library, this scene file cannot be parsed by the library.", + signal == SIGABRT ? "assert" : "unknown error"); + } +#endif // AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL + bool AssImpSceneWrapper::LoadSceneFromFile(const char* fileName) { AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "AssImpSceneWrapper::LoadSceneFromFile %s", fileName); AZ_TraceContext("Filename", fileName); + +#if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL + // Turn off the abort popup because it can disrupt automation. + // AssImp calls abort when asserts are enabled, and an assert is encountered. +#ifdef _WRITE_ABORT_MSG + _set_abort_behavior(0, _WRITE_ABORT_MSG); +#endif // #ifdef _WRITE_ABORT_MSG + // Instead, capture any calls to abort with a signal handler, and report them. + auto previous_handler = std::signal(SIGABRT, signal_handler); +#endif // AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL + // aiProcess_JoinIdenticalVertices is not enabled because O3DE has a mesh optimizer that also does this, // this flag is disabled to keep AssImp output similar to FBX SDK to reduce downstream bugs for the initial AssImp release. // There's currently a minimum of properties and flags set to maximize compatibility with the existing node graph. @@ -49,6 +77,15 @@ namespace AZ | aiProcess_LimitBoneWeights //Limits the number of bones that can affect a vertex to a maximum value //dropping the least important and re-normalizing | aiProcess_GenNormals); //Generate normals for meshes + +#if AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL + // Reset abort behavior for anything else that may call abort. + std::signal(SIGABRT, previous_handler); +#ifdef _WRITE_ABORT_MSG + _set_abort_behavior(1, _WRITE_ABORT_MSG); +#endif // #ifdef _WRITE_ABORT_MSG +#endif // AZ_TRAIT_COMPILER_SUPPORT_CSIGNAL + if (!m_assImpScene) { AZ_TracePrintf(SceneAPI::Utilities::ErrorWindow, "Failed to import Asset Importer Scene. Error returned: %s", m_importer.GetErrorString()); diff --git a/Code/Tools/SerializeContextTools/SliceConverter.cpp b/Code/Tools/SerializeContextTools/SliceConverter.cpp index 3fbf7cb25c..d06534e303 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.cpp +++ b/Code/Tools/SerializeContextTools/SliceConverter.cpp @@ -244,7 +244,7 @@ namespace AZ } else { - return SavePrefab(templateId); + return SavePrefab(outputPath, templateId); } } @@ -318,7 +318,7 @@ namespace AZ nestedPrefabPath.ReplaceExtension("prefab"); auto prefabLoaderInterface = AZ::Interface::Get(); - nestedPrefabPath = prefabLoaderInterface->GetRelativePathToProject(nestedPrefabPath); + nestedPrefabPath = prefabLoaderInterface->GenerateRelativePath(nestedPrefabPath); AzToolsFramework::Prefab::TemplateId nestedTemplateId = prefabSystemComponentInterface->GetTemplateIdFromFilePath(nestedPrefabPath); @@ -439,17 +439,31 @@ namespace AZ AZ::Debug::Trace::Instance().Output("", "\n"); } - bool SliceConverter::SavePrefab(AzToolsFramework::Prefab::TemplateId templateId) + bool SliceConverter::SavePrefab(AZ::IO::PathView outputPath, AzToolsFramework::Prefab::TemplateId templateId) { auto prefabLoaderInterface = AZ::Interface::Get(); - if (!prefabLoaderInterface->SaveTemplate(templateId)) + AZStd::string out; + if (prefabLoaderInterface->SaveTemplateToString(templateId, out)) { - AZ_Printf("Convert-Slice", " Could not save prefab - internal error (Json write operation failure).\n"); - return false; + IO::SystemFile outputFile; + if (!outputFile.Open( + AZStd::string(outputPath.Native()).c_str(), + IO::SystemFile::OpenMode::SF_OPEN_CREATE | + IO::SystemFile::OpenMode::SF_OPEN_CREATE_PATH | + IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY)) + { + AZ_Error("Convert-Slice", false, " Unable to create output file '%.*s'.", AZ_STRING_ARG(outputPath.Native())); + return false; + } + + outputFile.Write(out.data(), out.size()); + outputFile.Close(); + return true; } - return true; + AZ_Printf("Convert-Slice", " Could not save prefab - internal error (Json write operation failure).\n"); + return false; } bool SliceConverter::ConnectToAssetProcessor() diff --git a/Code/Tools/SerializeContextTools/SliceConverter.h b/Code/Tools/SerializeContextTools/SliceConverter.h index a977095f02..bec893ff56 100644 --- a/Code/Tools/SerializeContextTools/SliceConverter.h +++ b/Code/Tools/SerializeContextTools/SliceConverter.h @@ -56,7 +56,7 @@ namespace AZ AZ::SliceComponent::SliceInstance& instance, AZ::Data::Asset& sliceAsset, AzToolsFramework::Prefab::TemplateReference nestedTemplate, AzToolsFramework::Prefab::Instance* topLevelInstance); static void PrintPrefab(AzToolsFramework::Prefab::TemplateId templateId); - static bool SavePrefab(AzToolsFramework::Prefab::TemplateId templateId); + static bool SavePrefab(AZ::IO::PathView outputPath, AzToolsFramework::Prefab::TemplateId templateId); }; } // namespace SerializeContextTools } // namespace AZ diff --git a/Gems/AWSCore/Code/Include/Private/Editor/AWSCoreEditorManager.h b/Gems/AWSCore/Code/Include/Private/Editor/AWSCoreEditorManager.h index 721cd6dd6a..98467727ea 100644 --- a/Gems/AWSCore/Code/Include/Private/Editor/AWSCoreEditorManager.h +++ b/Gems/AWSCore/Code/Include/Private/Editor/AWSCoreEditorManager.h @@ -18,7 +18,7 @@ namespace AWSCore class AWSCoreEditorManager { public: - static constexpr const char CLOUD_SERVICES_MENU_TEXT[] = "&Cloud services"; + static constexpr const char AWS_MENU_TEXT[] = "&AWS"; AWSCoreEditorManager(); virtual ~AWSCoreEditorManager(); diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Constants/AWSCoreEditorMenuLinks.h b/Gems/AWSCore/Code/Include/Private/Editor/Constants/AWSCoreEditorMenuLinks.h new file mode 100644 index 0000000000..46acfbd4a3 --- /dev/null +++ b/Gems/AWSCore/Code/Include/Private/Editor/Constants/AWSCoreEditorMenuLinks.h @@ -0,0 +1,53 @@ +/* + * 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 + +namespace AWSCore +{ + static constexpr const char NewToAWSUrl[] = "https://docs.o3de.org/docs/user-guide/gems/reference/aws/"; + + static constexpr const char AWSAndScriptCanvasUrl[] = "https://docs.o3de.org/docs/user-guide/components/reference/aws/"; + static constexpr const char AWSAndComponentsUrl[] = "https://docs.o3de.org/docs/user-guide/components/reference/aws/"; + static constexpr const char CallAWSResourcesUrl[] = "https://docs.o3de.org/docs/user-guide/components/reference/aws/"; + + static constexpr const char AWSCredentialConfigurationUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-core/configuring-credentials/"; + + static constexpr const char AWSClientAuthGemOverviewUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-client-auth/"; + static constexpr const char AWSClientAuthCDKAndResourcesUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-client-auth/"; + static constexpr const char AWSClientAuthScriptCanvasAndLuaUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-client-auth/"; + static constexpr const char AWSClientAuth3rdPartyAuthProviderUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-client-auth/"; + static constexpr const char AWSClientAuthCustomAuthProviderUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-client-auth/"; + static constexpr const char AWSClientAuthPlatformSpecificUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-client-auth/"; + static constexpr const char AWSClientAuthAPIReferenceUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-client-auth/"; + + static constexpr const char AWSMetricsGemOverviewUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-metrics/"; + static constexpr const char AWSMetricsSetupGemUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-metrics/"; + static constexpr const char AWSMetricsScriptingUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-metrics/"; + static constexpr const char AWSMetricsAPIReferenceUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-metrics/"; + static constexpr const char AWSMetricsAdvancedTopicsUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-metrics/"; + static constexpr const char AWSMetricsSettingsUrl[] = + "https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-metrics/"; +} // namespace AWSCore diff --git a/Gems/AWSCore/Code/Include/Private/Editor/Constants/AWSCoreEditorMenuNames.h b/Gems/AWSCore/Code/Include/Private/Editor/Constants/AWSCoreEditorMenuNames.h new file mode 100644 index 0000000000..a9a8198e52 --- /dev/null +++ b/Gems/AWSCore/Code/Include/Private/Editor/Constants/AWSCoreEditorMenuNames.h @@ -0,0 +1,44 @@ +/* + * 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 + +namespace AWSCore +{ + static constexpr const char NewToAWSActionText[] = "Getting started with AWS?"; + + static constexpr const char AWSAndO3DEGlobalDocsText[] = "AWS & O3DE global docs"; + static constexpr const char AWSAndScriptCanvasActionText[] = "AWS && ScriptCanvas"; + static constexpr const char AWSAndComponentsActionText[] = "AWS & Components"; + static constexpr const char CallAWSResourcesActionText[] = "Call AWS resources"; + + static constexpr const char AWSCredentialConfigurationActionText[] = "AWS credential configuration"; + + static constexpr const char AWSResourceMappingToolActionText[] = "AWS Resource Mapping Tool..."; + + static constexpr const char AWSClientAuthActionText[] = "Client Auth"; + static constexpr const char AWSClientAuthGemOverviewActionText[] = "Gem Overview"; + static constexpr const char AWSClientAuthCDKAndResourcesActionText[] = "CDK Application and Resource Mappings"; + static constexpr const char AWSClientAuthScriptCanvasAndLuaActionText[] = "Script Canvas and Lua"; + static constexpr const char AWSClientAuth3rdPartyAuthProviderActionText[] = "3rd Party developer Authentication Provider support"; + static constexpr const char AWSClientAuthCustomAuthProviderActionText[] = "Custom developer Authentication Provider support"; + static constexpr const char AWSClientAuthPlatformSpecificActionText[] = "Platform specific Callouts"; + static constexpr const char AWSClientAuthAPIReferenceActionText[] = "API Reference"; + + static constexpr const char AWSMetricsActionText[] = "Metrics"; + static constexpr const char AWSMetricsGemOverviewActionText[] = "Metrics Overview"; + static constexpr const char AWSMetricsSetupGemActionText[] = "Setup Metrics Gem"; + static constexpr const char AWSMetricsScriptingActionText[] = "Scripting with AWS Metrics"; + static constexpr const char AWSMetricsAPIReferenceActionText[] = "C++ API with AWS Metrics Gem"; + static constexpr const char AWSMetricsAdvancedTopicsActionText[] = "Advanced topics"; + static constexpr const char AWSMetricsSettingsActionText[] = "Metrics Settings"; +} // namespace AWSCore diff --git a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h index 19f241e368..c892f86b66 100644 --- a/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h +++ b/Gems/AWSCore/Code/Include/Private/Editor/UI/AWSCoreEditorMenu.h @@ -35,29 +35,23 @@ namespace AWSCore static constexpr const char AWSResourceMappingToolIsRunningText[] = "Resource Mapping Tool is running..."; static constexpr const char AWSResourceMappingToolLogWarningText[] = "Failed to launch Resource Mapping Tool, please check logs for details."; - static constexpr const char AWSResourceMappingToolActionText[] = "AWS Resource Mapping Tool..."; - static constexpr const char CredentialConfigurationActionText[] = "Credential Configuration"; - static constexpr const char CredentialConfigurationUrl[] = "https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/credentials.html"; - static constexpr const char NewToAWSActionText[] = "New to AWS?"; - static constexpr const char NewToAWSUrl[] = "https://o3deorg.netlify.app/docs/user-guide/gems/reference/aws"; - static constexpr const char AWSAndScriptCanvasActionText[] = "AWS && ScriptCanvas"; - static constexpr const char AWSAndScriptCanvasUrl[] = "https://o3deorg.netlify.app/docs/user-guide/gems/reference/aws"; - static constexpr const char AWSClientAuthActionText[] = "Client Auth"; - static constexpr const char AWSMetricsActionText[] = "Metrics"; AWSCoreEditorMenu(const QString& text); ~AWSCoreEditorMenu(); private: + QAction* AddExternalLinkAction(const AZStd::string& name, const AZStd::string& url, const AZStd::string& icon = ""); + void InitializeResourceMappingToolAction(); void InitializeAWSDocActions(); + void InitializeAWSGlobalDocsSubMenu(); void InitializeAWSFeatureGemActions(); // AWSCoreEditorRequestBus interface implementation void SetAWSClientAuthEnabled() override; void SetAWSMetricsEnabled() override; - void SetAWSFeatureActionsEnabled(const AZStd::string actionText); + QMenu* SetAWSFeatureSubMenu(const AZStd::string& menuText); // To improve experience, use process watcher to keep track of ongoing tool process AZStd::unique_ptr m_resourceMappingToolWatcher; diff --git a/Gems/AWSCore/Code/Source/Editor/AWSCoreEditorManager.cpp b/Gems/AWSCore/Code/Source/Editor/AWSCoreEditorManager.cpp index 1e3e44255a..89956d61b8 100644 --- a/Gems/AWSCore/Code/Source/Editor/AWSCoreEditorManager.cpp +++ b/Gems/AWSCore/Code/Source/Editor/AWSCoreEditorManager.cpp @@ -16,7 +16,7 @@ namespace AWSCore { AWSCoreEditorManager::AWSCoreEditorManager() - : m_awsCoreEditorMenu(new AWSCoreEditorMenu(CLOUD_SERVICES_MENU_TEXT)) + : m_awsCoreEditorMenu(new AWSCoreEditorMenu(AWS_MENU_TEXT)) { } diff --git a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp index 754cc32751..c319788547 100644 --- a/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp +++ b/Gems/AWSCore/Code/Source/Editor/UI/AWSCoreEditorMenu.cpp @@ -13,10 +13,13 @@ #include #include #include +#include #include #include #include +#include +#include #include #include @@ -36,8 +39,8 @@ namespace AWSCore : QMenu(text) , m_resourceMappingToolWatcher(nullptr) { - InitializeResourceMappingToolAction(); InitializeAWSDocActions(); + InitializeResourceMappingToolAction(); this->addSeparator(); InitializeAWSFeatureGemActions(); @@ -58,6 +61,21 @@ namespace AWSCore this->clear(); } + QAction* AWSCoreEditorMenu::AddExternalLinkAction( + const AZStd::string& name, const AZStd::string& url, const AZStd::string& icon) + { + QAction* linkAction = new QAction(QObject::tr(name.c_str())); + QObject::connect(linkAction, &QAction::triggered, this, + [url]() { + QDesktopServices::openUrl(QUrl(url.c_str())); + }); + if (!icon.empty()) + { + linkAction->setIcon(QIcon(icon.c_str())); + } + return linkAction; + } + void AWSCoreEditorMenu::InitializeResourceMappingToolAction() { #ifdef AWSCORE_EDITOR_RESOURCE_MAPPING_TOOL_ENABLED @@ -103,21 +121,21 @@ namespace AWSCore void AWSCoreEditorMenu::InitializeAWSDocActions() { - QAction* credentialConfiguration = new QAction(QObject::tr(CredentialConfigurationActionText)); - QObject::connect(credentialConfiguration, &QAction::triggered, this, []() { - QDesktopServices::openUrl(QUrl(CredentialConfigurationUrl)); - }); - this->addAction(credentialConfiguration); + this->addAction(AddExternalLinkAction(NewToAWSActionText, NewToAWSUrl, ":/Notifications/link.svg")); - QAction* newToAWS = new QAction(QObject::tr(NewToAWSActionText)); - QObject::connect(newToAWS, &QAction::triggered, this, []() { - QDesktopServices::openUrl(QUrl(NewToAWSUrl)); }); - this->addAction(newToAWS); + InitializeAWSGlobalDocsSubMenu(); - QAction* awsAndScriptCanvas = new QAction(QObject::tr(AWSAndScriptCanvasActionText)); - QObject::connect(awsAndScriptCanvas, &QAction::triggered, this, []() { - QDesktopServices::openUrl(QUrl(AWSAndScriptCanvasUrl)); }); - this->addAction(awsAndScriptCanvas); + this->addAction(AddExternalLinkAction( + AWSCredentialConfigurationActionText, AWSCredentialConfigurationUrl, ":/Notifications/link.svg")); + } + + void AWSCoreEditorMenu::InitializeAWSGlobalDocsSubMenu() + { + QMenu* globalDocsMenu = this->addMenu(QObject::tr(AWSAndO3DEGlobalDocsText)); + + globalDocsMenu->addAction(AddExternalLinkAction(AWSAndScriptCanvasActionText, AWSAndScriptCanvasUrl, ":/Notifications/link.svg")); + globalDocsMenu->addAction(AddExternalLinkAction(AWSAndComponentsActionText, AWSAndComponentsUrl, ":/Notifications/link.svg")); + globalDocsMenu->addAction(AddExternalLinkAction(CallAWSResourcesActionText, CallAWSResourcesUrl, ":/Notifications/link.svg")); } void AWSCoreEditorMenu::InitializeAWSFeatureGemActions() @@ -135,25 +153,67 @@ namespace AWSCore void AWSCoreEditorMenu::SetAWSClientAuthEnabled() { - SetAWSFeatureActionsEnabled(AWSClientAuthActionText); + // TODO: instead of creating submenu in core editor, aws feature gem should return submenu component directly + QMenu* subMenu = SetAWSFeatureSubMenu(AWSClientAuthActionText); + + subMenu->addAction(AddExternalLinkAction( + AWSClientAuthGemOverviewActionText, AWSClientAuthGemOverviewUrl, ":/Notifications/link.svg")); + subMenu->addAction(AddExternalLinkAction( + AWSClientAuthCDKAndResourcesActionText, AWSClientAuthCDKAndResourcesUrl, ":/Notifications/link.svg")); + subMenu->addAction(AddExternalLinkAction( + AWSClientAuthScriptCanvasAndLuaActionText, AWSClientAuthScriptCanvasAndLuaUrl, ":/Notifications/link.svg")); + subMenu->addAction(AddExternalLinkAction( + AWSClientAuth3rdPartyAuthProviderActionText, AWSClientAuth3rdPartyAuthProviderUrl, ":/Notifications/link.svg")); + subMenu->addAction(AddExternalLinkAction( + AWSClientAuthCustomAuthProviderActionText, AWSClientAuthCustomAuthProviderUrl, ":/Notifications/link.svg")); + subMenu->addAction(AddExternalLinkAction( + AWSClientAuthPlatformSpecificActionText, AWSClientAuthPlatformSpecificUrl, ":/Notifications/link.svg")); + subMenu->addAction(AddExternalLinkAction( + AWSClientAuthAPIReferenceActionText, AWSClientAuthAPIReferenceUrl, ":/Notifications/link.svg")); } void AWSCoreEditorMenu::SetAWSMetricsEnabled() { - SetAWSFeatureActionsEnabled(AWSMetricsActionText); + // TODO: instead of creating submenu in core editor, aws feature gem should return submenu component directly + QMenu* subMenu = SetAWSFeatureSubMenu(AWSMetricsActionText); + + subMenu->addAction(AddExternalLinkAction( + AWSMetricsGemOverviewActionText, AWSMetricsGemOverviewUrl, ":/Notifications/link.svg")); + subMenu->addAction(AddExternalLinkAction( + AWSMetricsSetupGemActionText, AWSMetricsSetupGemUrl, ":/Notifications/link.svg")); + subMenu->addAction(AddExternalLinkAction( + AWSMetricsScriptingActionText, AWSMetricsScriptingUrl, ":/Notifications/link.svg")); + subMenu->addAction(AddExternalLinkAction( + AWSMetricsAPIReferenceActionText, AWSMetricsAPIReferenceUrl, ":/Notifications/link.svg")); + subMenu->addAction(AddExternalLinkAction( + AWSMetricsAdvancedTopicsActionText, AWSMetricsAdvancedTopicsUrl, ":/Notifications/link.svg")); + + AZStd::string priorAlias = AZ::IO::FileIOBase::GetInstance()->GetAlias("@devroot@"); + AZStd::string configFilePath = priorAlias + "\\Gems\\AWSMetrics\\Code\\" + AZ::SettingsRegistryInterface::RegistryFolder; + AzFramework::StringFunc::Path::Normalize(configFilePath); + + QAction* settingsAction = new QAction(QObject::tr(AWSMetricsSettingsActionText)); + QObject::connect(settingsAction, &QAction::triggered, this, + [configFilePath](){ + QDesktopServices::openUrl(QUrl::fromLocalFile(configFilePath.c_str())); + }); + subMenu->addAction(settingsAction); } - void AWSCoreEditorMenu::SetAWSFeatureActionsEnabled(const AZStd::string actionText) + QMenu* AWSCoreEditorMenu::SetAWSFeatureSubMenu(const AZStd::string& menuText) { auto actionList = this->actions(); for (QList::iterator itr = actionList.begin(); itr != actionList.end(); itr++) { - if (QString::compare((*itr)->text(), actionText.c_str()) == 0) + if (QString::compare((*itr)->text(), menuText.c_str()) == 0) { - (*itr)->setIcon(QIcon(QString(":/Notifications/checkmark.svg"))); - (*itr)->setEnabled(true); - break; + QMenu* subMenu = new QMenu(QObject::tr(menuText.c_str())); + subMenu->setIcon(QIcon(QString(":/Notifications/checkmark.svg"))); + this->insertMenu(*itr, subMenu); + this->removeAction(*itr); + return subMenu; } } + return nullptr; } } // namespace AWSCore diff --git a/Gems/AWSCore/Code/Tests/AWSCoreEditorSystemComponentTest.cpp b/Gems/AWSCore/Code/Tests/AWSCoreEditorSystemComponentTest.cpp index e9c249f1c8..ff78d8e252 100644 --- a/Gems/AWSCore/Code/Tests/AWSCoreEditorSystemComponentTest.cpp +++ b/Gems/AWSCore/Code/Tests/AWSCoreEditorSystemComponentTest.cpp @@ -85,7 +85,7 @@ TEST_F(AWSCoreEditorSystemComponentTest, NotifyMainWindowInitialized_HaveDummyMe testMenuBar->addMenu("dummy menu"); AzToolsFramework::EditorEvents::Bus::Broadcast(&AzToolsFramework::EditorEvents::NotifyMainWindowInitialized, &testMainWindow); EXPECT_TRUE(testMenuBar->actions().size() == 2); - EXPECT_TRUE(QString::compare(testMenuBar->actions()[1]->text(), AWSCoreEditorManager::CLOUD_SERVICES_MENU_TEXT) == 0); + EXPECT_TRUE(QString::compare(testMenuBar->actions()[1]->text(), AWSCoreEditorManager::AWS_MENU_TEXT) == 0); } TEST_F(AWSCoreEditorSystemComponentTest, NotifyMainWindowInitialized_HaveHelpMenuInMenuBar_ExpectedMenuGetsAddedAtFront) @@ -95,5 +95,5 @@ TEST_F(AWSCoreEditorSystemComponentTest, NotifyMainWindowInitialized_HaveHelpMen testMenuBar->addMenu(AWSCoreEditorSystemComponent::EDITOR_HELP_MENU_TEXT); AzToolsFramework::EditorEvents::Bus::Broadcast(&AzToolsFramework::EditorEvents::NotifyMainWindowInitialized, &testMainWindow); EXPECT_TRUE(testMenuBar->actions().size() == 2); - EXPECT_TRUE(QString::compare(testMenuBar->actions()[0]->text(), AWSCoreEditorManager::CLOUD_SERVICES_MENU_TEXT) == 0); + EXPECT_TRUE(QString::compare(testMenuBar->actions()[0]->text(), AWSCoreEditorManager::AWS_MENU_TEXT) == 0); } diff --git a/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp b/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp index 7a578d2bbe..bde2a43993 100644 --- a/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp +++ b/Gems/AWSCore/Code/Tests/Editor/UI/AWSCoreEditorMenuTest.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,7 @@ class AWSCoreEditorMenuTest { AWSCoreEditorUIFixture::SetUp(); AWSCoreFixture::SetUp(); + m_localFileIO->SetAlias("@devroot@", "dummy engine root"); } void TearDown() override @@ -77,12 +79,12 @@ TEST_F(AWSCoreEditorMenuTest, AWSCoreEditorMenu_BroadcastFeatureGemsAreEnabled_C QList actualActions = testMenu.actions(); for (QList::iterator itr = actualActions.begin(); itr != actualActions.end(); itr++) { - if (QString::compare((*itr)->text(), AWSCoreEditorMenu::AWSClientAuthActionText) == 0) + if (QString::compare((*itr)->text(), AWSClientAuthActionText) == 0) { EXPECT_TRUE((*itr)->isEnabled()); } - if (QString::compare((*itr)->text(), AWSCoreEditorMenu::AWSMetricsActionText) == 0) + if (QString::compare((*itr)->text(), AWSMetricsActionText) == 0) { EXPECT_TRUE((*itr)->isEnabled()); } diff --git a/Gems/AWSCore/Code/awscore_editor_files.cmake b/Gems/AWSCore/Code/awscore_editor_files.cmake index 652f0455e1..13bfbb6102 100644 --- a/Gems/AWSCore/Code/awscore_editor_files.cmake +++ b/Gems/AWSCore/Code/awscore_editor_files.cmake @@ -12,6 +12,8 @@ set(FILES Include/Private/AWSCoreEditorSystemComponent.h Include/Private/Editor/AWSCoreEditorManager.h + Include/Private/Editor/Constants/AWSCoreEditorMenuLinks.h + Include/Private/Editor/Constants/AWSCoreEditorMenuNames.h Include/Private/Editor/UI/AWSCoreEditorMenu.h Include/Private/Editor/UI/AWSCoreResourceMappingToolAction.h Source/AWSCoreEditorSystemComponent.cpp diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype index 954e01c592..4d13663aae 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR.materialtype @@ -1,5 +1,5 @@ { - "description": "Material Type with properties used to define Enhanced PBR material shading model.", + "description": "Material Type with properties used to define Enhanced PBR, a metallic-roughness Physically-Based Rendering (PBR) material shading model, with advanced features like subsurface scattering, transmission, and anisotropy.", "propertyLayout": { "version": 3, "groups": [ @@ -32,7 +32,7 @@ "id": "clearCoat", "displayName": "Clear Coat", "description": "Properties for configuring gloss clear coat" - }, + }, { "id": "normal", "displayName": "Normal", @@ -205,6 +205,13 @@ "id": "m_baseColorMap" } }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map.", + "type": "Bool", + "defaultValue": true + }, { "id": "textureMapUv", "displayName": "UV", @@ -228,13 +235,6 @@ "type": "ShaderOption", "id": "o_baseColorTextureBlendMode" } - }, - { - "id": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture map.", - "type": "Bool", - "defaultValue": true } ], "metallic": [ @@ -261,6 +261,13 @@ "id": "m_metallicMap" } }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, { "id": "textureMapUv", "displayName": "UV", @@ -272,29 +279,9 @@ "type": "ShaderInput", "id": "m_metallicMapUvIndex" } - }, - { - "id": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture map, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true } ], "roughness": [ - { - "id": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the values", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "max": 1.0, - "connection": { - "type": "ShaderInput", - "id": "m_roughnessFactor" - } - }, { "id": "textureMap", "displayName": "Texture Map", @@ -305,6 +292,13 @@ "id": "m_roughnessMap" } }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, { "id": "textureMapUv", "displayName": "UV", @@ -346,11 +340,18 @@ } }, { - "id": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture map, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true + // Note that "factor" is mutually exclusive with "lowerBound"/"upperBound". These are swapped by a lua functor. + "id": "factor", + "displayName": "Factor", + "description": "Controls the roughness value", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "max": 1.0, + "connection": { + "type": "ShaderInput", + "id": "m_roughnessFactor" + } } ], "anisotropy": [ @@ -416,6 +417,13 @@ "id": "m_specularF0Map" } }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, { "id": "textureMapUv", "displayName": "UV", @@ -428,13 +436,7 @@ "id": "m_specularF0MapUvIndex" } }, - { - "id": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture map, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, + // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR { "id": "enableMultiScatterCompensation", "displayName": "Multiscattering Compensation", @@ -452,11 +454,7 @@ "displayName": "Enable", "description": "Enable clear coat", "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "id": "o_clearCoat_feature_enabled" - } + "defaultValue": false }, { "id": "factor", @@ -481,6 +479,13 @@ "id": "m_clearCoatInfluenceMap" } }, + { + "id": "useInfluenceMap", + "displayName": " Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, { "id": "influenceMapUv", "displayName": " UV", @@ -493,13 +498,6 @@ "id": "m_clearCoatInfluenceMapUvIndex" } }, - { - "id": "useInfluenceMap", - "displayName": " Use Texture", - "description": "Whether to use the texture map, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, { "id": "roughness", "displayName": "Roughness", @@ -523,6 +521,13 @@ "id": "m_clearCoatRoughnessMap" } }, + { + "id": "useRoughnessMap", + "displayName": " Use Texture", + "description": "Whether to use the texture map, or just default to the roughness value.", + "type": "Bool", + "defaultValue": true + }, { "id": "roughnessMapUv", "displayName": " UV", @@ -535,13 +540,6 @@ "id": "m_clearCoatRoughnessMapUvIndex" } }, - { - "id": "useRoughnessMap", - "displayName": " Use Texture", - "description": "Whether to use the texture map, or just default to the roughness value.", - "type": "Bool", - "defaultValue": true - }, { "id": "normalStrength", "displayName": "Normal Strength", @@ -565,9 +563,16 @@ "id": "m_clearCoatNormalMap" } }, + { + "id": "useNormalMap", + "displayName": " Use Texture", + "description": "Whether to use the normal map", + "type": "Bool", + "defaultValue": true + }, { "id": "normalMapUv", - "displayName": "UV", + "displayName": " UV", "description": "Normal texture map UV set", "type": "Enum", "enumIsUv": true, @@ -576,29 +581,9 @@ "type": "ShaderInput", "id": "m_clearCoatNormalMapUvIndex" } - }, - { - "id": "useNormalMap", - "displayName": "Use Texture", - "description": "Whether to use the normal map", - "type": "Bool", - "defaultValue": true } ], "normal": [ - { - "id": "factor", - "displayName": "Factor", - "description": "Strength factor for scaling the values", - "type": "Float", - "defaultValue": 1.0, - "min": 0.0, - "softMax": 2.0, - "connection": { - "type": "ShaderInput", - "id": "m_normalFactor" - } - }, { "id": "textureMap", "displayName": "Texture Map", @@ -609,6 +594,13 @@ "id": "m_normalMap" } }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just rely on vertex normals.", + "type": "Bool", + "defaultValue": true + }, { "id": "textureMapUv", "displayName": "UV", @@ -621,13 +613,6 @@ "id": "m_normalMapUvIndex" } }, - { - "id": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture map, or just rely on vertex normals.", - "type": "Bool", - "defaultValue": true - }, { "id": "flipX", "displayName": "Flip X Channel", @@ -649,6 +634,19 @@ "type": "ShaderInput", "id": "m_flipNormalY" } + }, + { + "id": "factor", + "displayName": "Factor", + "description": "Strength factor for scaling the values", + "type": "Float", + "defaultValue": 1.0, + "min": 0.0, + "softMax": 2.0, + "connection": { + "type": "ShaderInput", + "id": "m_normalFactor" + } } ], "opacity": [ @@ -725,7 +723,7 @@ "description": "Center point for scaling and rotation transformations.", "type": "vector2", "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.0, 0.0 ] + "defaultValue": [ 0.5, 0.5 ] }, { "id": "tileU", @@ -872,18 +870,14 @@ "displayName": "Enable", "description": "Enable the emissive group", "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "id": "o_emissiveEnabled" - } + "defaultValue": false }, { "id": "unit", "displayName": "Units", "description": "The photometric units of the Intensity property.", "type": "Enum", - "enumValues": [ "Ev100" ], + "enumValues": ["Ev100"], "defaultValue": "Ev100" }, { @@ -918,34 +912,27 @@ "id": "m_emissiveMap" } }, - { - "id": "textureMapUv", - "displayName": "UV", - "description": "Emissive texture map UV set", - "type": "Enum", - "enumValues": [ "UV0", "UV1" ], - "defaultValue": "UV0", - "connection": { - "type": "ShaderInput", - "id": "m_emissiveMapUvIndex" - } - }, { "id": "useTexture", "displayName": "Use Texture", "description": "Whether to use the texture map.", "type": "Bool", "defaultValue": true + }, + { + "id": "textureMapUv", + "displayName": "UV", + "description": "Emissive texture map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_emissiveMapUvIndex" + } } ], "parallax": [ - { - "id": "enable", - "displayName": "Enable", - "description": "Whether to enable the parallax feature.", - "type": "Bool", - "defaultValue": false - }, { "id": "textureMap", "displayName": "Texture Map", @@ -956,13 +943,20 @@ "id": "m_depthMap" } }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map.", + "type": "Bool", + "defaultValue": true + }, { "id": "textureMapUv", "displayName": "UV", "description": "Depth texture map UV set", "type": "Enum", - "enumValues": [ "UV0", "UV1" ], - "defaultValue": "UV0", + "enumIsUv": true, + "defaultValue": "Tiled", "connection": { "type": "ShaderInput", "id": "m_parallaxUvIndex" @@ -973,7 +967,7 @@ "displayName": "Heightmap Scale", "description": "The total height of the heightmap in local model units.", "type": "Float", - "defaultValue": 0.0, + "defaultValue": 0.05, "min": 0.0, "softMax": 0.1, "connection": { @@ -1011,7 +1005,7 @@ "description": "Select the algorithm to use for parallax mapping.", "type": "Enum", "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], - "defaultValue": "Basic", + "defaultValue": "POM", "connection": { "type": "ShaderOption", "id": "o_parallax_algorithm" @@ -1055,7 +1049,7 @@ "subsurfaceScattering": [ { "id": "enableSubsurfaceScattering", - "displayName": "Enable Subsurface Scattering", + "displayName": "Subsurface Scattering", "description": "Enable subsurface scattering feature, this will disable metallic and parallax mapping property due to incompatibility", "type": "Bool", "defaultValue": false, @@ -1069,7 +1063,7 @@ "displayName": " Factor", "description": "Strength factor for scaling percentage of subsurface scattering effect applied", "type": "float", - "defaultValue": 0.0, + "defaultValue": 1.0, "min": 0.0, "max": 1.0, "connection": { @@ -1087,18 +1081,6 @@ "id": "m_subsurfaceScatteringInfluenceMap" } }, - { - "id": "influenceMapUv", - "displayName": " UV", - "description": "Influence map UV set", - "type": "Enum", - "enumValues": [ "UV0", "UV1" ], - "defaultValue": "UV0", - "connection": { - "type": "ShaderInput", - "id": "m_subsurfaceScatteringInfluenceMapUvIndex" - } - }, { "id": "useInfluenceMap", "displayName": " Use Influence Map", @@ -1106,6 +1088,18 @@ "type": "Bool", "defaultValue": true }, + { + "id": "influenceMapUv", + "displayName": " UV", + "description": "Influence map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_subsurfaceScatteringInfluenceMapUvIndex" + } + }, { "id": "scatterColor", "displayName": " Scatter color", @@ -1136,11 +1130,16 @@ } }, { - "id": "enableTransmission", - "displayName": "Enable Transmission", - "description": "Enable transmission feature", - "type": "Bool", - "defaultValue": false + "id": "transmissionMode", + "displayName": "Transmission", + "description": "Algorithm used for calculating transmission", + "type": "Enum", + "enumValues": [ "None", "ThickObject", "ThinObject" ], + "defaultValue": "None", + "connection": { + "type": "ShaderOption", + "id": "o_transmission_mode" + } }, { "id": "thickness", @@ -1161,18 +1160,6 @@ "id": "m_transmissionThicknessMap" } }, - { - "id": "thicknessMapUv", - "displayName": " UV", - "description": "Thickness map UV set", - "type": "Enum", - "enumValues": [ "UV0", "UV1" ], - "defaultValue": "UV0", - "connection": { - "type": "ShaderInput", - "id": "m_transmissionThicknessMapUvIndex" - } - }, { "id": "useThicknessMap", "displayName": " Use Thickness Map", @@ -1180,6 +1167,18 @@ "type": "Bool", "defaultValue": true }, + { + "id": "thicknessMapUv", + "displayName": " UV", + "description": "Thickness map UV set", + "type": "Enum", + "enumIsUv": true, + "defaultValue": "Tiled", + "connection": { + "type": "ShaderInput", + "id": "m_transmissionThicknessMapUvIndex" + } + }, { "id": "transmissionTint", "displayName": " Transmission Tint", @@ -1187,18 +1186,6 @@ "type": "Color", "defaultValue": [ 1.0, 0.8, 0.6 ] }, - { - "id": "transmissionMode", - "displayName": " Mode", - "description": "Algorithm used for calculating transmission", - "type": "Enum", - "enumValues": [ "None", "ThickObject", "ThinObject" ], - "defaultValue": "None", - "connection": { - "type": "ShaderOption", - "id": "o_transmission_mode" - } - }, { "id": "transmissionPower", "displayName": " Power", @@ -1287,7 +1274,7 @@ } }, { - "id": "detailMapsMapUv", + "id": "textureMapUv", "displayName": "Detail Map UVs", "description": "Which UV set to use for detail map texture sampling", "type": "Enum", @@ -1388,7 +1375,7 @@ "description": "Center point for scaling and rotation transformations.", "type": "vector2", "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.0, 0.0 ] + "defaultValue": [ 0.5, 0.5 ] }, { "id": "tileU", @@ -1506,7 +1493,7 @@ { "file": "Shaders/Depth/DepthPassTransparentMax.shader", "tag": "DepthPassTransparentMax" - } + } ], "functors": [ { @@ -1549,26 +1536,9 @@ "lightUnitProperty": "emissive.unit", "shaderInput": "m_emissiveIntensity", "ev100Index": 0, - "nitIndex": 1, - "ev100MinMax": [ -10, 20 ], - "nitMinMax": [ 0.001, 100000.0 ] - } - }, - { - // Enable/Disable shader based on different option. - "type": "ShaderEnable", - "args": { - "opacityMode": "opacity.mode", - "parallaxEnable": "parallax.enable", - "parallaxPdoEnable": "parallax.pdo", - "pbrShaderNoEdsIndex": 0, - "pbrShaderWithEdsIndex": 1, - "shadowShaderNoPSIndex": 2, - "shadowShaderWithPSIndex": 3, - "depthShaderNoPSIndex": 4, - "depthShaderWithPSIndex": 5, - "depthShaderTransparentMin": 8, - "depthShaderTransparentMax": 9 + "nitIndex" : 1, + "ev100MinMax": [-10, 20], + "nitMinMax": [0.001, 100000.0] } }, { @@ -1590,120 +1560,40 @@ "tintThickenssShaderInput": "m_transmissionTintThickness" } }, - { - // Reads material properties to determine whether a specific texture map should be sampled at runtime, and sets a shader option accordingly. - // @param textureProperty - which material property contains the texture asset reference (or maybe null) - // @param useTextureProperty - a boolean flag that toggles whether the texture should be sampled (if it's not null) - // @param shaderTags - which shader in the 'shaders' list above is configured by this functor - // @param shaderOption - the name of a shader option in the AZSL file that controls sampling of this texture + { "type": "UseTexture", "args": { "textureProperty": "baseColor.textureMap", - "dependentProperties": ["baseColor.textureMapUv"], "useTextureProperty": "baseColor.useTexture", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], + "dependentProperties": ["baseColor.textureMapUv", "baseColor.textureBlendMode"], "shaderOption": "o_baseColor_useTexture" } }, { - // See the comment above for details. "type": "UseTexture", "args": { "textureProperty": "metallic.textureMap", - "dependentProperties": ["metallic.textureMapUv"], "useTextureProperty": "metallic.useTexture", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], + "dependentProperties": ["metallic.textureMapUv"], "shaderOption": "o_metallic_useTexture" } }, { - // See the comment above for details. - "type": "UseTexture", - "args": { - "textureProperty": "roughness.textureMap", - "dependentProperties": ["roughness.textureMapUv"], - "useTextureProperty": "roughness.useTexture", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], - "shaderOption": "o_roughness_useTexture" - } - }, - { - // See the comment above for details. "type": "UseTexture", "args": { "textureProperty": "specularF0.textureMap", - "dependentProperties": ["specularF0.textureMapUv"], "useTextureProperty": "specularF0.useTexture", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], + "dependentProperties": ["specularF0.textureMapUv"], "shaderOption": "o_specularF0_useTexture" } }, { - // See the comment above for details. - "type": "UseTexture", - "args": { - "textureProperty": "clearCoat.influenceMap", - "dependentProperties": ["clearCoat.influenceMapUv"], - "useTextureProperty": "clearCoat.useInfluenceMap", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], - "shaderOption": "o_clearCoat_factor_useTexture" - } - }, - { - // See the comment above for details. - "type": "UseTexture", - "args": { - "textureProperty": "clearCoat.roughnessMap", - "dependentProperties": ["clearCoat.roughnessMapUv"], - "useTextureProperty": "clearCoat.useRoughnessMap", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], - "shaderOption": "o_clearCoat_roughness_useTexture" - } - }, - { - // See the comment above for details. - "type": "UseTexture", - "args": { - "textureProperty": "clearCoat.normalMap", - "dependentProperties": ["clearCoat.normalMapUv"], - "useTextureProperty": "clearCoat.useNormalMap", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], - "shaderOption": "o_clearCoat_normal_useTexture" - } - }, - { - // See the comment above for details. "type": "UseTexture", "args": { "textureProperty": "normal.textureMap", - "dependentProperties": ["normal.textureMapUv"], "useTextureProperty": "normal.useTexture", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], - "shaderOption": "o_normal_useTexture" + "dependentProperties": ["normal.textureMapUv", "normal.factor", "normal.flipX", "normal.flipY"], + "shaderOption": "o_normal_useTexture" } }, { @@ -1725,335 +1615,21 @@ } }, { - // See the comment above for details. - "type": "UseTexture", + "type": "Lua", "args": { - "textureProperty": "emissive.textureMap", - "dependentProperties": ["emissive.textureMapUv"], - "useTextureProperty": "emissive.useTexture", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], - "shaderOption": "o_emissive_useTexture" + "file": "StandardPBR_ClearCoatState.lua" } }, { - // See the comment above for details. - "type": "UseTexture", + "type": "Lua", "args": { - "textureProperty": "subsurfaceScattering.influenceMap", - "dependentProperties": ["subsurfaceScattering.influenceMapUv"], - "useTextureProperty": "subsurfaceScattering.useInfluenceMap", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], - "shaderOption": "o_subsurfaceScattering_useTexture" + "file": "StandardPBR_ClearCoatEnableFeature.lua" } }, { - // See the comment above for details. - "type": "UseTexture", + "type": "Lua", "args": { - "textureProperty": "subsurfaceScattering.thicknessMap", - "dependentProperties": ["subsurfaceScattering.thicknessMapUv"], - "useTextureProperty": "subsurfaceScattering.useThicknessMap", - "shaderTags": [ - "ForwardPass", - "ForwardPass_EDS" - ], - "shaderOption": "o_transmission_useTexture" - } - }, - { - // Controls visibility for properties in the editor. - // @param actions - a list of actions that are executed in order. visibility will be set when triggerProperty hits the triggerValue. - // @param affectedProperties - the properties that are affected by actions. - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "emissive.enable", - "triggerValue": true, - "visibility": "Enabled" - }, - { - "triggerProperty": "emissive.enable", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "emissive.color", - "emissive.intensity", - "emissive.useTexture", - "emissive.unit" - ] - } - }, - { - // Controls visibility for properties in the editor. - // @param actions - a list of actions that are executed in order. visibility will be set when triggerProperty hits the triggerValue. - // @param affectedProperties - the properties that are affected by actions. - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "emissive.useTexture", - "triggerValue": true, - "visibility": "Enabled" - }, - { - "triggerProperty": "emissive.useTexture", - "triggerValue": false, - "visibility": "Disabled" - }, - { - "triggerProperty": "emissive.enable", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "emissive.textureMap", - "emissive.textureMapUv" - ] - } - }, - { - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "clearCoat.useInfluenceMap", - "triggerValue": true, - "visibility": "Enabled" - }, - { - "triggerProperty": "clearCoat.useInfluenceMap", - "triggerValue": false, - "visibility": "Disabled" - }, - { - "triggerProperty": "clearCoat.enable", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "clearCoat.influenceMap", - "clearCoat.influenceMapUv" - ] - } - }, - { - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "clearCoat.useRoughnessMap", - "triggerValue": true, - "visibility": "Enabled" - }, - { - "triggerProperty": "clearCoat.useRoughnessMap", - "triggerValue": false, - "visibility": "Disabled" - }, - { - "triggerProperty": "clearCoat.enable", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "clearCoat.roughnessMap", - "clearCoat.roughnessMapUv" - ] - } - }, - { - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "clearCoat.useNormalMap", - "triggerValue": true, - "visibility": "Enabled" - }, - { - "triggerProperty": "clearCoat.useNormalMap", - "triggerValue": false, - "visibility": "Disabled" - }, - { - "triggerProperty": "clearCoat.enable", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "clearCoat.normalMap", - "clearCoat.normalMapUv" - ] - } - - }, - { - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "subsurfaceScattering.useInfluenceMap", - "triggerValue": true, - "visibility": "Enabled" - }, - { - "triggerProperty": "subsurfaceScattering.useInfluenceMap", - "triggerValue": false, - "visibility": "Disabled" - }, - { - "triggerProperty": "subsurfaceScattering.enableSubsurfaceScattering", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "subsurfaceScattering.influenceMap", - "subsurfaceScattering.influenceMapUv" - ] - } - }, - { - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "subsurfaceScattering.useThicknessMap", - "triggerValue": true, - "visibility": "Enabled" - }, - { - "triggerProperty": "subsurfaceScattering.useThicknessMap", - "triggerValue": false, - "visibility": "Disabled" - }, - { - "triggerProperty": "subsurfaceScattering.enableTransmission", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "subsurfaceScattering.thicknessMap", - "subsurfaceScattering.thicknessMapUv" - ] - } - }, - { - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "clearCoat.enable", - "triggerValue": true, - "visibility": "Enabled" - }, - { - "triggerProperty": "clearCoat.enable", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "clearCoat.factor", - "clearCoat.useInfluenceMap", - "clearCoat.roughness", - "clearCoat.useRoughnessMap", - "clearCoat.useNormalMap" - ] - } - }, - { - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "subsurfaceScattering.transmissionMode", - "triggerValue": "ThickObject", - "visibility": "Enabled" - }, - { - "triggerProperty": "subsurfaceScattering.transmissionMode", - "triggerValue": "None", - "visibility": "Hidden" - }, - { - "triggerProperty": "subsurfaceScattering.transmissionMode", - "triggerValue": "ThinObject", - "visibility": "Hidden" - }, - { - "triggerProperty": "subsurfaceScattering.enableTransmission", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "subsurfaceScattering.transmissionPower", - "subsurfaceScattering.transmissionDistortion", - "subsurfaceScattering.transmissionAttenuation" - ] - } - }, - { - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "subsurfaceScattering.enableSubsurfaceScattering", - "triggerValue": true, - "visibility": "Enabled" - }, - { - "triggerProperty": "subsurfaceScattering.enableSubsurfaceScattering", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "subsurfaceScattering.subsurfaceScatterFactor", - "subsurfaceScattering.useInfluenceMap", - "subsurfaceScattering.scatterColor", - "subsurfaceScattering.scatterDistance", - "subsurfaceScattering.quality" - ] - } - }, - { - "type": "UpdatePropertyVisibility", - "args": { - "actions": [ - { - "triggerProperty": "subsurfaceScattering.enableTransmission", - "triggerValue": true, - "visibility": "Enabled" - }, - { - "triggerProperty": "subsurfaceScattering.enableTransmission", - "triggerValue": false, - "visibility": "Hidden" - } - ], - "affectedProperties": [ - "subsurfaceScattering.thickness", - "subsurfaceScattering.useThicknessMap", - "subsurfaceScattering.transmissionTint", - "subsurfaceScattering.transmissionMode", - "subsurfaceScattering.transmissionScale" - ] + "file": "StandardPBR_EmissiveState.lua" } }, { @@ -2062,30 +1638,24 @@ "file": "StandardPBR_ParallaxState.lua" } }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_Roughness.lua" + } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_SubsurfaceState.lua" + } + }, { "type": "Lua", "args": { "file": "StandardPBR_HandleOpacityDoubleSided.lua" } }, - { - "type": "OverrideDrawList", - "args": { - "triggerProperty": "opacity.mode", - "triggerValue": "Blended", - "shaderIndex": 1, - "drawList": "transparent" - } - }, - { - "type": "OverrideDrawList", - "args": { - "triggerProperty": "opacity.mode", - "triggerValue": "TintedTransparent", - "shaderIndex": 1, - "drawList": "transparent" - } - }, { "type": "Lua", "args": { @@ -2097,6 +1667,12 @@ "args": { "file": "MaterialInputs/DetailMapsCommonFunctor.lua" } + }, + { + "type": "Lua", + "args": { + "file": "StandardPBR_ShaderEnable.lua" + } } ], "uvNameMap": { @@ -2104,3 +1680,4 @@ "UV1": "Unwrapped" } } + diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl index 440bb97c4e..a4fcccb5f5 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/EnhancedPBR_ForwardPass.azsl @@ -267,16 +267,16 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float // Directional light shadow coordinates lightingData.shadowCoords = IN.m_shadowCoords; - // ------- Occlusion ------- - - lightingData.diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_diffuseOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_diffuseOcclusionMapUvIndex], MaterialSrg::m_diffuseOcclusionFactor, o_diffuseOcclusion_useTexture); - lightingData.specularOcclusion = GetOcclusionInput(MaterialSrg::m_specularOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_specularOcclusionMapUvIndex], MaterialSrg::m_specularOcclusionFactor, o_specularOcclusion_useTexture); - // ------- Emissive ------- float2 emissiveUv = IN.m_uv[MaterialSrg::m_emissiveMapUvIndex]; lightingData.emissiveLighting = GetEmissiveInput(MaterialSrg::m_emissiveMap, MaterialSrg::m_sampler, emissiveUv, MaterialSrg::m_emissiveIntensity, MaterialSrg::m_emissiveColor.rgb, o_emissiveEnabled, o_emissive_useTexture); + // ------- Occlusion ------- + + lightingData.diffuseAmbientOcclusion = GetOcclusionInput(MaterialSrg::m_diffuseOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_diffuseOcclusionMapUvIndex], MaterialSrg::m_diffuseOcclusionFactor, o_diffuseOcclusion_useTexture); + lightingData.specularOcclusion = GetOcclusionInput(MaterialSrg::m_specularOcclusionMap, MaterialSrg::m_sampler, IN.m_uv[MaterialSrg::m_specularOcclusionMapUvIndex], MaterialSrg::m_specularOcclusionFactor, o_specularOcclusion_useTexture); + // ------- Clearcoat ------- // [GFX TODO][ATOM-14603]: Clean up the double uses of these clear coat flags diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype index 101a03b907..f8c49d579c 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/Skin.materialtype @@ -287,6 +287,13 @@ "id": "m_specularF0Map" } }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map, or just default to the Factor value.", + "type": "Bool", + "defaultValue": true + }, { "id": "textureMapUv", "displayName": "UV", @@ -299,13 +306,7 @@ "id": "m_specularF0MapUvIndex" } }, - { - "id": "useTexture", - "displayName": "Use Texture", - "description": "Whether to use the texture map, or just default to the Factor value.", - "type": "Bool", - "defaultValue": true - }, + // Consider moving this to the "general" group to be consistent with StandardMultilayerPBR { "id": "enableMultiScatterCompensation", "displayName": "Multiscattering Compensation", @@ -616,7 +617,7 @@ "type": "float", "defaultValue": 6.0, "min": 0.0, - "softMax": 20.0 + "softMax": 20.0 }, { "id": "transmissionDistortion", @@ -909,7 +910,7 @@ "description": "Center point for scaling and rotation transformations.", "type": "vector2", "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.0, 0.0 ] + "defaultValue": [ 0.5, 0.5 ] }, { "id": "tileU", @@ -1011,18 +1012,18 @@ "type": "HandleSubsurfaceScatteringParameters", "args": { "mode": "subsurfaceScattering.transmissionMode", - "scale" : "subsurfaceScattering.transmissionScale", - "power" : "subsurfaceScattering.transmissionPower", - "distortion" : "subsurfaceScattering.transmissionDistortion", - "attenuation" : "subsurfaceScattering.transmissionAttenuation", - "tintColor" : "subsurfaceScattering.transmissionTint", - "thickness" : "subsurfaceScattering.thickness", + "scale": "subsurfaceScattering.transmissionScale", + "power": "subsurfaceScattering.transmissionPower", + "distortion": "subsurfaceScattering.transmissionDistortion", + "attenuation": "subsurfaceScattering.transmissionAttenuation", + "tintColor": "subsurfaceScattering.transmissionTint", + "thickness": "subsurfaceScattering.thickness", "enabled": "subsurfaceScattering.enableSubsurfaceScattering", - "scatterDistanceColor" : "subsurfaceScattering.scatterColor", - "scatterDistanceIntensity" : "subsurfaceScattering.scatterDistance", - "scatterDistanceShaderInput" : "m_scatterDistance", - "parametersShaderInput" : "m_transmissionParams", - "tintThickenssShaderInput" : "m_transmissionTintThickness" + "scatterDistanceColor": "subsurfaceScattering.scatterColor", + "scatterDistanceIntensity": "subsurfaceScattering.scatterDistance", + "scatterDistanceShaderInput": "m_scatterDistance", + "parametersShaderInput": "m_transmissionParams", + "tintThickenssShaderInput": "m_transmissionTintThickness" } }, { @@ -1038,8 +1039,8 @@ "type": "UseTexture", "args": { "textureProperty": "specularF0.textureMap", - "dependentProperties": ["specularF0.textureMapUv"], "useTextureProperty": "specularF0.useTexture", + "dependentProperties": ["specularF0.textureMapUv"], "shaderOption": "o_specularF0_useTexture" } }, diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype index 274cb4dcb5..ec1298ae77 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR.materialtype @@ -369,15 +369,14 @@ ], "parallax": [ { + // Note parallax is enabled by default so that as soon as a user hooks up displacement settings they will see some parallax applied. + // The functor that controls parallax will set o_parallax_feature_enabled=false when all the individual layers have no displacement, so + // a default value of true here will not have any initial impact on performance. "id": "enable", "displayName": "Enable", "description": "Whether to enable the parallax feature for this material.", "type": "Bool", - "defaultValue": false, - "connection": { - "type": "ShaderOption", - "id": "o_parallax_feature_enabled" - } + "defaultValue": true }, { "id": "parallaxUv", @@ -409,7 +408,7 @@ "description": "Quality of parallax mapping.", "type": "Enum", "enumValues": [ "Low", "Medium", "High", "Ultra" ], - "defaultValue": "Medium", + "defaultValue": "Low", "connection": { "type": "ShaderOption", "id": "o_parallax_quality" @@ -445,7 +444,7 @@ "description": "Center point for scaling and rotation transformations.", "type": "vector2", "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.0, 0.0 ] + "defaultValue": [ 0.5, 0.5 ] }, { "id": "tileU", @@ -1141,7 +1140,7 @@ "displayName": "Scale", "description": "The total height of the displacement texture map in local model units.", "type": "Float", - "defaultValue": 0.0, + "defaultValue": 0.05, "min": 0.0, "softMax": 0.1, "connection": { @@ -1170,7 +1169,7 @@ "description": "Center point for scaling and rotation transformations.", "type": "vector2", "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.0, 0.0 ] + "defaultValue": [ 0.5, 0.5 ] }, { "id": "tileU", @@ -1847,7 +1846,7 @@ "displayName": "Scale", "description": "The total height of the displacement texture map in local model units.", "type": "Float", - "defaultValue": 0.0, + "defaultValue": 0.05, "min": 0.0, "softMax": 0.1, "connection": { @@ -1876,7 +1875,7 @@ "description": "Center point for scaling and rotation transformations.", "type": "vector2", "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.0, 0.0 ] + "defaultValue": [ 0.5, 0.5 ] }, { "id": "tileU", @@ -2553,7 +2552,7 @@ "displayName": "Scale", "description": "The total height of the displacement texture map in local model units.", "type": "Float", - "defaultValue": 0.0, + "defaultValue": 0.05, "min": 0.0, "softMax": 0.1, "connection": { @@ -2582,7 +2581,7 @@ "description": "Center point for scaling and rotation transformations.", "type": "vector2", "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.0, 0.0 ] + "defaultValue": [ 0.5, 0.5 ] }, { "id": "tileU", diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Displacement.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Displacement.lua index 34a067577d..d2bf8f28d3 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Displacement.lua +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardMultilayerPBR_Displacement.lua @@ -35,6 +35,10 @@ function GetMaterialPropertyDependencies() } end +function GetShaderOptionDependencies() + return {"o_parallax_feature_enabled"} +end + -- These values must align with LayerBlendSource in StandardMultilayerPBR_Common.azsli. LayerBlendSource_BlendMaskTexture = 0 LayerBlendSource_BlendMaskVertexColors = 1 @@ -50,6 +54,39 @@ function BlendSourceUsesDisplacement(context) return blendSourceIncludesDisplacement end +function IsParallaxNeededForLayer(context, layerNumber) + local enableLayer = true + if(layerNumber > 1) then -- layer 1 is always enabled, it is the implicit base layer + enableLayer = context:GetMaterialPropertyValue_bool("blend.enableLayer" .. layerNumber) + end + + if not enableLayer then + return false + end + + local parallaxGroupName = "layer" .. layerNumber .. "_parallax." + + local factor = context:GetMaterialPropertyValue_float(parallaxGroupName .. "factor") + local offset = context:GetMaterialPropertyValue_float(parallaxGroupName .. "offset") + + if factor == 0.0 and offset == 0.0 then + return false + end + + local hasTexture = nil ~= context:GetMaterialPropertyValue_Image(parallaxGroupName .. "textureMap") + local useTexture = context:GetMaterialPropertyValue_bool(parallaxGroupName .. "useTexture") + + if not hasTexture or not useTexture then + factorLayer = 0.0 + end + + if factor == 0.0 and offset == 0.0 then + return false + end + + return true +end + -- Calculates the min and max displacement height values encompassing all enabled layers. -- @return a table with two values {min,max}. Negative values are below the surface and positive values are above the surface. function CalcOverallHeightRange(context) @@ -114,21 +151,32 @@ function Process(context) local heightMinMax = CalcOverallHeightRange(context) context:SetShaderConstant_float("m_displacementMin", heightMinMax[0]) context:SetShaderConstant_float("m_displacementMax", heightMinMax[1]) + + local parallaxFeatureEnabled = context:GetMaterialPropertyValue_bool("parallax.enable") + if parallaxFeatureEnabled then + if not IsParallaxNeededForLayer(context, 1) and + not IsParallaxNeededForLayer(context, 2) and + not IsParallaxNeededForLayer(context, 3) then + parallaxFeatureEnabled = false + end + end + + context:SetShaderOptionValue_bool("o_parallax_feature_enabled", parallaxFeatureEnabled) end function ProcessEditor(context) - local enable = context:GetMaterialPropertyValue_bool("parallax.enable") + local enableParallaxSettings = context:GetMaterialPropertyValue_bool("parallax.enable") - local visibility = MaterialPropertyVisibility_Enabled - if(not enable) then - visibility = MaterialPropertyVisibility_Hidden + local parallaxSettingVisibility = MaterialPropertyVisibility_Enabled + if(not enableParallaxSettings) then + parallaxSettingVisibility = MaterialPropertyVisibility_Hidden end - context:SetMaterialPropertyVisibility("parallax.parallaxUv", visibility) - context:SetMaterialPropertyVisibility("parallax.algorithm", visibility) - context:SetMaterialPropertyVisibility("parallax.quality", visibility) - context:SetMaterialPropertyVisibility("parallax.pdo", visibility) - context:SetMaterialPropertyVisibility("parallax.showClipping", visibility) + context:SetMaterialPropertyVisibility("parallax.parallaxUv", parallaxSettingVisibility) + context:SetMaterialPropertyVisibility("parallax.algorithm", parallaxSettingVisibility) + context:SetMaterialPropertyVisibility("parallax.quality", parallaxSettingVisibility) + context:SetMaterialPropertyVisibility("parallax.pdo", parallaxSettingVisibility) + context:SetMaterialPropertyVisibility("parallax.showClipping", parallaxSettingVisibility) if BlendSourceUsesDisplacement(context) then context:SetMaterialPropertyVisibility("blend.displacementBlendDistance", MaterialPropertyVisibility_Enabled) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype index 2b0d09bc5c..ca3e5e1ce4 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR.materialtype @@ -601,7 +601,7 @@ "displayName": "Opacity Mode", "description": "Opacity mode for this texture.", "type": "Enum", - "enumValues": [ "Opaque", "Cutout", "Blended" ], + "enumValues": [ "Opaque", "Cutout", "Blended", "TintedTransparent" ], "defaultValue": "Opaque", "connection": { "type": "ShaderOption", @@ -669,12 +669,12 @@ "description": "Center point for scaling and rotation transformations.", "type": "vector2", "vectorLabels": [ "U", "V" ], - "defaultValue": [ 0.0, 0.0 ] + "defaultValue": [ 0.5, 0.5 ] }, { "id": "tileU", "displayName": "Tile U", - "description": "Scales texture coordinates in V.", + "description": "Scales texture coordinates in U.", "type": "float", "defaultValue": 1.0, "step": 0.1 @@ -879,13 +879,6 @@ } ], "parallax": [ - { - "id": "enable", - "displayName": "Enable", - "description": "Whether to enable the parallax feature.", - "type": "Bool", - "defaultValue": false - }, { "id": "textureMap", "displayName": "Texture Map", @@ -896,6 +889,13 @@ "id": "m_depthMap" } }, + { + "id": "useTexture", + "displayName": "Use Texture", + "description": "Whether to use the texture map.", + "type": "Bool", + "defaultValue": true + }, { "id": "textureMapUv", "displayName": "UV", @@ -913,7 +913,7 @@ "displayName": "Heightmap Scale", "description": "The total height of the heightmap in local model units.", "type": "Float", - "defaultValue": 0.0, + "defaultValue": 0.05, "min": 0.0, "softMax": 0.1, "connection": { @@ -951,7 +951,7 @@ "description": "Select the algorithm to use for parallax mapping.", "type": "Enum", "enumValues": [ "Basic", "Steep", "POM", "Relief", "ContactRefinement" ], - "defaultValue": "Basic", + "defaultValue": "POM", "connection": { "type": "ShaderOption", "id": "o_parallax_algorithm" @@ -1139,7 +1139,7 @@ "type": "float", "defaultValue": 6.0, "min": 0.0, - "softMax": 20.0 + "softMax": 20.0 }, { "id": "transmissionDistortion", @@ -1170,7 +1170,7 @@ } ], "irradiance": [ - // Note: this property group is used in the DiffuseGlobalIllumination pass, it is not read by the StandardPBR shader + // Note: this property group is used in the DiffuseGlobalIllumination pass and not by the main forward shader { "id": "color", "displayName": "Color", @@ -1277,18 +1277,18 @@ "type": "HandleSubsurfaceScatteringParameters", "args": { "mode": "subsurfaceScattering.transmissionMode", - "scale" : "subsurfaceScattering.transmissionScale", - "power" : "subsurfaceScattering.transmissionPower", - "distortion" : "subsurfaceScattering.transmissionDistortion", - "attenuation" : "subsurfaceScattering.transmissionAttenuation", - "tintColor" : "subsurfaceScattering.transmissionTint", - "thickness" : "subsurfaceScattering.thickness", + "scale": "subsurfaceScattering.transmissionScale", + "power": "subsurfaceScattering.transmissionPower", + "distortion": "subsurfaceScattering.transmissionDistortion", + "attenuation": "subsurfaceScattering.transmissionAttenuation", + "tintColor": "subsurfaceScattering.transmissionTint", + "thickness": "subsurfaceScattering.thickness", "enabled": "subsurfaceScattering.enableSubsurfaceScattering", - "scatterDistanceColor" : "subsurfaceScattering.scatterColor", - "scatterDistanceIntensity" : "subsurfaceScattering.scatterDistance", - "scatterDistanceShaderInput" : "m_scatterDistance", - "parametersShaderInput" : "m_transmissionParams", - "tintThickenssShaderInput" : "m_transmissionTintThickness" + "scatterDistanceColor": "subsurfaceScattering.scatterColor", + "scatterDistanceIntensity": "subsurfaceScattering.scatterDistance", + "scatterDistanceShaderInput": "m_scatterDistance", + "parametersShaderInput": "m_transmissionParams", + "tintThickenssShaderInput": "m_transmissionTintThickness" } }, { @@ -1387,15 +1387,6 @@ "file": "StandardPBR_HandleOpacityDoubleSided.lua" } }, - { - "type": "OverrideDrawList", - "args": { - "triggerProperty": "opacity.mode", - "triggerValue": "Blended", - "shaderIndex": 1, - "drawList": "transparent" - } - }, { "type": "Lua", "args": { diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl index 2667c8123b..10fa3814f3 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ForwardPass.azsl @@ -294,6 +294,24 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular } + else if (o_opacity_mode == OpacityMode::TintedTransparent) + { + // See OpacityMode::Blended above for the basic method. TintedTransparent adds onto the above concept by supporting + // colored alpha. This is currently a very basic calculation that uses the baseColor as a multiplier with strength + // determined by the alpha. We'll modify this later to be more physically accurate and allow surface depth, + // absorption, and interior color to be specified. + // + // The technique uses dual source blending to allow two separate sources to be part of the blending equation + // even though ultimately only a single render target is being written to. m_diffuseColor is render target 0 and + // m_specularColor render target 1, and the blend mode is (dest * source1color) + (source * 1.0). + // + // This means that m_specularColor.rgb (source 1) is multiplied against the destination, then + // m_diffuseColor.rgb (source) is added to that, and the final result is stored in render target 0. + + lightingOutput.m_diffuseColor.rgb *= lightingOutput.m_diffuseColor.w; // pre-multiply diffuse + lightingOutput.m_diffuseColor.rgb += lightingOutput.m_specularColor.rgb; // add specular + lightingOutput.m_specularColor.rgb = baseColor * (1.0 - lightingOutput.m_diffuseColor.w); + } else { // Pack factor and quality, drawback: because of precision limit of float16 cannot represent exact 1, maximum representable value is 0.9961 diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua index 541b1ac1ce..20d3ee47ae 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_HandleOpacityMode.lua @@ -60,10 +60,13 @@ function Process(context) if(opacityMode == OpacityMode_Blended) then ConfigureAlphaBlending(context:GetShader(ForwardPassIndex)) + context:GetShader(ForwardPassIndex):SetDrawListTagOverride("transparent") elseif(opacityMode == OpacityMode_TintedTransparent) then ConfigureDualSourceBlending(context:GetShader(ForwardPassIndex)) + context:GetShader(ForwardPassIndex):SetDrawListTagOverride("transparent") else ResetAlphaBlending(context:GetShader(ForwardPassIndex)) + context:GetShader(ForwardPassIndex):SetDrawListTagOverride("") -- reset to default draw list end end diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ParallaxState.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ParallaxState.lua index e6689da327..53d6334f28 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ParallaxState.lua +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ParallaxState.lua @@ -13,7 +13,7 @@ ---------------------------------------------------------------------------------------------------- function GetMaterialPropertyDependencies() - return {"parallax.enable", "parallax.textureMap"} + return {"parallax.textureMap", "parallax.useTexture"} end function GetShaderOptionDependencies() @@ -21,27 +21,31 @@ function GetShaderOptionDependencies() end function Process(context) - local enable = context:GetMaterialPropertyValue_bool("parallax.enable") local textureMap = context:GetMaterialPropertyValue_Image("parallax.textureMap") + local useTexture = context:GetMaterialPropertyValue_bool("parallax.useTexture") + local enable = textureMap ~= nil and useTexture context:SetShaderOptionValue_bool("o_parallax_feature_enabled", enable) - context:SetShaderOptionValue_bool("o_useDepthMap", enable and textureMap ~= nil) + context:SetShaderOptionValue_bool("o_useDepthMap", enable) end function ProcessEditor(context) - local enable = context:GetMaterialPropertyValue_bool("parallax.enable") - - if enable then - context:SetMaterialPropertyVisibility("parallax.textureMap", MaterialPropertyVisibility_Enabled) - else - context:SetMaterialPropertyVisibility("parallax.textureMap", MaterialPropertyVisibility_Hidden) - end - local textureMap = context:GetMaterialPropertyValue_Image("parallax.textureMap") - local visibility = MaterialPropertyVisibility_Enabled - if(not enable or textureMap == nil) then - visibility = MaterialPropertyVisibility_Hidden + + if textureMap ~= nil then + context:SetMaterialPropertyVisibility("parallax.useTexture", MaterialPropertyVisibility_Enabled) + else + context:SetMaterialPropertyVisibility("parallax.useTexture", MaterialPropertyVisibility_Hidden) end + local useTexture = context:GetMaterialPropertyValue_bool("parallax.useTexture") + + local visibility = MaterialPropertyVisibility_Enabled + if(textureMap == nil) then + visibility = MaterialPropertyVisibility_Hidden + elseif not useTexture then + visibility = MaterialPropertyVisibility_Disabled + end + context:SetMaterialPropertyVisibility("parallax.factor", visibility) context:SetMaterialPropertyVisibility("parallax.offset", visibility) context:SetMaterialPropertyVisibility("parallax.showClipping", visibility) diff --git a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua index e502eb38f8..b245fde3df 100644 --- a/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua +++ b/Gems/Atom/Feature/Common/Assets/Materials/Types/StandardPBR_ShaderEnable.lua @@ -13,7 +13,7 @@ ---------------------------------------------------------------------------------------------------- function GetMaterialPropertyDependencies() - return {"opacity.mode", "parallax.enable", "parallax.pdo"} + return {"opacity.mode", "parallax.textureMap", "parallax.useTexture", "parallax.pdo"} end OpacityMode_Opaque = 0 @@ -21,41 +21,61 @@ OpacityMode_Cutout = 1 OpacityMode_Blended = 2 OpacityMode_TintedTransparent = 3 +function TryGetShaderByTag(context, shaderTag) + if context:HasShaderWithTag(shaderTag) then + return context:GetShaderByTag(shaderTag) + else + return nil + end +end + +function TrySetShaderEnabled(shader, enabled) + if shader then + shader:SetEnabled(enabled) + end +end + function Process(context) local opacityMode = context:GetMaterialPropertyValue_enum("opacity.mode") - local parallaxEnabled = context:GetMaterialPropertyValue_bool("parallax.enable") + local displacementMap = context:GetMaterialPropertyValue_Image("parallax.textureMap") + local useDisplacementMap = context:GetMaterialPropertyValue_bool("parallax.useTexture") + local parallaxEnabled = displacementMap ~= nil and useDisplacementMap local parallaxPdoEnabled = context:GetMaterialPropertyValue_bool("parallax.pdo") local depthPass = context:GetShaderByTag("DepthPass") local shadowMap = context:GetShaderByTag("Shadowmap") local forwardPassEDS = context:GetShaderByTag("ForwardPass_EDS") - local lowEndForwardEDS = context:GetShaderByTag("LowEndForward_EDS") local depthPassWithPS = context:GetShaderByTag("DepthPass_WithPS") local shadowMapWithPS = context:GetShaderByTag("Shadowmap_WithPS") local forwardPass = context:GetShaderByTag("ForwardPass") - local lowEndForward = context:GetShaderByTag("LowEndForward") + + -- Use TryGetShaderByTag because these shaders only exist in StandardPBR but this script is also used for EnhancedPBR + local lowEndForwardEDS = TryGetShaderByTag(context, "LowEndForward_EDS") + local lowEndForward = TryGetShaderByTag(context, "LowEndForward") if parallaxEnabled and parallaxPdoEnabled then depthPass:SetEnabled(false) shadowMap:SetEnabled(false) forwardPassEDS:SetEnabled(false) - lowEndForwardEDS:SetEnabled(false) depthPassWithPS:SetEnabled(true) shadowMapWithPS:SetEnabled(true) forwardPass:SetEnabled(true) - lowEndForward:SetEnabled(true) + + TrySetShaderEnabled(lowEndForwardEDS, false) + TrySetShaderEnabled(lowEndForward, true) else depthPass:SetEnabled(opacityMode == OpacityMode_Opaque) shadowMap:SetEnabled(opacityMode == OpacityMode_Opaque) forwardPassEDS:SetEnabled((opacityMode == OpacityMode_Opaque) or (opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent)) - lowEndForwardEDS:SetEnabled((opacityMode == OpacityMode_Opaque) or (opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent)) depthPassWithPS:SetEnabled(opacityMode == OpacityMode_Cutout) shadowMapWithPS:SetEnabled(opacityMode == OpacityMode_Cutout) forwardPass:SetEnabled(opacityMode == OpacityMode_Cutout) - lowEndForward:SetEnabled(opacityMode == OpacityMode_Cutout) + + TrySetShaderEnabled(lowEndForwardEDS, (opacityMode == OpacityMode_Opaque) or (opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent)) + TrySetShaderEnabled(lowEndForward, opacityMode == OpacityMode_Cutout) end context:GetShaderByTag("DepthPassTransparentMin"):SetEnabled((opacityMode == OpacityMode_Blended) or (opacityMode == OpacityMode_TintedTransparent)) diff --git a/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass b/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass index b19569fb9d..38a4524aa2 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/LowEndPipeline.pass @@ -243,6 +243,13 @@ "Attachment": "LightListRemapped" } }, + { + "LocalSlot": "InputLinearDepth", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "DepthLinear" + } + }, { "LocalSlot": "DepthStencil", "AttachmentRef": { diff --git a/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass b/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass index ee943f6d39..af7408b48c 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/MainPipeline.pass @@ -251,6 +251,13 @@ "Attachment": "LightListRemapped" } }, + { + "LocalSlot": "InputLinearDepth", + "AttachmentRef": { + "Pass": "DepthPrePass", + "Attachment": "DepthLinear" + } + }, { "LocalSlot": "DepthStencil", "AttachmentRef": { diff --git a/Gems/Atom/Feature/Common/Assets/Passes/Transparent.pass b/Gems/Atom/Feature/Common/Assets/Passes/Transparent.pass index 415aa2fec0..3bb184a1f8 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/Transparent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/Transparent.pass @@ -67,6 +67,12 @@ "ShaderInputName": "m_lightListRemapped", "ScopeAttachmentUsage": "Shader" }, + { + "Name": "InputLinearDepth", + "SlotType": "Input", + "ShaderInputName": "m_linearDepthTexture", + "ScopeAttachmentUsage": "Shader" + }, // Input/Outputs { "Name": "DepthStencil", diff --git a/Gems/Atom/Feature/Common/Assets/Passes/TransparentParent.pass b/Gems/Atom/Feature/Common/Assets/Passes/TransparentParent.pass index 32517484f3..b278f2bcb4 100644 --- a/Gems/Atom/Feature/Common/Assets/Passes/TransparentParent.pass +++ b/Gems/Atom/Feature/Common/Assets/Passes/TransparentParent.pass @@ -32,6 +32,10 @@ "Name": "LightListRemapped", "SlotType": "Input" }, + { + "Name": "InputLinearDepth", + "SlotType": "Input" + }, // Input/Outputs... { "Name": "DepthStencil", @@ -91,6 +95,13 @@ "Attachment": "LightListRemapped" } }, + { + "LocalSlot": "InputLinearDepth", + "AttachmentRef": { + "Pass": "Parent", + "Attachment": "InputLinearDepth" + } + }, // Input/Outputs... { "LocalSlot": "DepthStencil", diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli index 14cff21739..d9367f9d03 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/PBR/TransparentPassSrg.azsli @@ -35,4 +35,5 @@ ShaderResourceGroup PassSrg : SRG_PerPass Texture2D m_tileLightData; StructuredBuffer m_lightListRemapped; + Texture2D m_linearDepthTexture; } diff --git a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp index 089a6168b1..16f20d7178 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CommonSystemComponent.cpp @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include @@ -114,7 +112,6 @@ namespace AZ ProjectedShadowFeatureProcessor::Reflect(context); SkyBoxFeatureProcessor::Reflect(context); UseTextureFunctor::Reflect(context); - PropertyVisibilityFunctor::Reflect(context); DrawListFunctor::Reflect(context); SubsurfaceTransmissionParameterFunctor::Reflect(context); Transform2DFunctor::Reflect(context); @@ -126,7 +123,6 @@ namespace AZ DisplayMapperPassData::Reflect(context); ConvertEmissiveUnitFunctor::Reflect(context); LookupTableAsset::Reflect(context); - ShaderEnableFunctor::Reflect(context); ReflectionProbeFeatureProcessor::Reflect(context); DecalTextureArrayFeatureProcessor::Reflect(context); SMAAFeatureProcessor::Reflect(context); diff --git a/Gems/Atom/Feature/Common/Code/Source/EditorCommonSystemComponent.cpp b/Gems/Atom/Feature/Common/Code/Source/EditorCommonSystemComponent.cpp index 32a29cf4d3..2373d0cb00 100644 --- a/Gems/Atom/Feature/Common/Code/Source/EditorCommonSystemComponent.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/EditorCommonSystemComponent.cpp @@ -12,11 +12,9 @@ #include #include -#include #include #include #include -#include #include #include @@ -58,11 +56,9 @@ namespace AZ } AZ::Render::UseTextureFunctorSourceData::Reflect(context); - AZ::Render::PropertyVisibilityFunctorSourceData::Reflect(context); AZ::Render::DrawListFunctorSourceData::Reflect(context); AZ::Render::Transform2DFunctorSourceData::Reflect(context); AZ::Render::ConvertEmissiveUnitFunctorSourceData::Reflect(context); - AZ::Render::ShaderEnableFunctorSourceData::Reflect(context); AZ::Render::SubsurfaceTransmissionParameterFunctorSourceData::Reflect(context); AZ::Render::EditorLightingPreset::Reflect(context); @@ -104,11 +100,9 @@ namespace AZ } materialFunctorRegistration->RegisterMaterialFunctor("UseTexture", azrtti_typeid()); - materialFunctorRegistration->RegisterMaterialFunctor("UpdatePropertyVisibility", azrtti_typeid()); materialFunctorRegistration->RegisterMaterialFunctor("OverrideDrawList", azrtti_typeid()); materialFunctorRegistration->RegisterMaterialFunctor("Transform2D", azrtti_typeid()); materialFunctorRegistration->RegisterMaterialFunctor("ConvertEmissiveUnit", azrtti_typeid()); - materialFunctorRegistration->RegisterMaterialFunctor("ShaderEnable", azrtti_typeid()); materialFunctorRegistration->RegisterMaterialFunctor("HandleSubsurfaceScatteringParameters", azrtti_typeid()); materialFunctorRegistration->RegisterMaterialFunctor("Lua", azrtti_typeid()); diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctor.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctor.cpp deleted file mode 100644 index da8730f1ed..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctor.cpp +++ /dev/null @@ -1,77 +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 "PropertyVisibilityFunctor.h" - -namespace AZ -{ - namespace Render - { - void PropertyVisibilityFunctor::Reflect(ReflectContext* context) - { - if (auto* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Version(1) - ->Field("triggerProperty", &Action::m_triggerPropertyIndex) - ->Field("triggerValue", &Action::m_triggerValue) - ->Field("visibility", &Action::m_visibility) - ; - serializeContext->Class() - ->Version(1) - ->Field("actions", &PropertyVisibilityFunctor::m_actions) - ->Field("affectedProperties", &PropertyVisibilityFunctor::m_affectedProperties) - ; - } - } - - void PropertyVisibilityFunctor::Process(EditorContext& context) - { - bool visibilityApplied = false; - RPI::MaterialPropertyVisibility lastAppliedVisibility; - - for (const auto& action : m_actions) - { - bool willSetVisibility = false; - if (action.m_triggerValue.Is() || action.m_triggerValue.Is() || action.m_triggerValue.Is()) - { - willSetVisibility = action.m_triggerValue == context.GetMaterialPropertyValue(action.m_triggerPropertyIndex); - } - else if (action.m_triggerValue.Is()) - { - willSetVisibility = AZ::IsClose(action.m_triggerValue.GetValue(), - context.GetMaterialPropertyValue(action.m_triggerPropertyIndex), - std::numeric_limits::epsilon()); - } - else // for types Vector2, Vector3, Vector4, Color, Image - { - AZ_Error("PropertyVisibilityFunctor", false, "Unsupported property data type as an enable property."); - } - - if (willSetVisibility) - { - visibilityApplied = true; - lastAppliedVisibility = action.m_visibility; - } - } - - if (visibilityApplied) - { - for (const auto& propertyIndex : m_affectedProperties) - { - context.SetMaterialPropertyVisibility(propertyIndex, lastAppliedVisibility); - } - } - } - - } // namespace Render -} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctor.h b/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctor.h deleted file mode 100644 index d1a7772fc8..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctor.h +++ /dev/null @@ -1,49 +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. -* -*/ - -#pragma once - -#include -#include - -namespace AZ -{ - namespace Render - { - //! Materials can use this functor to control when and how to set the visibility of a group of properties. - class PropertyVisibilityFunctor final - : public RPI::MaterialFunctor - { - friend class PropertyVisibilityFunctorSourceData; - public: - AZ_RTTI(AZ::Render::PropertyVisibilityFunctor, "{2582B36F-FA7C-450F-B46A-39AAE18356A0}", RPI::MaterialFunctor); - - static void Reflect(ReflectContext* context); - - void Process(EditorContext& context) override; - - private: - struct Action - { - AZ_TYPE_INFO(AZ::Render::PropertyVisibilityFunctor::Action, "{5DF4D981-9D0C-4040-A6C5-52E1D0BD876B}"); - - RPI::MaterialPropertyIndex m_triggerPropertyIndex; //! The control property for affected properties. - RPI::MaterialPropertyValue m_triggerValue; //! The trigger value of the control property. - RPI::MaterialPropertyVisibility m_visibility; //! The visibility of affected properties when the trigger value is hit. - }; - // Material property inputs... - AZStd::vector m_actions; //! The actions that describes when and what to do with visibilities. - AZStd::vector m_affectedProperties; //! The properties that are affected by actions. - }; - - } // namespace Render -} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctorSourceData.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctorSourceData.cpp deleted file mode 100644 index 3baf27de60..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctorSourceData.cpp +++ /dev/null @@ -1,100 +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 "PropertyVisibilityFunctorSourceData.h" -#include -#include - -#include - -namespace AZ -{ - namespace Render - { - void PropertyVisibilityFunctorSourceData::Reflect(ReflectContext* context) - { - if (auto* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Version(1) - ->Field("triggerProperty", &ActionSourceData::m_triggerPropertyName) - ->Field("triggerValue", &ActionSourceData::m_triggerValue) - ->Field("visibility", &ActionSourceData::m_visibility) - ; - serializeContext->Class() - ->Version(2) - ->Field("actions", &PropertyVisibilityFunctorSourceData::m_actions) - ->Field("affectedProperties", &PropertyVisibilityFunctorSourceData::m_affectedPropertyNames) - ; - } - } - - RPI::MaterialFunctorSourceData::FunctorResult PropertyVisibilityFunctorSourceData::CreateFunctor(const EditorContext& context) const - { - using namespace RPI; - - RPI::Ptr functor = aznew PropertyVisibilityFunctor; - - functor->m_actions.reserve(m_actions.size()); - - for (const auto& actionSource : m_actions) - { - functor->m_actions.emplace_back(); - PropertyVisibilityFunctor::Action& action = functor->m_actions.back(); - action.m_triggerPropertyIndex = context.FindMaterialPropertyIndex(AZ::Name{ actionSource.m_triggerPropertyName }); - if (action.m_triggerPropertyIndex.IsNull()) - { - return Failure(); - } - AddMaterialPropertyDependency(functor, action.m_triggerPropertyIndex); - - if (!actionSource.m_triggerValue.Resolve(*context.GetMaterialPropertiesLayout(), Name{ actionSource.m_triggerPropertyName })) - { - // Error is reported in Resolve(). - return Failure(); - } - - const MaterialPropertyDescriptor* propertyDescriptor = context.GetMaterialPropertiesLayout()->GetPropertyDescriptor(action.m_triggerPropertyIndex); - // Enum type should resolve further to a unit32_t from the string source. - if (propertyDescriptor->GetDataType() == RPI::MaterialPropertyDataType::Enum) - { - if (!RPI::MaterialUtils::ResolveMaterialPropertyEnumValue( - propertyDescriptor, - Name(actionSource.m_triggerValue.GetValue().GetValue()), - action.m_triggerValue)) - { - return Failure(); - } - } - else - { - action.m_triggerValue = actionSource.m_triggerValue.GetValue(); - } - - action.m_visibility = actionSource.m_visibility; - } - - functor->m_affectedProperties.reserve(m_affectedPropertyNames.size()); - for (const AZStd::string& name : m_affectedPropertyNames) - { - RPI::MaterialPropertyIndex index = context.FindMaterialPropertyIndex(AZ::Name{ name }); - if (index.IsNull()) - { - return Failure(); - } - functor->m_affectedProperties.push_back(index); - } - - return Success(RPI::Ptr(functor)); - } - } // namespace Render -} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctorSourceData.h b/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctorSourceData.h deleted file mode 100644 index 6b212f78a0..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Material/PropertyVisibilityFunctorSourceData.h +++ /dev/null @@ -1,48 +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. -* -*/ - -#pragma once - -#include "PropertyVisibilityFunctor.h" -#include -#include - -namespace AZ -{ - namespace Render - { - //! Builds a PropertyVisibilityFunctor. - //! Materials can use this functor to control whether a specific property group will be enabled. - class PropertyVisibilityFunctorSourceData final - : public RPI::MaterialFunctorSourceData - { - public: - AZ_RTTI(AZ::Render::PropertyVisibilityFunctorSourceData, "{B44E6929-8FFF-405F-9056-B9B811F97676}", RPI::MaterialFunctorSourceData); - - static void Reflect(ReflectContext* context); - - FunctorResult CreateFunctor(const EditorContext& context) const override; - private: - struct ActionSourceData - { - AZ_TYPE_INFO(AZ::Render::PropertyVisibilityFunctorSourceData::ActionSourceData, "{70E01DA6-0B42-4CCB-AAD0-51980DB43F62}"); - AZStd::string m_triggerPropertyName; //! The control property for affected properties. - RPI::MaterialPropertyValueSourceData m_triggerValue; //! The trigger value of the control property. - RPI::MaterialPropertyVisibility m_visibility; //! The visibility of affected properties when the trigger value is hit. - }; - // Material property inputs... - AZStd::vector m_actions; //! The actions that describes when and what to do with visibilities. - AZStd::vector m_affectedPropertyNames; //! The properties that are affected by actions. - }; - - } // namespace Render -} // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctor.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctor.cpp deleted file mode 100644 index dd602cc4ba..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctor.cpp +++ /dev/null @@ -1,74 +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 "./ShaderEnableFunctor.h" -#include -#include -#include - -namespace AZ -{ - namespace Render - { - void ShaderEnableFunctor::Reflect(ReflectContext* context) - { - if (auto* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Version(4) - ->Field("opacityModeIndex", &ShaderEnableFunctor::m_opacityModeIndex) - ->Field("parallaxEnableIndex", &ShaderEnableFunctor::m_parallaxEnableIndex) - ->Field("parallaxPdoEnableIndex", &ShaderEnableFunctor::m_parallaxPdoEnableIndex) - ->Field("shadowShaderNoPSIndex", &ShaderEnableFunctor::m_shadowShaderNoPSIndex) - ->Field("shadowShaderWithPSIndex", &ShaderEnableFunctor::m_shadowShaderWithPSIndex) - ->Field("depthShaderNoPSIndex", &ShaderEnableFunctor::m_depthShaderNoPSIndex) - ->Field("depthShaderWithPSIndex", &ShaderEnableFunctor::m_depthShaderWithPSIndex) - ->Field("pbrShaderNoEdsIndex", &ShaderEnableFunctor::m_pbrShaderNoEdsIndex) - ->Field("pbrShaderWithEdsIndex", &ShaderEnableFunctor::m_pbrShaderWithEdsIndex) - ->Field("depthShaderTransparentMin", &ShaderEnableFunctor::m_depthShaderTransparentMin) - ->Field("depthShaderTransparentMax", &ShaderEnableFunctor::m_depthShaderTransparentMax) - ; - } - } - - void ShaderEnableFunctor::Process(RuntimeContext& context) - { - unsigned int opacityMode = context.GetMaterialPropertyValue(m_opacityModeIndex); - bool parallaxEnabled = context.GetMaterialPropertyValue(m_parallaxEnableIndex); - bool parallaxPdoEnabled = context.GetMaterialPropertyValue(m_parallaxPdoEnableIndex); - - if (parallaxEnabled && parallaxPdoEnabled) - { - context.SetShaderEnabled(m_depthShaderNoPSIndex, false); - context.SetShaderEnabled(m_shadowShaderNoPSIndex, false); - context.SetShaderEnabled(m_pbrShaderWithEdsIndex, false); - - context.SetShaderEnabled(m_depthShaderWithPSIndex, true); - context.SetShaderEnabled(m_shadowShaderWithPSIndex, true); - context.SetShaderEnabled(m_pbrShaderNoEdsIndex, true); - } - else - { - context.SetShaderEnabled(m_depthShaderNoPSIndex, opacityMode == OpacityMode::Opaque ); - context.SetShaderEnabled(m_shadowShaderNoPSIndex, opacityMode == OpacityMode::Opaque); - context.SetShaderEnabled(m_pbrShaderWithEdsIndex, opacityMode == OpacityMode::Opaque || opacityMode == OpacityMode::Blended || opacityMode == OpacityMode::TintedTransparent); - - context.SetShaderEnabled(m_depthShaderWithPSIndex, opacityMode == OpacityMode::Cutout); - context.SetShaderEnabled(m_shadowShaderWithPSIndex, opacityMode == OpacityMode::Cutout); - context.SetShaderEnabled(m_pbrShaderNoEdsIndex, opacityMode == OpacityMode::Cutout); - } - - context.SetShaderEnabled(m_depthShaderTransparentMin, opacityMode == OpacityMode::Blended || opacityMode == OpacityMode::TintedTransparent); - context.SetShaderEnabled(m_depthShaderTransparentMax, opacityMode == OpacityMode::Blended || opacityMode == OpacityMode::TintedTransparent); - } - } -} diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctor.h b/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctor.h deleted file mode 100644 index ac5f31ba30..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctor.h +++ /dev/null @@ -1,63 +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. -* -*/ - -#pragma once - -#include -#include -#include - -namespace AZ -{ - namespace Render - { - enum OpacityMode - { - Opaque = 0, - Cutout, - Blended, - TintedTransparent, - }; - - //! Select shadow and depth shader based on opacity mode and parallax state - //! Opaque: Enable shader without PS - //! Cutout or Parallax enable: Enable shader with PS - //! Blended: Disable both - //! TintedTransparent: Disable both - class ShaderEnableFunctor final - : public RPI::MaterialFunctor - { - friend class ShaderEnableFunctorSourceData; - public: - AZ_RTTI(ShaderEnableFunctor, "{2079A693-FE4F-46A7-95C0-09D88AC156D0}", RPI::MaterialFunctor); - - static void Reflect(ReflectContext* context); - - void Process(RuntimeContext& context) override; - - private: - RPI::MaterialPropertyIndex m_opacityModeIndex; - RPI::MaterialPropertyIndex m_parallaxEnableIndex; - RPI::MaterialPropertyIndex m_parallaxPdoEnableIndex; - - uint32_t m_shadowShaderNoPSIndex = -1; - uint32_t m_shadowShaderWithPSIndex = -1; - uint32_t m_depthShaderNoPSIndex = -1; - uint32_t m_depthShaderWithPSIndex = -1; - uint32_t m_pbrShaderWithEdsIndex = -1; - uint32_t m_pbrShaderNoEdsIndex = -1; - // The following are used by the light culling system to produce min/max depth bounds - uint32_t m_depthShaderTransparentMin = -1; - uint32_t m_depthShaderTransparentMax = -1; - }; - } -} diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctorSourceData.cpp b/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctorSourceData.cpp deleted file mode 100644 index 3c16666f82..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctorSourceData.cpp +++ /dev/null @@ -1,116 +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 "./ShaderEnableFunctorSourceData.h" -#include -#include - -namespace AZ -{ - namespace Render - { - void ShaderEnableFunctorSourceData::Reflect(ReflectContext* context) - { - if (auto* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Version(5) - ->Field("opacityMode", &ShaderEnableFunctorSourceData::m_opacityMode) - ->Field("parallaxEnable", &ShaderEnableFunctorSourceData::m_parallaxEnable) - ->Field("parallaxPdoEnable", &ShaderEnableFunctorSourceData::m_parallaxPdoEnable) - ->Field("shadowShaderNoPSIndex", &ShaderEnableFunctorSourceData::m_shadowShaderNoPSIndex) - ->Field("shadowShaderWithPSIndex", &ShaderEnableFunctorSourceData::m_shadowShaderWithPSIndex) - ->Field("depthShaderNoPSIndex", &ShaderEnableFunctorSourceData::m_depthShaderNoPSIndex) - ->Field("depthShaderWithPSIndex", &ShaderEnableFunctorSourceData::m_depthShaderWithPSIndex) - ->Field("pbrShaderNoEdsIndex", &ShaderEnableFunctorSourceData::m_pbrShaderNoEdsIndex) - ->Field("pbrShaderWithEdsIndex", &ShaderEnableFunctorSourceData::m_pbrShaderWithEdsIndex) - ->Field("depthShaderTransparentMin", &ShaderEnableFunctorSourceData::m_depthShaderTransparentMin) - ->Field("depthShaderTransparentMax", &ShaderEnableFunctorSourceData::m_depthShaderTransparentMax) - ; - } - } - - RPI::MaterialFunctorSourceData::FunctorResult ShaderEnableFunctorSourceData::CreateFunctor(const RuntimeContext& context) const - { - RPI::Ptr functor = aznew ShaderEnableFunctor; - - functor->m_opacityModeIndex = context.FindMaterialPropertyIndex(Name{ m_opacityMode }); - if (functor->m_opacityModeIndex.IsNull()) - { - return Failure(); - } - AddMaterialPropertyDependency(functor, functor->m_opacityModeIndex); - - functor->m_parallaxEnableIndex = context.FindMaterialPropertyIndex(Name{ m_parallaxEnable }); - if (functor->m_parallaxEnableIndex.IsNull()) - { - return Failure(); - } - AddMaterialPropertyDependency(functor, functor->m_parallaxEnableIndex); - - functor->m_parallaxPdoEnableIndex = context.FindMaterialPropertyIndex(Name{ m_parallaxPdoEnable }); - if (functor->m_parallaxPdoEnableIndex.IsNull()) - { - return Failure(); - } - AddMaterialPropertyDependency(functor, functor->m_parallaxPdoEnableIndex); - - if (!context.CheckShaderIndexValid(m_shadowShaderWithPSIndex)) - { - return Failure(); - } - functor->m_shadowShaderWithPSIndex = m_shadowShaderWithPSIndex; - - if (!context.CheckShaderIndexValid(m_shadowShaderNoPSIndex)) - { - return Failure(); - } - functor->m_shadowShaderNoPSIndex = m_shadowShaderNoPSIndex; - - if (!context.CheckShaderIndexValid(m_depthShaderWithPSIndex)) - { - return Failure(); - } - functor->m_depthShaderWithPSIndex = m_depthShaderWithPSIndex; - - if (!context.CheckShaderIndexValid(m_depthShaderNoPSIndex)) - { - return Failure(); - } - functor->m_depthShaderNoPSIndex = m_depthShaderNoPSIndex; - - if (!context.CheckShaderIndexValid(m_pbrShaderNoEdsIndex)) - { - return Failure(); - } - functor->m_pbrShaderNoEdsIndex = m_pbrShaderNoEdsIndex; - - if (!context.CheckShaderIndexValid(m_pbrShaderWithEdsIndex)) - { - return Failure(); - } - functor->m_pbrShaderWithEdsIndex = m_pbrShaderWithEdsIndex; - if (!context.CheckShaderIndexValid(m_depthShaderTransparentMin)) - { - return Failure(); - } - functor->m_depthShaderTransparentMin = m_depthShaderTransparentMin; - if (!context.CheckShaderIndexValid(m_depthShaderTransparentMax)) - { - return Failure(); - } - functor->m_depthShaderTransparentMax = m_depthShaderTransparentMax; - - return Success(RPI::Ptr(functor)); - } - } -} diff --git a/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctorSourceData.h b/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctorSourceData.h deleted file mode 100644 index 2d00a4a015..0000000000 --- a/Gems/Atom/Feature/Common/Code/Source/Material/ShaderEnableFunctorSourceData.h +++ /dev/null @@ -1,52 +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. -* -*/ - -#pragma once - -#include "./ShaderEnableFunctor.h" -#include - -namespace AZ -{ - namespace Render - { - class ShaderEnableFunctor; - - //! Builds a ShaderEnableFunctor - class ShaderEnableFunctorSourceData final - : public RPI::MaterialFunctorSourceData - { - public: - AZ_RTTI(ShaderEnableFunctorSourceData, "{63775ECB-5C3E-44D3-B175-4537BF76C3A7}", RPI::MaterialFunctorSourceData); - - static void Reflect(ReflectContext* context); - - FunctorResult CreateFunctor(const RuntimeContext& context) const override; - - private: - - AZStd::string m_opacityMode; - AZStd::string m_parallaxEnable; - AZStd::string m_parallaxPdoEnable; - - uint32_t m_shadowShaderNoPSIndex = -1; - uint32_t m_shadowShaderWithPSIndex = -1; - uint32_t m_depthShaderNoPSIndex = -1; - uint32_t m_depthShaderWithPSIndex = -1; - uint32_t m_pbrShaderWithEdsIndex = -1; - uint32_t m_pbrShaderNoEdsIndex = -1; - // The following are used by the light culling system to produce min/max depth bounds - uint32_t m_depthShaderTransparentMin = -1; - uint32_t m_depthShaderTransparentMax = -1; - }; - } -} diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_editor_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_editor_files.cmake index 3a749a4b67..4e7cc9dab3 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_editor_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_editor_files.cmake @@ -24,16 +24,12 @@ set(FILES Source/Material/ConvertEmissiveUnitFunctorSourceData.h Source/Material/MaterialConverterSystemComponent.cpp Source/Material/MaterialConverterSystemComponent.h - Source/Material/ShaderEnableFunctorSourceData.cpp - Source/Material/ShaderEnableFunctorSourceData.h Source/Material/SubsurfaceTransmissionParameterFunctorSourceData.cpp Source/Material/SubsurfaceTransmissionParameterFunctorSourceData.h Source/Material/Transform2DFunctorSourceData.cpp Source/Material/Transform2DFunctorSourceData.h Source/Material/UseTextureFunctorSourceData.cpp Source/Material/UseTextureFunctorSourceData.h - Source/Material/PropertyVisibilityFunctorSourceData.cpp - Source/Material/PropertyVisibilityFunctorSourceData.h Source/Material/DrawListFunctorSourceData.cpp Source/Material/DrawListFunctorSourceData.h ) diff --git a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake index 46a4e06ac2..4f98046adb 100644 --- a/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake +++ b/Gems/Atom/Feature/Common/Code/atom_feature_common_files.cmake @@ -155,16 +155,12 @@ set(FILES Source/LookupTable/LookupTableAsset.cpp Source/Material/ConvertEmissiveUnitFunctor.cpp Source/Material/ConvertEmissiveUnitFunctor.h - Source/Material/ShaderEnableFunctor.cpp - Source/Material/ShaderEnableFunctor.h Source/Material/SubsurfaceTransmissionParameterFunctor.cpp Source/Material/SubsurfaceTransmissionParameterFunctor.h Source/Material/Transform2DFunctor.cpp Source/Material/Transform2DFunctor.h Source/Material/UseTextureFunctor.cpp Source/Material/UseTextureFunctor.h - Source/Material/PropertyVisibilityFunctor.cpp - Source/Material/PropertyVisibilityFunctor.h Source/Material/DrawListFunctor.cpp Source/Material/DrawListFunctor.h Source/Math/GaussianMathFilter.h diff --git a/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp b/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp index 3a04bf6b88..09cd1c125e 100644 --- a/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI.Edit/ShaderCompilerArguments.cpp @@ -164,7 +164,7 @@ namespace AZ arguments += " -Zi"; // Generate debug information arguments += " -Zss"; // Compute Shader Hash considering source information } - arguments += m_dxcAdditionalFreeArguments; + arguments += " " + m_dxcAdditionalFreeArguments; return arguments; } } diff --git a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/NullDescriptorManager.cpp b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/NullDescriptorManager.cpp index cdacd2578f..791fa006b0 100644 --- a/Gems/Atom/RHI/Vulkan/Code/Source/RHI/NullDescriptorManager.cpp +++ b/Gems/Atom/RHI/Vulkan/Code/Source/RHI/NullDescriptorManager.cpp @@ -180,6 +180,7 @@ namespace AZ for (uint32_t imageIndex = static_cast(NullDescriptorManager::ImageTypes::General2D); imageIndex < static_cast(NullDescriptorManager::ImageTypes::Count); imageIndex++) { // different options for the images + imageCreateInfo.imageType = (imageIndex >= static_cast(NullDescriptorManager::ImageTypes::General3D)) ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D; imageCreateInfo.extent = { m_imageNullDescriptor.m_images[imageIndex].m_dimension, m_imageNullDescriptor.m_images[imageIndex].m_dimension, 1 }; imageCreateInfo.samples = m_imageNullDescriptor.m_images[imageIndex].m_sampleCountFlag; imageCreateInfo.format = m_imageNullDescriptor.m_images[imageIndex].m_format; diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/LuaMaterialFunctor.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/LuaMaterialFunctor.h index 396ba14810..f372f40981 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/LuaMaterialFunctor.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Material/LuaMaterialFunctor.h @@ -288,6 +288,7 @@ namespace AZ AZStd::size_t GetShaderCount() const; LuaMaterialFunctorShaderItem GetShader(AZStd::size_t index); LuaMaterialFunctorShaderItem GetShaderByTag(const char* shaderTag); + bool HasShaderWithTag(const char* shaderTag); private: diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/Query.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/Query.cpp index 227e096594..1d6e8cdc65 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/Query.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/GpuQuery/Query.cpp @@ -96,12 +96,6 @@ namespace AZ return QueryResultCode::Fail; } - // Limit calling BeginQuery() to the first CommandList in the array. - if (context.GetCommandListIndex() != 0) - { - return QueryResultCode::Success; - } - const auto rhiQueryIndices = GetRhiQueryIndicesFromCurrentFrame(); if (!rhiQueryIndices) { @@ -124,12 +118,6 @@ namespace AZ return QueryResultCode::Fail; } - // Limit calling EndQuery() to the last CommandList in the array. - if (context.GetCommandListIndex() != context.GetCommandListCount() - 1) - { - return QueryResultCode::Success; - } - // Validate that the queries are recorded for the same scope. if (m_cachedScopeId != context.GetScopeId()) { 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 9c6a95e582..3a2a556429 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/RenderPass.cpp @@ -522,8 +522,11 @@ namespace AZ } }; - ExecuteOnTimestampQuery(beginQuery); - ExecuteOnPipelineStatisticsQuery(beginQuery); + if (context.GetCommandListIndex() == 0) + { + ExecuteOnTimestampQuery(beginQuery); + ExecuteOnPipelineStatisticsQuery(beginQuery); + } } void RenderPass::EndScopeQuery(const RHI::FrameGraphExecuteContext& context) @@ -533,8 +536,23 @@ namespace AZ query->EndQuery(context); }; - ExecuteOnTimestampQuery(endQuery); - ExecuteOnPipelineStatisticsQuery(endQuery); + // This scopy query implmentation should be replaced by + // [ATOM-5407] [RHI][Core] - Add GPU timestamp and pipeline statistic support for scopes + + // For timestamp query, it's okay to execute across different command lists + if (context.GetCommandListIndex() == context.GetCommandListCount() - 1) + { + ExecuteOnTimestampQuery(endQuery); + } + // For all the other types of queries except timestamp, the query start and end has to be in the same command list + // Here only tracks the PipelineStatistics for the first command list due to that we don't know how many queries are + // needed when AddScopeQueryToFrameGraph is called. + // This implementation leads to an issue that we may not get accurate pipeline statistic data + // for passes which were executed with more than one command list + if (context.GetCommandListIndex() == 0) + { + ExecuteOnPipelineStatisticsQuery(endQuery); + } } void RenderPass::ReadbackScopeQueryResults() diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp index 6579e6a98d..3fc2bbd197 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/ShaderVariantAsyncLoader.cpp @@ -150,10 +150,7 @@ namespace AZ } } - if (!shaderVariantTreePendingRequests.empty() || !shaderVariantPendingRequests.empty()) - { - AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1000)); - } + AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(1000)); } } diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp index 7db5f12560..d6421e1337 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Material/LuaMaterialFunctor.cpp @@ -296,6 +296,7 @@ namespace AZ ->Method("GetShaderCount", &LuaMaterialFunctorRuntimeContext::GetShaderCount) ->Method("GetShader", &LuaMaterialFunctorRuntimeContext::GetShader) ->Method("GetShaderByTag", &LuaMaterialFunctorRuntimeContext::GetShaderByTag) + ->Method("HasShaderWithTag", &LuaMaterialFunctorRuntimeContext::HasShaderWithTag) ; } @@ -424,6 +425,11 @@ namespace AZ return LuaMaterialFunctorShaderItem{nullptr}; } } + + bool LuaMaterialFunctorRuntimeContext::HasShaderWithTag(const char* shaderTag) + { + return m_runtimeContextImpl->m_shaderCollection->HasShaderTag(AZ::Name{shaderTag}); + } void LuaMaterialFunctorEditorContext::LuaMaterialFunctorEditorContext::Reflect(BehaviorContext* behaviorContext) { diff --git a/Gems/Atom/RPI/Code/Tests/System/GpuQueryTests.cpp b/Gems/Atom/RPI/Code/Tests/System/GpuQueryTests.cpp index e55ec8012b..98ff6befdd 100644 --- a/Gems/Atom/RPI/Code/Tests/System/GpuQueryTests.cpp +++ b/Gems/Atom/RPI/Code/Tests/System/GpuQueryTests.cpp @@ -159,7 +159,9 @@ namespace UnitTest const uint32_t ResultSize = sizeof(uint64_t); uint64_t mockData; - const RHI::FrameGraphExecuteContext::Descriptor desc = {}; + RHI::FrameGraphExecuteContext::Descriptor desc = {}; + uint64_t dummyCommandList; + desc.m_commandList = reinterpret_cast(&dummyCommandList); RHI::FrameGraphExecuteContext context(desc); RHI::Scope scope; @@ -209,7 +211,9 @@ namespace UnitTest const uint32_t ResultSize = sizeof(uint64_t) * 4u; uint64_t mockData; - const RHI::FrameGraphExecuteContext::Descriptor desc = {}; + RHI::FrameGraphExecuteContext::Descriptor desc = {}; + uint64_t dummyCommandList; + desc.m_commandList = reinterpret_cast(&dummyCommandList); RHI::FrameGraphExecuteContext context(desc); RHI::Scope scope; @@ -273,7 +277,9 @@ namespace UnitTest const uint32_t ResultSize = sizeof(uint64_t) * 2u; uint64_t mockData; - const RHI::FrameGraphExecuteContext::Descriptor desc = {}; + RHI::FrameGraphExecuteContext::Descriptor desc = {}; + uint64_t dummyCommandList; + desc.m_commandList = reinterpret_cast(&dummyCommandList); RHI::FrameGraphExecuteContext context(desc); RHI::Scope scope; diff --git a/Gems/Atom/TestData/TestData/Materials/ParallaxRock.material b/Gems/Atom/TestData/TestData/Materials/ParallaxRock.material index 4c3a925e52..c9276216eb 100644 --- a/Gems/Atom/TestData/TestData/Materials/ParallaxRock.material +++ b/Gems/Atom/TestData/TestData/Materials/ParallaxRock.material @@ -17,7 +17,6 @@ "textureMap": "TestData/Textures/cc0/Rock030_2K_Normal.jpg" }, "parallax": { - "enable": true, "algorithm": "POM", "factor": 0.03, "quality": "High", diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material index 17353a0603..415bd36dcf 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/001_ManyFeatures.material @@ -86,6 +86,10 @@ "textureMap": "TestData/Textures/cc0/Lava004_1K_Roughness.jpg" }, "layer2_uv": { + "center": [ + 0.0, + 0.0 + ], "offsetU": 0.5, "offsetV": 0.25 }, @@ -128,11 +132,15 @@ "factor": 0.47474750876426699 }, "layer3_uv": { + "center": [ + 0.0, + 0.0 + ], "offsetU": 0.11999999731779099, "rotateDegrees": -57.599998474121097 }, "parallax": { - "enable": true + "quality": "Medium" }, "uv": { "center": [ diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/002_ParallaxPdo.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/002_ParallaxPdo.material index 8cddab24bc..64adf317a9 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/002_ParallaxPdo.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/002_ParallaxPdo.material @@ -48,8 +48,8 @@ "textureMap": "TestData/Textures/cc0/Concrete019_1K_Color.jpg" }, "parallax": { - "enable": true, - "pdo": true + "pdo": true, + "quality": "Medium" } } } \ No newline at end of file diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/004_UseVertexColors.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/004_UseVertexColors.material index 3201fa3864..ea3ea8b519 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/004_UseVertexColors.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/004_UseVertexColors.material @@ -6,6 +6,9 @@ "properties": { "blend": { "blendSource": "BlendMaskVertexColors" + }, + "parallax": { + "quality": "Medium" } } -} +} \ No newline at end of file diff --git a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/005_UseDisplacement.material b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/005_UseDisplacement.material index 55a4774d49..9163fe0a0c 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/005_UseDisplacement.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardMultilayerPbrTestCases/005_UseDisplacement.material @@ -46,8 +46,8 @@ }, "layer2_uv": { "center": [ - 0.5, - 0.5 + 0.0, + 0.0 ], "offsetU": 0.1599999964237213, "offsetV": 0.07999999821186066, @@ -67,13 +67,15 @@ "textureMap": "TestData/Textures/cc0/Rocks002_1K_Roughness.jpg" }, "layer3_uv": { + "center": [ + 0.0, + 0.0 + ], "scale": 3.4999988079071047 }, "parallax": { "algorithm": "Relief", - "enable": true, - "pdo": true, - "quality": "Low" + "pdo": true } } } \ No newline at end of file diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_TintedTransparent.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_TintedTransparent.material new file mode 100644 index 0000000000..1716792af1 --- /dev/null +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/009_Opacity_TintedTransparent.material @@ -0,0 +1,23 @@ +{ + "description": "", + "materialType": "Materials/Types/StandardPBR.materialtype", + "parentMaterial": "", + "propertyLayoutVersion": 3, + "properties": { + "baseColor": { + "color": [ + 0.5906767249107361, + 1.0, + 0.11703670024871826, + 1.0 + ], + "textureMap": "Textures/Default/default_basecolor.tif" + }, + "opacity": { + "alphaSource": "Split", + "factor": 0.75, + "mode": "TintedTransparent", + "textureMap": "TestData/Textures/checker8x8_gray_512.png" + } + } +} \ No newline at end of file diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/012_Parallax_POM.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/012_Parallax_POM.material index a94d90d04d..ed070d5de2 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/012_Parallax_POM.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/012_Parallax_POM.material @@ -8,7 +8,6 @@ }, "parallax": { "algorithm": "POM", - "enable": true, "factor": 0.02500000037252903, "quality": "High", "textureMap": "TestData/Textures/TextureHaven/4k_castle_brick_02_red/4k_castle_brick_02_red_disp.png" diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/012_Parallax_POM_Cutout.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/012_Parallax_POM_Cutout.material index fb862dc5d3..f5ec0e8287 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/012_Parallax_POM_Cutout.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/012_Parallax_POM_Cutout.material @@ -13,13 +13,15 @@ "textureMap": "TestData/Textures/checker8x8_512.png" }, "parallax": { - "algorithm": "POM", - "enable": true, "factor": 0.10000000149011612, "quality": "High", "textureMap": "TestData/Textures/TextureHaven/4k_castle_brick_02_red/4k_castle_brick_02_red_disp.png" }, "uv": { + "center": [ + 0.0, + 0.0 + ], "scale": 0.5 } } diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission.material index dbaf6cb587..38adbc70cd 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/015_SubsurfaceScattering_Transmission.material @@ -6,7 +6,6 @@ "properties": { "subsurfaceScattering": { "enableSubsurfaceScattering": true, - "enableTransmission": true, "scatterDistance": 64.6464614868164, "subsurfaceScatterFactor": 1.0, "thicknessMap": "TestData/Textures/checker8x8_512.png", diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/100_UvTiling_Parallax_A.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/100_UvTiling_Parallax_A.material index 7bf12e5358..b3e69212db 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/100_UvTiling_Parallax_A.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/100_UvTiling_Parallax_A.material @@ -13,7 +13,6 @@ }, "parallax": { "algorithm": "POM", - "enable": true, "factor": 0.10000000149011612, "quality": "High", "textureMap": "TestData/Objects/cube/cube_diff.tif" diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/100_UvTiling_Parallax_B.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/100_UvTiling_Parallax_B.material index 4b9f233a85..3d52f3b9e6 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/100_UvTiling_Parallax_B.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/100_UvTiling_Parallax_B.material @@ -13,7 +13,6 @@ }, "parallax": { "algorithm": "POM", - "enable": true, "factor": 0.05000000074505806, "quality": "High", "textureMap": "TestData/Objects/cube/cube_diff.tif" diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/101_DetailMaps_LucyBaseNoDetailMaps.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/101_DetailMaps_LucyBaseNoDetailMaps.material index 7b1f0ba6a9..6d77be5a49 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/101_DetailMaps_LucyBaseNoDetailMaps.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/101_DetailMaps_LucyBaseNoDetailMaps.material @@ -8,18 +8,24 @@ "textureMap": "Objects/Lucy/Lucy_bronze_BaseColor.png", "textureMapUv": "Unwrapped" }, + "detailUV": { + "center": [ + 0.0, + 0.0 + ] + }, "metallic": { - "textureMap": "Objects/Lucy/Lucy_bronze_metallic.png", + "textureMap": "Objects/Lucy/Lucy_bronze_Metallic.png", "textureMapUv": "Unwrapped" }, "normal": { "flipY": true, - "textureMap": "Objects/Lucy/Lucy_normal.png", + "textureMap": "Objects/Lucy/Lucy_Normal.png", "textureMapUv": "Unwrapped" }, "roughness": { - "textureMap": "Objects/Lucy/Lucy_bronze_roughness.png", + "textureMap": "Objects/Lucy/Lucy_bronze_Roughness.png", "textureMapUv": "Unwrapped" } } -} +} \ No newline at end of file diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/102_DetailMaps_All.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/102_DetailMaps_All.material index 55a01866b5..1a29f392c8 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/102_DetailMaps_All.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/102_DetailMaps_All.material @@ -5,7 +5,7 @@ "propertyLayoutVersion": 3, "properties": { "baseColor": { - "textureMap": "Objects/Lucy/Lucy_bronze_baseColor.png", + "textureMap": "Objects/Lucy/Lucy_bronze_BaseColor.png", "textureMapUv": "Unwrapped" }, "detailLayerGroup": { @@ -19,20 +19,24 @@ "normalDetailStrength": 1.5 }, "detailUV": { + "center": [ + 0.0, + 0.0 + ], "scale": 10.0 }, "metallic": { - "textureMap": "Objects/Lucy/Lucy_bronze_metallic.png", + "textureMap": "Objects/Lucy/Lucy_bronze_Metallic.png", "textureMapUv": "Unwrapped" }, "normal": { "flipY": true, - "textureMap": "Objects/Lucy/Lucy_normal.png", + "textureMap": "Objects/Lucy/Lucy_Normal.png", "textureMapUv": "Unwrapped" }, "roughness": { - "textureMap": "Objects/Lucy/Lucy_bronze_roughness.png", + "textureMap": "Objects/Lucy/Lucy_bronze_Roughness.png", "textureMapUv": "Unwrapped" } } -} +} \ No newline at end of file diff --git a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/105_DetailMaps_BlendMaskUsingDetailUVs.material b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/105_DetailMaps_BlendMaskUsingDetailUVs.material index 6193cf4eed..a69b72b623 100644 --- a/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/105_DetailMaps_BlendMaskUsingDetailUVs.material +++ b/Gems/Atom/TestData/TestData/Materials/StandardPbrTestCases/105_DetailMaps_BlendMaskUsingDetailUVs.material @@ -5,7 +5,7 @@ "propertyLayoutVersion": 3, "properties": { "baseColor": { - "textureMap": "Objects/Lucy/Lucy_bronze_baseColor.png", + "textureMap": "Objects/Lucy/Lucy_bronze_BaseColor.png", "textureMapUv": "Unwrapped" }, "detailLayerGroup": { @@ -18,20 +18,24 @@ "normalDetailStrength": 1.5 }, "detailUV": { + "center": [ + 0.0, + 0.0 + ], "scale": 10.0 }, "metallic": { - "textureMap": "Objects/Lucy/Lucy_bronze_metallic.png", + "textureMap": "Objects/Lucy/Lucy_bronze_Metallic.png", "textureMapUv": "Unwrapped" }, "normal": { "flipY": true, - "textureMap": "Objects/Lucy/Lucy_normal.png", + "textureMap": "Objects/Lucy/Lucy_Normal.png", "textureMapUv": "Unwrapped" }, "roughness": { - "textureMap": "Objects/Lucy/Lucy_bronze_roughness.png", + "textureMap": "Objects/Lucy/Lucy_bronze_Roughness.png", "textureMapUv": "Unwrapped" } } -} +} \ No newline at end of file diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h index a41c8221f0..f2c120dbcd 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/RenderViewportWidget.h @@ -98,6 +98,7 @@ namespace AtomToolsFramework AZStd::optional ViewportScreenToWorld(const AzFramework::ScreenPoint& screenPosition, float depth) override; AZStd::optional ViewportScreenToWorldRay( const AzFramework::ScreenPoint& screenPosition) override; + float DeviceScalingFactor() override; //! Set interface for providing viewport specific settings (e.g. snapping properties). void SetViewportSettings(const AzToolsFramework::ViewportInteraction::ViewportSettings* viewportSettings); diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp index cee178c724..35edb3af5b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/RenderViewportWidget.cpp @@ -313,8 +313,7 @@ namespace AtomToolsFramework // Scale the size by the DPI of the platform to // get the proper size in pixels. const QSize uiWindowSize = size(); - const qreal deficePixelRatio = devicePixelRatioF(); - const QSize windowSize = uiWindowSize * deficePixelRatio; + const QSize windowSize = uiWindowSize * devicePixelRatioF(); const AzFramework::NativeWindowHandle windowId = reinterpret_cast(winId()); AzFramework::WindowNotificationBus::Event(windowId, &AzFramework::WindowNotifications::OnWindowResized, windowSize.width(), windowSize.height()); @@ -465,6 +464,11 @@ namespace AtomToolsFramework return AzToolsFramework::ViewportInteraction::ProjectedViewportRay{rayOrigin, rayDirection}; } + float RenderViewportWidget::DeviceScalingFactor() + { + return aznumeric_cast(devicePixelRatioF()); + } + AzFramework::ScreenPoint RenderViewportWidget::ViewportCursorScreenPosition() { return AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(m_mousePosition.toPoint()); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp index 6a4bb8c0f4..887019787b 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Window/CreateMaterialDialog/CreateMaterialDialog.cpp @@ -71,6 +71,8 @@ namespace MaterialEditor QObject::connect(m_ui->m_materialTypeComboBox, static_cast(&QComboBox::currentIndexChanged), this, [this]() { UpdateMaterialTypeSelection(); }); QObject::connect(m_ui->m_materialTypeComboBox, &QComboBox::currentTextChanged, this, [this]() { UpdateMaterialTypeSelection(); }); + m_ui->m_materialTypeComboBox->model()->sort(0, Qt::AscendingOrder); + // Select the default material type from settings auto settings = AZ::UserSettings::CreateFind(AZ::Crc32("MaterialDocumentSettings"), AZ::UserSettings::CT_GLOBAL); diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Bricks038_8K/bricks038.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Bricks038_8K/bricks038.material index 25e29b55e5..82b1cdb590 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Bricks038_8K/bricks038.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Bricks038_8K/bricks038.material @@ -26,7 +26,6 @@ }, "parallax": { "algorithm": "POM", - "enable": true, "factor": 0.02500000037252903, "pdo": true, "quality": "Ultra", diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Concrete016_8K/Concrete016.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Concrete016_8K/Concrete016.material index 336d479b30..03fb0ea5be 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Concrete016_8K/Concrete016.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Concrete016_8K/Concrete016.material @@ -31,7 +31,8 @@ "algorithm": "ContactRefinement", "factor": 0.019999999552965165, "quality": "Ultra", - "textureMap": "Materials/Concrete016_8K/Concrete016_8K_Displacement.png" + "textureMap": "Materials/Concrete016_8K/Concrete016_8K_Displacement.png", + "useTexture": false }, "roughness": { "textureMap": "Materials/Concrete016_8K/Concrete016_8K_Roughness.png" diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Fabric001_8K/Fabric001.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Fabric001_8K/Fabric001.material index 72610e8bb6..7d8c3d5142 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Fabric001_8K/Fabric001.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Fabric001_8K/Fabric001.material @@ -20,7 +20,6 @@ }, "parallax": { "algorithm": "ContactRefinement", - "enable": true, "factor": 0.004999999888241291, "quality": "Ultra", "textureMap": "Materials/Fabric001_8K/Fabric001_8K_Displacement.png" diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Fabric030_4K/Fabric030.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Fabric030_4K/Fabric030.material index 458ab811b6..493bfab455 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Fabric030_4K/Fabric030.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/Fabric030_4K/Fabric030.material @@ -20,7 +20,6 @@ }, "parallax": { "algorithm": "ContactRefinement", - "enable": true, "factor": 0.0020000000949949028, "pdo": true, "quality": "Medium", diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/PaintedPlaster015_8K/PaintedPlaster015.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/PaintedPlaster015_8K/PaintedPlaster015.material index 57163f520d..a2bb2c7704 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/PaintedPlaster015_8K/PaintedPlaster015.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/PaintedPlaster015_8K/PaintedPlaster015.material @@ -19,7 +19,6 @@ }, "parallax": { "algorithm": "ContactRefinement", - "enable": true, "factor": 0.009999999776482582, "pdo": true, "quality": "Ultra", diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/baseboards.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/baseboards.material index 625d872475..f75490c2ad 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/baseboards.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/baseboards.material @@ -30,7 +30,8 @@ "factor": 0.02500000037252903, "pdo": true, "quality": "Ultra", - "textureMap": "Materials/Bricks038_8K/Bricks038_8K_Displacement.png" + "textureMap": "Materials/Bricks038_8K/Bricks038_8K_Displacement.png", + "useTexture": false }, "roughness": { "factor": 0.4343433976173401, diff --git a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/crown.material b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/crown.material index e3c6d9eae6..d7e2050dbd 100644 --- a/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/crown.material +++ b/Gems/AtomContent/LookDevelopmentStudioPixar/Assets/Materials/crown.material @@ -22,7 +22,6 @@ }, "parallax": { "algorithm": "POM", - "enable": true, "factor": 0.02500000037252903, "pdo": true, "quality": "Ultra", diff --git a/Gems/AtomContent/ReferenceMaterials/Assets/Materials/ConcreteStucco/concrete_stucco.material b/Gems/AtomContent/ReferenceMaterials/Assets/Materials/ConcreteStucco/concrete_stucco.material index ab9f366ff6..d4e2016022 100644 --- a/Gems/AtomContent/ReferenceMaterials/Assets/Materials/ConcreteStucco/concrete_stucco.material +++ b/Gems/AtomContent/ReferenceMaterials/Assets/Materials/ConcreteStucco/concrete_stucco.material @@ -19,7 +19,8 @@ }, "parallax": { "factor": 0.0010101000079885126, - "textureMap": "Materials/ConcreteStucco/concrete_stucco_height.jpg" + "textureMap": "Materials/ConcreteStucco/concrete_stucco_height.jpg", + "useTexture": false }, "specularF0": { "factor": 0.5050504803657532 diff --git a/Gems/AtomContent/Sponza/Assets/license.txt b/Gems/AtomContent/Sponza/Assets/license.txt new file mode 100644 index 0000000000..e303d8c767 --- /dev/null +++ b/Gems/AtomContent/Sponza/Assets/license.txt @@ -0,0 +1,8 @@ +The content in this gem "O3DE\Gems\AtomContent\Sponza" is ported +from the original source, and modified for the O3DE Engine and Atom Renderer. + +The original "Crytek Sponza" scene data can be downloaded from the +"McGuire Computer Graphics Archive": https://casual-effects.com/data/ + +The original content is under the "CC BY 3.0" License: +https://creativecommons.org/licenses/by/3.0/ \ No newline at end of file diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_arch.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_arch.material index 1102fb150a..d95e84121c 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_arch.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_arch.material @@ -41,7 +41,8 @@ "factor": 0.050999999046325687, "pdo": true, "quality": "High", - "textureMap": "Textures/arch_1k_height.png" + "textureMap": "Textures/arch_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/arch_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_background.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_background.material index c1853250d7..710f790419 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_background.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_background.material @@ -47,7 +47,8 @@ "factor": 0.03099999949336052, "pdo": true, "quality": "High", - "textureMap": "Textures/background_1k_height.png" + "textureMap": "Textures/background_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/background_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_bricks.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_bricks.material index a269098b4d..26d64c7db9 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_bricks.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_bricks.material @@ -46,7 +46,8 @@ "algorithm": "ContactRefinement", "factor": 0.03500000014901161, "quality": "Medium", - "textureMap": "Textures/bricks_1k_height.png" + "textureMap": "Textures/bricks_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/bricks_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_ceiling.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_ceiling.material index 94225cd00e..95d08d398b 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_ceiling.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_ceiling.material @@ -48,7 +48,8 @@ "factor": 0.019999999552965165, "pdo": true, "quality": "Medium", - "textureMap": "Textures/ceiling_1k_height.png" + "textureMap": "Textures/ceiling_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/ceiling_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columna.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columna.material index 8f1cea8649..cc1f685c7c 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columna.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columna.material @@ -47,7 +47,8 @@ "factor": 0.017000000923871995, "pdo": true, "quality": "High", - "textureMap": "Textures/columnA_1k_height.png" + "textureMap": "Textures/columnA_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/columnA_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columnb.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columnb.material index ac474d7e76..a1e8747f65 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columnb.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columnb.material @@ -46,7 +46,8 @@ "factor": 0.020999999716877939, "pdo": true, "quality": "High", - "textureMap": "Textures/columnB_1k_height.png" + "textureMap": "Textures/columnB_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/columnB_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columnc.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columnc.material index 81fd03fc4a..6edbfde47c 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columnc.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_columnc.material @@ -47,7 +47,8 @@ "factor": 0.014000000432133675, "pdo": true, "quality": "High", - "textureMap": "Textures/columnC_1k_height.png" + "textureMap": "Textures/columnC_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/columnC_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_details.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_details.material index fde599fd4c..1b66a51ec0 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_details.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_details.material @@ -38,7 +38,8 @@ "algorithm": "POM", "factor": 0.02500000037252903, "pdo": true, - "textureMap": "Textures/details_1k_height.png" + "textureMap": "Textures/details_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/details_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_flagpole.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_flagpole.material index e50e8a0ed2..19010d66e5 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_flagpole.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_flagpole.material @@ -41,7 +41,8 @@ "factor": 0.014000000432133675, "pdo": true, "quality": "High", - "textureMap": "Textures/flagpole_1k_height.png" + "textureMap": "Textures/flagpole_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/flagpole_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_floor.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_floor.material index 064a2b24a6..bee92e0edb 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_floor.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_floor.material @@ -43,7 +43,8 @@ "algorithm": "POM", "factor": 0.012000000104308129, "pdo": true, - "textureMap": "Textures/floor_1k_height.png" + "textureMap": "Textures/floor_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/floor_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_leaf.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_leaf.material index 269e1e5684..ac326ae935 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_leaf.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_leaf.material @@ -42,7 +42,8 @@ "mode": "Cutout" }, "parallax": { - "textureMap": "Textures/thorn_height.png" + "textureMap": "Textures/thorn_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/thorn_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_lion.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_lion.material index 8dc4852b03..b1f78aa33f 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_lion.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_lion.material @@ -38,7 +38,6 @@ }, "parallax": { "algorithm": "ContactRefinement", - "enable": true, "factor": 0.009999999776482582, "pdo": true, "quality": "Ultra", diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_roof.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_roof.material index 0a7246703c..a3e066a438 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_roof.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_roof.material @@ -35,7 +35,8 @@ "algorithm": "ContactRefinement", "factor": 0.019999999552965165, "quality": "Medium", - "textureMap": "Textures/roof_1k_height.png" + "textureMap": "Textures/roof_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/roof_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vase.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vase.material index 77adc798a0..dea9aa2a8a 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vase.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vase.material @@ -41,7 +41,8 @@ "factor": 0.027000000700354577, "pdo": true, "quality": "High", - "textureMap": "Textures/vase_1k_height.png" + "textureMap": "Textures/vase_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/vase_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vasehanging.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vasehanging.material index 22e78f03ae..b2a342dd76 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vasehanging.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vasehanging.material @@ -41,7 +41,8 @@ "factor": 0.04600000008940697, "pdo": true, "quality": "High", - "textureMap": "Textures/vaseHanging_1k_height.png" + "textureMap": "Textures/vaseHanging_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/vaseHanging_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vaseround.material b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vaseround.material index c773146b51..fba07379c0 100644 --- a/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vaseround.material +++ b/Gems/AtomContent/Sponza/Assets/objects/sponza_mat_vaseround.material @@ -45,7 +45,8 @@ "factor": 0.019999999552965165, "pdo": true, "quality": "High", - "textureMap": "Textures/vaseRound_1k_height.png" + "textureMap": "Textures/vaseRound_1k_height.png", + "useTexture": false }, "roughness": { "textureMap": "Textures/vaseRound_1k_roughness.png" diff --git a/Gems/AtomContent/Sponza/Assets/stub b/Gems/AtomContent/Sponza/Assets/stub deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.cpp index dce83c3072..5fe8c50350 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -145,12 +146,24 @@ namespace AZ::Render } // Initialize our shader - auto viewportSize = viewportContext->GetViewportSize(); + AZ::Vector2 viewportSize; + { + AzFramework::WindowSize viewportWindowSize = viewportContext->GetViewportSize(); + viewportSize = AZ::Vector2{aznumeric_cast(viewportWindowSize.m_width), aznumeric_cast(viewportWindowSize.m_height)}; + } AZ::Data::Instance drawSrg = dynamicDraw->NewDrawSrg(); - drawSrg->SetConstant(m_viewportSizeIndex, AZ::Vector2(aznumeric_cast(viewportSize.m_width), aznumeric_cast(viewportSize.m_height))); + drawSrg->SetConstant(m_viewportSizeIndex,viewportSize); drawSrg->SetImageView(m_textureParameterIndex, image->GetImageView()); drawSrg->Compile(); + // Scale icons by screen DPI + float scalingFactor = 1.0f; + { + using ViewportRequestBus = AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus; + ViewportRequestBus::EventResult( + scalingFactor, drawParameters.m_viewport, &ViewportRequestBus::Events::DeviceScalingFactor); + } + AZ::Vector3 screenPosition; if (drawParameters.m_positionSpace == CoordinateSpace::ScreenSpace) { @@ -158,9 +171,11 @@ namespace AZ::Render } else if (drawParameters.m_positionSpace == CoordinateSpace::WorldSpace) { - using ViewportRequestBus = AzToolsFramework::ViewportInteraction::ViewportInteractionRequestBus; - AzFramework::ScreenPoint position; - ViewportRequestBus::EventResult(position, drawParameters.m_viewport, &ViewportRequestBus::Events::ViewportWorldToScreen, drawParameters.m_position); + // Calculate our screen space position using the viewport size + // We want this instead of RenderViewportWidget::WorldToScreen which works in QWidget virtual coordinate space + AzFramework::ScreenPoint position = AzFramework::WorldToScreen( + drawParameters.m_position, viewportContext->GetCameraViewMatrix(), viewportContext->GetCameraProjectionMatrix(), + viewportSize); screenPosition.SetX(aznumeric_cast(position.m_x)); screenPosition.SetY(aznumeric_cast(position.m_y)); } @@ -179,8 +194,8 @@ namespace AZ::Render { Vertex vertex; screenPosition.StoreToFloat3(vertex.m_position); - vertex.m_position[0] += offsetX * drawParameters.m_size.GetX(); - vertex.m_position[1] += offsetY * drawParameters.m_size.GetY(); + vertex.m_position[0] += offsetX * drawParameters.m_size.GetX() * scalingFactor; + vertex.m_position[1] += offsetY * drawParameters.m_size.GetY() * scalingFactor; vertex.m_color = drawParameters.m_color.ToU32(); vertex.m_uv[0] = u; vertex.m_uv[1] = v; @@ -197,8 +212,15 @@ namespace AZ::Render dynamicDraw->DrawIndexed(&vertices, vertices.size(), &indices, indices.size(), RHI::IndexFormat::Uint16, drawSrg); } - QString AtomViewportDisplayIconsSystemComponent::FindAssetPath(const QString& sourceRelativePath) const + QString AtomViewportDisplayIconsSystemComponent::FindAssetPath(const QString& path) const { + // If we get an absolute path, just use it. + QFileInfo pathInfo(path); + if (pathInfo.isAbsolute()) + { + return path; + } + bool found = false; AZStd::vector scanFolders; AzToolsFramework::AssetSystemRequestBus::BroadcastResult( @@ -212,9 +234,9 @@ namespace AZ::Render for (const auto& folder : scanFolders) { QDir dir(folder.data()); - if (dir.exists(sourceRelativePath)) + if (dir.exists(path)) { - return dir.absoluteFilePath(sourceRelativePath); + return dir.absoluteFilePath(path); } } @@ -256,10 +278,6 @@ namespace AZ::Render AzToolsFramework::EditorViewportIconDisplayInterface::IconId AtomViewportDisplayIconsSystemComponent::GetOrLoadIconForPath( AZStd::string_view path) { - AZ_Error( - "AtomViewportDisplayIconsSystemComponent", AzFramework::StringFunc::Path::IsRelative(path.data()), - "GetOrLoadIconForPath assumes that it will always be given a relative path, but got '%s'", path.data()); - // Check our cache to see if the image is already loaded auto existingEntryIt = AZStd::find_if(m_iconData.begin(), m_iconData.end(), [&path](const auto& iconData) { diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.h b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.h index 0c7366f23b..b44957b51d 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.h +++ b/Gems/AtomLyIntegration/AtomViewportDisplayIcons/Code/Source/AtomViewportDisplayIconsSystemComponent.h @@ -61,7 +61,7 @@ namespace AZ static constexpr QSize MinimumRenderedSvgSize = QSize(128, 128); static constexpr QImage::Format QtImageFormat = QImage::Format_RGBA8888; - QString FindAssetPath(const QString& sourceRelativePath) const; + QString FindAssetPath(const QString& path) const; QImage RenderSvgToImage(const QString& svgPath) const; AZ::Data::Instance ConvertToAtomImage(AZ::Uuid assetId, QImage image) const; diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt index de4ee9b4b5..0f134d4218 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/CMakeLists.txt @@ -10,7 +10,7 @@ # ly_add_target( - NAME AtomViewportDisplayInfo GEM_MODULE + NAME AtomViewportDisplayInfo ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE} NAMESPACE Gem FILES_CMAKE atomviewportdisplayinfo_files.cmake diff --git a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp index 672c26a9ab..7d830b4ca9 100644 --- a/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp +++ b/Gems/AtomLyIntegration/AtomViewportDisplayInfo/Code/Source/AtomViewportDisplayInfoSystemComponent.cpp @@ -18,10 +18,11 @@ #include #include +#include +#include #include #include #include -#include #include #include @@ -146,7 +147,7 @@ namespace AZ::Render if (m_updateRootPassQuery) { - if (auto rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass()) + if (auto rootPass = viewportContext->GetCurrentPipeline()->GetRootPass()) { rootPass->SetPipelineStatisticsQueryEnabled(displayLevel != AtomBridge::ViewportInfoDisplayState::CompactInfo); m_updateRootPassQuery = false; @@ -226,7 +227,8 @@ namespace AZ::Render void AtomViewportDisplayInfoSystemComponent::DrawPassInfo() { - auto rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass(); + AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext(); + auto rootPass = viewportContext->GetCurrentPipeline()->GetRootPass(); const RPI::PipelineStatisticsResult stats = rootPass->GetLatestPipelineStatisticsResult(); AZStd::function)> containingPassCount = [&containingPassCount](const AZ::RPI::Ptr pass) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.h index 1acaa6fdf8..41ea80f8d1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/EditorMeshComponent.h @@ -35,14 +35,13 @@ namespace AZ , private MeshComponentNotificationBus::Handler { public: - using BaseClass = EditorRenderComponentAdapter; AZ_EDITOR_COMPONENT(AZ::Render::EditorMeshComponent, EditorMeshComponentTypeId, BaseClass); static void Reflect(AZ::ReflectContext* context); EditorMeshComponent() = default; - EditorMeshComponent(const MeshComponentConfig& config); + explicit EditorMeshComponent(const MeshComponentConfig& config); // AZ::Component overrides ... void Activate() override; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponent.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponent.h index a57780c384..fe7f45d7d1 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponent.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponent.h @@ -25,12 +25,11 @@ namespace AZ : public AzFramework::Components::ComponentAdapter { public: - using BaseClass = AzFramework::Components::ComponentAdapter; AZ_COMPONENT(AZ::Render::MeshComponent, MeshComponentTypeId, BaseClass); MeshComponent() = default; - MeshComponent(const MeshComponentConfig& config); + explicit MeshComponent(const MeshComponentConfig& config); static void Reflect(AZ::ReflectContext* context); }; diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp index a4a91cf708..c089dd01f9 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.cpp @@ -177,28 +177,33 @@ namespace AZ FixUpModelAsset(m_configuration.m_modelAsset); } - void MeshComponentController::Activate(AZ::EntityId entityId) + void MeshComponentController::Activate(const AZ::EntityComponentIdPair& entityComponentIdPair) { FixUpModelAsset(m_configuration.m_modelAsset); - m_entityId = entityId; + const AZ::EntityId entityId = entityComponentIdPair.GetEntityId(); + m_entityComponentIdPair = entityComponentIdPair; - m_transformInterface = TransformBus::FindFirstHandler(m_entityId); + m_transformInterface = TransformBus::FindFirstHandler(entityId); AZ_Warning("MeshComponentController", m_transformInterface, "Unable to attach to a TransformBus handler. This mesh will always be rendered at the origin."); - m_meshFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity(m_entityId); + m_meshFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity(entityId); AZ_Error("MeshComponentController", m_meshFeatureProcessor, "Unable to find a MeshFeatureProcessorInterface on the entityId."); m_cachedNonUniformScale = AZ::Vector3::CreateOne(); - AZ::NonUniformScaleRequestBus::EventResult(m_cachedNonUniformScale, m_entityId, &AZ::NonUniformScaleRequests::GetScale); - AZ::NonUniformScaleRequestBus::Event(m_entityId, &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent, + AZ::NonUniformScaleRequestBus::EventResult(m_cachedNonUniformScale, entityId, &AZ::NonUniformScaleRequests::GetScale); + AZ::NonUniformScaleRequestBus::Event(entityId, &AZ::NonUniformScaleRequests::RegisterScaleChangedEvent, m_nonUniformScaleChangedHandler); - MeshComponentRequestBus::Handler::BusConnect(m_entityId); - TransformNotificationBus::Handler::BusConnect(m_entityId); - MaterialReceiverRequestBus::Handler::BusConnect(m_entityId); - MaterialComponentNotificationBus::Handler::BusConnect(m_entityId); - AzFramework::BoundsRequestBus::Handler::BusConnect(m_entityId); + MeshComponentRequestBus::Handler::BusConnect(entityId); + TransformNotificationBus::Handler::BusConnect(entityId); + MaterialReceiverRequestBus::Handler::BusConnect(entityId); + MaterialComponentNotificationBus::Handler::BusConnect(entityId); + AzFramework::BoundsRequestBus::Handler::BusConnect(entityId); + AzFramework::EntityContextId contextId; + AzFramework::EntityIdContextQueryBus::EventResult( + contextId, entityId, &AzFramework::EntityIdContextQueries::GetOwningContextId); + AzFramework::RenderGeometry::IntersectionRequestBus::Handler::BusConnect({entityId, contextId}); //Buses must be connected before RegisterModel in case requests are made as a result of HandleModelChange RegisterModel(); @@ -209,6 +214,7 @@ namespace AZ // Buses must be disconnected after unregistering the model, otherwise they can't deliver the events during the process. UnregisterModel(); + AzFramework::RenderGeometry::IntersectionRequestBus::Handler::BusDisconnect(); AzFramework::BoundsRequestBus::Handler::BusDisconnect(); MeshComponentRequestBus::Handler::BusDisconnect(); TransformNotificationBus::Handler::BusDisconnect(); @@ -219,7 +225,7 @@ namespace AZ m_meshFeatureProcessor = nullptr; m_transformInterface = nullptr; - m_entityId = AZ::EntityId(AZ::EntityId::InvalidEntityId); + m_entityComponentIdPair = AZ::EntityComponentIdPair(AZ::EntityId(), AZ::InvalidComponentId); m_configuration.m_modelAsset.Release(); } @@ -293,10 +299,11 @@ namespace AZ Data::Asset modelAsset = m_meshFeatureProcessor->GetModelAsset(m_meshHandle); if (model && modelAsset) { + const AZ::EntityId entityId = m_entityComponentIdPair.GetEntityId(); m_configuration.m_modelAsset = modelAsset; - MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelReady, m_configuration.m_modelAsset, model); - MaterialReceiverNotificationBus::Event(m_entityId, &MaterialReceiverNotificationBus::Events::OnMaterialAssignmentsChanged); - AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(m_entityId); + MeshComponentNotificationBus::Event(entityId, &MeshComponentNotificationBus::Events::OnModelReady, m_configuration.m_modelAsset, model); + MaterialReceiverNotificationBus::Event(entityId, &MaterialReceiverNotificationBus::Events::OnMaterialAssignmentsChanged); + AZ::Interface::Get()->RefreshEntityLocalBoundsUnion(entityId); } } @@ -304,8 +311,10 @@ namespace AZ { if (m_meshFeatureProcessor && m_configuration.m_modelAsset.GetId().IsValid()) { + const AZ::EntityId entityId = m_entityComponentIdPair.GetEntityId(); + MaterialAssignmentMap materials; - MaterialComponentRequestBus::EventResult(materials, m_entityId, &MaterialComponentRequests::GetMaterialOverrides); + MaterialComponentRequestBus::EventResult(materials, entityId, &MaterialComponentRequests::GetMaterialOverrides); m_meshFeatureProcessor->ReleaseMesh(m_meshHandle); m_meshHandle = m_meshFeatureProcessor->AcquireMesh(m_configuration.m_modelAsset, materials, @@ -330,7 +339,8 @@ namespace AZ { if (m_meshFeatureProcessor && m_meshHandle.IsValid()) { - MeshComponentNotificationBus::Event(m_entityId, &MeshComponentNotificationBus::Events::OnModelPreDestroy); + MeshComponentNotificationBus::Event( + m_entityComponentIdPair.GetEntityId(), &MeshComponentNotificationBus::Events::OnModelPreDestroy); m_meshFeatureProcessor->ReleaseMesh(m_meshHandle); } } @@ -462,5 +472,34 @@ namespace AZ return Aabb::CreateNull(); } } + + AzFramework::RenderGeometry::RayResult MeshComponentController::RenderGeometryIntersect( + const AzFramework::RenderGeometry::RayRequest& ray) + { + AzFramework::RenderGeometry::RayResult result; + if (const Data::Instance model = GetModel()) + { + float t; + AZ::Vector3 normal; + if (model->RayIntersection( + m_transformInterface->GetWorldTM(), m_cachedNonUniformScale, ray.m_startWorldPosition, + ray.m_endWorldPosition - ray.m_startWorldPosition, t, normal)) + { + // note: this is a temporary workaround to handle cases where model->RayIntersection + // returns negative distances, follow-up ATOM-15673 + const auto absT = AZStd::abs(t); + + // fill in ray result structure after successful intersection + const auto intersectionLine = (ray.m_endWorldPosition - ray.m_startWorldPosition); + result.m_uv = AZ::Vector2::CreateZero(); + result.m_worldPosition = ray.m_startWorldPosition + intersectionLine * absT; + result.m_worldNormal = normal; + result.m_distance = intersectionLine.GetLength() * absT; + result.m_entityAndComponent = m_entityComponentIdPair; + } + } + + return result; + } } // namespace Render } // namespace AZ diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h index 0cda34ea42..4d63e5e88d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Mesh/MeshComponentController.h @@ -13,11 +13,13 @@ #pragma once #include +#include #include #include #include +#include #include #include @@ -32,9 +34,7 @@ namespace AZ { namespace Render { - /** - * A configuration structure for the MeshComponentController - */ + //! A configuration structure for the MeshComponentController class MeshComponentConfig final : public AZ::ComponentConfig { @@ -57,6 +57,7 @@ namespace AZ class MeshComponentController final : private MeshComponentRequestBus::Handler , public AzFramework::BoundsRequestBus::Handler + , public AzFramework::RenderGeometry::IntersectionRequestBus::Handler , private TransformNotificationBus::Handler , private MaterialReceiverRequestBus::Handler , private MaterialComponentNotificationBus::Handler @@ -77,7 +78,7 @@ namespace AZ MeshComponentController() = default; MeshComponentController(const MeshComponentConfig& config); - void Activate(AZ::EntityId entityId); + void Activate(const AZ::EntityComponentIdPair& entityComponentIdPair); void Deactivate(); void SetConfiguration(const MeshComponentConfig& config); const MeshComponentConfig& GetConfiguration() const; @@ -103,10 +104,13 @@ namespace AZ void SetVisibility(bool visible) override; bool GetVisibility() const override; - // BoundsRequestBus and MeshComponentRequestBus ... + // BoundsRequestBus and MeshComponentRequestBus overrides ... AZ::Aabb GetWorldBounds() override; AZ::Aabb GetLocalBounds() override; + // IntersectionRequestBus overrides ... + AzFramework::RenderGeometry::RayResult RenderGeometryIntersect(const AzFramework::RenderGeometry::RayRequest& ray) override; + // TransformNotificationBus::Handler overrides ... void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override; @@ -134,7 +138,7 @@ namespace AZ Render::MeshFeatureProcessorInterface* m_meshFeatureProcessor = nullptr; Render::MeshFeatureProcessorInterface::MeshHandle m_meshHandle; TransformInterface* m_transformInterface = nullptr; - AZ::EntityId m_entityId; + AZ::EntityComponentIdPair m_entityComponentIdPair; bool m_isVisible = true; MeshComponentConfig m_configuration; AZ::Vector3 m_cachedNonUniformScale = AZ::Vector3::CreateOne(); diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h index 16cc4146dd..85c7e85c0a 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h +++ b/Gems/Multiplayer/Code/Include/Multiplayer/MultiplayerTypes.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,7 @@ namespace Multiplayer //! This is a strong typedef for representing the number of application frames since application start. AZ_TYPE_SAFE_INTEGRAL(HostFrameId, uint32_t); - static constexpr HostFrameId InvalidHostFrameId = HostFrameId{ 0xFFFFFFFF }; + static constexpr HostFrameId InvalidHostFrameId = HostFrameId{ AzPhysics::SimulatedBody::UndefinedFrameId }; using LongNetworkString = AZ::CVarFixedString; using ReliabilityType = AzNetworking::ReliabilityType; diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/Physics/PhysicsUtils.h b/Gems/Multiplayer/Code/Include/Multiplayer/Physics/PhysicsUtils.h new file mode 100644 index 0000000000..4013e20a1e --- /dev/null +++ b/Gems/Multiplayer/Code/Include/Multiplayer/Physics/PhysicsUtils.h @@ -0,0 +1,37 @@ +/* + * 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 + +namespace Multiplayer +{ + namespace Physics + { + //! Performs rewind-aware ray cast in the default physics world. + //! @param request The ray cast request to make. + //! @return Returns a structure that contains a list of Hits. + AzPhysics::SceneQueryHits RayCast(const AzPhysics::RayCastRequest& request); + + //! Performs rewind-aware shape cast in the default physics world. + //! @param request The shape cast request to make. + //! @return Returns a structure that contains a list of Hits. + AzPhysics::SceneQueryHits ShapeCast(const AzPhysics::ShapeCastRequest& request); + + //! Performs rewind-aware overlap in the default physics world. + //! @param request The overlap request to make. + //! @return Returns a structure that contains a list of Hits. + AzPhysics::SceneQueryHits Overlap(const AzPhysics::OverlapRequest& request); + + } // namespace Physics +} // namespace Multiplayer diff --git a/Gems/Multiplayer/Code/Source/Physics/PhysicsUtils.cpp b/Gems/Multiplayer/Code/Source/Physics/PhysicsUtils.cpp new file mode 100644 index 0000000000..6341f5b060 --- /dev/null +++ b/Gems/Multiplayer/Code/Source/Physics/PhysicsUtils.cpp @@ -0,0 +1,104 @@ +/* + * 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 + +namespace +{ + template + AzPhysics::SceneQueryHits SceneQueryInternal(const RequestT& request) + { + auto* sceneInterface = AZ::Interface::Get(); + if (!sceneInterface) + { + return {}; + } + + AzPhysics::SceneHandle sceneHandle = sceneInterface->GetSceneHandle(AzPhysics::DefaultPhysicsSceneName); + if (sceneHandle == AzPhysics::InvalidSceneHandle) + { + return {}; + } + + Multiplayer::INetworkTime* currentNetTime = Multiplayer::GetNetworkTime(); + + if(!currentNetTime->IsTimeRewound()) + { + // If the time is not rewound, we simply execute the scene query as is. + AzPhysics::SceneQueryHits result = sceneInterface->QueryScene(sceneHandle, &request); + return result; + } + + // If the time is rewound, we want to query against rigid bodies present at the same frame ID: the same as the current rewound time is. + RequestT netSceneQueryRequest = request; + netSceneQueryRequest.m_filterCallback = [&request, currentFrameId = (uint32_t)currentNetTime->GetHostFrameId()]( + const AzPhysics::SimulatedBody* body, const ::Physics::Shape* shape) + { + if (body->GetFrameId() == AzPhysics::SimulatedBody::UndefinedFrameId || body->GetFrameId() == currentFrameId) + { + if (request.m_filterCallback) + { + return request.m_filterCallback(body, shape); + } + + // Overlap filter callbacks return true/false rather than Touch/Block/None + if constexpr (AZStd::is_same_v) + { + return true; + } + else + { + return AzPhysics::SceneQuery::QueryHitType::Touch; + } + } + + if constexpr (AZStd::is_same_v) + { + return false; + } + else + { + return AzPhysics::SceneQuery::QueryHitType::None; + } + }; + + // Execute the scene query modified for the time rewind. + AzPhysics::SceneQueryHits result = sceneInterface->QueryScene(sceneHandle, &netSceneQueryRequest); + return result; + } +} + +namespace Multiplayer +{ + namespace Physics + { + AzPhysics::SceneQueryHits RayCast(const AzPhysics::RayCastRequest& request) + { + return SceneQueryInternal(request); + } + + AzPhysics::SceneQueryHits ShapeCast(const AzPhysics::ShapeCastRequest& request) + { + return SceneQueryInternal(request); + } + + AzPhysics::SceneQueryHits Overlap(const AzPhysics::OverlapRequest& request) + { + return SceneQueryInternal(request); + } + } // namespace Physics +} // namespace Multiplayer diff --git a/Gems/Multiplayer/Code/multiplayer_files.cmake b/Gems/Multiplayer/Code/multiplayer_files.cmake index 1cfef93240..73de45ba9d 100644 --- a/Gems/Multiplayer/Code/multiplayer_files.cmake +++ b/Gems/Multiplayer/Code/multiplayer_files.cmake @@ -39,6 +39,7 @@ set(FILES Include/Multiplayer/NetworkTime/RewindableFixedVector.inl Include/Multiplayer/NetworkTime/RewindableObject.h Include/Multiplayer/NetworkTime/RewindableObject.inl + Include/Multiplayer/Physics/PhysicsUtils.h Include/Multiplayer/ReplicationWindows/IReplicationWindow.h Source/Multiplayer_precompiled.cpp Source/Multiplayer_precompiled.h @@ -107,6 +108,7 @@ set(FILES Source/Pipeline/NetBindMarkerComponent.h Source/Pipeline/NetworkSpawnableHolderComponent.cpp Source/Pipeline/NetworkSpawnableHolderComponent.h + Source/Physics/PhysicsUtils.cpp Source/ReplicationWindows/NullReplicationWindow.cpp Source/ReplicationWindows/NullReplicationWindow.h Source/ReplicationWindows/ServerToClientReplicationWindow.cpp diff --git a/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp b/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp index 3aeb3ad797..56042fbc91 100644 --- a/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp +++ b/Gems/PhysX/Code/Source/Pipeline/MeshExporter.cpp @@ -794,6 +794,9 @@ namespace PhysX ); } + // Convex and primitive methods can only have 1 material + const bool limitToOneMaterial = pxMeshGroup.GetExportAsConvex() || pxMeshGroup.GetExportAsPrimitive(); + for (AZ::u32 faceIndex = 0; faceIndex < faceCount; ++faceIndex) { AZStd::string materialName = DefaultMaterialName; @@ -810,6 +813,14 @@ namespace PhysX } materialName = localFbxMaterialsList[materialId]; + + // Keep using the first material when it has to be limited to one. + if (limitToOneMaterial && + assetMaterialData.m_fbxMaterialNames.size() == 1 && + assetMaterialData.m_fbxMaterialNames[0] != materialName) + { + materialName = assetMaterialData.m_fbxMaterialNames[0]; + } } const AZ::SceneAPI::DataTypes::IMeshData::Face& face = nodeMesh->GetFaceInfo(faceIndex); diff --git a/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py b/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py index 5a14ef9419..ec4b43b023 100755 --- a/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py +++ b/Tools/LyTestTools/ly_test_tools/_internal/managers/abstract_resource_locator.py @@ -16,8 +16,10 @@ import pathlib import warnings from abc import ABCMeta, abstractmethod +import ly_test_tools._internal.pytest_plugin from ly_test_tools.environment.file_system import find_ancestor_file + def _find_engine_root(initial_path): # type: (str) -> str """ @@ -34,11 +36,9 @@ def _find_engine_root(initial_path): # Assumes folder structure similar to: engine_root/dev/Tools/.../ly_test_tools/builtin for _ in range(15): if os.path.exists(os.path.join(current_dir, root_file)): - # The parent of the directory containing the engineroot.txt is the root directory - engine_root = current_dir - return engine_root - # Using an explicit else to avoid aberrant behavior from following filesystem links - else: + # parent of the directory containing root_file + return current_dir + else: # explicit else avoids aberrant behavior from following filesystem links current_dir = os.path.abspath(os.path.join(current_dir, os.path.pardir)) raise OSError(f"Unable to find engine root directory. Verify root file '{root_file}' exists") @@ -50,8 +50,10 @@ def _find_project_json(engine_root, project): Find the project.json file for this project. :return: Full path to the project.json file """ - project_json = find_ancestor_file('project.json') - if not project_json: + # First check relative to defined build directory, for external projects which configure through SDK settings + project_json = find_ancestor_file(target_file_name='project.json', + start_path=ly_test_tools._internal.pytest_plugin.build_directory) + if not project_json: # check internally for a project bundled with the engine project_json = os.path.join(engine_root, project, 'project.json') return project_json diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index fbeffa94eb..84bad13687 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -17,6 +17,8 @@ endif() set(LY_INSTALLER_DOWNLOAD_URL "" CACHE STRING "URL embedded into the installer to download additional artifacts") set(LY_INSTALLER_LICENSE_URL "" CACHE STRING "Optionally embed a link to the license instead of raw text") +set(CPACK_DESIRED_CMAKE_VERSION 3.20.2) + # set all common cpack variable overrides first so they can be accessible via configure_file # when the platform specific settings are applied below. additionally, any variable with # the "CPACK_" prefix will automatically be cached for use in any phase of cpack namely @@ -38,6 +40,7 @@ set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_VENDOR}/${CPACK_PACKAGE_VER # neither of the SOURCE_DIR variables equate to anything during execution of pre/post build scripts set(CPACK_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +set(CPACK_BINARY_DIR ${CMAKE_BINARY_DIR}/_CPack) # to match other CPack out dirs # attempt to apply platform specific settings ly_get_absolute_pal_filename(pal_dir ${CPACK_SOURCE_DIR}/Platform/${PAL_HOST_PLATFORM_NAME}) @@ -48,6 +51,53 @@ if(NOT CPACK_GENERATOR) return() endif() +# pull down the desired copy of CMake so it can be included in the package +if(NOT (CPACK_CMAKE_PACKAGE_FILE AND CPACK_CMAKE_PACKAGE_HASH)) + message(FATAL_ERROR + "Packaging is missing one or more following properties required to include CMake: " + " CPACK_CMAKE_PACKAGE_FILE, CPACK_CMAKE_PACKAGE_HASH") +endif() + +set(_cmake_package_dest ${CPACK_BINARY_DIR}/${CPACK_CMAKE_PACKAGE_FILE}) + +string(REPLACE "." ";" _version_componets "${CPACK_DESIRED_CMAKE_VERSION}") +list(GET _version_componets 0 _major_version) +list(GET _version_componets 1 _minor_version) + +set(_url_version_tag "v${_major_version}.${_minor_version}") +set(_package_url "https://cmake.org/files/${_url_version_tag}/${CPACK_CMAKE_PACKAGE_FILE}") + +message(STATUS "Ensuring CMake ${CPACK_DESIRED_CMAKE_VERSION} is available for packaging...") +download_file( + URL ${_package_url} + TARGET_FILE ${_cmake_package_dest} + EXPECTED_HASH ${CPACK_CMAKE_PACKAGE_HASH} + RESULTS _results +) +list(GET _results 0 _status_code) + +if (${_status_code} EQUAL 0 AND EXISTS ${_cmake_package_dest}) + message(STATUS "-> Package found and verified!") +else() + file(REMOVE ${_cmake_package_dest}) + list(REMOVE_AT _results 0) + + set(_error_message "An error occurred, code ${_status_code}. URL ${_package_url} - ${_results}") + + if(${_status_code} EQUAL 1) + string(APPEND _error_message + " Please double check the CPACK_CMAKE_PACKAGE_FILE and " + "CPACK_CMAKE_PACKAGE_HASH properties before trying again.") + endif() + + message(FATAL_ERROR ${_error_message}) +endif() + +install(FILES ${_cmake_package_dest} + DESTINATION ./Tools/Redistributables/CMake + COMPONENT ${LY_DEFAULT_INSTALL_COMPONENT} +) + # IMPORTANT: required to be included AFTER setting all property overrides include(CPack REQUIRED) diff --git a/cmake/Platform/Windows/Packaging/PostInstallSetup.wxs b/cmake/Platform/Windows/Packaging/PostInstallSetup.wxs new file mode 100644 index 0000000000..d4f6c181dd --- /dev/null +++ b/cmake/Platform/Windows/Packaging/PostInstallSetup.wxs @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cmake/Platform/Windows/Packaging/Template.wxs.in b/cmake/Platform/Windows/Packaging/Template.wxs.in index 2900b96f41..e14e064fbc 100644 --- a/cmake/Platform/Windows/Packaging/Template.wxs.in +++ b/cmake/Platform/Windows/Packaging/Template.wxs.in @@ -17,8 +17,7 @@ - @@ -41,8 +40,24 @@ + + + + + + + NOT Installed Or REINSTALL + + + NOT Installed Or REINSTALL + + + NOT Installed Or REINSTALL + + + diff --git a/cmake/Platform/Windows/Packaging_windows.cmake b/cmake/Platform/Windows/Packaging_windows.cmake index ce73e9a07b..db9c7fc906 100644 --- a/cmake/Platform/Windows/Packaging_windows.cmake +++ b/cmake/Platform/Windows/Packaging_windows.cmake @@ -28,6 +28,10 @@ endif() set(CPACK_GENERATOR "WIX") +set(_cmake_package_name "cmake-${CPACK_DESIRED_CMAKE_VERSION}-windows-x86_64") +set(CPACK_CMAKE_PACKAGE_FILE "${_cmake_package_name}.zip") +set(CPACK_CMAKE_PACKAGE_HASH "15a49e2ab81c1822d75b1b1a92f7863f58e31f6d6aac1c4103eef2b071be3112") + # CPack will generate the WiX product/upgrade GUIDs further down the chain if they weren't supplied # however, they are unique for each run. instead, let's do the auto generation here and add it to # the cache for run persistence and have the ability to detect if they are still being used. @@ -83,9 +87,14 @@ set(CPACK_WIX_PRODUCT_ICON ${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/produc set(CPACK_WIX_TEMPLATE "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/Template.wxs.in") set(CPACK_WIX_EXTRA_SOURCES + "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/PostInstallSetup.wxs" "${CPACK_SOURCE_DIR}/Platform/Windows/Packaging/Shortcuts.wxs" ) +set(CPACK_WIX_EXTENSIONS + WixUtilExtension +) + set(_embed_artifacts "yes") if(LY_INSTALLER_DOWNLOAD_URL) @@ -101,4 +110,5 @@ endif() set(CPACK_WIX_CANDLE_EXTRA_FLAGS -dCPACK_EMBED_ARTIFACTS=${_embed_artifacts} + -dCPACK_CMAKE_PACKAGE_NAME=${_cmake_package_name} ) diff --git a/cmake/Tools/common.py b/cmake/Tools/common.py index 8189bb3ca3..c6a3e89e67 100755 --- a/cmake/Tools/common.py +++ b/cmake/Tools/common.py @@ -149,7 +149,7 @@ def get_bootstrap_values(bootstrap_dir, keys_to_extract): raise logging.error(f'Bootstrap.setreg file {bootstrap_file} does not exist.') result_map = {} - with bootstrap_file.open('r') as f: + with open(bootstrap_file, 'r') as f: try: json_data = json.load(f) except Exception as e: @@ -157,9 +157,9 @@ def get_bootstrap_values(bootstrap_dir, keys_to_extract): else: for search_key in keys_to_extract: try: - search_result = json_data["Amazon"]["AzCore"]["Bootstrap"][f'"{search_key}"'] + search_result = json_data["Amazon"]["AzCore"]["Bootstrap"][search_key] except KeyError as e: - logging.error(f'Bootstrap.setreg cannot find Amazon:AzCore:Bootstrap:{search_result}: {str(e)}') + logging.warning(f'Bootstrap.setreg cannot find /Amazon/AzCore/Bootstrap/{search_key}: {str(e)}') else: result_map[search_key] = search_result diff --git a/cmake/Tools/layout_tool.py b/cmake/Tools/layout_tool.py index 69f5b34ae7..3fcab241d7 100755 --- a/cmake/Tools/layout_tool.py +++ b/cmake/Tools/layout_tool.py @@ -107,7 +107,7 @@ def verify_layout(layout_dir, platform_name, project_path, asset_mode, asset_typ project_name_lower = project_path.lower() layout_path = pathlib.Path(layout_dir) - bootstrap_path = layout_path / 'Registry' + bootstrap_path = pathlib.Path(ROOT_ENGINE_PATH) / 'Registry' bootstrap_values = common.get_bootstrap_values(str(bootstrap_path), [f'{platform_name_lower}_remote_filesystem', f'{platform_name_lower}_connect_to_remote', f'{platform_name_lower}_wait_for_connect',