diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py index 34b2217916..6f3113d771 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/aws_metrics/aws_metrics_automation_test.py @@ -14,6 +14,7 @@ from datetime import datetime import ly_test_tools.log.log_monitor from AWS.common import constants +from AWS.common.resource_mappings import AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY from .aws_metrics_custom_thread import AWSMetricsThread # fixture imports @@ -200,6 +201,59 @@ class TestAWSMetricsWindows(object): for thread in operational_threads: thread.join() + @pytest.mark.parametrize('level', ['AWS/Metrics']) + def test_realtime_and_batch_analytics_no_global_accountid(self, + level: str, + launcher: pytest.fixture, + asset_processor: pytest.fixture, + workspace: pytest.fixture, + aws_utils: pytest.fixture, + resource_mappings: pytest.fixture, + aws_metrics_utils: pytest.fixture): + """ + Verify that the metrics events are sent to CloudWatch and S3 for analytics. + """ + # Remove top-level account ID from resource mappings + resource_mappings.clear_select_keys([AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY]) + # Start Kinesis analytics application on a separate thread to avoid blocking the test. + kinesis_analytics_application_thread = AWSMetricsThread(target=update_kinesis_analytics_application_status, + args=(aws_metrics_utils, resource_mappings, True)) + kinesis_analytics_application_thread.start() + + log_monitor = setup(launcher, asset_processor) + + # Kinesis analytics application needs to be in the running state before we start the game launcher. + kinesis_analytics_application_thread.join() + launcher.args = ['+LoadLevel', level] + launcher.args.extend(['-rhi=null']) + start_time = datetime.utcnow() + with launcher.start(launch_ap=False): + monitor_metrics_submission(log_monitor) + + # Verify that real-time analytics metrics are delivered to CloudWatch. + aws_metrics_utils.verify_cloud_watch_delivery( + AWS_METRICS_FEATURE_NAME, + 'TotalLogins', + [], + start_time) + logger.info('Real-time metrics are sent to CloudWatch.') + + # Run time-consuming operations on separate threads to avoid blocking the test. + operational_threads = list() + operational_threads.append( + AWSMetricsThread(target=query_metrics_from_s3, + args=(aws_metrics_utils, resource_mappings))) + operational_threads.append( + AWSMetricsThread(target=verify_operational_metrics, + args=(aws_metrics_utils, resource_mappings, start_time))) + operational_threads.append( + AWSMetricsThread(target=update_kinesis_analytics_application_status, + args=(aws_metrics_utils, resource_mappings, False))) + for thread in operational_threads: + thread.start() + for thread in operational_threads: + thread.join() + @pytest.mark.parametrize('level', ['AWS/Metrics']) def test_unauthorized_user_request_rejected(self, level: str, diff --git a/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py b/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py index 949186ad50..59c517fd1c 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/Windows/core/test_aws_resource_interaction.py @@ -18,6 +18,7 @@ import ly_test_tools.environment.process_utils as process_utils import ly_test_tools.o3de.asset_processor_utils as asset_processor_utils from AWS.common import constants +from AWS.common.resource_mappings import AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY # fixture imports from assetpipeline.ap_fixtures.asset_processor_fixture import asset_processor @@ -141,3 +142,51 @@ class TestAWSCoreAWSResourceInteraction(object): 'The expected file wasn\'t successfully downloaded.' # clean up the file directories. shutil.rmtree(s3_download_dir) + + @pytest.mark.parametrize('expected_lines', [ + ['(Script) - [S3] Head object request is done', + '(Script) - [S3] Head object success: Object example.txt is found.', + '(Script) - [S3] Get object success: Object example.txt is downloaded.', + '(Script) - [Lambda] Completed Invoke', + '(Script) - [Lambda] Invoke success: {"statusCode": 200, "body": {}}', + '(Script) - [DynamoDB] Results finished']]) + @pytest.mark.parametrize('unexpected_lines', [ + ['(Script) - [S3] Head object error: No response body.', + '(Script) - [S3] Get object error: Request validation failed, output file directory doesn\'t exist.', + '(Script) - Request validation failed, output file miss full path.', + '(Script) - ']]) + def test_scripting_behavior_no_global_accountid(self, + level: str, + launcher: pytest.fixture, + workspace: pytest.fixture, + asset_processor: pytest.fixture, + resource_mappings: pytest.fixture, + aws_utils: pytest.fixture, + expected_lines: typing.List[str], + unexpected_lines: typing.List[str]): + """ + Setup: Updates resource mapping file using existing CloudFormation stacks. + Tests: Interact with AWS S3, DynamoDB and Lambda services. + Verification: Script canvas nodes can communicate with AWS services successfully. + """ + + resource_mappings.clear_select_keys([AWS_RESOURCE_MAPPINGS_ACCOUNT_ID_KEY]) + log_monitor, s3_download_dir = setup(launcher, asset_processor) + write_test_data_to_dynamodb_table(resource_mappings, aws_utils) + + launcher.args = ['+LoadLevel', level] + launcher.args.extend(['-rhi=null']) + + with launcher.start(launch_ap=False): + result = log_monitor.monitor_log_for_lines( + expected_lines=expected_lines, + unexpected_lines=unexpected_lines, + halt_on_unexpected=True + ) + + assert result, "Expected lines weren't found." + + assert os.path.exists(os.path.join(s3_download_dir, 'output.txt')), \ + 'The expected file wasn\'t successfully downloaded.' + # clean up the file directories. + shutil.rmtree(s3_download_dir) diff --git a/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py b/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py index 5f01ecdbf8..988d5bf1fc 100644 --- a/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py +++ b/AutomatedTesting/Gem/PythonTests/AWS/common/resource_mappings.py @@ -102,3 +102,17 @@ class ResourceMappings: def get_resource_name_id(self, resource_key: str): return self._resource_mappings[AWS_RESOURCE_MAPPINGS_KEY][resource_key]['Name/ID'] + + def clear_select_keys(self, resource_keys=None) -> None: + """ + Clears values from select resource mapping keys. + :param resource_keys: list of keys to clear out + """ + with open(self._resource_mapping_file_path) as file_content: + resource_mappings = json.load(file_content) + + for key in resource_keys: + resource_mappings[key] = '' + + with open(self._resource_mapping_file_path, 'w') as file_content: + json.dump(resource_mappings, file_content, indent=4) \ No newline at end of file diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py index ff362c732c..9281d5947e 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/ap_fixtures/bundler_batch_setup_fixture.py @@ -158,7 +158,7 @@ def bundler_batch_setup_fixture(request, workspace, asset_processor, timeout) -> else: cmd.append(f"--{key}") if append_defaults: - cmd.append(f"--project-path={workspace.project}") + cmd.append(f"--project-path={workspace.paths.project()}") return cmd # ****** diff --git a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py index 7f85e5e317..f5e5642573 100755 --- a/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py +++ b/AutomatedTesting/Gem/PythonTests/assetpipeline/asset_processor_tests/asset_bundler_batch_tests.py @@ -88,214 +88,6 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): bundler_batch_helper.call_bundles(help="") bundler_batch_helper.call_bundleSeed(help="") - @pytest.mark.BAT - @pytest.mark.assetpipeline - @pytest.mark.test_case_id("C16877175") - @pytest.mark.skip("'animations/animationeditorfiles/sample1.animgraph' missing, needs investigation") - def test_WindowsAndMac_CreateAssetList_DependenciesCorrect(self, workspace, bundler_batch_helper): - r""" - Tests that an asset list created maps dependencies correctly. - testdependencieslevel\level.pak and lists of known dependencies are used for validation - - Test Steps: - 1. Create an asset list from the level.pak - 2. Create Lists of expected assets in the level.pak - 3. Add lists of expected assets to a single list - 4. Compare list of expected assets to actual assets - """ - helper = bundler_batch_helper - - # Create the asset list file - helper.call_assetLists( - addSeed=r"levels\testdependencieslevel\level.pak", - assetListFile=helper['asset_info_file_request'] - ) - - assert os.path.isfile(helper["asset_info_file_result"]) - - # Lists of known relative locations of assets - default_level_assets = [ - "engineassets/texturemsg/defaultnouvs.dds", - "engineassets/texturemsg/defaultnouvs.dds.1", - "engineassets/texturemsg/defaultnouvs.dds.2", - "engineassets/texturemsg/defaultnouvs.dds.3", - "engineassets/texturemsg/defaultnouvs.dds.4", - "engineassets/texturemsg/defaultnouvs.dds.5", - "engineassets/texturemsg/defaultnouvs.dds.6", - "engineassets/texturemsg/defaultnouvs.dds.7", - "engineassets/texturemsg/defaultnouvs_ddn.dds", - "engineassets/texturemsg/defaultnouvs_ddn.dds.1", - "engineassets/texturemsg/defaultnouvs_ddn.dds.2", - "engineassets/texturemsg/defaultnouvs_ddn.dds.3", - "engineassets/texturemsg/defaultnouvs_ddn.dds.4", - "engineassets/texturemsg/defaultnouvs_ddn.dds.5", - "engineassets/texturemsg/defaultnouvs_spec.dds", - "engineassets/texturemsg/defaultnouvs_spec.dds.1", - "engineassets/texturemsg/defaultnouvs_spec.dds.2", - "engineassets/texturemsg/defaultnouvs_spec.dds.3", - "engineassets/texturemsg/defaultnouvs_spec.dds.4", - "engineassets/texturemsg/defaultnouvs_spec.dds.5", - "engineassets/textures/defaults/16_grey.dds", - "engineassets/textures/cubemap/default_level_cubemap.dds", - "engineassets/textures/cubemap/default_level_cubemap.dds.1", - "engineassets/textures/cubemap/default_level_cubemap.dds.2", - "engineassets/textures/cubemap/default_level_cubemap.dds.3", - "engineassets/textures/cubemap/default_level_cubemap.dds.4", - "engineassets/textures/cubemap/default_level_cubemap_diff.dds", - "engineassets/materials/water/ocean_default.mtl", - "engineassets/textures/defaults/spot_default.dds", - "engineassets/textures/defaults/spot_default.dds.1", - "engineassets/textures/defaults/spot_default.dds.2", - "engineassets/textures/defaults/spot_default.dds.3", - "engineassets/textures/defaults/spot_default.dds.4", - "engineassets/textures/defaults/spot_default.dds.5", - "materials/material_terrain_default.mtl", - "textures/skys/night/half_moon.dds", - "textures/skys/night/half_moon.dds.1", - "textures/skys/night/half_moon.dds.2", - "textures/skys/night/half_moon.dds.3", - "textures/skys/night/half_moon.dds.4", - "textures/skys/night/half_moon.dds.5", - "textures/skys/night/half_moon.dds.6", - "engineassets/materials/sky/sky.mtl", - "levels/testdependencieslevel/level.pak", - "levels/testdependencieslevel/terrain/cover.ctc", - "levels/testdependencieslevel/terraintexture.pak", - ] - - sequence_material_cube_assets = [ - "textures/test_texture_sequence/test_texture_sequence000.dds", - "textures/test_texture_sequence/test_texture_sequence001.dds", - "textures/test_texture_sequence/test_texture_sequence002.dds", - "textures/test_texture_sequence/test_texture_sequence003.dds", - "textures/test_texture_sequence/test_texture_sequence004.dds", - "textures/test_texture_sequence/test_texture_sequence005.dds", - "objects/_primitives/_box_1x1.cgf", - "materials/test_texture_sequence.mtl", - "objects/_primitives/_box_1x1.mtl", - "textures/_primitives/middle_gray_checker.dds", - "textures/_primitives/middle_gray_checker.dds.1", - "textures/_primitives/middle_gray_checker.dds.2", - "textures/_primitives/middle_gray_checker.dds.3", - "textures/_primitives/middle_gray_checker.dds.4", - "textures/_primitives/middle_gray_checker.dds.5", - "textures/_primitives/middle_gray_checker_ddn.dds", - "textures/_primitives/middle_gray_checker_ddn.dds.1", - "textures/_primitives/middle_gray_checker_ddn.dds.2", - "textures/_primitives/middle_gray_checker_ddn.dds.3", - "textures/_primitives/middle_gray_checker_ddn.dds.4", - "textures/_primitives/middle_gray_checker_ddn.dds.5", - "textures/_primitives/middle_gray_checker_spec.dds", - "textures/_primitives/middle_gray_checker_spec.dds.1", - "textures/_primitives/middle_gray_checker_spec.dds.2", - "textures/_primitives/middle_gray_checker_spec.dds.3", - "textures/_primitives/middle_gray_checker_spec.dds.4", - "textures/_primitives/middle_gray_checker_spec.dds.5", - ] - - character_with_simplified_material_assets = [ - "objects/characters/jack/jack.actor", - "objects/characters/jack/jack.mtl", - "objects/characters/jack/textures/jack_diff.dds", - "objects/characters/jack/textures/jack_diff.dds.1", - "objects/characters/jack/textures/jack_diff.dds.2", - "objects/characters/jack/textures/jack_diff.dds.3", - "objects/characters/jack/textures/jack_diff.dds.4", - "objects/characters/jack/textures/jack_diff.dds.5", - "objects/characters/jack/textures/jack_diff.dds.6", - "objects/characters/jack/textures/jack_diff.dds.7", - "objects/characters/jack/textures/jack_spec.dds", - "objects/characters/jack/textures/jack_spec.dds.1", - "objects/characters/jack/textures/jack_spec.dds.2", - "objects/characters/jack/textures/jack_spec.dds.3", - "objects/characters/jack/textures/jack_spec.dds.4", - "objects/characters/jack/textures/jack_spec.dds.5", - "objects/characters/jack/textures/jack_spec.dds.6", - "objects/characters/jack/textures/jack_spec.dds.7", - "objects/default/editorprimitive.mtl", - "engineassets/textures/grey.dds", - "animations/animationeditorfiles/sample0.animgraph", - "animations/motions/jack_death_fall_back_zup.motion", - "animations/animationeditorfiles/sample1.animgraph", - "animations/animationeditorfiles/sample0.motionset", - "animations/motions/rin_jump.motion", - "animations/animationeditorfiles/sample1.motionset", - "animations/motions/rin_idle.motion", - "animations/motions/jack_idle_aim_zup.motion", - ] - - spawner_assets = [ - "slices/sphere.dynamicslice", - "objects/default/primitive_sphere.cgf", - "test1.luac", - "test2.luac", - ] - - ui_canvas_assets = [ - "fonts/vera.ttf", - "fonts/vera.font", - "scriptcanvas/mainmenu.scriptcanvas_compiled", - "fonts/vera.fontfamily", - "ui/canvas/start.uicanvas", - "fonts/vera-italic.font", - "ui/textureatlas/sample.texatlasidx", - "fonts/vera-bold-italic.ttf", - "fonts/vera-bold.font", - "ui/textures/prefab/button_normal.dds", - "ui/textures/prefab/button_normal.sprite", - "fonts/vera-italic.ttf", - "ui/textureatlas/sample.dds", - "fonts/vera-bold-italic.font", - "fonts/vera-bold.ttf", - "ui/textures/prefab/button_disabled.dds", - "ui/textures/prefab/button_disabled.sprite", - ] - - wwise_and_atl_assets = [ - "libs/gameaudio/wwise/levels/testdependencieslevel/test_dependencies_level.xml", - "sounds/wwise/test_bank3.bnk", - "sounds/wwise/test_bank4.bnk", - "sounds/wwise/test_bank5.bnk", - "sounds/wwise/test_bank1.bnk", - "sounds/wwise/init.bnk", - "sounds/wwise/499820003.wem", - "sounds/wwise/196049145.wem", - ] - - particle_library_assets = [ - "libs/particles/milestone2particles.xml", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds.1", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds.2", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds.3", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds.4", - "textures/milestone2/particles/fx_launchermuzzlering_01.dds.5", - "textures/milestone2/particles/fx_sparkstreak_01.dds", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.1", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.2", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.3", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.4", - "textures/milestone2/particles/fx_launchermuzzlefront_01.dds.5", - ] - - lens_flares_library_assets = ["libs/flares/flares.xml", "textures/lights/flare01.dds"] - - expected_assets_list = default_level_assets - expected_assets_list.extend(sequence_material_cube_assets) - expected_assets_list.extend(character_with_simplified_material_assets) - expected_assets_list.extend(spawner_assets) - expected_assets_list.extend(ui_canvas_assets) - expected_assets_list.extend(wwise_and_atl_assets) - expected_assets_list.extend(particle_library_assets) - expected_assets_list.extend(lens_flares_library_assets) # All expected assets - - # Get actual calculated dependencies from the asset list created - actual_assets_list = [] - for rel_path in helper.get_asset_relative_paths(helper["asset_info_file_result"]): - actual_assets_list.append(rel_path) - - assert sorted(actual_assets_list) == sorted(expected_assets_list) @pytest.mark.BAT @pytest.mark.assetpipeline @@ -310,9 +102,9 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): 3. Read and store contents of asset list into memory 4. Attempt to create a new asset list in without using --allowOverwrites 5. Verify that Asset Bundler returns false - 6. Verify that file contents of the orignally created asset list did not change from what was stored in memory + 6. Verify that file contents of the originally created asset list did not change from what was stored in memory 7. Attempt to create a new asset list without debug while allowing overwrites - 8. Verify that file contents of the orignally created asset list changed from what was stored in memory + 8. Verify that file contents of the originally created asset list changed from what was stored in memory """ helper = bundler_batch_helper seed_list = os.path.join(workspace.paths.engine_root(), "Assets", "Engine", "SeedAssetList.seed") # Engine seed list @@ -919,7 +711,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): # Extra arguments for pattern comparison cmd.extend([f"--filePatternType={pattern_type}", f"--filePattern={pattern}"]) if workspace.project: - cmd.append(f'--project-path={project_name}') + cmd.append(f'--project-path={workspace.paths.project()}') return cmd # End generate_compare_command() @@ -960,7 +752,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): output_mac_asset_list = helper.platform_file_name(last_output_arg, platform) # Build execution command - cmd = generate_compare_command(platform_arg, workspace.project) + cmd = generate_compare_command(platform_arg, workspace.paths.project()) # Execute command subprocess.check_call(cmd) @@ -995,7 +787,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): f"--comparisonRulesFile={rule_file}", f"--comparisonType={args[1]}", r"--addComparison", - f"--project-path={workspace.project}", + f"--project-path={workspace.paths.project()}", ] if args[1] == "4": # If pattern comparison, append a few extra arguments @@ -1117,7 +909,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): "--addDefaultSeedListFiles", "--platform=pc", "--print", - f"--project-path={workspace.project}" + f"--project-path={workspace.paths.project()}" ], universal_newlines=True, ) @@ -1189,7 +981,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): # Make sure file gets deleted on teardown request.addfinalizer(lambda: fs.delete([bundle_result_path], True, False)) - bundles_folder = os.path.join(workspace.paths.engine_root(), workspace.project, "Bundles") + bundles_folder = os.path.join(workspace.paths.project(), "Bundles") level_pak = r"levels\testdependencieslevel\level.pak" bundle_request_path = os.path.join(bundles_folder, "bundle.pak") bundle_result_path = os.path.join(bundles_folder, @@ -1243,23 +1035,64 @@ class TestsAssetBundlerBatch_WindowsAndMac(object): 2. Verify file was created 3. Verify that only the expected assets are present in the created asset list """ - expected_assets = [ + expected_assets = sorted([ "ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas", - "ui/textures/prefab/button_normal.sprite" - ] + "ui/textures/prefab/button_disabled.tif.streamingimage", + "ui/textures/prefab/tooltip_sliced.tif.streamingimage", + "ui/textures/prefab/button_normal.tif.streamingimage" + ]) + # Printing these lists out can save a step in debugging if this test fails on Jenkins. + logger.info(f"expected_assets: {expected_assets}") + + skip_assets = sorted([ + "ui/scripts/lyshineexamples/animation/multiplesequences.luac", + "ui/scripts/lyshineexamples/unloadthiscanvasbutton.luac", + "fonts/vera.fontfamily", + "fonts/vera-italic.font", + "fonts/vera.font", + "fonts/vera-bold.font", + "fonts/vera-bold-italic.font", + "fonts/vera-italic.ttf", + "fonts/vera.ttf", + "fonts/vera-bold.ttf", + "fonts/vera-bold-italic.ttf" + ]) + logger.info(f"skip_assets: {skip_assets}") + + expected_and_skip_assets = sorted(expected_assets + skip_assets) + # Printing both together to make it quick to compare the results in the logs for a test failure on Jenkins + logger.info(f"expected_and_skip_assets: {expected_and_skip_assets}") + + # First, generate an asset info file without skipping, to get a list that can be used as a baseline to verify + # the files were actually skipped, and not just missing. + bundler_batch_helper.call_assetLists( + assetListFile=bundler_batch_helper['asset_info_file_request'], + addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas" + ) + assert os.path.isfile(bundler_batch_helper["asset_info_file_result"]) + assets_in_no_skip_list = [] + for rel_path in bundler_batch_helper.get_asset_relative_paths(bundler_batch_helper["asset_info_file_result"]): + assets_in_no_skip_list.append(rel_path) + assets_in_no_skip_list = sorted(assets_in_no_skip_list) + logger.info(f"assets_in_no_skip_list: {assets_in_no_skip_list}") + assert assets_in_no_skip_list == expected_and_skip_assets + + # Now generate an asset info file using the skip command, and verify the skip files are not in the list. bundler_batch_helper.call_assetLists( assetListFile=bundler_batch_helper['asset_info_file_request'], addSeed="ui/canvases/lyshineexamples/animation/multiplesequences.uicanvas", - skip="ui/textures/prefab/button_disabled.sprite,ui/scripts/lyshineexamples/animation/multiplesequences.luac," - "ui/textures/prefab/tooltip_sliced.sprite,ui/scripts/lyshineexamples/unloadthiscanvasbutton.luac,fonts/vera.fontfamily,fonts/vera-italic.font," - "fonts/vera.font,fonts/vera-bold.font,fonts/vera-bold-italic.font,fonts/vera-italic.ttf,fonts/vera.ttf,fonts/vera-bold.ttf,fonts/vera-bold-italic.ttf" + allowOverwrites="", + skip=','.join(skip_assets) ) + assert os.path.isfile(bundler_batch_helper["asset_info_file_result"]) assets_in_list = [] for rel_path in bundler_batch_helper.get_asset_relative_paths(bundler_batch_helper["asset_info_file_result"]): assets_in_list.append(rel_path) + assets_in_list = sorted(assets_in_list) + logger.info(f"assets_in_list: {assets_in_list}") + assert assets_in_list == expected_assets - assert sorted(assets_in_list) == sorted(expected_assets) @pytest.mark.BAT @pytest.mark.assetpipeline diff --git a/Code/Editor/AboutDialog.ui b/Code/Editor/AboutDialog.ui index a6c5bb5d52..a36d65e35b 100644 --- a/Code/Editor/AboutDialog.ui +++ b/Code/Editor/AboutDialog.ui @@ -125,7 +125,7 @@ - General Availability + Stable 21.11 Qt::AutoText diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp index 1c2be16a3d..6fc10e379a 100644 --- a/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp +++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserRequestHandler.cpp @@ -199,41 +199,6 @@ namespace AzAssetBrowserRequestHandlerPrivate } } } - - // Helper utility - determines if the thing being dragged is a FBX from the scene import pipeline - // This is important to differentiate. - // when someone drags a MTL file directly into the viewport, even from a FBX, we want to spawn it as a decal - // but when someone drags a FBX that contains MTL files, we want only to spawn the meshes. - // so we have to specifically differentiate here between the mimeData type that contains the source as the root - // (dragging the fbx file itself) - // and one which contains the actual product at its root. - - bool IsDragOfFBX(const QMimeData* mimeData) - { - AZStd::vector entries; - if (!AssetBrowserEntry::FromMimeData(mimeData, entries)) - { - // if mimedata does not even contain entries, no point in proceeding. - return false; - } - - for (auto entry : entries) - { - if (entry->GetEntryType() != AssetBrowserEntry::AssetEntryType::Source) - { - continue; - } - // this is a source file. Is it the filetype we're looking for? - if (SourceAssetBrowserEntry* source = azrtti_cast(entry)) - { - if (AzFramework::StringFunc::Equal(source->GetExtension().c_str(), ".fbx", false)) - { - return true; - } - } - } - return false; - } } AzAssetBrowserRequestHandler::AzAssetBrowserRequestHandler() diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 4008710786..b77c6c4b3a 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -4181,6 +4181,8 @@ extern "C" int AZ_DLL_EXPORT CryEditMain(int argc, char* argv[]) "\nThis could be because of incorrectly configured components, or missing required gems." "\nSee other errors for more details."); + AzToolsFramework::EditorEventsBus::Broadcast(&AzToolsFramework::EditorEvents::NotifyEditorInitialized); + if (didCryEditStart) { app->EnableOnIdle(); diff --git a/Code/Editor/Include/IEditorMaterialManager.h b/Code/Editor/Include/IEditorMaterialManager.h index d76ec32829..6f71c5ddd1 100644 --- a/Code/Editor/Include/IEditorMaterialManager.h +++ b/Code/Editor/Include/IEditorMaterialManager.h @@ -9,10 +9,6 @@ #define CRYINCLUDE_EDITOR_MATERIAL_IEDITORMATERIALMANAGER_H #pragma once -#define MATERIAL_FILE_EXT ".mtl" -#define DCC_MATERIAL_FILE_EXT ".dccmtl" -#define MATERIALS_PATH "materials/" - #include #include diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp index d0091f968e..2073d0dd5a 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/AssetCatalogModel.cpp @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -136,14 +135,6 @@ AssetCatalogModel::AssetCatalogModel(QObject* parent) } } - // Special cases for SimpleAssets. If these get full-fledged AssetData types, these cases can be removed. - QString textureExtensions = LmbrCentral::TextureAsset::GetFileFilter(); - m_extensionToAssetType.insert(AZStd::make_pair(textureExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector { AZ::AzTypeInfo::Uuid() })); - QString materialExtensions = LmbrCentral::MaterialAsset::GetFileFilter(); - m_extensionToAssetType.insert(AZStd::make_pair(materialExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector { AZ::AzTypeInfo::Uuid() })); - QString dccMaterialExtensions = LmbrCentral::DccMaterialAsset::GetFileFilter(); - m_extensionToAssetType.insert(AZStd::make_pair(dccMaterialExtensions.replace("*", "").replace(" ", "").toStdString().c_str(), AZStd::vector { AZ::AzTypeInfo::Uuid() })); - AZ::SerializeContext* serializeContext = nullptr; EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext); AZ_Assert(serializeContext, "Failed to acquire application serialize context."); diff --git a/Code/Editor/StartupLogoDialog.ui b/Code/Editor/StartupLogoDialog.ui index c0b8115cb0..c2cbfcfd69 100644 --- a/Code/Editor/StartupLogoDialog.ui +++ b/Code/Editor/StartupLogoDialog.ui @@ -103,7 +103,7 @@ - General Availability + Stable 21.11 diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp index 06bb0b0cac..b03e1affdc 100644 --- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp +++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp @@ -1677,9 +1677,13 @@ namespace AZ // they will trigger a ReleaseAsset call sometime after the AssetManager has begun to shut down, which can lead to // race conditions. + // Make sure the streamer request is removed first before the asset is released + // If the asset is released first it could lead to a race condition where another thread starts loading the asset + // again and attempts to add a new streamer request with the same ID before the old one has been removed, causing + // that load request to fail + RemoveActiveStreamerRequest(assetId); weakAsset = {}; loadingAsset.Reset(); - RemoveActiveStreamerRequest(assetId); }; auto&& [deadline, priority] = GetEffectiveDeadlineAndPriority(*handler, asset.GetType(), loadParams); diff --git a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp index 6f5ccc93e4..2307a9372c 100644 --- a/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Jobs/JobManagerComponent.cpp @@ -56,11 +56,12 @@ namespace AZ int numberOfWorkerThreads = m_numberOfWorkerThreads; if (numberOfWorkerThreads <= 0) // spawn default number of threads { + #if (AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS) + numberOfWorkerThreads = AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS; + #else uint32_t scaledHardwareThreads = Threading::CalcNumWorkerThreads(cl_jobThreadsConcurrencyRatio, cl_jobThreadsMinNumber, cl_jobThreadsNumReserved); numberOfWorkerThreads = AZ::GetMin(static_cast(desc.m_workerThreads.capacity()), scaledHardwareThreads); - #if (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS) - numberOfWorkerThreads = AZ::GetMin(numberOfWorkerThreads, AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS); - #endif // (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS) + #endif // (AZ_TRAIT_THREAD_NUM_JOB_MANAGER_WORKER_THREADS) } threadDesc.m_cpuId = AFFINITY_MASK_USERTHREADS; diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp index da02e70181..0ba44e4e61 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/JsonSystemComponent.cpp @@ -104,6 +104,8 @@ namespace AZ ->HandlesType(); jsonContext->Serializer() ->HandlesType(); + jsonContext->Serializer() + ->HandlesType(); MathReflect(jsonContext); } diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp index 2392ff435f..ad1839f974 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.cpp @@ -15,6 +15,7 @@ namespace AZ AZ_CLASS_ALLOCATOR_IMPL(JsonAnySerializer, SystemAllocator, 0); AZ_CLASS_ALLOCATOR_IMPL(JsonVariantSerializer, SystemAllocator, 0); AZ_CLASS_ALLOCATOR_IMPL(JsonOptionalSerializer, SystemAllocator, 0); + AZ_CLASS_ALLOCATOR_IMPL(JsonBitsetSerializer, SystemAllocator, 0); JsonSerializationResult::Result JsonUnsupportedTypesSerializer::Load(void*, const Uuid&, const rapidjson::Value&, JsonDeserializerContext& context) @@ -49,4 +50,10 @@ namespace AZ return "The Json Serialization doesn't support AZStd::optional by design. No JSON format has yet been found that wasn't deemed too " "complex or overly verbose."; } + + AZStd::string_view JsonBitsetSerializer::GetMessage() const + { + return "The Json Serialization doesn't support AZStd::bitset by design. No JSON format has yet been found that is content creator " + "friendly i.e., easy to comprehend the intent."; + } } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h index d913289d3d..fdcac4c761 100644 --- a/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h +++ b/Code/Framework/AzCore/AzCore/Serialization/Json/UnsupportedTypesSerializer.h @@ -65,4 +65,14 @@ namespace AZ protected: AZStd::string_view GetMessage() const override; }; + + class JsonBitsetSerializer : public JsonUnsupportedTypesSerializer + { + public: + AZ_RTTI(JsonBitsetSerializer, "{10CE969D-D69E-4B3F-8593-069736F8F705}", JsonUnsupportedTypesSerializer); + AZ_CLASS_ALLOCATOR_DECL; + + protected: + AZStd::string_view GetMessage() const override; + }; } // namespace AZ diff --git a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp index 56b56e96a1..1cacef7ff3 100644 --- a/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp +++ b/Code/Framework/AzCore/AzCore/Task/TaskGraphSystemComponent.cpp @@ -30,8 +30,13 @@ namespace AZ if (Interface::Get() == nullptr) { + #if (AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS) + const uint32_t numberOfWorkerThreads = AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS; + #else + const uint32_t numberOfWorkerThreads = Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved); + #endif // (AZ_TRAIT_THREAD_NUM_TASK_GRAPH_WORKER_THREADS) Interface::Register(this); // small window that another thread can try to use taskgraph between this line and the set instance. - m_taskExecutor = aznew TaskExecutor(Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved)); + m_taskExecutor = aznew TaskExecutor(numberOfWorkerThreads); TaskExecutor::SetInstance(m_taskExecutor); } } diff --git a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h index 495c8d5f2c..e05e000a4e 100644 --- a/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h +++ b/Code/Framework/AzCore/Platform/Android/AzCore/AzCore_Traits_Android.h @@ -75,7 +75,6 @@ #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 0 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0 -#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0 #define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 diff --git a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h index 6ba369e86d..2c0d554078 100644 --- a/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h +++ b/Code/Framework/AzCore/Platform/Linux/AzCore/AzCore_Traits_Linux.h @@ -75,7 +75,6 @@ #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0 -#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0 #define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 diff --git a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h index a41b5c6baa..816a28b728 100644 --- a/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h +++ b/Code/Framework/AzCore/Platform/Mac/AzCore/AzCore_Traits_Mac.h @@ -75,7 +75,6 @@ #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0 -#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0 #define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h index 2f9fcefdbd..83cff9b54f 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/AzCore_Traits_Windows.h @@ -75,7 +75,6 @@ #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 1 -#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0 #define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 1 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 diff --git a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h index d53f4b057e..b0832c54f6 100644 --- a/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h +++ b/Code/Framework/AzCore/Platform/iOS/AzCore/AzCore_Traits_iOS.h @@ -76,7 +76,6 @@ #define AZ_TRAIT_HEAPSCHEMA_COMPILE_MALLINFO 1 #define AZ_TRAIT_IS_ABS_PATH_IF_COLON_FOUND_ANYWHERE 0 #define AZ_TRAIT_JSON_CLANG_IGNORE_UNKNOWN_WARNING 0 -#define AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS 0 #define AZ_TRAIT_PERF_MEMORYBENCHMARK_IS_AVAILABLE 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING 0 #define AZ_TRAIT_PUMP_SYSTEM_EVENTS_WHILE_LOADING_INTERVAL_MS 0 diff --git a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp index e33dbce9c1..3f2d9491a7 100644 --- a/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp +++ b/Code/Framework/AzCore/Tests/Asset/AssetManagerLoadingTests.cpp @@ -652,7 +652,7 @@ namespace UnitTest threads.emplace_back([this, &threadCount, &cv, assetUuid]() { bool checkLoaded = true; - for (int i = 0; i < 5000; i++) + for (int i = 0; i < 1000; i++) { Asset asset1 = m_testAssetManager->GetAsset(assetUuid, azrtti_typeid(), AZ::Data::AssetLoadBehavior::PreLoad); @@ -678,7 +678,7 @@ namespace UnitTest while (threadCount > 0 && !timedOut) { AZStd::unique_lock lock(mutex); - timedOut = (AZStd::cv_status::timeout == cv.wait_until(lock, AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds * 20000)); + timedOut = (AZStd::cv_status::timeout == cv.wait_until(lock, AZStd::chrono::system_clock::now() + DefaultTimeoutSeconds)); } ASSERT_EQ(threadCount, 0) << "Thread count is non-zero, a thread has likely deadlocked. Test will not shut down cleanly."; @@ -1190,7 +1190,7 @@ namespace UnitTest #if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) #else - TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) + TEST_F(AssetJobsFloodTest, ContainerFilterTest_ContainersWithAndWithoutFiltering_Success) #endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS { m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect(); diff --git a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp index c1c5775958..0fede85aa7 100644 --- a/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp +++ b/Code/Framework/AzFramework/AzFramework/Archive/Archive.cpp @@ -1241,6 +1241,10 @@ namespace AZ::IO m_arrZips.insert(revItZip.base(), desc); + // This lock is for m_arrZips. + // Unlock it now because the modification is complete, and events responding to this signal + // will attempt to lock the same mutex, causing the application to lock up. + lock.unlock(); m_levelOpenEvent.Signal(levelDirs); } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h index fd4196a296..282898c37d 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/ToolsApplicationAPI.h @@ -927,6 +927,9 @@ namespace AzToolsFramework /// Notify that the MainWindow has been fully initialized virtual void NotifyMainWindowInitialized(QMainWindow* /*mainWindow*/) {} + /// Notify that the Editor has been fully initialized + virtual void NotifyEditorInitialized() {} + /// Signal that an asset should be highlighted / selected virtual void SelectAsset(const QString& /* assetPath */) {} }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp index 3c7495e836..056872edab 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Application/ToolsApplication.cpp @@ -214,12 +214,17 @@ namespace AzToolsFramework , public AZ::BehaviorEBusHandler { AZ_EBUS_BEHAVIOR_BINDER(EditorEventsBusHandler, "{352F80BB-469A-40B6-B322-FE57AB51E4DA}", AZ::SystemAllocator, - NotifyRegisterViews); + NotifyRegisterViews, NotifyEditorInitialized); void NotifyRegisterViews() override { Call(FN_NotifyRegisterViews); } + + void NotifyEditorInitialized() override + { + Call(FN_NotifyEditorInitialized); + } }; } // Internal @@ -443,6 +448,7 @@ namespace AzToolsFramework ->Attribute(AZ::Script::Attributes::Module, "editor") ->Handler() ->Event("NotifyRegisterViews", &EditorEvents::NotifyRegisterViews) + ->Event("NotifyEditorInitialized", &EditorEvents::NotifyEditorInitialized) ; behaviorContext->EBus("ViewPaneCallbackBus") diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp index 7da6f794d6..172bd3a29c 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetBrowserComponent.cpp @@ -234,11 +234,6 @@ namespace AzToolsFramework return SourceFileDetails("Icons/AssetBrowser/Lua_16.svg"); } - if (AzFramework::StringFunc::Equal(extension.c_str(), ".mtl")) - { - return SourceFileDetails("Icons/AssetBrowser/Material_16.svg"); - } - if (AzFramework::StringFunc::Equal(extension.c_str(), AzToolsFramework::SliceUtilities::GetSliceFileExtension().c_str())) { return SourceFileDetails("Icons/AssetBrowser/Slice_16.svg"); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp index 4ebeb03a71..eae8ec2a1e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp @@ -31,7 +31,10 @@ AZ_POP_DISABLE_WARNING AZ_CVAR( bool, ed_hideAssetPickerPathColumn, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Hide AssetPicker path column for a clearer view."); -AZ_CVAR_EXTERNED(bool, ed_useNewAssetBrowserTableView); + +AZ_CVAR( + bool, ed_useNewAssetPickerView, false, nullptr, AZ::ConsoleFunctorFlags::Null, + "Uses the new Asset Picker View."); namespace AzToolsFramework { @@ -106,7 +109,7 @@ namespace AzToolsFramework m_persistentState = AZ::UserSettings::CreateFind(AZ::Crc32(("AssetBrowserTreeView_Dialog_" + name).toUtf8().data()), AZ::UserSettings::CT_GLOBAL); m_ui->m_assetBrowserTableViewWidget->setVisible(false); - if (ed_useNewAssetBrowserTableView) + if (ed_useNewAssetPickerView) { m_ui->m_assetBrowserTreeViewWidget->setVisible(false); m_ui->m_assetBrowserTableViewWidget->setVisible(true); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp index 2cca3804ea..20a15643c6 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/Component/EditorComponentAPIComponent.cpp @@ -597,11 +597,13 @@ namespace AzToolsFramework pte.SetVisibleEnforcement(true); } + ScopedUndoBatch undo("Modify Entity Property"); PropertyOutcome result = pte.SetProperty(propertyPath, value); if (result.IsSuccess()) { PropertyEditorEntityChangeNotificationBus::Event(componentInstance.GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, componentInstance.GetComponentId()); } + undo.MarkEntityDirty(componentInstance.GetEntityId()); return result; } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp index 920e99665d..c1fc9138d1 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Prefab/PrefabViewportFocusPathHandler.cpp @@ -64,6 +64,9 @@ namespace AzToolsFramework::Prefab ); m_backButton->setToolTip("Up one level (-)"); + + // Currently hide this button until we can correctly disable/enable it based on context. + m_backButton->hide(); } void PrefabViewportFocusPathHandler::OnPrefabFocusChanged() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index 29bc106eed..9ecbdf5ffc 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -4705,13 +4705,6 @@ namespace AzToolsFramework { if (mimeData->hasFormat(AssetBrowser::AssetBrowserEntry::GetMimeType())) { - // extra special case: MTLs from FBX drags are ignored. are we dragging a FBX file? - bool isDraggingFBXFile = false; - AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData(mimeData, [&](const AssetBrowser::SourceAssetBrowserEntry* source) - { - isDraggingFBXFile = isDraggingFBXFile || AzFramework::StringFunc::Equal(source->GetExtension().c_str(), ".fbx", false); - }); - // the usual case - we only allow asset browser drops of assets that have actually been associated with a kind of component. AssetBrowser::AssetBrowserEntry::ForEachEntryInMimeData(mimeData, [&](const AssetBrowser::ProductAssetBrowserEntry* product) { @@ -4723,17 +4716,7 @@ namespace AzToolsFramework if (canCreateComponent && !componentTypeId.IsNull()) { - // we have a component type that handles this asset. - // but we disallow it if its a MTL file from a FBX and the FBX itself is being dragged. Its still allowed - // to drag the actual MTL. - EBusFindAssetTypeByName materialAssetTypeResult("Material"); - AZ::AssetTypeInfoBus::BroadcastResult(materialAssetTypeResult, &AZ::AssetTypeInfo::GetAssetType); - AZ::Data::AssetType materialAssetType = materialAssetTypeResult.GetAssetType(); - - if ((!isDraggingFBXFile) || (product->GetAssetType() != materialAssetType)) - { - callbackFunction(product); - } + callbackFunction(product); } }); } diff --git a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp index a02eef8b75..f9b5d6aef7 100644 --- a/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp +++ b/Code/Tools/AssetProcessor/AssetBuilderSDK/AssetBuilderSDK/AssetBuilderSDK.cpp @@ -690,7 +690,6 @@ namespace AssetBuilderSDK static const char* textureExtensions = ".dds"; static const char* staticMeshExtensions = ".cgf"; static const char* skinnedMeshExtensions = ".skin"; - static const char* materialExtensions = ".mtl"; // MIPS static const int c_MaxMipsCount = 11; // 11 is for 8k textures non-compressed. When not compressed it is using one file per mip. @@ -805,11 +804,6 @@ namespace AssetBuilderSDK return textureAssetType; } - if (AzFramework::StringFunc::Find(materialExtensions, extension.c_str()) != AZStd::string::npos) - { - return materialAssetType; - } - if (AzFramework::StringFunc::Find(staticMeshExtensions, extension.c_str()) != AZStd::string::npos) { return meshAssetType; diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h index 7c0543361f..d7edcfcf12 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectManager_Traits_Linux.h @@ -9,3 +9,4 @@ #pragma once #define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false +#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false diff --git a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp index dc3ec55dee..a7bd2dae08 100644 --- a/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp +++ b/Code/Tools/ProjectManager/Platform/Linux/ProjectUtils_linux.cpp @@ -96,5 +96,10 @@ namespace O3DE::ProjectManager { return AZ::Utils::GetExecutableDirectory(); } + + AZ::Outcome CreateDesktopShortcut([[maybe_unused]] const QString& filename, [[maybe_unused]] const QString& targetPath, [[maybe_unused]] const QStringList& arguments) + { + return AZ::Failure(QObject::tr("Creating desktop shortcuts functionality not implemented for this platform yet.")); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h index 7c0543361f..d7edcfcf12 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectManager_Traits_Mac.h @@ -9,3 +9,4 @@ #pragma once #define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false +#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT false diff --git a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp index b768200398..62011bf04b 100644 --- a/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp +++ b/Code/Tools/ProjectManager/Platform/Mac/ProjectUtils_mac.cpp @@ -137,5 +137,10 @@ namespace O3DE::ProjectManager return editorPath; } + + AZ::Outcome CreateDesktopShortcut([[maybe_unused]] const QString& filename, [[maybe_unused]] const QString& targetPath, [[maybe_unused]] const QStringList& arguments) + { + return AZ::Failure(QObject::tr("Creating desktop shortcuts functionality not implemented for this platform yet.")); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h index e6422b5a77..9e4d29b58f 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectManager_Traits_Windows.h @@ -9,3 +9,4 @@ #pragma once #define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true +#define AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT true diff --git a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp index 871f8e9567..d08da1d5e1 100644 --- a/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp +++ b/Code/Tools/ProjectManager/Platform/Windows/ProjectUtils_windows.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -146,5 +147,26 @@ namespace O3DE::ProjectManager { return AZ::Utils::GetExecutableDirectory(); } + + AZ::Outcome CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments) + { + const QString cmd{"powershell.exe"}; + const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + const QString shortcutPath = QString("%1/%2.lnk").arg(desktopPath).arg(filename); + const QString arg = QString("$s=(New-Object -COM WScript.Shell).CreateShortcut('%1');$s.TargetPath='%2';$s.Arguments='%3';$s.Save();") + .arg(shortcutPath) + .arg(targetPath) + .arg(arguments.join(' ')); + auto createShortcutResult = ExecuteCommandResult(cmd, QStringList{"-Command", arg}, QProcessEnvironment::systemEnvironment()); + if (!createShortcutResult.IsSuccess()) + { + return AZ::Failure(QObject::tr("Failed to create desktop shortcut %1

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

%2") + .arg(shortcutPath) + .arg(createShortcutResult.GetError())); + } + + return AZ::Success(QObject::tr("Desktop shortcut created at
%2").arg(desktopPath).arg(shortcutPath)); + } } // namespace ProjectUtils } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 6abbfe16ba..0dacbbb906 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -126,7 +126,8 @@ namespace O3DE::ProjectManager // Select the first entry after everything got correctly sized QTimer::singleShot(200, [=]{ QModelIndex firstModelIndex = m_gemModel->index(0, 0); - m_gemModel->GetSelectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); + QModelIndex proxyIndex = m_proxyModel->mapFromSource(firstModelIndex); + m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); }); } @@ -209,7 +210,7 @@ namespace O3DE::ProjectManager const bool gemFound = gemInfoHash.contains(gemName); if (!gemFound && !m_gemModel->IsAdded(index) && !m_gemModel->IsAddedDependency(index)) { - m_gemModel->removeRow(i); + m_gemModel->RemoveGem(index); } else { @@ -239,7 +240,7 @@ namespace O3DE::ProjectManager m_filterWidget->ResetAllFilters(); // Reselect the same selection to proc UI updates - m_proxyModel->GetSelectionModel()->select(m_proxyModel->GetSelectionModel()->selection(), QItemSelectionModel::Select); + m_proxyModel->GetSelectionModel()->setCurrentIndex(m_proxyModel->GetSelectionModel()->currentIndex(), QItemSelectionModel::Select); } void GemCatalogScreen::OnGemStatusChanged(const QString& gemName, uint32_t numChangedDependencies) @@ -268,7 +269,7 @@ namespace O3DE::ProjectManager if (added && GemModel::GetDownloadStatus(modelIndex) == GemInfo::DownloadStatus::NotDownloaded) { m_downloadController->AddGemDownload(GemModel::GetName(modelIndex)); - GemModel::SetDownloadStatus(*m_proxyModel, m_proxyModel->mapFromSource(modelIndex), GemInfo::DownloadStatus::Downloading); + GemModel::SetDownloadStatus(*m_gemModel, modelIndex, GemInfo::DownloadStatus::Downloading); } } @@ -300,7 +301,7 @@ namespace O3DE::ProjectManager } QModelIndex proxyIndex = m_proxyModel->mapFromSource(modelIndex); - m_proxyModel->GetSelectionModel()->select(proxyIndex, QItemSelectionModel::ClearAndSelect); + m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); m_gemListView->scrollTo(proxyIndex); } @@ -362,6 +363,9 @@ namespace O3DE::ProjectManager { const QString selectedGemPath = m_gemModel->GetPath(modelIndex); + // Remove gem from gems to be added + GemModel::SetIsAdded(*m_gemModel, modelIndex, false); + // Unregister the gem auto unregisterResult = PythonBindingsInterface::Get()->UnregisterGem(selectedGemPath); if (!unregisterResult) @@ -370,8 +374,10 @@ namespace O3DE::ProjectManager } else { + const QString selectedGemName = m_gemModel->GetName(modelIndex); + // Remove gem from model - m_gemModel->removeRow(modelIndex.row()); + m_gemModel->RemoveGem(modelIndex); // Delete uninstalled gem directory if (!ProjectUtils::DeleteProjectFiles(selectedGemPath, /*force*/true)) @@ -382,6 +388,11 @@ namespace O3DE::ProjectManager // Show undownloaded remote gem again Refresh(); + + // Select remote gem + QModelIndex remoteGemIndex = m_gemModel->FindIndexByNameString(selectedGemName); + QModelIndex proxyIndex = m_proxyModel->mapFromSource(remoteGemIndex); + m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); } } } @@ -564,7 +575,8 @@ namespace O3DE::ProjectManager if (succeeded) { // refresh the information for downloaded gems - const AZ::Outcome, AZStd::string>& allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath); + const AZ::Outcome, AZStd::string>& allGemInfosResult = + PythonBindingsInterface::Get()->GetAllGemInfos(m_projectPath); if (allGemInfosResult.IsSuccess()) { // we should find the gem name now in all gem infos @@ -572,15 +584,33 @@ namespace O3DE::ProjectManager { if (gemInfo.m_name == gemName) { - QModelIndex index = m_gemModel->FindIndexByNameString(gemName); - if (index.isValid()) + QModelIndex oldIndex = m_gemModel->FindIndexByNameString(gemName); + if (oldIndex.isValid()) { - m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadSuccessful, GemModel::RoleDownloadStatus); - m_gemModel->setData(index, gemInfo.m_path, GemModel::RolePath); - m_gemModel->setData(index, gemInfo.m_path, GemModel::RoleDirectoryLink); + // Check if old gem is selected + bool oldGemSelected = false; + if (m_gemModel->GetSelectionModel()->currentIndex() == oldIndex) + { + oldGemSelected = true; + } + + // Remove old remote gem + m_gemModel->RemoveGem(oldIndex); + + // Add new downloaded version of gem + QModelIndex newIndex = m_gemModel->AddGem(gemInfo); + GemModel::SetDownloadStatus(*m_gemModel, newIndex, GemInfo::DownloadSuccessful); + GemModel::SetIsAdded(*m_gemModel, newIndex, true); + + // Select new version of gem if it was previously selected + if (oldGemSelected) + { + QModelIndex proxyIndex = m_proxyModel->mapFromSource(newIndex); + m_proxyModel->GetSelectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::ClearAndSelect); + } } - return; + break; } } } @@ -590,7 +620,7 @@ namespace O3DE::ProjectManager QModelIndex index = m_gemModel->FindIndexByNameString(gemName); if (index.isValid()) { - m_proxyModel->setData(m_proxyModel->mapFromSource(index), GemInfo::DownloadFailed, GemModel::RoleDownloadStatus); + GemModel::SetDownloadStatus(*m_gemModel, index, GemInfo::DownloadFailed); } } } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index 886b9e57c7..95fdc8e1e2 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -26,14 +26,14 @@ namespace O3DE::ProjectManager return m_selectionModel; } - void GemModel::AddGem(const GemInfo& gemInfo) + QModelIndex GemModel::AddGem(const GemInfo& gemInfo) { if (FindIndexByNameString(gemInfo.m_name).isValid()) { // do not add gems with duplicate names // this can happen by mistake or when a gem repo has a gem with the same name as a local gem AZ_TracePrintf("GemModel", "Ignoring duplicate gem: %s", gemInfo.m_name.toUtf8().constData()); - return; + return QModelIndex(); } QStandardItem* item = new QStandardItem(); @@ -67,6 +67,22 @@ namespace O3DE::ProjectManager const QModelIndex modelIndex = index(rowCount()-1, 0); m_nameToIndexMap[gemInfo.m_name] = modelIndex; + + return modelIndex; + } + + void GemModel::RemoveGem(const QModelIndex& modelIndex) + { + removeRow(modelIndex.row()); + } + + void GemModel::RemoveGem(const QString& gemName) + { + auto nameFind = m_nameToIndexMap.find(gemName); + if (nameFind != m_nameToIndexMap.end()) + { + removeRow(nameFind->row()); + } } void GemModel::Clear() @@ -391,11 +407,11 @@ namespace O3DE::ProjectManager // Select a valid row if currently selected row was removed if (selectedRowRemoved) { - for (const QModelIndex& index : m_nameToIndexMap) + for (const QModelIndex& index : m_nameToIndexMap) { if (index.isValid()) { - GetSelectionModel()->select(index, QItemSelectionModel::ClearAndSelect); + GetSelectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); break; } } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 87a718d8c7..bb89d46861 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -55,7 +55,9 @@ namespace O3DE::ProjectManager RoleRepoUri }; - void AddGem(const GemInfo& gemInfo); + QModelIndex AddGem(const GemInfo& gemInfo); + void RemoveGem(const QModelIndex& modelIndex); + void RemoveGem(const QString& gemName); void Clear(); void UpdateGemDependencies(); diff --git a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp index 794635a3e3..91432c2346 100644 --- a/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemRepo/GemRepoScreen.cpp @@ -75,7 +75,7 @@ namespace O3DE::ProjectManager // Select the first entry after everything got correctly sized QTimer::singleShot(200, [=]{ QModelIndex firstModelIndex = m_gemRepoListView->model()->index(0,0); - m_gemRepoListView->selectionModel()->select(firstModelIndex, QItemSelectionModel::ClearAndSelect); + m_gemRepoListView->selectionModel()->setCurrentIndex(firstModelIndex, QItemSelectionModel::ClearAndSelect); }); } diff --git a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp index c425c344e1..98916cccf6 100644 --- a/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp @@ -8,7 +8,11 @@ #include #include +#include +#include #include +#include +#include #include #include @@ -23,6 +27,7 @@ #include #include #include +#include namespace O3DE::ProjectManager { @@ -205,6 +210,29 @@ namespace O3DE::ProjectManager { AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path); }); + +#if AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT + menu->addAction(tr("Create Editor desktop shortcut..."), this, [this]() + { + AZ::IO::FixedMaxPath executableDirectory = ProjectUtils::GetEditorDirectory(); + AZStd::string executableFilename = "Editor"; + AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION); + + const QString shortcutName = QString("%1 Editor").arg(m_projectInfo.m_displayName); + const QString arg = QString("--regset=\"/Amazon/AzCore/Bootstrap/project_path=%1\"").arg(m_projectInfo.m_path); + + auto result = ProjectUtils::CreateDesktopShortcut(shortcutName, editorExecutablePath.c_str(), { arg }); + if(result.IsSuccess()) + { + QMessageBox::information(this, tr("Desktop Shortcut Created"), result.GetValue()); + } + else + { + QMessageBox::critical(this, tr("Failed to create shortcut"), result.GetError()); + } + }); +#endif // AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT + menu->addSeparator(); menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo); }); menu->addSeparator(); diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index bb2bcd070e..4a0e1c153c 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -628,11 +628,11 @@ namespace O3DE::ProjectManager return AZ::Failure(QObject::tr("Process for command '%1' timed out at %2 seconds").arg(cmd).arg(commandTimeoutSeconds)); } int resultCode = execProcess.exitCode(); + QString resultOutput = execProcess.readAllStandardOutput(); if (resultCode != 0) { - return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2").arg(cmd).arg(resultCode)); + return AZ::Failure(QObject::tr("Process for command '%1' failed (result code %2) %3").arg(cmd).arg(resultCode).arg(resultOutput)); } - QString resultOutput = execProcess.readAllStandardOutput(); return AZ::Success(resultOutput); } diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index 890d50d2de..ee605b5117 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -68,6 +68,15 @@ namespace O3DE::ProjectManager AZ::Outcome GetProjectBuildPath(const QString& projectPath); AZ::Outcome OpenCMakeGUI(const QString& projectPath); AZ::Outcome RunGetPythonScript(const QString& enginePath); + + /** + * Create a desktop shortcut. + * @param filename the name of the desktop shorcut file + * @param target the path to the target to run + * @param arguments the argument list to provide to the target + * @return AZ::Outcome with the command result on success + */ + AZ::Outcome CreateDesktopShortcut(const QString& filename, const QString& targetPath, const QStringList& arguments); AZ::IO::FixedMaxPath GetEditorDirectory(); diff --git a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h index 97eb5b6492..a3d18c1ea1 100644 --- a/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h +++ b/Gems/AWSCore/Code/Include/Private/ResourceMapping/AWSResourceMappingConstants.h @@ -68,7 +68,7 @@ namespace AWSCore }, "AccountIdString": { "type": "string", - "pattern": "^[0-9]{12}$|EMPTY" + "pattern": "^[0-9]{12}$|EMPTY|^$" }, "NonEmptyString": { "type": "string", diff --git a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp index fb03dea4c0..a90518006f 100644 --- a/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp +++ b/Gems/AWSCore/Code/Tests/ResourceMapping/AWSResourceMappingManagerTest.cpp @@ -59,6 +59,34 @@ R"({ "Version": "1.0.0" })"; +static constexpr const char TEST_VALID_EMPTY_ACCOUNTID_RESOURCE_MAPPING_CONFIG_FILE[] = + R"({ + "AWSResourceMappings": { + "TestLambda": { + "Type": "AWS::Lambda::Function", + "Name/ID": "MyTestLambda", + "Region": "us-east-1", + "AccountId": "012345678912" + }, + "TestS3Bucket": { + "Type": "AWS::S3::Bucket", + "Name/ID": "MyTestS3Bucket" + }, + "TestService.RESTApiId": { + "Type": "AWS::ApiGateway::RestApi", + "Name/ID": "1234567890" + }, + "TestService.RESTApiStage": { + "Type": "AWS::ApiGateway::Stage", + "Name/ID": "prod", + "Region": "us-east-1" + } + }, + "AccountId": "", + "Region": "us-west-2", + "Version": "1.0.0" +})"; + static constexpr const char TEST_INVALID_RESOURCE_MAPPING_CONFIG_FILE[] = R"({ "AWSResourceMappings": {}, @@ -237,6 +265,21 @@ TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_Confi EXPECT_TRUE(actualEbusCalls == testThreadNumber); } +TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_GlobalAccountIdEmpty) +{ + CreateTestConfigFile(TEST_VALID_EMPTY_ACCOUNTID_RESOURCE_MAPPING_CONFIG_FILE); + m_resourceMappingManager->ActivateManager(); + + AZStd::string actualAccountId; + AZStd::string actualRegion; + AWSResourceMappingRequestBus::BroadcastResult(actualAccountId, &AWSResourceMappingRequests::GetDefaultAccountId); + AWSResourceMappingRequestBus::BroadcastResult(actualRegion, &AWSResourceMappingRequests::GetDefaultRegion); + EXPECT_EQ(m_reloadConfigurationCounter, 0); + EXPECT_TRUE(actualAccountId.empty()); + EXPECT_FALSE(actualRegion.empty()); + EXPECT_TRUE(m_resourceMappingManager->GetStatus() == AWSResourceMappingManager::Status::Ready); +} + TEST_F(AWSResourceMappingManagerTest, DeactivateManager_AfterActivatingWithValidConfigFile_ConfigDataGetCleanedUp) { CreateTestConfigFile(TEST_VALID_RESOURCE_MAPPING_CONFIG_FILE); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp index e41c04a0be..99b7c814d1 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/AzslShaderBuilderSystemComponent.cpp @@ -82,7 +82,7 @@ namespace AZ // Register Shader Asset Builder AssetBuilderSDK::AssetBuilderDesc shaderAssetBuilderDescriptor; shaderAssetBuilderDescriptor.m_name = "Shader Asset Builder"; - shaderAssetBuilderDescriptor.m_version = 107; // Required .azsl extension in .shader file references + shaderAssetBuilderDescriptor.m_version = 108; // The Build Time Stamp of ShaderAsset And ShaderVariantAsset Should Be Based On GetTimeUTCMilliSecond() // .shader file changes trigger rebuilds shaderAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern( AZStd::string::format("*.%s", RPI::ShaderSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); shaderAssetBuilderDescriptor.m_busId = azrtti_typeid(); @@ -108,7 +108,7 @@ namespace AZ shaderVariantAssetBuilderDescriptor.m_name = "Shader Variant Asset Builder"; // Both "Shader Variant Asset Builder" and "Shader Asset Builder" produce ShaderVariantAsset products. If you update // ShaderVariantAsset you will need to update BOTH version numbers, not just "Shader Variant Asset Builder". - shaderVariantAssetBuilderDescriptor.m_version = 26; // [AZSL] Changing inlineConstant to rootConstant keyword work. + shaderVariantAssetBuilderDescriptor.m_version = 27; // The Build Time Stamp of ShaderAsset And ShaderVariantAsset Should Be Based On GetTimeUTCMilliSecond(). shaderVariantAssetBuilderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern(AZStd::string::format("*.%s", RPI::ShaderVariantListSourceData::Extension), AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); shaderVariantAssetBuilderDescriptor.m_busId = azrtti_typeid(); shaderVariantAssetBuilderDescriptor.m_createJobFunction = AZStd::bind(&ShaderVariantAssetBuilder::CreateJobs, &m_shaderVariantAssetBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp index 89e202a4bc..e431b74282 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderAssetBuilder.cpp @@ -162,7 +162,7 @@ namespace AZ // has the same value, because later the ShaderVariantTreeAsset job will fetch this value from the local ShaderAsset // which could cross platforms (i.e. building an android ShaderVariantTreeAsset on PC would fetch the tiemstamp from // the PC's ShaderAsset). - AZStd::sys_time_t shaderAssetBuildTimestamp = AZStd::GetTimeNowMicroSecond(); + AZ::u64 shaderAssetBuildTimestamp = AZStd::GetTimeUTCMilliSecond(); // Need to get the name of the azsl file from the .shader source asset, to be able to declare a dependency to SRG Layout Job. // and the macro options to preprocess. @@ -229,8 +229,8 @@ namespace AZ } // for all request.m_enabledPlatforms AZ_TracePrintf( - ShaderAssetBuilderName, "CreateJobs for %s took %llu microseconds", shaderAssetSourceFileFullPath.c_str(), - AZStd::GetTimeNowMicroSecond() - shaderAssetBuildTimestamp); + ShaderAssetBuilderName, "CreateJobs for %s took %llu milliseconds", shaderAssetSourceFileFullPath.c_str(), + AZStd::GetTimeUTCMilliSecond() - shaderAssetBuildTimestamp); response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; } @@ -355,8 +355,8 @@ namespace AZ return; } - // Get the time stamp string as sys_time_t, and also convert back to string to make sure it was converted correctly. - AZStd::sys_time_t shaderAssetBuildTimestamp = 0; + // Get the time stamp string as u64, and also convert back to string to make sure it was converted correctly. + AZ::u64 shaderAssetBuildTimestamp = 0; auto shaderAssetBuildTimestampIterator = request.m_jobDescription.m_jobParameters.find(ShaderAssetBuildTimestampParam); if (shaderAssetBuildTimestampIterator != request.m_jobDescription.m_jobParameters.end()) { diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index bb40baca7d..5eaa0d9ddb 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -765,7 +765,7 @@ namespace AZ return; } - const AZStd::sys_time_t shaderVariantAssetBuildTimestamp = AZStd::GetTimeNowMicroSecond(); + const AZ::u64 shaderVariantAssetBuildTimestamp = AZStd::GetTimeUTCMilliSecond(); auto supervariantList = ShaderBuilderUtility::GetSupervariantListFromShaderSourceData(shaderSourceDescriptor); diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h index 2eaf1d9d8b..b0457656af 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.h @@ -38,7 +38,7 @@ namespace AZ const AZStd::string& m_tempDirPath; //! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset, //! especially during hot-reload. A (ShaderVariantAsset.timestamp) >= (ShaderAsset.timestamp). - const AZStd::sys_time_t m_assetBuildTimestamp; + const AZ::u64 m_assetBuildTimestamp; const RPI::ShaderSourceData& m_shaderSourceDataDescriptor; const RPI::ShaderOptionGroupLayout& m_shaderOptionGroupLayout; const MapOfStringToStageType& m_shaderEntryPoints; diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli index a7122aaf3a..59817af701 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/Shadow/DirectionalLightShadow.azsli @@ -166,7 +166,7 @@ float DirectionalLightShadow::GetThickness(uint lightIndex, float3 shadowCoords[ bool2 DirectionalLightShadow::IsShadowed(float3 shadowCoord, uint indexOfCascade) { static const float PixelMargin = 1.5; // avoiding artifact between cascade levels. - static const float DepthMargin = 0.01; // avoiding artifact when near depth bounds. + static const float DepthMargin = 1e-8; // avoiding artifact when near depth bounds. // size is the shadowap's width and height. const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize; @@ -210,8 +210,8 @@ float DirectionalLightShadow::GetVisibilityFromLightNoFilter() float DirectionalLightShadow::GetVisibilityFromLightPcf() { - static const float DepthMargin = 0.01; // avoiding artifact when near depth bounds. static const float PixelMargin = 1.5; // avoiding artifact between cascade levels. + static const float DepthMargin = 1e-8; // avoiding artifact when near depth bounds. const uint size = ViewSrg::m_directionalLightShadows[m_lightIndex].m_shadowmapSize; const uint cascadeCount = ViewSrg::m_directionalLightShadows[m_lightIndex].m_cascadeCount; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader index 31fae5d98b..a9b5567f6b 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance.azshader differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant index 19e9fdfc8d..6d4b6d0fca 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_dx12_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_null_0.azshadervariant index 43c4a615cf..5d8800a6fe 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_null_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_vulkan_0.azshadervariant index 75f070a03e..930f7898c4 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblenddistance_vulkan_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader index 0025388bc1..268020b431 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance.azshader differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_dx12_0.azshadervariant index 34a9b3659f..d95ec6c1b9 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_dx12_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant index 4a2b0e9944..3253ddba37 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_null_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant index c053a7db19..c38b94c4f1 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridblendirradiance_vulkan_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader index c507b12563..5c46d368ce 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn.azshader differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant index f60c713597..eb6938f8c9 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_dx12_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant index 3e810bcfb5..8c83c1e3ff 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_null_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant index 5918f277b5..2fbb9ffffe 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdatecolumn_vulkan_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader index 120eb70e54..96053f4091 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow.azshader differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant index d38d779696..4bdbdddf33 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_dx12_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant index 6d7a604701..77668a2450 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_null_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant index dee941cfae..fb3dd771ca 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridborderupdaterow_vulkan_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader index e2e0fa90f5..eda8d53376 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification.azshader differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_dx12_0.azshadervariant index 7a92fc2de5..2df610df77 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_dx12_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant index 43408b26f3..f2458e692b 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_null_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_vulkan_0.azshadervariant index 877085446d..0e08e84f74 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridclassification_vulkan_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader index 2c403c77f8..1cea4860a1 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing.azshader differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant index 4bcc47ee43..5605a47e9c 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_dx12_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_null_0.azshadervariant index f173416210..15f3477cb5 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_null_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_vulkan_0.azshadervariant index 0eb04a25b8..c2bcd4ab07 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracing_vulkan_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit.azshader index 2847d0035a..9958708a64 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit.azshader differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant index 93cfb47819..fbd1d90251 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_dx12_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant index 4a16e24211..483be0eceb 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_null_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant index df52c9c8d2..530eef2f10 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingclosesthit_vulkan_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader index d95fd5b3b2..eddac4e2bd 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss.azshader differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_dx12_0.azshadervariant index c853de4d14..ad06bbd104 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_dx12_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_null_0.azshadervariant index 40e18c215c..527b42569a 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_null_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant index 34761ccf98..426d955938 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridraytracingmiss_vulkan_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader index c19020dc84..08ed61ab03 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation.azshader differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant index a7d44b5541..d1012a896f 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_dx12_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant index 82e0065216..cb730be1df 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_null_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant index 20b81aee6c..b58af4c473 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrelocation_vulkan_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader index aec2786540..56009d56ab 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender.azshader differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_dx12_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_dx12_0.azshadervariant index de851f187e..e9893c96da 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_dx12_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_dx12_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant index 5d8207dfdb..d195b08c34 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_null_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant index c819e57c4c..47789d9b9b 100644 Binary files a/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant and b/Gems/Atom/Feature/Common/Assets/Shaders/DiffuseGlobalIllumination/diffuseprobegridrender_vulkan_0.azshadervariant differ diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp index 410c80dbdc..ce5d3cc363 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.cpp @@ -1248,6 +1248,32 @@ namespace AZ property.m_shadowmapViewNeedsUpdate = true; } + float DirectionalLightFeatureProcessor::GetShadowmapSizeFromCameraView(const LightHandle handle, const RPI::View* cameraView) const + { + const DirectionalLightShadowData& shadowData = m_shadowData.at(cameraView).GetData(handle.GetIndex()); + return static_cast(shadowData.m_shadowmapSize); + } + + void DirectionalLightFeatureProcessor::SnapAabbToPixelIncrements(const float invShadowmapSize, Vector3& orthoMin, Vector3& orthoMax) + { + // This function stops the cascaded shadowmap from shimmering as the camera moves. + // See CascadedShadowsManager.cpp in the Microsoft CascadedShadowMaps11 sample for details. + + const Vector3 normalizeByBufferSize = Vector3(invShadowmapSize, invShadowmapSize, invShadowmapSize); + + const Vector3 worldUnitsPerTexel = (orthoMax - orthoMin) * normalizeByBufferSize; + + // We snap the camera to 1 pixel increments so that moving the camera does not cause the shadows to jitter. + // This is a matter of dividing by the world space size of a texel + orthoMin /= worldUnitsPerTexel; + orthoMin = orthoMin.GetFloor(); + orthoMin *= worldUnitsPerTexel; + + orthoMax /= worldUnitsPerTexel; + orthoMax = orthoMax.GetFloor(); + orthoMax *= worldUnitsPerTexel; + } + void DirectionalLightFeatureProcessor::UpdateShadowmapViews(LightHandle handle) { ShadowProperty& property = m_shadowProperties.GetData(handle.GetIndex()); @@ -1259,18 +1285,26 @@ namespace AZ for (auto& segmentIt : property.m_segments) { + const float invShadowmapSize = 1.0f / GetShadowmapSizeFromCameraView(handle, segmentIt.first); + for (uint16_t cascadeIndex = 0; cascadeIndex < segmentIt.second.size(); ++cascadeIndex) { - const Aabb viewAabb = CalculateShadowViewAabb( - handle, segmentIt.first, cascadeIndex, lightTransform); + const Aabb viewAabb = CalculateShadowViewAabb(handle, segmentIt.first, cascadeIndex, lightTransform); if (viewAabb.IsValid() && viewAabb.IsFinite()) { + const float cascadeNear = viewAabb.GetMin().GetY(); + const float cascadeFar = viewAabb.GetMax().GetY(); + + Vector3 snappedAabbMin = viewAabb.GetMin(); + Vector3 snappedAabbMax = viewAabb.GetMax(); + + SnapAabbToPixelIncrements(invShadowmapSize, snappedAabbMin, snappedAabbMax); + Matrix4x4 viewToClipMatrix = Matrix4x4::CreateIdentity(); - MakeOrthographicMatrixRH(viewToClipMatrix, - viewAabb.GetMin().GetElement(0), viewAabb.GetMax().GetElement(0), - viewAabb.GetMin().GetElement(2), viewAabb.GetMax().GetElement(2), - viewAabb.GetMin().GetElement(1), viewAabb.GetMax().GetElement(1)); + MakeOrthographicMatrixRH( + viewToClipMatrix, snappedAabbMin.GetElement(0), snappedAabbMax.GetElement(0), snappedAabbMin.GetElement(2), + snappedAabbMax.GetElement(2), cascadeNear, cascadeFar); CascadeSegment& segment = segmentIt.second[cascadeIndex]; segment.m_aabb = viewAabb; diff --git a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h index 8d7a9d76e4..77f2db38d6 100644 --- a/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/CoreLights/DirectionalLightFeatureProcessor.h @@ -341,6 +341,9 @@ namespace AZ //! This draws bounding boxes of cascades. void DrawCascadeBoundingBoxes(LightHandle handle); + float GetShadowmapSizeFromCameraView(const LightHandle handle, const RPI::View* cameraView) const; + void SnapAabbToPixelIncrements(const float invShadowmapSize, Vector3& orthoMin, Vector3& orthoMax); + IndexedDataVector m_shadowProperties; // [GFX TODO][ATOM-2012] shadow for multiple directional lights LightHandle m_shadowingLightHandle; diff --git a/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp b/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp index 5f85d3ad03..fc80cc50d6 100644 --- a/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp +++ b/Gems/Atom/RHI/DX12/Code/Source/RHI/AsyncUploadQueue.cpp @@ -33,12 +33,20 @@ namespace AZ ID3D12DeviceX* dx12Device = device.GetDevice(); m_copyQueue = CommandQueue::Create(); - + + // The async upload queue should always use the primary copy queue, + // but because this change is being made in the stabilization branch + // we will put it behind a define out of an abundance of caution, and + // change it to always do this once the change gets back to development. + #if defined(AZ_DX12_USE_PRIMARY_COPY_QUEUE_FOR_ASYNC_UPLOAD_QUEUE) + m_copyQueue = &device.GetCommandQueueContext().GetCommandQueue(RHI::HardwareQueueClass::Copy); + #else // Make a secondary Copy queue, the primary queue is owned by the CommandQueueContext CommandQueueDescriptor commandQueueDesc; commandQueueDesc.m_hardwareQueueClass = RHI::HardwareQueueClass::Copy; commandQueueDesc.m_hardwareQueueSubclass = HardwareQueueSubclass::Secondary; m_copyQueue->Init(device, commandQueueDesc); + #endif // defined(AZ_DX12_ASYNC_UPLOAD_QUEUE_USE_PRIMARY_COPY_QUEUE) m_uploadFence.Init(dx12Device, RHI::FenceState::Signaled); for (size_t i = 0; i < descriptor.m_frameCount; ++i) diff --git a/Gems/Atom/RPI/Code/CMakeLists.txt b/Gems/Atom/RPI/Code/CMakeLists.txt index 521178be20..f0459a23c2 100644 --- a/Gems/Atom/RPI/Code/CMakeLists.txt +++ b/Gems/Atom/RPI/Code/CMakeLists.txt @@ -160,6 +160,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) Gem::Atom_RPI.Public Gem::Atom_RHI.Public Gem::Atom_RPI.Edit + Gem::Atom_Utils.TestUtils.Static ) ly_add_googletest( NAME Gem::Atom_RPI.Tests diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h index 3dbedb7a4b..f5336807c7 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Material/MaterialTypeSourceData.h @@ -209,10 +209,6 @@ namespace AZ //! Traversal will stop once all properties have been enumerated or the callback function returns false void EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const; - //! Convert the property value into the format that will be stored in the source data - //! This is primarily needed to support conversions of special types like enums and images - bool ConvertPropertyValueToSourceDataFormat(const AZ::Name& propertyId, const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const; - Outcome> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const; //! Possibly renames @propertyId based on the material version update steps. diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Shader/ShaderVariantAssetCreator.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Shader/ShaderVariantAssetCreator.h index fd069f21e0..488bfb09f8 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Shader/ShaderVariantAssetCreator.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Edit/Shader/ShaderVariantAssetCreator.h @@ -40,7 +40,7 @@ namespace AZ //! Set the timestamp value when the ProcessJob() started. //! This is needed to synchronize between the ShaderAsset and ShaderVariantAsset when hot-reloading shaders. //! The idea is that this timestamp must be greater or equal than the ShaderAsset. - void SetBuildTimestamp(AZStd::sys_time_t buildTimestamp); + void SetBuildTimestamp(AZ::u64 buildTimestamp); //! Assigns a shaderStageFunction, which contains the byte code, to the slot dictated by the shader stage. void SetShaderFunction(RHI::ShaderStage shaderStage, RHI::Ptr shaderStageFunction); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h index c5df9a4b51..5dc990d93a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderAsset.h @@ -294,7 +294,7 @@ namespace AZ Name m_drawListName; //! Use to synchronize versions of the ShaderAsset and ShaderVariantTreeAsset, especially during hot-reload. - AZStd::sys_time_t m_shaderAssetBuildTimestamp = 0; + AZ::u64 m_shaderAssetBuildTimestamp = 0; /////////////////////////////////////////////////////////////////// diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h index 66bbd7b188..5146ae370a 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Reflect/Shader/ShaderVariantAsset.h @@ -61,7 +61,7 @@ namespace AZ //! Return the timestamp when this asset was built, and it must be >= than the timestamp of the main ShaderAsset. //! This is used to synchronize versions of the ShaderAsset and ShaderVariantAsset, especially during hot-reload. - AZStd::sys_time_t GetBuildTimestamp() const; + AZ::u64 GetBuildTimestamp() const; bool IsRootVariant() const { return m_stableId == RPI::RootShaderVariantStableId; } @@ -80,7 +80,7 @@ namespace AZ AZStd::array, RHI::ShaderStageCount> m_functionsByStage; //! Used to synchronize versions of the ShaderAsset and ShaderVariantAsset, especially during hot-reload. - AZStd::sys_time_t m_buildTimestamp = 0; + AZ::u64 m_buildTimestamp = 0; }; class ShaderVariantAssetHandler final diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp index 8d439c99ab..c6fa4653c3 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Material/MaterialTypeSourceData.cpp @@ -300,48 +300,6 @@ namespace AZ } } - bool MaterialTypeSourceData::ConvertPropertyValueToSourceDataFormat([[maybe_unused]] const AZ::Name& propertyId, const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const - { - if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) - { - const uint32_t index = propertyValue.GetValue(); - if (index >= propertyDefinition.m_enumValues.size()) - { - AZ_Error("Material source data", false, "Invalid value for material enum property: '%s'.", propertyId.GetCStr()); - return false; - } - - propertyValue = propertyDefinition.m_enumValues[index]; - return true; - } - - // Image asset references must be converted from asset IDs to a relative source file path - if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image && propertyValue.Is>()) - { - const Data::Asset& imageAsset = propertyValue.GetValue>(); - - Data::AssetInfo imageAssetInfo; - if (imageAsset.GetId().IsValid()) - { - bool result = false; - AZStd::string rootFilePath; - const AZStd::string platformName = ""; // Empty for default - AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAssetInfoById, - imageAsset.GetId(), imageAsset.GetType(), platformName, imageAssetInfo, rootFilePath); - if (!result) - { - AZ_Error("Material source data", false, "Image asset could not be found for property: '%s'.", propertyId.GetCStr()); - return false; - } - } - - propertyValue = imageAssetInfo.m_relativePath; - return true; - } - - return true; - } - Outcome> MaterialTypeSourceData::CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath, bool elevateWarnings) const { MaterialTypeAssetCreator materialTypeAssetCreator; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantAssetCreator.cpp b/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantAssetCreator.cpp index e0e83cfce2..5b32edc0bf 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantAssetCreator.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Edit/Shader/ShaderVariantAssetCreator.cpp @@ -92,7 +92,7 @@ namespace AZ ///////////////////////////////////////////////////////////////////// // Methods for all shader variant types - void ShaderVariantAssetCreator::SetBuildTimestamp(AZStd::sys_time_t buildTimestamp) + void ShaderVariantAssetCreator::SetBuildTimestamp(AZ::u64 buildTimestamp) { if (ValidateIsReady()) { diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp index a2d91fefd6..7dbeac7098 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Shader/Shader.cpp @@ -202,17 +202,17 @@ namespace AZ return; } AZ_Assert(m_asset->m_shaderAssetBuildTimestamp == m_reloadedRootShaderVariantAsset->GetBuildTimestamp(), - "shaderAsset timeStamp=%lld, but Root ShaderVariantAsset timeStamp=%lld", + "shaderAsset '%s' timeStamp=%lld, but Root ShaderVariantAsset timeStamp=%lld", m_asset.GetHint().c_str(), m_asset->m_shaderAssetBuildTimestamp, m_reloadedRootShaderVariantAsset->GetBuildTimestamp()); m_asset->UpdateRootShaderVariantAsset(m_supervariantIndex, m_reloadedRootShaderVariantAsset); m_reloadedRootShaderVariantAsset = {}; // Clear the temporary reference. if (ShaderReloadDebugTracker::IsEnabled()) { - auto makeTimeString = [](AZStd::sys_time_t timestamp, AZStd::sys_time_t now) + auto makeTimeString = [](AZ::u64 timestamp, AZ::u64 now) { - AZStd::sys_time_t elapsedMicroseconds = now - timestamp; - double elapsedSeconds = aznumeric_cast(elapsedMicroseconds / 1'000'000); + AZ::u64 elapsedMillis = now - timestamp; + double elapsedSeconds = aznumeric_cast(elapsedMillis / 1'000); AZStd::string timeString = AZStd::string::format("%lld (%f seconds ago)", timestamp, elapsedSeconds); return timeString; }; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp index 442fc6a79f..ec1a65a6d5 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Reflect/Shader/ShaderVariantAsset.cpp @@ -60,7 +60,7 @@ namespace AZ } } - AZStd::sys_time_t ShaderVariantAsset::GetBuildTimestamp() const + AZ::u64 ShaderVariantAsset::GetBuildTimestamp() const { return m_buildTimestamp; } diff --git a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h index 48d404d268..0707528d7f 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h +++ b/Gems/Atom/RPI/Code/Tests/Common/RPITestFixture.h @@ -21,7 +21,7 @@ #include #include #include -#include +#include namespace UnitTest { diff --git a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake index e99e4e456b..5d67948ac8 100644 --- a/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake +++ b/Gems/Atom/RPI/Code/atom_rpi_tests_files.cmake @@ -10,8 +10,6 @@ set(FILES Tests/Buffer/BufferTests.cpp Tests/Common/AssetManagerTestFixture.cpp Tests/Common/AssetManagerTestFixture.h - Tests/Common/AssetSystemStub.cpp - Tests/Common/AssetSystemStub.h Tests/Common/ErrorMessageFinder.cpp Tests/Common/ErrorMessageFinder.h Tests/Common/ErrorMessageFinderTests.cpp diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt index e64c9b80e7..40c8d7956e 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/CMakeLists.txt @@ -61,3 +61,31 @@ ly_add_target( PRIVATE Gem::AtomToolsFramework.Static ) + +################################################################################ +# Tests +################################################################################ +if(PAL_TRAIT_BUILD_TESTS_SUPPORTED) + + ly_add_target( + NAME AtomToolsFramework.Tests ${PAL_TRAIT_TEST_TARGET_TYPE} + NAMESPACE Gem + FILES_CMAKE + atomtoolsframework_tests_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + . + Tests + BUILD_DEPENDENCIES + PRIVATE + AZ::AzTest + AZ::AzTestShared + Gem::AtomToolsFramework.Static + Gem::Atom_Utils.TestUtils.Static + ) + + ly_add_googletest( + NAME Gem::AtomToolsFramework.Tests + ) + +endif() \ No newline at end of file diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h index 333796493d..08f59f9e0b 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Util/MaterialPropertyUtil.h @@ -7,11 +7,12 @@ */ #pragma once -#include -#include #include #include #include +#include +#include +#include namespace AzToolsFramework { @@ -35,12 +36,31 @@ namespace AtomToolsFramework //! Convert and assign material property meta data fields to editor dynamic property configuration void ConvertToPropertyConfig(AtomToolsFramework::DynamicPropertyConfig& propertyConfig, const AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData); - //! Convert and assign editor dynamic property configuration fields to material property meta data + //! Convert and assign editor dynamic property configuration fields to material property meta data void ConvertToPropertyMetaData(AZ::RPI::MaterialPropertyDynamicMetadata& propertyMetaData, const AtomToolsFramework::DynamicPropertyConfig& propertyConfig); //! Compare equality of data types and values of editor property stored in AZStd::any bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB); + //! Convert the property value into the format that will be stored in the source data + //! This is primarily needed to support conversions of special types like enums and images + //! @param exportPath absolute path of the file being saved + //! @param propertyDefinition describes type information and other details about propertyValue + //! @param propertyValue the value being converted before saving + bool ConvertToExportFormat( + const AZStd::string& exportPath, + const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, + AZ::RPI::MaterialPropertyValue& propertyValue); + + //! Generate a file path from the exported file to the external reference. + //! This function returns a relative path from the export file to the reference file. + //! If the relative path is too different or distant from the export path then we return the asset folder relative path. + //! @param exportPath absolute path of the file being saved + //! @param referencePath absolute path of a file that will be treated as an external reference + //! @param maxPathDepth the maximum relative depth or number of parent or child folders between the export path and the reference path + AZStd::string GetExteralReferencePath( + const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth = 2); + //! Traverse up the instance data node hierarchy to find the containing dynamic property object const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode); } // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp index 3f8a173918..c49cd3fafb 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Util/MaterialPropertyUtil.cpp @@ -6,9 +6,10 @@ * */ -#include #include +#include +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include #include namespace AtomToolsFramework @@ -163,6 +165,88 @@ namespace AtomToolsFramework return false; } + bool ConvertToExportFormat( + const AZStd::string& exportPath, + const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition, + AZ::RPI::MaterialPropertyValue& propertyValue) + { + if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is()) + { + const uint32_t index = propertyValue.GetValue(); + if (index >= propertyDefinition.m_enumValues.size()) + { + AZ_Error("AtomToolsFramework", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str()); + return false; + } + + propertyValue = propertyDefinition.m_enumValues[index]; + return true; + } + + // Image asset references must be converted from asset IDs to a relative source file path + if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image) + { + if (propertyValue.Is>()) + { + const auto& imageAsset = propertyValue.GetValue>(); + const auto& imagePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAsset.GetId()); + propertyValue = GetExteralReferencePath(exportPath, imagePath); + return true; + } + + if (propertyValue.Is>()) + { + const auto& image = propertyValue.GetValue>(); + const auto& imagePath = image ? AZ::RPI::AssetUtils::GetSourcePathByAssetId(image->GetAssetId()) : ""; + propertyValue = GetExteralReferencePath(exportPath, imagePath); + return true; + } + } + + return true; + } + + AZStd::string GetExteralReferencePath(const AZStd::string& exportPath, const AZStd::string& referencePath, const uint32_t maxPathDepth) + { + if (referencePath.empty()) + { + return {}; + } + + AZ::IO::BasicPath exportFolder(exportPath); + exportFolder.RemoveFilename(); + + const AZStd::string relativePath = AZ::IO::PathView(referencePath).LexicallyRelative(exportFolder).StringAsPosix(); + + // Count the difference in depth between the export file path and the referenced file path. + uint32_t parentFolderCount = 0; + AZStd::string::size_type pos = 0; + const AZStd::string parentFolderToken = ".."; + while ((pos = relativePath.find(parentFolderToken, pos)) != AZStd::string::npos) + { + parentFolderCount++; + pos += parentFolderToken.length(); + } + + // If the difference in depth is too great then revert to using the asset folder relative path. + // We could change this to only use relative paths for references in subfolders. + if (parentFolderCount > maxPathDepth) + { + AZStd::string watchFolder; + AZ::Data::AssetInfo assetInfo; + bool sourceInfoFound = false; + AzToolsFramework::AssetSystemRequestBus::BroadcastResult( + sourceInfoFound, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, referencePath.c_str(), + assetInfo, watchFolder); + if (sourceInfoFound) + { + return assetInfo.m_relativePath; + } + } + + return relativePath; + } + const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode) { // Traverse up the hierarchy from the input node to search for an instance corresponding to material inspector property @@ -172,7 +256,8 @@ namespace AtomToolsFramework const AZ::SerializeContext::ClassData* classData = currentNode->GetClassMetadata(); if (context && classData) { - if (context->CanDowncast(classData->m_typeId, azrtti_typeid(), classData->m_azRtti, nullptr)) + if (context->CanDowncast( + classData->m_typeId, azrtti_typeid(), classData->m_azRtti, nullptr)) { return static_cast(currentNode->FirstInstance()); } diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp index aeca51230a..f07fd9c536 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Window/AtomToolsMainWindow.cpp @@ -50,8 +50,9 @@ namespace AtomToolsFramework void AtomToolsMainWindow::ActivateWindow() { - activateWindow(); + show(); raise(); + activateWindow(); } bool AtomToolsMainWindow::AddDockWidget(const AZStd::string& name, QWidget* widget, uint32_t area, uint32_t orientation) diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp index aee8e2a775..df16cfbc43 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Tests/AtomToolsFrameworkTest.cpp @@ -7,25 +7,71 @@ */ #include +#include +#include -class AtomToolsFrameworkTest - : public ::testing::Test +namespace UnitTest { -protected: - void SetUp() override + class AtomToolsFrameworkTest : public ::testing::Test { + protected: + void SetUp() override + { + if (!AZ::AllocatorInstance::IsReady()) + { + AZ::AllocatorInstance::Create(AZ::SystemAllocator::Descriptor()); + } - } + m_assetSystemStub.Activate(); - void TearDown() override - { + RegisterSourceAsset("objects/upgrades/materials/supercondor.material"); + RegisterSourceAsset("materials/condor.material"); + RegisterSourceAsset("materials/talisman.material"); + RegisterSourceAsset("materials/city.material"); + RegisterSourceAsset("materials/totem.material"); + RegisterSourceAsset("textures/orange.png"); + RegisterSourceAsset("textures/red.png"); + RegisterSourceAsset("textures/gold.png"); + RegisterSourceAsset("textures/fuzz.png"); + } - } -}; + void TearDown() override + { + m_assetSystemStub.Deactivate(); -TEST_F(AtomToolsFrameworkTest, SanityTest) -{ - ASSERT_TRUE(true); -} + if (AZ::AllocatorInstance::IsReady()) + { + AZ::AllocatorInstance::Destroy(); + } + } + + void RegisterSourceAsset(const AZStd::string& path) + { + const AZ::IO::BasicPath assetRootPath = AZ::IO::PathView(m_assetRoot).LexicallyNormal(); + const AZ::IO::BasicPath normalizedPath = AZ::IO::BasicPath(assetRootPath).Append(path).LexicallyNormal(); + + AZ::Data::AssetInfo assetInfo = {}; + assetInfo.m_assetId = AZ::Uuid::CreateRandom(); + assetInfo.m_relativePath = normalizedPath.LexicallyRelative(assetRootPath).StringAsPosix(); + m_assetSystemStub.RegisterSourceInfo(normalizedPath.StringAsPosix().c_str(), assetInfo, assetRootPath.StringAsPosix().c_str()); + } + + static constexpr const char* m_assetRoot = "d:/project/assets/"; + AssetSystemStub m_assetSystemStub; + }; + + TEST_F(AtomToolsFrameworkTest, GetExteralReferencePath_Succeeds) + { + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("", "", 2), ""); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/condor.material", "", 2), ""); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "", 2), ""); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "d:/project/assets/textures/gold.png", 2), "../textures/gold.png"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/materials/talisman.material", "d:/project/assets/textures/gold.png", 0), "textures/gold.png"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 3), "../../../materials/condor.material"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 2), "materials/condor.material"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 1), "materials/condor.material"); + ASSERT_EQ(AtomToolsFramework::GetExteralReferencePath("d:/project/assets/objects/upgrades/materials/supercondor.material", "d:/project/assets/materials/condor.material", 0), "materials/condor.material"); + } -AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); + AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV); +} // namespace UnitTest diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake new file mode 100644 index 0000000000..bd9ad9b3d8 --- /dev/null +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_tests_files.cmake @@ -0,0 +1,11 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + Tests/AtomToolsFrameworkTest.cpp +) \ No newline at end of file diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp index 0174871502..4ac0b745fd 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.cpp @@ -231,18 +231,13 @@ namespace MaterialEditor // create source data from properties MaterialSourceData sourceData; - sourceData.m_materialType = m_materialSourceData.m_materialType; - sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial; - - AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null."); sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); - - // Force save data to store forward slashes - AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/"); - AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); + sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(m_absolutePath, m_materialSourceData.m_materialType); + sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(m_absolutePath, m_materialSourceData.m_parentMaterial); // populate sourceData with modified or overwritten properties - const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { + const bool savedProperties = SavePropertiesToSourceData(m_absolutePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) + { return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); }); @@ -305,18 +300,13 @@ namespace MaterialEditor // create source data from properties MaterialSourceData sourceData; - sourceData.m_materialType = m_materialSourceData.m_materialType; - sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial; - - AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null."); sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); - - // Force save data to store forward slashes - AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/"); - AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); + sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_materialType); + sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_parentMaterial); // populate sourceData with modified or overwritten properties - const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { + const bool savedProperties = SavePropertiesToSourceData(normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) + { return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); }); @@ -378,23 +368,18 @@ namespace MaterialEditor // create source data from properties MaterialSourceData sourceData; - sourceData.m_materialType = m_materialSourceData.m_materialType; - - AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null."); sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion(); + sourceData.m_materialType = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_materialSourceData.m_materialType); // Only assign a parent path if the source was a .material if (AzFramework::StringFunc::Path::IsExtension(m_relativePath.c_str(), MaterialSourceData::Extension)) { - sourceData.m_parentMaterial = m_relativePath; + sourceData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(normalizedSavePath, m_absolutePath); } - // Force save data to store forward slashes - AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/"); - AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); - // populate sourceData with modified properties - const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { + const bool savedProperties = SavePropertiesToSourceData(normalizedSavePath, sourceData, [](const AtomToolsFramework::DynamicProperty& property) + { return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); }); @@ -591,7 +576,8 @@ namespace MaterialEditor } } - bool MaterialDocument::SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const + bool MaterialDocument::SavePropertiesToSourceData( + const AZStd::string& exportPath, AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const { using namespace AZ; using namespace RPI; @@ -599,7 +585,7 @@ namespace MaterialEditor bool result = true; // populate sourceData with properties that meet the filter - m_materialTypeSourceData.EnumerateProperties([this, &sourceData, &propertyFilter, &result](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { + m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { const MaterialPropertyId propertyId(groupName, propertyName); @@ -609,7 +595,7 @@ namespace MaterialEditor MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); if (propertyValue.IsValid()) { - if (!m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyId.GetFullName(), propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyId.GetFullName(), propertyDefinition, propertyValue)) { AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str()); result = false; @@ -663,8 +649,6 @@ namespace MaterialEditor return false; } - AZStd::string materialTypeSourceFilePath; - // The material document and inspector are constructed from source data if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialSourceData::Extension)) { @@ -675,13 +659,24 @@ namespace MaterialEditor return false; } - // We must also always load the material type data for a complete, ordered set of the - // groups and properties that will be needed for comparison and building the inspector - materialTypeSourceFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); - auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath); + // We always need the absolute path for the material type and parent material to load source data and resolving + // relative paths when saving. This will convert and store them as absolute paths for use within the document. + if (!m_materialSourceData.m_parentMaterial.empty()) + { + m_materialSourceData.m_parentMaterial = + AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial); + } + + if (!m_materialSourceData.m_materialType.empty()) + { + m_materialSourceData.m_materialType = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); + } + + // Load the material type source data which provides the layout and default values of all of the properties + auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_materialSourceData.m_materialType); if (!materialTypeOutcome.IsSuccess()) { - AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", materialTypeSourceFilePath.c_str()); + AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_materialSourceData.m_materialType.c_str()); return false; } m_materialTypeSourceData = materialTypeOutcome.GetValue(); @@ -694,10 +689,10 @@ namespace MaterialEditor } else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension)) { - materialTypeSourceFilePath = m_absolutePath; - - // Load the material type source data, which will be used for enumerating properties and building material source data - auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath); + // A material document can be created or loaded from material or material type source data. If we are attempting to load + // material type source data then the material source data object can be created just by referencing the document path as the + // material type path. + auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_absolutePath); if (!materialTypeOutcome.IsSuccess()) { AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_absolutePath.c_str()); @@ -705,9 +700,8 @@ namespace MaterialEditor } m_materialTypeSourceData = materialTypeOutcome.GetValue(); - // The document represents a material, not a material type. - // If the input data is a material type file we have to generate the material source data by referencing it. - m_materialSourceData.m_materialType = m_relativePath; + // We are storing absolute paths in the loaded version of the source data so that the files can be resolved at all times. + m_materialSourceData.m_materialType = m_absolutePath; m_materialSourceData.m_parentMaterial.clear(); } else @@ -751,25 +745,24 @@ namespace MaterialEditor if (!m_materialSourceData.m_parentMaterial.empty()) { AZ::RPI::MaterialSourceData parentMaterialSourceData; - const auto parentMaterialFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial); - if (!AZ::RPI::JsonUtils::LoadObjectFromFile(parentMaterialFilePath, parentMaterialSourceData)) + if (!AZ::RPI::JsonUtils::LoadObjectFromFile(m_materialSourceData.m_parentMaterial, parentMaterialSourceData)) { - AZ_Error("MaterialDocument", false, "Material parent source data could not be loaded for: '%s'.", parentMaterialFilePath.c_str()); + AZ_Error("MaterialDocument", false, "Material parent source data could not be loaded for: '%s'.", m_materialSourceData.m_parentMaterial.c_str()); return false; } - const auto parentMaterialAssetIdResult = AssetUtils::MakeAssetId(parentMaterialFilePath, 0); + const auto parentMaterialAssetIdResult = AssetUtils::MakeAssetId(m_materialSourceData.m_parentMaterial, 0); if (!parentMaterialAssetIdResult) { - AZ_Error("MaterialDocument", false, "Material parent asset ID could not be created: '%s'.", parentMaterialFilePath.c_str()); + AZ_Error("MaterialDocument", false, "Material parent asset ID could not be created: '%s'.", m_materialSourceData.m_parentMaterial.c_str()); return false; } auto parentMaterialAssetResult = parentMaterialSourceData.CreateMaterialAssetFromSourceData( - parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, elevateWarnings, true); + parentMaterialAssetIdResult.GetValue(), parentMaterialFilePath, true, true); if (!parentMaterialAssetResult) { - AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", parentMaterialFilePath.c_str()); + AZ_Error("MaterialDocument", false, "Material parent asset could not be created from source data: '%s'.", m_materialSourceData.m_parentMaterial.c_str()); return false; } @@ -880,7 +873,8 @@ namespace MaterialEditor m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); } - const MaterialFunctorSourceData::EditorContext editorContext = MaterialFunctorSourceData::EditorContext(materialTypeSourceFilePath, m_materialAsset->GetMaterialPropertiesLayout()); + const MaterialFunctorSourceData::EditorContext editorContext = + MaterialFunctorSourceData::EditorContext(m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout()); for (Ptr functorData : m_materialTypeSourceData.m_materialFunctorSourceData) { MaterialFunctorSourceData::FunctorResult result2 = functorData->CreateFunctor(editorContext); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h index 452111f99a..ceb3190f26 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Document/MaterialDocument.h @@ -104,7 +104,8 @@ namespace MaterialEditor void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) override; ////////////////////////////////////////////////////////////////////////// - bool SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const; + bool SavePropertiesToSourceData( + const AZStd::string& exportPath, AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const; bool OpenInternal(AZStd::string_view loadPath); diff --git a/Gems/Atom/Utils/Code/CMakeLists.txt b/Gems/Atom/Utils/Code/CMakeLists.txt index 89bc8dd0a5..90d7ce501b 100644 --- a/Gems/Atom/Utils/Code/CMakeLists.txt +++ b/Gems/Atom/Utils/Code/CMakeLists.txt @@ -27,6 +27,27 @@ ly_add_target( 3rdParty::libpng ) +if(PAL_TRAIT_BUILD_HOST_TOOLS) + + ly_add_target( + NAME Atom_Utils.TestUtils.Static STATIC + NAMESPACE Gem + FILES_CMAKE + atom_utils_editor_files.cmake + INCLUDE_DIRECTORIES + PRIVATE + Source + PUBLIC + Include + BUILD_DEPENDENCIES + PRIVATE + AZ::AtomCore + AZ::AzCore + AZ::AzFramework + AZ::AzToolsFramework + ) +endif() + ################################################################################ # Tests ################################################################################ diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h b/Gems/Atom/Utils/Code/Include/Atom/Utils/TestUtils/AssetSystemStub.h similarity index 100% rename from Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.h rename to Gems/Atom/Utils/Code/Include/Atom/Utils/TestUtils/AssetSystemStub.h diff --git a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp b/Gems/Atom/Utils/Code/Source/TestUtils/AssetSystemStub.cpp similarity index 98% rename from Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp rename to Gems/Atom/Utils/Code/Source/TestUtils/AssetSystemStub.cpp index 31a46e9a6f..d57969ea9c 100644 --- a/Gems/Atom/RPI/Code/Tests/Common/AssetSystemStub.cpp +++ b/Gems/Atom/Utils/Code/Source/TestUtils/AssetSystemStub.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include namespace UnitTest diff --git a/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake b/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake new file mode 100644 index 0000000000..6c4202fe09 --- /dev/null +++ b/Gems/Atom/Utils/Code/atom_utils_editor_files.cmake @@ -0,0 +1,12 @@ +# +# Copyright (c) Contributors to the Open 3D Engine Project. +# For complete copyright and license terms please see the LICENSE at the root of this distribution. +# +# SPDX-License-Identifier: Apache-2.0 OR MIT +# +# + +set(FILES + Include/Atom/Utils/TestUtils/AssetSystemStub.h + Source/TestUtils/AssetSystemStub.cpp +) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp index 8620ec34f4..d3e125426c 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/Material/EditorMaterialComponentUtil.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -97,51 +98,28 @@ namespace AZ bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData) { - // Construct the material source data object that will be exported - AZ::RPI::MaterialSourceData exportData; - - // Converting absolute material paths to relative paths - bool result = false; - AZ::Data::AssetInfo info; - AZStd::string watchFolder; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, - editData.m_materialTypeSourcePath.c_str(), info, watchFolder); - if (!result) + if (path.empty() || !editData.m_materialAsset.IsReady() || !editData.m_materialTypeAsset.IsReady() || + editData.m_materialTypeSourcePath.empty()) { - AZ_Error( - "AZ::Render::EditorMaterialComponentUtil", false, - "Failed to get material type source file info while attempting to export: %s", path.c_str()); + AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Can not export: %s", path.c_str()); return false; } - exportData.m_materialType = info.m_relativePath; - - if (!editData.m_materialParentSourcePath.empty()) - { - result = false; - AzToolsFramework::AssetSystemRequestBus::BroadcastResult( - result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, - editData.m_materialParentSourcePath.c_str(), info, watchFolder); - if (!result) - { - AZ_Error( - "AZ::Render::EditorMaterialComponentUtil", false, - "Failed to get parent material source file info while attempting to export: %s", path.c_str()); - return false; - } - - exportData.m_parentMaterial = info.m_relativePath; - } + // Construct the material source data object that will be exported + AZ::RPI::MaterialSourceData exportData; + exportData.m_materialTypeVersion = editData.m_materialTypeAsset->GetVersion(); + exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath); + exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath); // Copy all of the properties from the material asset to the source data that will be exported - result = true; - editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { + bool result = true; + editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition){ const AZ::RPI::MaterialPropertyId propertyId(groupName, propertyName); const AZ::RPI::MaterialPropertyIndex propertyIndex = editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); - AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; + AZ::RPI::MaterialPropertyValue propertyValue = + editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition.m_value; if (editData.m_materialParentAsset.IsReady()) @@ -151,12 +129,12 @@ namespace AZ // Check for and apply any property overrides before saving property values auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId.GetFullName()); - if(propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) + if (propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) { propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); } - if (!editData.m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyId.GetFullName(), propertyDefinition, propertyValue)) + if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId.GetFullName(), propertyDefinition, propertyValue)) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); result = false; diff --git a/Gems/AtomTressFX/Code/Builders/HairBuilderComponent.cpp b/Gems/AtomTressFX/Code/Builders/HairBuilderComponent.cpp index f80261f4b5..7f99e4c55f 100644 --- a/Gems/AtomTressFX/Code/Builders/HairBuilderComponent.cpp +++ b/Gems/AtomTressFX/Code/Builders/HairBuilderComponent.cpp @@ -46,14 +46,6 @@ namespace AZ { m_hairAssetBuilder.RegisterBuilder(); m_hairAssetHandler.Register(); - - // Add asset types and extensions to AssetCatalog. - auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); - if (assetCatalog) - { - assetCatalog->EnableCatalogForAsset(azrtti_typeid()); - assetCatalog->AddExtension(AMD::TFXCombinedFileExtension); - } } void HairBuilderComponent::Deactivate() diff --git a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp b/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp deleted file mode 100644 index 48973b2779..0000000000 --- a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp +++ /dev/null @@ -1,612 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "MaterialBuilderComponent.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace MaterialBuilder -{ - [[maybe_unused]] const char s_materialBuilder[] = "MaterialBuilder"; - - namespace Internal - { - const char g_nodeNameMaterial[] = "Material"; - const char g_nodeNameSubmaterial[] = "SubMaterials"; - const char g_nodeNameTexture[] = "Texture"; - const char g_nodeNameTextures[] = "Textures"; - const char g_attributeFileName[] = "File"; - - const int g_numSourceImageFormats = 9; - const char* g_sourceImageFormats[g_numSourceImageFormats] = { ".tif", ".tiff", ".bmp", ".gif", ".jpg", ".jpeg", ".tga", ".png", ".dds" }; - bool IsSupportedImageExtension(const AZStd::string& extension) - { - for (const char* format : g_sourceImageFormats) - { - if (extension == format) - { - return true; - } - } - return false; - } - - // Cleans up legacy pathing from older materials - const char* CleanLegacyPathingFromTexturePath(const char* texturePath) - { - // Copied from MaterialHelpers::SetTexturesFromXml, line 459 - // legacy. Some textures used to be referenced using "engine\\" or "engine/" - this is no longer valid - if ( - (strlen(texturePath) > 7) && - (azstrnicmp(texturePath, "engine", 6) == 0) && - ((texturePath[6] == '\\') || (texturePath[6] == '/')) - ) - { - texturePath = texturePath + 7; - } - - // legacy: Files were saved into a mtl with many leading forward or back slashes, we eat them all here. We want it to start with a relative path. - const char* actualFileName = texturePath; - while ((actualFileName[0]) && ((actualFileName[0] == '\\') || (actualFileName[0] == '/'))) - { - ++actualFileName; - } - return actualFileName; - } - - // Parses the material XML for all texture paths - AZ::Outcome GetTexturePathsFromMaterial(AZ::rapidxml::xml_node* materialNode, AZStd::vector& paths) - { - AZ::Outcome resultOutcome = AZ::Failure(AZStd::string("")); - AZStd::string success_with_warning_message; - - // check if this material has a set of textures defined, and if so, grab all the paths from the textures - AZ::rapidxml::xml_node* texturesNode = materialNode->first_node(g_nodeNameTextures); - if (texturesNode) - { - AZ::rapidxml::xml_node* textureNode = texturesNode->first_node(g_nodeNameTexture); - // it is possible for an empty node to exist for things like collision materials, so check - // to make sure that there is at least one child node before starting to iterate. - if (textureNode) - { - do - { - AZ::rapidxml::xml_attribute* fileAttribute = textureNode->first_attribute(g_attributeFileName); - if (!fileAttribute) - { - success_with_warning_message = "Texture node exists but does not have a file attribute defined"; - } - else - { - const char* rawTexturePath = fileAttribute->value(); - // do an initial clean-up of the path taken from the file, similar to MaterialHelpers::SetTexturesFromXml - AZStd::string texturePath = CleanLegacyPathingFromTexturePath(rawTexturePath); - paths.emplace_back(AZStd::move(texturePath)); - } - - textureNode = textureNode->next_sibling(g_nodeNameTexture); - } while (textureNode); - } - } - - // check to see if this material has sub materials defined. If so, recurse into this function for each sub material - AZ::rapidxml::xml_node* subMaterialsNode = materialNode->first_node(g_nodeNameSubmaterial); - if (subMaterialsNode) - { - AZ::rapidxml::xml_node* subMaterialNode = subMaterialsNode->first_node(g_nodeNameMaterial); - if (subMaterialNode == nullptr) - { - // this is a malformed material as there is no material node child in the SubMaterials node, so error out - return AZ::Failure(AZStd::string("SubMaterials node exists but does not have any child Material nodes.")); - } - - do - { - // grab the texture paths from the submaterial, or error out if necessary - AZ::Outcome subMaterialTexturePathsResult = GetTexturePathsFromMaterial(subMaterialNode, paths); - if (!subMaterialTexturePathsResult.IsSuccess()) - { - return subMaterialTexturePathsResult; - } - else if (!subMaterialTexturePathsResult.GetValue().empty()) - { - success_with_warning_message = subMaterialTexturePathsResult.GetValue(); - } - - subMaterialNode = subMaterialNode->next_sibling(g_nodeNameMaterial); - } while (subMaterialNode); - } - - if (texturesNode == nullptr && subMaterialsNode == nullptr) - { - return AZ::Failure(AZStd::string("Failed to find a Textures node or SubMaterials node in this material. At least one of these must exist to be able to gather texture dependencies.")); - } - - if (!success_with_warning_message.empty()) - { - return AZ::Success(success_with_warning_message); - } - return AZ::Success(AZStd::string()); - } - - // find a sequence of digits with a string starting from lastDigitIndex, and try to parse that sequence to and int - // and store it in outAnimIndex. - bool ParseFilePathForCompleteNumber(const AZStd::string& filePath, int& lastDigitIndex, int& outAnimIndex) - { - int firstAnimIndexDigit = lastDigitIndex; - while (isdigit(static_cast(filePath[lastDigitIndex]))) - { - ++lastDigitIndex; - } - if (!AzFramework::StringFunc::LooksLikeInt(filePath.substr(firstAnimIndexDigit, lastDigitIndex - firstAnimIndexDigit).c_str(), &outAnimIndex)) - { - return false; - } - return true; - } - - // Parse the texture path for a texture animation to determine the actual names of the textures to resolve that - // make up the entire sequence. - AZ::Outcome GetAllTexturesInTextureSequence(const AZStd::string& path, AZStd::vector& texturesInSequence) - { - // Taken from CShaderMan::mfReadTexSequence - // All comments next to variable declarations in this function are the original variable names in - // CShaderMan::mfReadTexSequence, to help keep track of how these variables relate to the original function - AZStd::string prefix; - AZStd::string postfix; - - AZStd::string filePath = path; // name - AZStd::string extension; // ext - AzFramework::StringFunc::Path::GetExtension(filePath.c_str(), extension); - AzFramework::StringFunc::Path::StripExtension(filePath); - - // unsure if it is actually possible to enter here or the original version with '$' as the indicator - // for texture sequences, but they check for both just in case, so this will match the behavior. - char separator = '#'; // chSep - int firstSeparatorIndex = static_cast(filePath.find(separator)); - if (firstSeparatorIndex == AZStd::string::npos) - { - firstSeparatorIndex = static_cast(filePath.find('$')); - if (firstSeparatorIndex == AZStd::string::npos) - { - return AZ::Failure(AZStd::string("Failed to find separator '#' or '$' in texture path.")); - } - separator = '$'; - } - - // we don't actually care about getting the speed of the animation, so just remove everything from the - // end of the string starting with the last open parenthesis - size_t speedStartIndex = filePath.find_last_of('('); - if (speedStartIndex != AZStd::string::npos) - { - AzFramework::StringFunc::LKeep(filePath, speedStartIndex); - AzFramework::StringFunc::Append(filePath, '\0'); - } - - // try to find where the digits start after the separator (there can be any number of separators - // between the texture name prefix and where the digit range starts) - int firstAnimIndexDigit = -1; // m - int numSeparators = 0; // j - for (int stringIndex = firstSeparatorIndex; stringIndex < filePath.length(); ++stringIndex) - { - if (filePath[stringIndex] == separator) - { - ++numSeparators; - if (firstSeparatorIndex == -1) - { - firstSeparatorIndex = stringIndex; - } - } - else if (firstSeparatorIndex > 0 && firstAnimIndexDigit < 0) - { - firstAnimIndexDigit = stringIndex; - break; - } - } - if (numSeparators == 0) - { - return AZ::Failure(AZStd::string("Failed to find separator '#' or '$' in texture path.")); - } - - // store off everything before the separator - prefix = AZStd::move(filePath.substr(0, firstSeparatorIndex)); - - int startAnimIndex = 0; // startn - int endAnimIndex = 0; // endn - // we only found the separator, but no indexes, so just assume its 0 - 999 - if (firstAnimIndexDigit < 0) - { - startAnimIndex = 0; - endAnimIndex = 999; - } - else - { - // find the length of the first index, then parse that to an int - int lastDigitIndex = firstAnimIndexDigit; - if (!ParseFilePathForCompleteNumber(filePath, lastDigitIndex, startAnimIndex)) - { - return AZ::Failure(AZStd::string("Failed to determine first index of the sequence after the separators in texture path.")); - } - - // reset to the start of the next index - ++lastDigitIndex; - - // find the length of the end index, then parse that to an int - if (!ParseFilePathForCompleteNumber(filePath, lastDigitIndex, endAnimIndex)) - { - return AZ::Failure(AZStd::string("Failed to determine last index of the sequence after the first index of the sequence in texture path.")); - } - - // save off the rest of the string - postfix = AZStd::move(filePath.substr(lastDigitIndex)); - } - - int numTextures = endAnimIndex - startAnimIndex + 1; - const char* textureNameFormat = "%s%.*d%s%s"; // prefix, num separators (number of digits), sequence index, postfix, extension) - for (int sequenceIndex = 0; sequenceIndex < numTextures; ++sequenceIndex) - { - texturesInSequence.emplace_back(AZStd::move(AZStd::string::format(textureNameFormat, prefix.c_str(), numSeparators, startAnimIndex + sequenceIndex, postfix.c_str(), extension.c_str()))); - } - - return AZ::Success(); - } - - // Determine which product path to use based on the path stored in the texture, and make it relative to - // the cache. - bool ResolveMaterialTexturePath(const AZStd::string& path, AZStd::string& outPath) - { - AZStd::string aliasedPath = path; - - //if its a source image format try to load the dds - AZStd::string extension; - bool hasExtension = AzFramework::StringFunc::Path::GetExtension(path.c_str(), extension); - - // Replace all supported extensions with DDS if it has an extension. If the extension exists but is not supported, fail out. - if (hasExtension && IsSupportedImageExtension(extension)) - { - AzFramework::StringFunc::Path::ReplaceExtension(aliasedPath, ".dds"); - } - else if (hasExtension) - { - AZ_Warning(s_materialBuilder, false, "Failed to resolve texture path %s as the path is not to a supported texture format. Please make sure that textures in materials are formats supported by Open 3D Engine.", aliasedPath.c_str()); - return false; - } - - AZStd::to_lower(aliasedPath.begin(), aliasedPath.end()); - AzFramework::StringFunc::Path::Normalize(aliasedPath); - - AZStd::string currentFolderSpecifier = AZStd::string::format(".%c", AZ_CORRECT_FILESYSTEM_SEPARATOR); - if (AzFramework::StringFunc::StartsWith(aliasedPath, currentFolderSpecifier)) - { - AzFramework::StringFunc::Strip(aliasedPath, currentFolderSpecifier.c_str(), false, true); - } - - AZStd::string resolvedPath; - char fullPathBuffer[AZ_MAX_PATH_LEN] = {}; - // if there is an alias already at the front of the path, resolve it, and try to make it relative to the - // cache (@products@). If it can't, then error out. - // This case handles the possibility of aliases existing in texture paths in materials that is still supported - // by the legacy loading code, however it is not currently used, so the else path is always taken. - if (aliasedPath[0] == '@') - { - if (!AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(aliasedPath.c_str(), fullPathBuffer, AZ_MAX_PATH_LEN)) - { - AZ_Warning(s_materialBuilder, false, "Failed to resolve the alias in texture path %s. Please make sure all aliases are registered with the engine.", aliasedPath.c_str()); - return false; - } - resolvedPath = fullPathBuffer; - AzFramework::StringFunc::Path::Normalize(resolvedPath); - if (!AzFramework::StringFunc::Replace(resolvedPath, AZ::IO::FileIOBase::GetDirectInstance()->GetAlias("@products@"), "")) - { - AZ_Warning(s_materialBuilder, false, "Failed to resolve aliased texture path %s to be relative to the asset cache. Please make sure this alias resolves to a path within the asset cache.", aliasedPath.c_str()); - return false; - } - } - else - { - resolvedPath = AZStd::move(aliasedPath); - } - - // AP deferred path resolution requires UNIX separators and no leading separators, so clean up and convert here - if (AzFramework::StringFunc::StartsWith(resolvedPath, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING)) - { - AzFramework::StringFunc::Strip(resolvedPath, AZ_CORRECT_FILESYSTEM_SEPARATOR, false, true); - } - AzFramework::StringFunc::Replace(resolvedPath, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING, "/"); - - outPath = AZStd::move(resolvedPath); - return true; - } - - } - - BuilderPluginComponent::BuilderPluginComponent() - { - } - - BuilderPluginComponent::~BuilderPluginComponent() - { - } - - void BuilderPluginComponent::Init() - { - } - - void BuilderPluginComponent::Activate() - { - // Register material builder - AssetBuilderSDK::AssetBuilderDesc builderDescriptor; - builderDescriptor.m_name = "MaterialBuilderWorker"; - builderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.mtl", AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard)); - builderDescriptor.m_busId = MaterialBuilderWorker::GetUUID(); - builderDescriptor.m_version = 5; - builderDescriptor.m_createJobFunction = AZStd::bind(&MaterialBuilderWorker::CreateJobs, &m_materialBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - builderDescriptor.m_processJobFunction = AZStd::bind(&MaterialBuilderWorker::ProcessJob, &m_materialBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2); - - // (optimization) this builder does not emit source dependencies: - builderDescriptor.m_flags |= AssetBuilderSDK::AssetBuilderDesc::BF_EmitsNoDependencies; - - m_materialBuilder.BusConnect(builderDescriptor.m_busId); - - EBUS_EVENT(AssetBuilderSDK::AssetBuilderBus, RegisterBuilderInformation, builderDescriptor); - } - - void BuilderPluginComponent::Deactivate() - { - m_materialBuilder.BusDisconnect(); - } - - void BuilderPluginComponent::Reflect([[maybe_unused]] AZ::ReflectContext* context) - { - if (AZ::SerializeContext* serializeContext = azrtti_cast(context)) - { - serializeContext->Class() - ->Version(1) - ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector({ AssetBuilderSDK::ComponentTags::AssetBuilder })); - } - } - - MaterialBuilderWorker::MaterialBuilderWorker() - { - } - MaterialBuilderWorker::~MaterialBuilderWorker() - { - } - - void MaterialBuilderWorker::ShutDown() - { - // This will be called on a different thread than the process job thread - m_isShuttingDown = true; - } - - // This happens early on in the file scanning pass. - // This function should always create the same jobs and not do any checking whether the job is up to date. - void MaterialBuilderWorker::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response) - { - if (m_isShuttingDown) - { - response.m_result = AssetBuilderSDK::CreateJobsResultCode::ShuttingDown; - return; - } - - for (const AssetBuilderSDK::PlatformInfo& info : request.m_enabledPlatforms) - { - AssetBuilderSDK::JobDescriptor descriptor; - descriptor.m_jobKey = "Material Builder Job"; - descriptor.SetPlatformIdentifier(info.m_identifier.c_str()); - descriptor.m_priority = 8; // meshes are more important (at 10) but mats are still pretty important. - response.m_createJobOutputs.push_back(descriptor); - } - - response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success; - } - - // The request will contain the CreateJobResponse you constructed earlier, including any keys and - // values you placed into the hash table - void MaterialBuilderWorker::ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response) - { - AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Starting Job.\n"); - AZStd::string fileName; - AzFramework::StringFunc::Path::GetFullFileName(request.m_fullPath.c_str(), fileName); - AZStd::string destPath; - - // Do all work inside the tempDirPath. - AzFramework::StringFunc::Path::ConstructFull(request.m_tempDirPath.c_str(), fileName.c_str(), destPath, true); - - AZ::IO::LocalFileIO fileIO; - if (!m_isShuttingDown && fileIO.Copy(request.m_fullPath.c_str(), destPath.c_str()) == AZ::IO::ResultCode::Success) - { - // Push assets back into the response's product list - // Assets you created in your temp path can be specified using paths relative to the temp path - // since that is assumed where you're writing stuff. - AZStd::string relPath = destPath; - AssetBuilderSDK::ProductPathDependencySet dependencyPaths; - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; - AssetBuilderSDK::JobProduct jobProduct(fileName); - - bool dependencyResult = GatherProductDependencies(request.m_fullPath, dependencyPaths); - if (dependencyResult) - { - jobProduct.m_pathDependencies = AZStd::move(dependencyPaths); - jobProduct.m_dependenciesHandled = true; // We've output the dependencies immediately above so it's OK to tell the AP we've handled dependencies - } - else - { - AZ_Error(s_materialBuilder, false, "Dependency gathering for %s failed.", request.m_fullPath.c_str()); - } - response.m_outputProducts.push_back(jobProduct); - } - else - { - if (m_isShuttingDown) - { - AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Cancelled job %s because shutdown was requested.\n", request.m_fullPath.c_str()); - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled; - } - else - { - AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Error during processing job %s.\n", request.m_fullPath.c_str()); - response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; - } - } - } - - bool MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial(const AZStd::string& path, AZStd::vector& resolvedPaths) - { - if (!AZ::IO::SystemFile::Exists(path.c_str())) - { - AZ_Error(s_materialBuilder, false, "Failed to find material at path %s. Please make sure this material exists on disk.", path.c_str()); - return false; - } - - uint64_t fileSize = AZ::IO::SystemFile::Length(path.c_str()); - if (fileSize == 0) - { - AZ_Error(s_materialBuilder, false, "Material at path %s is an empty file. Please make sure this material was properly saved to disk.", path.c_str()); - return false; - } - - AZStd::vector buffer(fileSize + 1); - buffer[fileSize] = 0; - if (!AZ::IO::SystemFile::Read(path.c_str(), buffer.data())) - { - AZ_Error(s_materialBuilder, false, "Failed to read material at path %s. Please make sure the file is not open or being edited by another program.", path.c_str()); - return false; - } - - AZ::rapidxml::xml_document* xmlDoc = azcreate(AZ::rapidxml::xml_document, (), AZ::SystemAllocator, "Mtl builder temp XML Reader"); - if (!xmlDoc->parse(buffer.data())) - { - azdestroy(xmlDoc, AZ::SystemAllocator, AZ::rapidxml::xml_document); - AZ_Error(s_materialBuilder, false, "Failed to parse material at path %s into XML. Please make sure that the material was properly saved to disk.", path.c_str()); - return false; - } - - // if the first node in this file isn't a material, this must not actually be a material so it can't have deps - AZ::rapidxml::xml_node* rootNode = xmlDoc->first_node(Internal::g_nodeNameMaterial); - if (!rootNode) - { - azdestroy(xmlDoc, AZ::SystemAllocator, AZ::rapidxml::xml_document); - AZ_Error(s_materialBuilder, false, "Failed to find root material node for material at path %s. Please make sure that the material was properly saved to disk.", path.c_str()); - return false; - } - - AZStd::vector texturePaths; - // gather all textures in the material file - AZ::Outcome texturePathsResult = Internal::GetTexturePathsFromMaterial(rootNode, texturePaths); - if (!texturePathsResult.IsSuccess()) - { - azdestroy(xmlDoc, AZ::SystemAllocator, AZ::rapidxml::xml_document); - AZ_Error(s_materialBuilder, false, "Failed to gather dependencies for %s as the material file is malformed. %s", path.c_str(), texturePathsResult.GetError().c_str()); - return false; - } - else if (!texturePathsResult.GetValue().empty()) - { - AZ_Warning(s_materialBuilder, false, "Some nodes in material %s could not be read as the material is malformed. %s. Some dependencies might not be reported correctly. Please make sure that the material was properly saved to disk.", path.c_str(), texturePathsResult.GetValue().c_str()); - } - azdestroy(xmlDoc, AZ::SystemAllocator, AZ::rapidxml::xml_document); - - // fail this if there are absolute paths. - for (const AZStd::string& texPath : texturePaths) - { - if (AZ::IO::PathView(texPath).IsAbsolute()) - { - AZ_Warning(s_materialBuilder, false, "Skipping resolving of texture path %s in material %s as the texture path is an absolute path. Please update the texture path to be relative to the asset cache.", texPath.c_str(), path.c_str()); - texturePaths.erase(AZStd::find(texturePaths.begin(), texturePaths.end(), texPath)); - } - } - - // for each path in the array, split any texture animation entry up into the individual files and add each to the list. - for (const AZStd::string& texPath : texturePaths) - { - if (texPath.find('#') != AZStd::string::npos) - { - AZStd::vector actualTexturePaths; - AZ::Outcome parseTextureSequenceResult = Internal::GetAllTexturesInTextureSequence(texPath, actualTexturePaths); - if (parseTextureSequenceResult.IsSuccess()) - { - texturePaths.erase(AZStd::find(texturePaths.begin(), texturePaths.end(), texPath)); - texturePaths.insert(texturePaths.end(), actualTexturePaths.begin(), actualTexturePaths.end()); - } - else - { - texturePaths.erase(AZStd::find(texturePaths.begin(), texturePaths.end(), texPath)); - AZ_Warning(s_materialBuilder, false, "Failed to parse texture sequence %s when trying to gather dependencies for %s. %s Please make sure the texture sequence path is formatted correctly. Registering dependencies for the texture sequence will be skipped.", texPath.c_str(), path.c_str(), parseTextureSequenceResult.GetError().c_str()); - } - } - } - - // for each texture in the file - for (const AZStd::string& texPath : texturePaths) - { - // if the texture path starts with a '$' then it is a special runtime defined texture, so it it doesn't have - // an actual asset on disk to depend on. If the texture path doesn't have an extension, then it is a texture - // that is determined at runtime (such as 'nearest_cubemap'), so also ignore those, as other things pull in - // those dependencies. - if (AzFramework::StringFunc::StartsWith(texPath, "$") || !AzFramework::StringFunc::Path::HasExtension(texPath.c_str())) - { - continue; - } - - // resolve the path in the file. - AZStd::string resolvedPath; - if (!Internal::ResolveMaterialTexturePath(texPath, resolvedPath)) - { - AZ_Warning(s_materialBuilder, false, "Failed to resolve texture path %s to a product path when gathering dependencies for %s. Registering dependencies on this texture path will be skipped.", texPath.c_str(), path.c_str()); - continue; - } - - resolvedPaths.emplace_back(AZStd::move(resolvedPath)); - } - - return true; - } - - bool MaterialBuilderWorker::PopulateProductDependencyList(AZStd::vector& resolvedPaths, AssetBuilderSDK::ProductPathDependencySet& dependencies) - { - for (const AZStd::string& texturePath : resolvedPaths) - { - if (texturePath.empty()) - { - AZ_Warning(s_materialBuilder, false, "Resolved path is empty.\n"); - return false; - } - - dependencies.emplace(texturePath, AssetBuilderSDK::ProductPathDependencyType::ProductFile); - } - return true; - } - - bool MaterialBuilderWorker::GatherProductDependencies(const AZStd::string& path, AssetBuilderSDK::ProductPathDependencySet& dependencies) - { - AZStd::vector resolvedTexturePaths; - if (!GetResolvedTexturePathsFromMaterial(path, resolvedTexturePaths)) - { - return false; - } - - if (!PopulateProductDependencyList(resolvedTexturePaths, dependencies)) - { - AZ_Warning(s_materialBuilder, false, "Failed to populate dependency list for material %s with possible variants for textures.", path.c_str()); - } - - return true; - } - - AZ::Uuid MaterialBuilderWorker::GetUUID() - { - return AZ::Uuid::CreateString("{258D34AC-12F8-4196-B535-3206D8E7287B}"); - } -} diff --git a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.h b/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.h deleted file mode 100644 index a7813cf0bd..0000000000 --- a/Gems/LmbrCentral/Code/Source/Builders/MaterialBuilder/MaterialBuilderComponent.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include - -namespace MaterialBuilder -{ - //! Material builder is responsible for building material files - class MaterialBuilderWorker - : public AssetBuilderSDK::AssetBuilderCommandBus::Handler - { - public: - MaterialBuilderWorker(); - ~MaterialBuilderWorker(); - - //! Asset Builder Callback Functions - void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request, AssetBuilderSDK::CreateJobsResponse& response); - void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request, AssetBuilderSDK::ProcessJobResponse& response); - - //!AssetBuilderSDK::AssetBuilderCommandBus interface - void ShutDown() override; - - //! Returns the UUID for this builder - static AZ::Uuid GetUUID(); - - bool GetResolvedTexturePathsFromMaterial(const AZStd::string& path, AZStd::vector& resolvedPaths); - bool PopulateProductDependencyList(AZStd::vector& resolvedPaths, AssetBuilderSDK::ProductPathDependencySet& dependencies); - - private: - bool GatherProductDependencies(const AZStd::string& path, AssetBuilderSDK::ProductPathDependencySet& dependencies); - - bool m_isShuttingDown = false; - }; - - class BuilderPluginComponent - : public AZ::Component - { - public: - AZ_COMPONENT(BuilderPluginComponent, "{4D1A4B0C-54CE-4397-B8AE-ADD08898C2CD}") - static void Reflect(AZ::ReflectContext* context); - - BuilderPluginComponent(); - - ////////////////////////////////////////////////////////////////////////// - // AZ::Component - virtual void Init(); // create objects, allocate memory and initialize yourself without reaching out to the outside world - virtual void Activate(); // reach out to the outside world and connect up to what you need to, register things, etc. - virtual void Deactivate(); // unregister things, disconnect from the outside world - ////////////////////////////////////////////////////////////////////////// - - virtual ~BuilderPluginComponent(); // free memory an uninitialize yourself. - - private: - MaterialBuilderWorker m_materialBuilder; - }; -} diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp index 027d19fdef..ad90c16f43 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentral.cpp @@ -38,9 +38,6 @@ #include "Geometry/GeometrySystemComponent.h" #include -// Unhandled asset types -// Material -#include "Unhandled/Material/MaterialAssetTypeInfo.h" // Other #include "Unhandled/Other/AudioAssetTypeInfo.h" #include "Unhandled/Other/CharacterPhysicsAssetTypeInfo.h" @@ -353,8 +350,6 @@ namespace LmbrCentral // Add asset types and extensions to AssetCatalog. Uses "AssetCatalogService". if (auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler(); assetCatalog) { - assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); - assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); assetCatalog->EnableCatalogForAsset(AZ::AzTypeInfo::Uuid()); @@ -364,24 +359,12 @@ namespace LmbrCentral assetCatalog->AddExtension("dds"); assetCatalog->AddExtension("caf"); assetCatalog->AddExtension("xml"); - assetCatalog->AddExtension("mtl"); - assetCatalog->AddExtension("dccmtl"); assetCatalog->AddExtension("sprite"); assetCatalog->AddExtension("cax"); } AZ::Data::AssetManagerNotificationBus::Handler::BusConnect(); - - // Register unhandled asset type info - // Material - auto materialAssetTypeInfo = aznew MaterialAssetTypeInfo(); - materialAssetTypeInfo->Register(); - m_unhandledAssetInfo.emplace_back(materialAssetTypeInfo); - // DCC Material - auto dccMaterialAssetTypeInfo = aznew DccMaterialAssetTypeInfo(); - dccMaterialAssetTypeInfo->Register(); - m_unhandledAssetInfo.emplace_back(dccMaterialAssetTypeInfo); // Other auto audioAssetTypeInfo = aznew AudioAssetTypeInfo(); audioAssetTypeInfo->Register(); diff --git a/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp b/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp index 511bf98582..61b8c8f73d 100644 --- a/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp +++ b/Gems/LmbrCentral/Code/Source/LmbrCentralEditor.cpp @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include "Builders/CopyDependencyBuilder/CopyDependencyBuilderComponent.h" @@ -84,7 +83,6 @@ namespace LmbrCentral CopyDependencyBuilder::CopyDependencyBuilderComponent::CreateDescriptor(), DependencyBuilder::DependencyBuilderComponent::CreateDescriptor(), LevelBuilder::LevelBuilderComponent::CreateDescriptor(), - MaterialBuilder::BuilderPluginComponent::CreateDescriptor(), SliceBuilder::BuilderPluginComponent::CreateDescriptor(), TranslationBuilder::BuilderPluginComponent::CreateDescriptor(), LuaBuilder::BuilderPluginComponent::CreateDescriptor(), diff --git a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp b/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp deleted file mode 100644 index 24bc43740d..0000000000 --- a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "MaterialAssetTypeInfo.h" - -#include - -namespace LmbrCentral -{ - // MaterialAssetTypeInfo - - MaterialAssetTypeInfo::~MaterialAssetTypeInfo() - { - Unregister(); - } - - void MaterialAssetTypeInfo::Register() - { - AZ::AssetTypeInfoBus::Handler::BusConnect(AZ::AzTypeInfo::Uuid()); - } - - void MaterialAssetTypeInfo::Unregister() - { - AZ::AssetTypeInfoBus::Handler::BusDisconnect(AZ::AzTypeInfo::Uuid()); - } - - AZ::Data::AssetType MaterialAssetTypeInfo::GetAssetType() const - { - return AZ::AzTypeInfo::Uuid(); - } - - const char* MaterialAssetTypeInfo::GetAssetTypeDisplayName() const - { - return "Material"; - } - - const char* MaterialAssetTypeInfo::GetGroup() const - { - return "Material"; - } - - const char* MaterialAssetTypeInfo::GetBrowserIcon() const - { - return "Icons/Components/Decal.svg"; - } - - // DccMaterialAssetTypeInfo - - DccMaterialAssetTypeInfo::~DccMaterialAssetTypeInfo() - { - Unregister(); - } - - void DccMaterialAssetTypeInfo::Register() - { - AZ::AssetTypeInfoBus::Handler::BusConnect(AZ::AzTypeInfo::Uuid()); - } - - void DccMaterialAssetTypeInfo::Unregister() - { - AZ::AssetTypeInfoBus::Handler::BusDisconnect(AZ::AzTypeInfo::Uuid()); - } - - AZ::Data::AssetType DccMaterialAssetTypeInfo::GetAssetType() const - { - return AZ::AzTypeInfo::Uuid(); - } - - const char* DccMaterialAssetTypeInfo::GetAssetTypeDisplayName() const - { - return "DccMaterial"; - } - - const char* DccMaterialAssetTypeInfo::GetGroup() const - { - return "DccMaterial"; - } - - const char* DccMaterialAssetTypeInfo::GetBrowserIcon() const - { - return "Icons/Components/Decal.svg"; - } -} // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h b/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h deleted file mode 100644 index 2eafa31b41..0000000000 --- a/Gems/LmbrCentral/Code/Source/Unhandled/Material/MaterialAssetTypeInfo.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ -#pragma once - -#include - -namespace LmbrCentral -{ - class MaterialAssetTypeInfo - : public AZ::AssetTypeInfoBus::Handler - { - public: - - AZ_CLASS_ALLOCATOR(MaterialAssetTypeInfo, AZ::SystemAllocator, 0); - - ~MaterialAssetTypeInfo() override; - - ////////////////////////////////////////////////////////////////////////////////////////////// - // AZ::AssetTypeInfoBus::Handler - AZ::Data::AssetType GetAssetType() const override; - const char* GetAssetTypeDisplayName() const override; - const char* GetGroup() const override; - const char* GetBrowserIcon() const override; - ////////////////////////////////////////////////////////////////////////////////////////////// - - void Register(); - void Unregister(); - }; - - class DccMaterialAssetTypeInfo - : public AZ::AssetTypeInfoBus::Handler - { - public: - - AZ_CLASS_ALLOCATOR(DccMaterialAssetTypeInfo, AZ::SystemAllocator, 0); - - ~DccMaterialAssetTypeInfo() override; - - ////////////////////////////////////////////////////////////////////////////////////////////// - // AZ::AssetTypeInfoBus::Handler - AZ::Data::AssetType GetAssetType() const override; - const char* GetAssetTypeDisplayName() const override; - const char* GetGroup() const override; - const char* GetBrowserIcon() const override; - ////////////////////////////////////////////////////////////////////////////////////////////// - - void Register(); - void Unregister(); - }; -} // namespace LmbrCentral diff --git a/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp b/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp deleted file mode 100644 index 3786ef7565..0000000000 --- a/Gems/LmbrCentral/Code/Tests/Builders/MaterialBuilderTests.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace UnitTest -{ - using namespace MaterialBuilder; - using namespace AZ; - - class MaterialBuilderTests - : public UnitTest::AllocatorsTestFixture - , public UnitTest::TraceBusRedirector - { - protected: - void SetUp() override - { - UnitTest::AllocatorsTestFixture::SetUp(); - - m_app.reset(aznew AzToolsFramework::ToolsApplication); - m_app->Start(AZ::ComponentApplication::Descriptor()); - // Without this, the user settings component would attempt to save on finalize/shutdown. Since the file is - // shared across the whole engine, if multiple tests are run in parallel, the saving could cause a crash - // in the unit tests. - AZ::UserSettingsComponentRequestBus::Broadcast(&AZ::UserSettingsComponentRequests::DisableSaveOnFinalize); - AZ::Debug::TraceMessageBus::Handler::BusConnect(); - - const AZStd::string engineRoot = AZ::Test::GetEngineRootPath(); - AZ::IO::FileIOBase::GetInstance()->SetAlias("@engroot@", engineRoot.c_str()); - - AZ::IO::Path assetRoot(AZ::Utils::GetProjectPath()); - assetRoot /= "Cache"; - AZ::IO::FileIOBase::GetInstance()->SetAlias("@products@", assetRoot.c_str()); - } - - void TearDown() override - { - AZ::Debug::TraceMessageBus::Handler::BusDisconnect(); - m_app->Stop(); - m_app.reset(); - - UnitTest::AllocatorsTestFixture::TearDown(); - } - - AZStd::string GetTestFileAliasedPath(AZStd::string_view fileName) - { - constexpr char testFileFolder[] = "@engroot@/Gems/LmbrCentral/Code/Tests/Materials/"; - return AZStd::string::format("%s%.*s", testFileFolder, aznumeric_cast(fileName.size()), fileName.data()); - } - - AZStd::string GetTestFileFullPath(AZStd::string_view fileName) - { - AZStd::string aliasedPath = GetTestFileAliasedPath(fileName); - char resolvedPath[AZ_MAX_PATH_LEN]; - AZ::IO::FileIOBase::GetInstance()->ResolvePath(aliasedPath.c_str(), resolvedPath, AZ_MAX_PATH_LEN); - return AZStd::string(resolvedPath); - } - - void TestFailureCase(AZStd::string_view fileName, [[maybe_unused]] int expectedErrorCount) - { - MaterialBuilderWorker worker; - AZStd::vector resolvedPaths; - - AZStd::string absoluteMatPath = GetTestFileFullPath(fileName); - - AZ_TEST_START_ASSERTTEST; - ASSERT_FALSE(worker.GetResolvedTexturePathsFromMaterial(absoluteMatPath, resolvedPaths)); - AZ_TEST_STOP_ASSERTTEST(expectedErrorCount * 2); // The assert tests double count AZ errors, so just multiply expected count by 2 - ASSERT_EQ(resolvedPaths.size(), 0); - } - - void TestSuccessCase(AZStd::string_view fileName, AZStd::vector& expectedTextures) - { - MaterialBuilderWorker worker; - AZStd::vector resolvedPaths; - size_t texturesInMaterialFile = expectedTextures.size(); - - AZStd::string absoluteMatPath = GetTestFileFullPath(fileName); - ASSERT_TRUE(worker.GetResolvedTexturePathsFromMaterial(absoluteMatPath, resolvedPaths)); - ASSERT_EQ(resolvedPaths.size(), texturesInMaterialFile); - if (texturesInMaterialFile > 0) - { - ASSERT_THAT(resolvedPaths, testing::ElementsAreArray(expectedTextures)); - - AssetBuilderSDK::ProductPathDependencySet dependencies; - ASSERT_TRUE(worker.PopulateProductDependencyList(resolvedPaths, dependencies)); - ASSERT_EQ(dependencies.size(), texturesInMaterialFile); - } - } - - void TestSuccessCase(AZStd::string_view fileName, const char* expectedTexture) - { - AZStd::vector expectedTextures; - expectedTextures.push_back(expectedTexture); - TestSuccessCase(fileName, expectedTextures); - } - - void TestSuccessCaseNoDependencies(AZStd::string_view fileName) - { - AZStd::vector expectedTextures; - TestSuccessCase(fileName, expectedTextures); - } - - AZStd::unique_ptr m_app; - }; - - TEST_F(MaterialBuilderTests, MaterialBuilder_EmptyFile_ExpectFailure) - { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial, when checking for the size of the file. - TestFailureCase("test_mat1.mtl", 1); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_NoChildren_ExpectFailure) - { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling - // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when both a Textures node and a - // SubMaterials node are not found. No other AZ_Errors should be generated. - TestFailureCase("test_mat2.mtl", 1); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptyTexturesNode_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat3.mtl"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptySubMaterialNode_ExpectFailure) - { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling - // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when a SubMaterials node is present, - // but has no children Material node. No other AZ_Errors should be generated. - TestFailureCase("test_mat4.mtl", 1); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptyTextureNode_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat5.mtl"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptyMaterialInSubMaterial_ExpectFailure) - { - // Should fail in MaterialBuilderWorker::GetResolvedTexturePathsFromMaterial after calling - // Internal::GetTexturePathsFromMaterial, which should return an AZ::Failure when a SubMaterials node is present, - // but a child Material node has no child Textures node and no child SubMaterials node. No other AZ_Errors should - // be generated. - TestFailureCase("test_mat6.mtl", 1); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_EmptyTextureNodeInSubMaterial_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat7.mtl"); - } - -#if AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS // The following test file 'test_mat8.mtl' has a windows-specific absolute path, so this test is only valid on windows - TEST_F(MaterialBuilderTests, MaterialBuilder_TextureAbsolutePath_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat8.mtl"); - } -#endif - - TEST_F(MaterialBuilderTests, MaterialBuilder_TextureRuntimeAlias_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat9.mtl"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_TextureRuntimeTexture_NoDependencies) - { - TestSuccessCaseNoDependencies("test_mat10.mtl"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SingleMaterialSingleTexture_ValidSourceFormat) - { - // texture referenced is textures/natural/terrain/am_floor_tile_ddn.png - const char* expectedPath = "textures/natural/terrain/am_floor_tile_ddn.dds"; - TestSuccessCase("test_mat11.mtl", expectedPath); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SingleMaterialSingleTexture_ValidProductFormat) - { - // texture referenced is textures/natural/terrain/am_floor_tile_ddn.dds - const char* expectedPath = "textures/natural/terrain/am_floor_tile_ddn.dds"; - TestSuccessCase("test_mat12.mtl", expectedPath); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SingleMaterialSingleTexture_InvalidSourceFormat_NoDependenices) - { - // texture referenced is textures/natural/terrain/am_floor_tile_ddn.txt - TestSuccessCaseNoDependencies("test_mat13.mtl"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_TextureAnimSequence) - { - AZStd::vector expectedPaths = { - "path/to/my/textures/test_anim_sequence_01_texture000.dds", - "path/to/my/textures/test_anim_sequence_01_texture001.dds", - "path/to/my/textures/test_anim_sequence_01_texture002.dds", - "path/to/my/textures/test_anim_sequence_01_texture003.dds", - "path/to/my/textures/test_anim_sequence_01_texture004.dds", - "path/to/my/textures/test_anim_sequence_01_texture005.dds" - }; - TestSuccessCase("test_mat14.mtl", expectedPaths); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SingleMaterialMultipleTexture) - { - AZStd::vector expectedPaths = { - "engineassets/textures/hex.dds", - "engineassets/textures/hex_ddn.dds" - }; - TestSuccessCase("test_mat15.mtl", expectedPaths); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_MalformedMaterial_MultipleTextures_OneEmptyTexture) - { - TestSuccessCase("test_mat16.mtl", "engineassets/textures/hex_ddn.dds"); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SingleMaterialMultipleTexture_ResolveLeadingSeparatorsAndAliases) - { - AZStd::vector expectedPaths = { - "engineassets/textures/hex.dds", // resolved from "/engineassets/textures/hex.dds" - "engineassets/textures/hex_ddn.dds", // resolved from "./engineassets/textures/hex_ddn.dds" - "engineassets/textures/hex_spec.dds" // resolved from "@products@/engineassets/textures/hex_spec.dds" - }; - TestSuccessCase("test_mat17.mtl", expectedPaths); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SubMaterialSingleTexture) - { - AZStd::vector expectedPaths = { - "engineassets/textures/scratch.dds", - "engineassets/textures/perlinnoise2d.dds" - }; - TestSuccessCase("test_mat18.mtl", expectedPaths); - } - - TEST_F(MaterialBuilderTests, MaterialBuilder_SubMaterialMultipleTexture) - { - AZStd::vector expectedPaths = { - "engineassets/textures/scratch.dds", - "engineassets/textures/scratch_ddn.dds", - "engineassets/textures/perlinnoise2d.dds", - "engineassets/textures/perlinnoisenormal_ddn.dds" - }; - TestSuccessCase("test_mat19.mtl", expectedPaths); - } -} diff --git a/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake b/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake index 5c77888922..aea2f493c7 100644 --- a/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake +++ b/Gems/LmbrCentral/Code/lmbrcentral_editor_files.cmake @@ -116,8 +116,6 @@ set(FILES Source/Builders/LevelBuilder/LevelBuilderComponent.h Source/Builders/LevelBuilder/LevelBuilderWorker.cpp Source/Builders/LevelBuilder/LevelBuilderWorker.h - Source/Builders/MaterialBuilder/MaterialBuilderComponent.cpp - Source/Builders/MaterialBuilder/MaterialBuilderComponent.h Source/Builders/SliceBuilder/SliceBuilderComponent.cpp Source/Builders/SliceBuilder/SliceBuilderComponent.h Source/Builders/SliceBuilder/SliceBuilderWorker.cpp diff --git a/Gems/LmbrCentral/Code/lmbrcentral_editor_tests_files.cmake b/Gems/LmbrCentral/Code/lmbrcentral_editor_tests_files.cmake index 0f0cf484d1..afba79e566 100644 --- a/Gems/LmbrCentral/Code/lmbrcentral_editor_tests_files.cmake +++ b/Gems/LmbrCentral/Code/lmbrcentral_editor_tests_files.cmake @@ -21,7 +21,6 @@ set(FILES Tests/Builders/CopyDependencyBuilderTest.cpp Tests/Builders/SliceBuilderTests.cpp Tests/Builders/LevelBuilderTest.cpp - Tests/Builders/MaterialBuilderTests.cpp Tests/Builders/LuaBuilderTests.cpp Tests/Builders/SeedBuilderTests.cpp Source/LmbrCentral.cpp diff --git a/Gems/LmbrCentral/Code/lmbrcentral_files.cmake b/Gems/LmbrCentral/Code/lmbrcentral_files.cmake index 18412e2a38..20a366b5f7 100644 --- a/Gems/LmbrCentral/Code/lmbrcentral_files.cmake +++ b/Gems/LmbrCentral/Code/lmbrcentral_files.cmake @@ -145,8 +145,6 @@ set(FILES Source/Shape/ShapeComponentConverters.inl Source/Shape/ShapeGeometryUtil.h Source/Shape/ShapeGeometryUtil.cpp - Source/Unhandled/Material/MaterialAssetTypeInfo.cpp - Source/Unhandled/Material/MaterialAssetTypeInfo.h Source/Unhandled/Other/AudioAssetTypeInfo.cpp Source/Unhandled/Other/AudioAssetTypeInfo.h Source/Unhandled/Other/CharacterPhysicsAssetTypeInfo.cpp diff --git a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja index e9bc21875b..d0b77159f8 100644 --- a/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja +++ b/Gems/Multiplayer/Code/Include/Multiplayer/AutoGen/AutoComponent_Source.jinja @@ -308,13 +308,21 @@ void {{ ClassName }}::Set{{ UpperFirst(Property.attrib['Name']) }}(const {{ Prop {% endmacro %} {# +#} +{% macro PrintRpcParameters(printPrefix, paramDefines) %} +{% if paramDefines|count > 0 %} +{{ printPrefix }}{{ ', '.join(paramDefines) }} +{% endif %} +{% endmacro %} +{# + #} {% macro DefineRpcInvocation(Component, ClassName, Property, InvokeFrom, HandleOn) %} {% set paramNames = [] %} {% set paramTypes = [] %} {% set paramDefines = [] %} {{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} -void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramDefines) }}) +void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ PrintRpcParameters('', paramDefines) }}) { constexpr Multiplayer::RpcIndex rpcId = static_cast({{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ UpperFirst(Property.attrib['Name']) }}); {% if Property.attrib['IsReliable']|booleanTrue %} @@ -358,7 +366,7 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par {% set paramTypes = [] %} {% set paramDefines = [] %} {{ AutoComponentMacros.ParseRpcParams(Property, paramNames, paramTypes, paramDefines) }} - ->Method("{{ UpperFirst(Property.attrib['Name']) }}", []({{ ClassName }}* self, {{ ', '.join(paramDefines) }}) { + ->Method("{{ UpperFirst(Property.attrib['Name']) }}", []({{ ClassName }}* self{{ PrintRpcParameters(', ', paramDefines) }}) { {% if (InvokeFrom == 'Server') %} self->{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(paramNames) }}); {% elif (InvokeFrom == 'Authority') or (InvokeFrom == 'Autonomous') %} @@ -372,7 +380,7 @@ void {{ ClassName }}::{{ UpperFirst(Property.attrib['Name']) }}({{ ', '.join(par } {% endif %} }) - ->Method("{{ UpperFirst(Property.attrib['Name']) }}ByEntityId", [](AZ::EntityId id, {{ ', '.join(paramDefines) }}) { + ->Method("{{ UpperFirst(Property.attrib['Name']) }}ByEntityId", [](AZ::EntityId id{{ PrintRpcParameters(', ', paramDefines) }}) { AZ::Entity* entity = AZ::Interface::Get()->FindEntity(id); if (!entity) @@ -497,9 +505,9 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp if (m_controller) { AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Authority, "Entity proxy does not have authority"); - m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); + m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection{{ PrintRpcParameters(', ', rpcParamList) }}); {% if (Property.attrib['GenerateEventBindings']|booleanTrue == true) %} - m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ ', '.join(rpcParamList) }}); + m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ PrintRpcParameters('', rpcParamList) }}); {% endif %} } else // Note that this rpc is marked reliable, trigger the appropriate rpc event so it can be forwarded @@ -513,15 +521,15 @@ case {{ UpperFirst(Component.attrib['Name']) }}Internal::RemoteProcedure::{{ Upp if (m_controller) { AZ_Assert(GetNetBindComponent()->GetNetEntityRole() == Multiplayer::NetEntityRole::Autonomous, "Entity proxy does not have autonomy"); - m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); + m_controller->Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection{{ PrintRpcParameters(', ', rpcParamList) }}); {% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} - m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ ', '.join(rpcParamList) }}); + m_controller->Get{{ UpperFirst(Property.attrib['Name']) }}Event().Signal({{ PrintRpcParameters('', rpcParamList) }}); {% endif %} } {% elif HandleOn == 'Client' %} - Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection, {{ ', '.join(rpcParamList) }}); + Handle{{ UpperFirst(Property.attrib['Name']) }}(invokingConnection{{ PrintRpcParameters(', ', rpcParamList) }}); {% if Property.attrib['GenerateEventBindings']|booleanTrue == true %} - m_{{ UpperFirst(Property.attrib['Name']) }}Event.Signal({{ ', '.join(rpcParamList) }}); + m_{{ UpperFirst(Property.attrib['Name']) }}Event.Signal({{ PrintRpcParameters('', rpcParamList) }}); {% endif %} {% endif %} } diff --git a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp index ce95e27db3..08e31a89f0 100644 --- a/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp +++ b/Gems/PhysX/Code/Editor/Source/ComponentModes/Joints/JointsComponentMode.cpp @@ -307,7 +307,16 @@ namespace PhysX AZStd::vector JointsComponentMode::PopulateViewportUiImpl() { - return AZStd::vector(m_modeSelectionClusterIds.begin(), m_modeSelectionClusterIds.end()); + AZStd::vector ids; + ids.reserve(m_modeSelectionClusterIds.size()); + for (auto clusterid : m_modeSelectionClusterIds) + { + if (clusterid != AzToolsFramework::ViewportUi::InvalidClusterId) + { + ids.emplace_back(clusterid); + } + } + return ids; } void JointsComponentMode::SetCurrentMode(JointsComponentModeCommon::SubComponentModes::ModeType newMode, ButtonData& buttonData) @@ -353,31 +362,64 @@ namespace PhysX void JointsComponentMode::SetupSubModes(const AZ::EntityComponentIdPair& entityComponentIdPair) { - //create the 3 cluster groups - for (auto& clusterId : m_modeSelectionClusterIds) - { - AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( - clusterId, AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, - AzToolsFramework::ViewportUi::Alignment::TopLeft); - } - //retrieve the enabled sub components from the entity AZStd::vector subModesState; EditorJointRequestBus::EventResult(subModesState, entityComponentIdPair, &EditorJointRequests::GetSubComponentModesState); + //group 1 is always available so create it + AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( + m_modeSelectionClusterIds[static_cast(ClusterGroups::Group1)], AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, AzToolsFramework::ViewportUi::Alignment::TopLeft); + + //check if groups 2 and/or 3 need to be created + for (auto [modeType, _] : subModesState) + { + const AzToolsFramework::ViewportUi::ClusterId group2Id = GetClusterId(ClusterGroups::Group2); + const AzToolsFramework::ViewportUi::ClusterId group3Id = GetClusterId(ClusterGroups::Group3); + switch (modeType) + { + case JointsComponentModeCommon::SubComponentModes::ModeType::Damping: + case JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness: + case JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits: + case JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits: + { + if (group2Id == AzToolsFramework::ViewportUi::InvalidClusterId) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( + m_modeSelectionClusterIds[static_cast(ClusterGroups::Group2)], + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, + AzToolsFramework::ViewportUi::Alignment::TopLeft); + } + } + break; + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce: + case JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque: + { + if (group3Id == AzToolsFramework::ViewportUi::InvalidClusterId) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::EventResult( + m_modeSelectionClusterIds[static_cast(ClusterGroups::Group3)], + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::CreateCluster, + AzToolsFramework::ViewportUi::Alignment::TopLeft); + } + } + break; + default: + AZ_Error("Joints", false, "Joints component mode cluster UI setup found unknown sub mode."); + break; + } + //if both are created - break; + if (group2Id != AzToolsFramework::ViewportUi::InvalidClusterId && group3Id != AzToolsFramework::ViewportUi::InvalidClusterId) + { + break; + } + } + const AzToolsFramework::ViewportUi::ClusterId group1ClusterId = GetClusterId(ClusterGroups::Group1); const AzToolsFramework::ViewportUi::ClusterId group2ClusterId = GetClusterId(ClusterGroups::Group2); - //hide cluster 2, if something is added to it. it will make is visible - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, - group2ClusterId, false); - const AzToolsFramework::ViewportUi::ClusterId group3ClusterId = GetClusterId(ClusterGroups::Group3); - // hide cluster 3, if something is added to it. it will make is visible - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, - group3ClusterId, false); //translation and rotation are enabled for all joints in group 1 m_subModes[JointsComponentModeCommon::SubComponentModes::ModeType::Translation] = @@ -408,10 +450,6 @@ namespace PhysX Internal::RegisterClusterButton(group3ClusterId, "joints/MaxForce", SubModeData::MaxForceToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxForce] = ButtonData{ group3ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group3ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque: @@ -424,10 +462,6 @@ namespace PhysX Internal::RegisterClusterButton(group3ClusterId, "joints/MaxTorque", SubModeData::MaxTorqueToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::MaxTorque] = ButtonData{ group3ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group3ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::Damping: @@ -439,10 +473,6 @@ namespace PhysX const AzToolsFramework::ViewportUi::ButtonId buttonId = Internal::RegisterClusterButton(group2ClusterId, "joints/Damping", SubModeData::DampingToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Damping] = ButtonData{ group2ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness: @@ -455,10 +485,6 @@ namespace PhysX Internal::RegisterClusterButton(group2ClusterId, "joints/Stiffness", SubModeData::StiffnessToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::Stiffness] = ButtonData{ group2ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits: @@ -473,10 +499,6 @@ namespace PhysX Internal::RegisterClusterButton(group2ClusterId, "joints/TwistLimits", SubModeData::TwistLimitsToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::TwistLimits] = ButtonData{ group2ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits: @@ -489,10 +511,6 @@ namespace PhysX Internal::RegisterClusterButton(group2ClusterId, "joints/SwingLimits", SubModeData::SwingLimitsToolTip); m_buttonData[JointsComponentModeCommon::SubComponentModes::ModeType::SwingLimits] = ButtonData{ group2ClusterId, buttonId }; - - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::SetClusterVisible, group2ClusterId, true); } break; case JointsComponentModeCommon::SubComponentModes::ModeType::SnapPosition: @@ -517,6 +535,9 @@ namespace PhysX ButtonData{ group1ClusterId, buttonId }; } break; + default: + AZ_Error("Joints", false, "Joints component mode cluster button setup found unknown sub mode."); + break; } } @@ -560,10 +581,13 @@ namespace PhysX for (int i = 0; i < static_cast(ClusterGroups::GroupCount); i++) { - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, - &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, m_modeSelectionClusterIds[i], - m_modeSelectionHandlers[i]); + if (m_modeSelectionClusterIds[i] != AzToolsFramework::ViewportUi::InvalidClusterId) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RegisterClusterEventHandler, + m_modeSelectionClusterIds[i], m_modeSelectionHandlers[i]); + } } // set the translate as enabled by default. @@ -588,10 +612,14 @@ namespace PhysX { for (auto clusterid : m_modeSelectionClusterIds) { - AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( - AzToolsFramework::ViewportUi::DefaultViewportId, &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, - clusterid); + if (clusterid != AzToolsFramework::ViewportUi::InvalidClusterId) + { + AzToolsFramework::ViewportUi::ViewportUiRequestBus::Event( + AzToolsFramework::ViewportUi::DefaultViewportId, + &AzToolsFramework::ViewportUi::ViewportUiRequestBus::Events::RemoveCluster, clusterid); + } } + m_modeSelectionClusterIds.assign(static_cast(ClusterGroups::GroupCount), AzToolsFramework::ViewportUi::InvalidClusterId); } AzToolsFramework::ViewportUi::ClusterId JointsComponentMode::GetClusterId(ClusterGroups group) diff --git a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp index e448f3ea40..dfa39b0047 100644 --- a/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp +++ b/Gems/ScriptCanvas/Code/Editor/View/Widgets/CanvasWidget.cpp @@ -84,9 +84,10 @@ namespace ScriptCanvasEditor { m_assetId = assetId; - EditorGraphRequests* editorGraphRequests = EditorGraphRequestBus::FindFirstHandler(m_scriptCanvasId); - - editorGraphRequests->SetAssetId(m_assetId); + if (EditorGraphRequests* editorGraphRequests = EditorGraphRequestBus::FindFirstHandler(m_scriptCanvasId)) + { + editorGraphRequests->SetAssetId(m_assetId); + } } const GraphCanvas::ViewId& CanvasWidget::GetViewId() const diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp index 0dcd8ebbbd..d55fcf7838 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.cpp @@ -59,6 +59,7 @@ namespace ScriptCanvas m_script = AZStd::move(other.m_script); m_requiredAssets = AZStd::move(other.m_requiredAssets); m_requiredScriptEvents = AZStd::move(other.m_requiredScriptEvents); + m_areStaticsInitialized = AZStd::move(other.m_areStaticsInitialized); } return *this; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h index 24c83b20a1..8c5da5ac07 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAsset.h @@ -76,6 +76,9 @@ namespace ScriptCanvas AZStd::vector m_activationInputStorage; Execution::ActivationInputRange m_activationInputRange; + // used to initialize statics only once, and not necessarily on the loading thread + bool m_areStaticsInitialized = false; + bool RequiresStaticInitialization() const; bool RequiresDependencyConstructionParameters() const; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp index df7b07d37b..05b6f4397b 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Asset/RuntimeAssetHandler.cpp @@ -94,7 +94,6 @@ namespace ScriptCanvas RuntimeAsset* runtimeAsset = asset.GetAs(); AZ_Assert(runtimeAsset, "RuntimeAssetHandler::InitAsset This should be a Script Canvas runtime asset, as this is the only type this handler processes!"); Execution::Context::InitializeActivationData(runtimeAsset->GetData()); - Execution::InitializeInterpretedStatics(runtimeAsset->GetData()); } } @@ -157,4 +156,5 @@ namespace ScriptCanvas } } } + } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/ExecutionState.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/ExecutionState.h index 8c2f0a67c4..89ddf178f3 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/ExecutionState.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/ExecutionState.h @@ -19,6 +19,10 @@ #include #include +#if !defined(_RELEASE) +#define SCRIPT_CANVAS_RUNTIME_ASSET_CHECK +#endif + namespace AZ { class ReflectContext; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp index 4d7c8a2cda..bba56847ce 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.cpp @@ -506,6 +506,8 @@ namespace ScriptCanvas #if defined(AZ_PROFILE_BUILD) || defined(AZ_DEBUG_BUILD) Execution::InitializeFromLuaStackFunctions(const_cast(runtimeData.m_debugMap)); #endif + AZ_WarningOnce("ScriptCanvas", !runtimeData.m_areStaticsInitialized, "ScriptCanvas runtime data already initalized"); + if (runtimeData.RequiresStaticInitialization()) { AZ::ScriptLoadResult result{}; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp index 9224d4f9a4..a92c13ac63 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/Interpreted/ExecutionStateInterpreted.cpp @@ -6,14 +6,13 @@ * */ -#include "ExecutionStateInterpreted.h" - #include #include #include - -#include "Execution/Interpreted/ExecutionStateInterpretedUtility.h" -#include "Execution/RuntimeComponent.h" +#include +#include +#include +#include namespace ExecutionStateInterpretedCpp { @@ -33,7 +32,29 @@ namespace ScriptCanvas ExecutionStateInterpreted::ExecutionStateInterpreted(const ExecutionStateConfig& config) : ExecutionState(config) , m_interpretedAsset(config.runtimeData.m_script) - {} + { + RuntimeAsset* runtimeAsset = config.asset.Get(); + +#if defined(SCRIPT_CANVAS_RUNTIME_ASSET_CHECK) + if (!runtimeAsset) + { + AZ_Error("ScriptCanvas", false + , "ExecutionStateInterpreted created with ExecutionStateConfig that contained bad runtime asset data. %s" + , config.asset.GetId().ToString().data()); + return; + } +#else + AZ_Assert(false + , "ExecutionStateInterpreted created with ExecutionStateConfig that contained bad runtime asset data. %s" + , config.asset.GetId().ToString().data()); +#endif + + if (!runtimeAsset->GetData().m_areStaticsInitialized) + { + runtimeAsset->GetData().m_areStaticsInitialized = true; + Execution::InitializeInterpretedStatics(runtimeAsset->GetData()); + } + } void ExecutionStateInterpreted::ClearLuaRegistryIndex() { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp index 5fe5c32a48..930b84abe4 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Execution/RuntimeComponent.cpp @@ -19,9 +19,8 @@ #include #include -#if !defined(_RELEASE) -#define SCRIPT_CANVAS_RUNTIME_ASSET_CHECK -#endif +#include +#include AZ_DECLARE_BUDGET(ScriptCanvas); @@ -112,11 +111,13 @@ namespace ScriptCanvas #if defined(SCRIPT_CANVAS_RUNTIME_ASSET_CHECK) if (!m_runtimeOverrides.m_runtimeAsset.Get()) { - AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); + AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run" + , m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); return; } #else - AZ_Assert(m_runtimeOverrides.m_runtimeAsset.Get(), "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); + AZ_Assert(m_runtimeOverrides.m_runtimeAsset.Get(), "RuntimeComponent::m_runtimeAsset AssetId: %s was valid, but the data was not pre-loaded, so this script will not run" + , m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); #endif AZ_PROFILE_SCOPE(ScriptCanvas, "RuntimeComponent::InitializeExecution (%s)", m_runtimeOverrides.m_runtimeAsset.GetId().ToString().c_str()); @@ -126,11 +127,13 @@ namespace ScriptCanvas #if defined(SCRIPT_CANVAS_RUNTIME_ASSET_CHECK) if (!m_executionState) { - AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s failed to create an execution state, possibly due to missing dependent asset, script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); + AZ_Error("ScriptCanvas", false, "RuntimeComponent::m_runtimeAsset AssetId: %s failed to create an execution state, possibly due to missing dependent asset, script will not run" + , m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); return; } #else - AZ_Assert(m_executionState, "RuntimeComponent::m_runtimeAsset AssetId: %s failed to create an execution state, possibly due to missing dependent asset, script will not run", m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); + AZ_Assert(m_executionState, "RuntimeComponent::m_runtimeAsset AssetId: %s failed to create an execution state, possibly due to missing dependent asset, script will not run" + , m_runtimeOverrides.m_runtimeAsset.GetId().ToString().data()); #endif AZ::EntityBus::Handler::BusConnect(GetEntityId()); @@ -179,4 +182,3 @@ namespace ScriptCanvas } } -#undef SCRIPT_CANVAS_RUNTIME_ASSET_CHECK diff --git a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp index 5031f149b8..1d8d6adf6c 100644 --- a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp +++ b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.cpp @@ -9,8 +9,8 @@ #include "SlideAlongAxisBasedOnAngle.h" #include "StartingPointCamera/StartingPointCameraUtilities.h" #include -#include #include +#include namespace Camera { @@ -32,31 +32,43 @@ namespace Camera AZ::EditContext* editContext = serializeContext->GetEditContext(); if (editContext) { - editContext->Class("SlideAlongAxisBasedOnAngle", "Slide 0..SlideDistance along Axis based on Angle Type. Maps from 90..-90 degrees") - ->ClassElement(AZ::Edit::ClassElements::EditorData, "") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_axisToSlideAlong, "Axis to slide along", "The Axis to slide along") - ->EnumAttribute(RelativeAxisType::ForwardBackward, "Forwards and Backwards") - ->EnumAttribute(RelativeAxisType::LeftRight, "Right and Left") - ->EnumAttribute(RelativeAxisType::UpDown, "Up and Down") - ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_angleTypeToChangeFor, "Angle Type", "The angle type to base the slide off of") - ->EnumAttribute(EulerAngleType::Pitch, "Pitch") - ->EnumAttribute(EulerAngleType::Roll, "Roll") - ->EnumAttribute(EulerAngleType::Yaw, "Yaw") - ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumPositiveSlideDistance, "Max Positive Slide Distance", "The maximum distance to slide in the positive") - ->Attribute(AZ::Edit::Attributes::Suffix, "m") - ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumNegativeSlideDistance, "Max Negative Slide Distance", "The maximum distance to slide in the negative") - ->Attribute(AZ::Edit::Attributes::Suffix, "m") - ->ClassElement(AZ::Edit::ClassElements::Group, "Vector Components To Ignore") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) - ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreX, "X", "When active, the X Component will be ignored.") - ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreY, "Y", "When active, the Y Component will be ignored.") - ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreZ, "Z", "When active, the Z Component will be ignored.") + editContext->Class("SlideAlongAxisBasedOnAngle", + "Slide 0..SlideDistance along Axis based on Angle Type. Maps from 90..-90 degrees") + ->ClassElement(AZ::Edit::ClassElements::EditorData, "") + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_axisToSlideAlong, "Axis to slide along", + "The Axis to slide along") + ->EnumAttribute(RelativeAxisType::ForwardBackward, "Forwards and Backwards") + ->EnumAttribute(RelativeAxisType::LeftRight, "Right and Left") + ->EnumAttribute(RelativeAxisType::UpDown, "Up and Down") + ->DataElement(AZ::Edit::UIHandlers::ComboBox, &SlideAlongAxisBasedOnAngle::m_angleTypeToChangeFor, "Angle Type", + "The angle type to base the slide off of") + ->EnumAttribute(EulerAngleType::Pitch, "Pitch") + ->EnumAttribute(EulerAngleType::Roll, "Roll") + ->EnumAttribute(EulerAngleType::Yaw, "Yaw") + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumPositiveSlideDistance, "Max Positive Slide Distance", + "The maximum distance to slide in the positive") + ->Attribute(AZ::Edit::Attributes::Suffix, "m") + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_maximumNegativeSlideDistance, "Max Negative Slide Distance", + "The maximum distance to slide in the negative") + ->Attribute(AZ::Edit::Attributes::Suffix, "m") + ->ClassElement(AZ::Edit::ClassElements::Group, "Vector Components To Ignore") + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreX, "X", "When active, the X Component will be ignored.") + ->Attribute(AZ::Edit::Attributes::ReadOnly, &SlideAlongAxisBasedOnAngle::YAndZIgnored) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreY, "Y", "When active, the Y Component will be ignored.") + ->Attribute(AZ::Edit::Attributes::ReadOnly, &SlideAlongAxisBasedOnAngle::XAndZIgnored) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) + ->DataElement(0, &SlideAlongAxisBasedOnAngle::m_ignoreZ, "Z", "When active, the Z Component will be ignored.") + ->Attribute(AZ::Edit::Attributes::ReadOnly, &SlideAlongAxisBasedOnAngle::XAndYIgnored) + ->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues) ; } } } - void SlideAlongAxisBasedOnAngle::AdjustLookAtTarget([[maybe_unused]] float deltaTime, [[maybe_unused]] const AZ::Transform& targetTransform, AZ::Transform& outLookAtTargetTransform) + void SlideAlongAxisBasedOnAngle::AdjustLookAtTarget( + [[maybe_unused]] float deltaTime, [[maybe_unused]] const AZ::Transform& targetTransform, AZ::Transform& outLookAtTargetTransform) { float angle = GetEulerAngleFromTransform(outLookAtTargetTransform, m_angleTypeToChangeFor); float currentPositionOnRange = -angle / AZ::Constants::HalfPi; @@ -67,4 +79,20 @@ namespace Camera outLookAtTargetTransform.SetTranslation(outLookAtTargetTransform.GetTranslation() + basis * currentPositionOnRange * slideScale); } -} + + bool SlideAlongAxisBasedOnAngle::XAndYIgnored() const + { + return m_ignoreX && m_ignoreY; + } + + bool SlideAlongAxisBasedOnAngle::XAndZIgnored() const + { + return m_ignoreX && m_ignoreZ; + } + + bool SlideAlongAxisBasedOnAngle::YAndZIgnored() const + { + return m_ignoreY && m_ignoreZ; + } + +} // namespace Camera diff --git a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h index 2c756d1ac7..e517b6ffbd 100644 --- a/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h +++ b/Gems/StartingPointCamera/Code/Source/CameraLookAtBehaviors/SlideAlongAxisBasedOnAngle.h @@ -6,11 +6,11 @@ * */ #pragma once -#include -#include -#include #include "StartingPointCamera/StartingPointCameraConstants.h" +#include #include +#include +#include namespace Camera { @@ -38,6 +38,10 @@ namespace Camera void Activate(AZ::EntityId) override {} void Deactivate() override {} + bool XAndYIgnored() const; + bool XAndZIgnored() const; + bool YAndZIgnored() const; + private: ////////////////////////////////////////////////////////////////////////// // Reflected data diff --git a/Gems/Vegetation/Code/Source/InstanceSystemComponent.cpp b/Gems/Vegetation/Code/Source/InstanceSystemComponent.cpp index dd38daa633..85ba4bda61 100644 --- a/Gems/Vegetation/Code/Source/InstanceSystemComponent.cpp +++ b/Gems/Vegetation/Code/Source/InstanceSystemComponent.cpp @@ -15,9 +15,6 @@ #include #include -#include -#include - #include #include #include