Merge branch 'development' of https://github.com/o3de/o3de into cgalvan/DraftStreamingImageAssetPixelAPI
This commit is contained in:
@@ -12,12 +12,6 @@
|
||||
################################################################################
|
||||
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
# Only enable AWS automated tests on Windows
|
||||
set(SUPPORTED_PLATFORMS "Windows" "Linux")
|
||||
if (NOT "${PAL_PLATFORM_NAME}" IN_LIST SUPPORTED_PLATFORMS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
ly_add_pytest(
|
||||
NAME AutomatedTesting::AWSTests
|
||||
TEST_SUITE awsi
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Prerequisites
|
||||
1. Build the O3DE Editor and AutomatedTesting.GameLauncher in Profile.
|
||||
2. Install the latest version of NodeJs.
|
||||
3. AWS CLI is installed and configured following [Configuration and Credential File Settings](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html).
|
||||
3. AWS CLI is installed and AWS crendentials are configured via [environment variables](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html) or [default profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html).
|
||||
4. [AWS Cloud Development Kit (CDK)](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html#getting_started_install) is installed.
|
||||
|
||||
## Deploy CDK Applications
|
||||
|
||||
@@ -68,6 +68,10 @@ class AwsCredentials:
|
||||
if (len(self._credentials.sections()) == 0) and (not self._credentials_file_exists):
|
||||
os.remove(self._credentials_path)
|
||||
return
|
||||
|
||||
credentials_file_dir = os.path.dirname(self._credentials_path)
|
||||
if not os.path.isdir(credentials_file_dir):
|
||||
os.makedirs(credentials_file_dir)
|
||||
|
||||
with open(self._credentials_path, 'w+') as credential_file:
|
||||
self._credentials.write(credential_file)
|
||||
|
||||
@@ -16,7 +16,7 @@ logging.getLogger('nose').setLevel(logging.WARNING)
|
||||
class AwsUtils:
|
||||
|
||||
def __init__(self, arn: str, session_name: str, region_name: str):
|
||||
local_session = boto3.Session(profile_name='default')
|
||||
local_session = boto3.Session()
|
||||
local_sts_client = local_session.client('sts')
|
||||
self._local_account_id = local_sts_client.get_caller_identity()["Account"]
|
||||
logger.info(f'Local Account Id: {self._local_account_id}')
|
||||
|
||||
@@ -6,11 +6,13 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
import os
|
||||
import platform
|
||||
|
||||
# ARN of the IAM role to assume for retrieving temporary AWS credentials
|
||||
ASSUME_ROLE_ARN = os.environ.get('ASSUME_ROLE_ARN', 'arn:aws:iam::645075835648:role/o3de-automation-tests')
|
||||
# Name of the AWS project deployed by the CDK applications
|
||||
AWS_PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME', 'AWSAUTO')
|
||||
AWS_PROJECT_NAME = os.environ.get('O3DE_AWS_PROJECT_NAME').upper() if os.environ.get('O3DE_AWS_PROJECT_NAME') else \
|
||||
(os.environ.get('BRANCH_NAME', '') + '-' + os.environ.get('PIPELINE_NAME', '') + '-' + platform.system()).upper()
|
||||
# Region for the existing CloudFormation stacks used by the automation tests
|
||||
AWS_REGION = os.environ.get('O3DE_AWS_DEPLOY_REGION', 'us-east-1')
|
||||
# Name of the default resource mapping config file used by the automation tests
|
||||
|
||||
@@ -21,7 +21,7 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
|
||||
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
|
||||
class TestAutomation(EditorTestSuite):
|
||||
|
||||
enable_prefab_system = False
|
||||
enable_prefab_system = True
|
||||
|
||||
@pytest.mark.test_case_id("C36525657")
|
||||
class AtomEditorComponents_BloomAdded(EditorSharedTest):
|
||||
@@ -120,6 +120,14 @@ class TestAutomation(EditorTestSuite):
|
||||
class AtomEditorComponents_SSAOAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_SSAOAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36529666")
|
||||
class AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded as test_module
|
||||
|
||||
@pytest.mark.test_case_id("C36525660")
|
||||
class AtomEditorComponentsLevel_DisplayMapperAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponentsLevel_DisplayMapperAdded as test_module
|
||||
|
||||
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
|
||||
from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
|
||||
|
||||
|
||||
@@ -26,13 +26,3 @@ class TestAutomation(EditorTestSuite):
|
||||
@pytest.mark.test_case_id("C36525660")
|
||||
class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
|
||||
|
||||
# this test causes editor to crash when using slices. once automation transitions to prefabs it should pass
|
||||
@pytest.mark.test_case_id("C36529666")
|
||||
class AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponentsLevel_DiffuseGlobalIlluminationAdded as test_module
|
||||
|
||||
# this test causes editor to crash when using slices. once automation transitions to prefabs it should pass
|
||||
@pytest.mark.test_case_id("C36525660")
|
||||
class AtomEditorComponentsLevel_DisplayMapperAdded(EditorSharedTest):
|
||||
from Atom.tests import hydra_AtomEditorComponentsLevel_DisplayMapperAdded as test_module
|
||||
|
||||
+3
-3
@@ -60,7 +60,7 @@ def AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Add Diffuse Global Illumination level component to the level entity.
|
||||
@@ -86,10 +86,10 @@ def AtomEditorComponentsLevel_DiffuseGlobalIllumination_AddedToEntity():
|
||||
|
||||
# 4. Set Quality Level property to Low
|
||||
diffuse_global_illumination_component.set_component_property_value(
|
||||
AtomComponentProperties.diffuse_global_illumination('Quality Level', GLOBAL_ILLUMINATION_QUALITY['Low']))
|
||||
AtomComponentProperties.diffuse_global_illumination('Quality Level'), GLOBAL_ILLUMINATION_QUALITY['Low'])
|
||||
quality = diffuse_global_illumination_component.get_component_property_value(
|
||||
AtomComponentProperties.diffuse_global_illumination('Quality Level'))
|
||||
Report.result(diffuse_global_illumination_quality, quality == GLOBAL_ILLUMINATION_QUALITY['Low'])
|
||||
Report.result(Tests.diffuse_global_illumination_quality, quality == GLOBAL_ILLUMINATION_QUALITY['Low'])
|
||||
|
||||
# 5. Enter/Exit game mode.
|
||||
TestHelper.enter_game_mode(Tests.enter_game_mode)
|
||||
|
||||
+2
-2
@@ -67,7 +67,7 @@ def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Add Display Mapper level component to the level entity.
|
||||
@@ -102,7 +102,7 @@ def AtomEditorComponentsLevel_DisplayMapper_AddedToEntity():
|
||||
display_mapper_component.set_component_property_value(
|
||||
AtomComponentProperties.display_mapper('Enable LDR color grading LUT'), True)
|
||||
Report.result(
|
||||
Test.enable_ldr_color_grading_lut,
|
||||
Tests.enable_ldr_color_grading_lut,
|
||||
display_mapper_component.get_component_property_value(
|
||||
AtomComponentProperties.display_mapper('Enable LDR color grading LUT')) is True)
|
||||
|
||||
|
||||
+3
-1
@@ -97,7 +97,7 @@ def AtomEditorComponents_Bloom_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an Bloom entity with no components.
|
||||
@@ -170,10 +170,12 @@ def AtomEditorComponents_Bloom_AddedToEntity():
|
||||
|
||||
# 13. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, bloom_entity.exists())
|
||||
|
||||
# 14. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not bloom_entity.exists())
|
||||
|
||||
# 15. Look for errors and asserts.
|
||||
|
||||
+2
-1
@@ -95,7 +95,7 @@ def AtomEditorComponents_Decal_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Decal entity with no components.
|
||||
@@ -162,6 +162,7 @@ def AtomEditorComponents_Decal_AddedToEntity():
|
||||
|
||||
# 11. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not decal_entity.exists())
|
||||
|
||||
# 12. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -97,7 +97,7 @@ def AtomEditorComponents_DeferredFog_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an Deferred Fog entity with no components.
|
||||
@@ -174,10 +174,12 @@ def AtomEditorComponents_DeferredFog_AddedToEntity():
|
||||
|
||||
# 13. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, deferred_fog_entity.exists())
|
||||
|
||||
# 14. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not deferred_fog_entity.exists())
|
||||
|
||||
# 15. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -107,7 +107,7 @@ def AtomEditorComponents_DepthOfField_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a DepthOfField entity with no components.
|
||||
@@ -189,10 +189,12 @@ def AtomEditorComponents_DepthOfField_AddedToEntity():
|
||||
|
||||
# 15. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, depth_of_field_entity.exists())
|
||||
|
||||
# 16. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not depth_of_field_entity.exists())
|
||||
|
||||
# 17. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -90,7 +90,7 @@ def AtomEditorComponents_DiffuseProbeGrid_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Diffuse Probe Grid entity with no components.
|
||||
@@ -168,10 +168,12 @@ def AtomEditorComponents_DiffuseProbeGrid_AddedToEntity():
|
||||
|
||||
# 12. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, diffuse_probe_grid_entity.exists())
|
||||
|
||||
# 13. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not diffuse_probe_grid_entity.exists())
|
||||
|
||||
# 14. Look for errors or asserts.
|
||||
|
||||
+3
-1
@@ -95,7 +95,7 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Directional Light entity with no components.
|
||||
@@ -168,10 +168,12 @@ def AtomEditorComponents_DirectionalLight_AddedToEntity():
|
||||
|
||||
# 12. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, directional_light_entity.exists())
|
||||
|
||||
# 13. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not directional_light_entity.exists())
|
||||
|
||||
# 14. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -91,7 +91,7 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Display Mapper entity with no components.
|
||||
@@ -166,10 +166,12 @@ def AtomEditorComponents_DisplayMapper_AddedToEntity():
|
||||
|
||||
# 11. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, display_mapper_entity.exists())
|
||||
|
||||
# 12. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not display_mapper_entity.exists())
|
||||
|
||||
# 13. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -81,7 +81,7 @@ def AtomEditorComponents_EntityReference_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an Entity Reference entity with no components.
|
||||
@@ -139,10 +139,12 @@ def AtomEditorComponents_EntityReference_AddedToEntity():
|
||||
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, entity_reference_entity.exists())
|
||||
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not entity_reference_entity.exists())
|
||||
|
||||
# 11. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -101,7 +101,7 @@ def AtomEditorComponents_ExposureControl_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Creation of Exposure Control entity with no components.
|
||||
@@ -169,10 +169,12 @@ def AtomEditorComponents_ExposureControl_AddedToEntity():
|
||||
|
||||
# 12. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, exposure_control_entity.exists())
|
||||
|
||||
# 13. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not exposure_control_entity.exists())
|
||||
|
||||
# 14. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -99,7 +99,7 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Global Skylight (IBL) entity with no components.
|
||||
@@ -176,10 +176,12 @@ def AtomEditorComponents_GlobalSkylightIBL_AddedToEntity():
|
||||
|
||||
# 11. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, global_skylight_entity.exists())
|
||||
|
||||
# 12. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not global_skylight_entity.exists())
|
||||
|
||||
# 13. Look for errors and asserts.
|
||||
|
||||
@@ -82,7 +82,7 @@ def AtomEditorComponents_Grid_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Grid entity with no components.
|
||||
@@ -139,10 +139,12 @@ def AtomEditorComponents_Grid_AddedToEntity():
|
||||
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, grid_entity.exists())
|
||||
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not grid_entity.exists())
|
||||
|
||||
# 11. Look for errors or asserts.
|
||||
|
||||
+3
-1
@@ -96,7 +96,7 @@ def AtomEditorComponents_HDRColorGrading_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an HDR Color Grading entity with no components.
|
||||
@@ -173,10 +173,12 @@ def AtomEditorComponents_HDRColorGrading_AddedToEntity():
|
||||
|
||||
# 13. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, hdr_color_grading_entity.exists())
|
||||
|
||||
# 14. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not hdr_color_grading_entity.exists())
|
||||
|
||||
# 15. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -87,7 +87,7 @@ def AtomEditorComponents_HDRiSkybox_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an HDRi Skybox with no components.
|
||||
@@ -158,10 +158,12 @@ def AtomEditorComponents_HDRiSkybox_AddedToEntity():
|
||||
|
||||
# 10. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, hdri_skybox_entity.exists())
|
||||
|
||||
# 11. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not hdri_skybox_entity.exists())
|
||||
|
||||
# 12. Look for errors or asserts.
|
||||
|
||||
+3
-1
@@ -89,7 +89,7 @@ def AtomEditorComponents_Light_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Light entity with no components.
|
||||
@@ -144,10 +144,12 @@ def AtomEditorComponents_Light_AddedToEntity():
|
||||
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, light_entity.exists())
|
||||
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not light_entity.exists())
|
||||
|
||||
# 11. Look for errors asserts.
|
||||
|
||||
+3
-1
@@ -104,7 +104,7 @@ def AtomEditorComponents_LookModification_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create an Look Modification entity with no components.
|
||||
@@ -192,10 +192,12 @@ def AtomEditorComponents_LookModification_AddedToEntity():
|
||||
|
||||
# 14. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, look_modification_entity.exists())
|
||||
|
||||
# 15. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not look_modification_entity.exists())
|
||||
|
||||
# 16. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -102,7 +102,7 @@ def AtomEditorComponents_Material_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Material entity with no components.
|
||||
@@ -184,10 +184,12 @@ def AtomEditorComponents_Material_AddedToEntity():
|
||||
|
||||
# 16. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, material_entity.exists())
|
||||
|
||||
# 17. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not material_entity.exists())
|
||||
|
||||
# 18. Look for errors or asserts.
|
||||
|
||||
@@ -87,7 +87,7 @@ def AtomEditorComponents_Mesh_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Mesh entity with no components.
|
||||
@@ -151,10 +151,12 @@ def AtomEditorComponents_Mesh_AddedToEntity():
|
||||
|
||||
# 10. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, mesh_entity.exists())
|
||||
|
||||
# 11. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not mesh_entity.exists())
|
||||
|
||||
# 12. Look for errors or asserts.
|
||||
|
||||
+3
-1
@@ -80,7 +80,7 @@ def AtomEditorComponents_OcclusionCullingPlane_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a occlusion culling plane entity with no components.
|
||||
@@ -140,10 +140,12 @@ def AtomEditorComponents_OcclusionCullingPlane_AddedToEntity():
|
||||
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, occlusion_culling_plane_entity.exists())
|
||||
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not occlusion_culling_plane_entity.exists())
|
||||
|
||||
# 11. Look for errors or asserts.
|
||||
|
||||
+3
-1
@@ -89,7 +89,7 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Physical Sky entity with no components.
|
||||
@@ -146,10 +146,12 @@ def AtomEditorComponents_PhysicalSky_AddedToEntity():
|
||||
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, physical_sky_entity.exists())
|
||||
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not physical_sky_entity.exists())
|
||||
|
||||
# 11. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -92,7 +92,7 @@ def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a PostFX Gradient Weight Modifier entity with no components.
|
||||
@@ -162,10 +162,12 @@ def AtomEditorComponents_PostFXGradientWeightModifier_AddedToEntity():
|
||||
|
||||
# 12. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, postfx_gradient_weight_entity.exists())
|
||||
|
||||
# 13. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not postfx_gradient_weight_entity.exists())
|
||||
|
||||
# 14. Look for errors or asserts.
|
||||
|
||||
+3
-1
@@ -80,7 +80,7 @@ def AtomEditorComponents_postfx_layer_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a PostFX Layer entity with no components.
|
||||
@@ -137,10 +137,12 @@ def AtomEditorComponents_postfx_layer_AddedToEntity():
|
||||
|
||||
# 9. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, postfx_layer_entity.exists())
|
||||
|
||||
# 10. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not postfx_layer_entity.exists())
|
||||
|
||||
# 11. Look for errors or asserts.
|
||||
|
||||
+3
-1
@@ -92,7 +92,7 @@ def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Post FX Radius Weight Modifier entity with no components.
|
||||
@@ -161,10 +161,12 @@ def AtomEditorComponents_PostFXRadiusWeightModifier_AddedToEntity():
|
||||
|
||||
# 12. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, postfx_radius_weight_entity.exists())
|
||||
|
||||
# 13. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not postfx_radius_weight_entity.exists())
|
||||
|
||||
# 14. Look for errors and asserts.
|
||||
|
||||
+3
-1
@@ -98,7 +98,7 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a PostFx Shape Weight Modifier entity with no components.
|
||||
@@ -188,10 +188,12 @@ def AtomEditorComponents_postfx_shape_weight_AddedToEntity():
|
||||
|
||||
# 15. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, postfx_shape_weight_entity.exists())
|
||||
|
||||
# 16. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not postfx_shape_weight_entity.exists())
|
||||
|
||||
# 17. Look for errors or asserts.
|
||||
|
||||
+3
-1
@@ -97,7 +97,7 @@ def AtomEditorComponents_ReflectionProbe_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a Reflection Probe entity with no components.
|
||||
@@ -183,10 +183,12 @@ def AtomEditorComponents_ReflectionProbe_AddedToEntity():
|
||||
|
||||
# 13. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, reflection_probe_entity.exists())
|
||||
|
||||
# 14. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not reflection_probe_entity.exists())
|
||||
|
||||
# 15. Look for errors or asserts.
|
||||
|
||||
@@ -94,7 +94,7 @@ def AtomEditorComponents_SSAO_AddedToEntity():
|
||||
# Test setup begins.
|
||||
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
|
||||
TestHelper.init_idle()
|
||||
TestHelper.open_level("", "Base")
|
||||
TestHelper.open_level("Graphics", "base_empty")
|
||||
|
||||
# Test steps begin.
|
||||
# 1. Create a SSAO entity with no components.
|
||||
@@ -163,10 +163,12 @@ def AtomEditorComponents_SSAO_AddedToEntity():
|
||||
|
||||
# 12. UNDO deletion.
|
||||
general.undo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_undo, ssao_entity.exists())
|
||||
|
||||
# 13. REDO deletion.
|
||||
general.redo()
|
||||
general.idle_wait_frames(1)
|
||||
Report.result(Tests.deletion_redo, not ssao_entity.exists())
|
||||
|
||||
# 14. Look for errors and asserts.
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"ContainerEntity": {
|
||||
"Id": "Entity_[1146574390643]",
|
||||
"Name": "Level",
|
||||
"Components": {
|
||||
"Component_[10641544592923449938]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 10641544592923449938
|
||||
},
|
||||
"Component_[12039882709170782873]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 12039882709170782873
|
||||
},
|
||||
"Component_[12265484671603697631]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 12265484671603697631
|
||||
},
|
||||
"Component_[14126657869720434043]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 14126657869720434043
|
||||
},
|
||||
"Component_[15230859088967841193]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 15230859088967841193,
|
||||
"Parent Entity": ""
|
||||
},
|
||||
"Component_[16239496886950819870]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 16239496886950819870
|
||||
},
|
||||
"Component_[5688118765544765547]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 5688118765544765547
|
||||
},
|
||||
"Component_[6545738857812235305]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 6545738857812235305
|
||||
},
|
||||
"Component_[7247035804068349658]": {
|
||||
"$type": "EditorPrefabComponent",
|
||||
"Id": 7247035804068349658
|
||||
},
|
||||
"Component_[9307224322037797205]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 9307224322037797205
|
||||
},
|
||||
"Component_[9562516168917670048]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 9562516168917670048
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
@@ -101,7 +101,7 @@ void CEditorPreferencesPage_AWS::SaveSettingsRegistryFile()
|
||||
return;
|
||||
}
|
||||
|
||||
bool saved{};
|
||||
[[maybe_unused]] bool saved{};
|
||||
constexpr auto configurationMode =
|
||||
AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
|
||||
if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPath.data(), configurationMode))
|
||||
|
||||
@@ -1128,7 +1128,7 @@ void SEditorSettings::SaveSettingsRegistryFile()
|
||||
return;
|
||||
}
|
||||
|
||||
bool saved{};
|
||||
[[maybe_unused]] bool saved{};
|
||||
constexpr auto configurationMode = AZ::IO::SystemFile::SF_OPEN_CREATE
|
||||
| AZ::IO::SystemFile::SF_OPEN_CREATE_PATH
|
||||
| AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
|
||||
|
||||
+18
-21
@@ -87,29 +87,15 @@ public:
|
||||
}
|
||||
|
||||
// Handle labels with submenus
|
||||
if (auto toolLabel = qobject_cast<QLabel*>(toolWidget))
|
||||
if (auto toolLabel = qobject_cast<QToolButton*>(toolWidget))
|
||||
{
|
||||
if (!toolLabel->isVisible())
|
||||
{
|
||||
// Manually turn the custom context menus into submenus
|
||||
if (toolLabel->objectName() == "m_fovStaticCtrl")
|
||||
if (toolLabel->menu())
|
||||
{
|
||||
QAction* newAction = menu->addMenu(m_viewportDlg->GetFovMenu());
|
||||
newAction->setText(QString("FOV: %1").arg(toolLabel->text()));
|
||||
}
|
||||
else if (toolLabel->objectName() == "m_ratioStaticCtrl")
|
||||
{
|
||||
QAction* newAction = menu->addMenu(m_viewportDlg->GetAspectMenu());
|
||||
newAction->setText(QString("Ratio: %1").arg(toolLabel->text()));
|
||||
}
|
||||
else if (toolLabel->objectName() == "m_sizeStaticCtrl")
|
||||
{
|
||||
QAction* newAction = menu->addMenu(m_viewportDlg->GetResolutionMenu());
|
||||
newAction->setText(QString("%1").arg(toolLabel->text()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't add actions for other Labels
|
||||
QAction* action = menu->addMenu(toolLabel->menu());
|
||||
action->setText(toolLabel->text());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -179,14 +165,25 @@ CLayoutViewPane::CLayoutViewPane(QWidget* parent)
|
||||
toolbar->installEventFilter(&m_viewportTitleDlg);
|
||||
toolbar->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(toolbar, &QWidget::customContextMenuRequested, &m_viewportTitleDlg, &QWidget::customContextMenuRequested);
|
||||
|
||||
setContextMenuPolicy(Qt::NoContextMenu);
|
||||
|
||||
|
||||
if (QToolButton* expansion = AzQtComponents::ToolBar::getToolBarExpansionButton(toolbar))
|
||||
{
|
||||
expansion->installEventFilter(m_expanderWatcher);
|
||||
}
|
||||
|
||||
AzQtComponents::BreadCrumbs* prefabsBreadcrumbs =
|
||||
qobject_cast<AzQtComponents::BreadCrumbs*>(toolbar->findChild<QWidget*>("m_prefabFocusPath"));
|
||||
QToolButton* backButton = qobject_cast<QToolButton*>(toolbar->findChild<QWidget*>("m_prefabFocusBackButton"));
|
||||
|
||||
AZ_Assert(prefabsBreadcrumbs, "Could not find Prefabs Breadcrumbs widget on CLayoutViewPane initialization!");
|
||||
AZ_Assert(backButton, "Could not find Prefabs Breadcrumbs back button on CLayoutViewPane initialization!");
|
||||
|
||||
if (prefabsBreadcrumbs && backButton)
|
||||
{
|
||||
m_viewportTitleDlg.InitializePrefabViewportFocusPathHandler(prefabsBreadcrumbs, backButton);
|
||||
}
|
||||
|
||||
m_id = -1;
|
||||
}
|
||||
|
||||
@@ -745,7 +742,7 @@ namespace
|
||||
|
||||
void PySetActiveViewport(unsigned int viewportIndex)
|
||||
{
|
||||
bool success = false;
|
||||
[[maybe_unused]] bool success = false;
|
||||
CLayoutWnd* layout = GetIEditor()->GetViewManager()->GetLayout();
|
||||
if (layout)
|
||||
{
|
||||
|
||||
@@ -383,12 +383,7 @@ void CViewportTitleDlg::OnInitDialog()
|
||||
bool isPrefabSystemEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
||||
|
||||
if (isPrefabSystemEnabled)
|
||||
{
|
||||
m_prefabViewportFocusPathHandler = new AzToolsFramework::Prefab::PrefabViewportFocusPathHandler();
|
||||
m_prefabViewportFocusPathHandler->Initialize(m_ui->m_prefabFocusPath, m_ui->m_prefabFocusBackButton);
|
||||
}
|
||||
else
|
||||
if (!isPrefabSystemEnabled)
|
||||
{
|
||||
m_ui->m_prefabFocusPath->setEnabled(false);
|
||||
m_ui->m_prefabFocusBackButton->setEnabled(false);
|
||||
@@ -397,6 +392,23 @@ void CViewportTitleDlg::OnInitDialog()
|
||||
}
|
||||
}
|
||||
|
||||
void CViewportTitleDlg::InitializePrefabViewportFocusPathHandler(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton)
|
||||
{
|
||||
if (m_prefabViewportFocusPathHandler != nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool isPrefabSystemEnabled = false;
|
||||
AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
||||
|
||||
if (isPrefabSystemEnabled)
|
||||
{
|
||||
m_prefabViewportFocusPathHandler = new AzToolsFramework::Prefab::PrefabViewportFocusPathHandler();
|
||||
m_prefabViewportFocusPathHandler->Initialize(breadcrumbsWidget, backButton);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CViewportTitleDlg::SetTitle(const QString& title)
|
||||
{
|
||||
|
||||
@@ -70,6 +70,8 @@ public:
|
||||
QMenu* const GetAspectMenu();
|
||||
QMenu* const GetResolutionMenu();
|
||||
|
||||
void InitializePrefabViewportFocusPathHandler(AzQtComponents::BreadCrumbs* breadcrumbsWidget, QToolButton* backButton);
|
||||
|
||||
Q_SIGNALS:
|
||||
void ActionTriggered(int command);
|
||||
|
||||
|
||||
@@ -80,6 +80,9 @@
|
||||
<property name="toolTip">
|
||||
<string>Camera settings</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Camera settings</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/Menu/camera.svg</normaloff>:/Menu/camera.svg</iconset>
|
||||
@@ -91,6 +94,9 @@
|
||||
<property name="toolTip">
|
||||
<string>Debug information</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Debug information</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/Menu/debug.svg</normaloff>:/Menu/debug.svg</iconset>
|
||||
@@ -105,6 +111,9 @@
|
||||
<property name="toolTip">
|
||||
<string>Toggle viewport helpers</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Toggle viewport helpers</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/Menu/helpers.svg</normaloff>:/Menu/helpers.svg</iconset>
|
||||
@@ -119,6 +128,9 @@
|
||||
<property name="toolTip">
|
||||
<string>Viewport resolution</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Viewport resolution</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/Menu/resolution.svg</normaloff>:/Menu/resolution.svg</iconset>
|
||||
@@ -130,6 +142,9 @@
|
||||
<property name="toolTip">
|
||||
<string>Other settings</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Other settings</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/Menu/menu.svg</normaloff>:/Menu/menu.svg</iconset>
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace AZ
|
||||
|
||||
void Matrix3x4SetRowGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc)
|
||||
{
|
||||
bool rowIsSet = false;
|
||||
[[maybe_unused]] bool rowIsSet = false;
|
||||
if (dc.GetNumArguments() >= 5)
|
||||
{
|
||||
if (dc.IsNumber(0))
|
||||
@@ -88,7 +88,7 @@ namespace AZ
|
||||
|
||||
void Matrix3x4SetColumnGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc)
|
||||
{
|
||||
bool columnIsSet = false;
|
||||
[[maybe_unused]] bool columnIsSet = false;
|
||||
if (dc.GetNumArguments() >= 4)
|
||||
{
|
||||
if (dc.IsNumber(0))
|
||||
@@ -133,7 +133,7 @@ namespace AZ
|
||||
|
||||
void Matrix3x4SetTranslationGeneric(Matrix3x4* thisPtr, ScriptDataContext& dc)
|
||||
{
|
||||
bool translationIsSet = false;
|
||||
[[maybe_unused]] bool translationIsSet = false;
|
||||
|
||||
if (dc.GetNumArguments() == 3 &&
|
||||
dc.IsNumber(0) &&
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace AZ
|
||||
|
||||
// check open brace
|
||||
char c = *current++;
|
||||
bool has_open_brace = false;
|
||||
[[maybe_unused]] bool has_open_brace = false;
|
||||
if (c == '{')
|
||||
{
|
||||
c = *current++;
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace AZ
|
||||
|
||||
NameDictionary::~NameDictionary()
|
||||
{
|
||||
bool leaksDetected = false;
|
||||
[[maybe_unused]] bool leaksDetected = false;
|
||||
|
||||
for (const auto& keyValue : m_dictionary)
|
||||
{
|
||||
|
||||
@@ -642,7 +642,7 @@ namespace UnitTest
|
||||
char buffer[RandomStringBufferSize];
|
||||
|
||||
AZStd::sys_time_t newNameTime;
|
||||
AZStd::sys_time_t existingNameTime;
|
||||
[[maybe_unused]] AZStd::sys_time_t existingNameTime;
|
||||
AZStd::sys_time_t stringTime;
|
||||
|
||||
{
|
||||
|
||||
@@ -195,7 +195,7 @@ namespace AzFramework::AssetBenchmark
|
||||
// Console command: Add the given list of assets to the list of assets to load with BenchmarkLoadAssetList
|
||||
void BenchmarkAddAssetsToList(const AZ::ConsoleCommandContainer& parameters)
|
||||
{
|
||||
bool allAssetsAdded = true;
|
||||
[[maybe_unused]] bool allAssetsAdded = true;
|
||||
|
||||
for (auto& assetName : parameters)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace AzFramework
|
||||
//! IntersectorBus::EventResult(result, editorContextId, &IntersectorInterface::RayIntersect, ray);
|
||||
//!
|
||||
//! Raycast against all entities
|
||||
//! RayResultAggregator rayResult;
|
||||
//! AZ::EBusReduceResult<RayResult, RayResultClosestAggregator> rayResult;
|
||||
//! IntersectorBus::BroadCastResult(rayResult, &IntersectorInterface::RayIntersect, ray);
|
||||
//
|
||||
class IntersectorInterface
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <AzCore/std/containers/span.h>
|
||||
#include <AzFramework/Entity/EntityContextBus.h>
|
||||
#include <AzFramework/Render/GeometryIntersectionStructures.h>
|
||||
#include <AzFramework/SurfaceData/SurfaceData.h>
|
||||
|
||||
namespace AzFramework
|
||||
@@ -185,6 +187,11 @@ namespace AzFramework
|
||||
SurfacePointRegionFillCallback perPositionCallback,
|
||||
Sampler sampleFilter = Sampler::DEFAULT) const = 0;
|
||||
|
||||
//! Get the terrain raycast entity context id.
|
||||
virtual EntityContextId GetTerrainRaycastEntityContextId() const = 0;
|
||||
|
||||
//! Given a ray, return the closest intersection with terrain.
|
||||
virtual RenderGeometry::RayResult GetClosestIntersection(const RenderGeometry::RayRequest& ray) const = 0;
|
||||
|
||||
private:
|
||||
// Private variations of the GetSurfacePoint API exposed to BehaviorContext that returns a value instead of
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace UnitTest
|
||||
|
||||
TEST_P(Rotation, Permutation)
|
||||
{
|
||||
int expectedErrors = -1;
|
||||
[[maybe_unused]] int expectedErrors = -1;
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
|
||||
// Given an orientation derived from the look at points
|
||||
|
||||
@@ -102,5 +102,9 @@ namespace UnitTest
|
||||
ProcessSurfaceWeightsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler));
|
||||
MOCK_CONST_METHOD4(
|
||||
ProcessSurfacePointsFromRegion, void(const AZ::Aabb&, const AZ::Vector2&, AzFramework::Terrain::SurfacePointRegionFillCallback, Sampler));
|
||||
MOCK_CONST_METHOD0(
|
||||
GetTerrainRaycastEntityContextId, AzFramework::EntityContextId());
|
||||
MOCK_CONST_METHOD1(
|
||||
GetClosestIntersection, AzFramework::RenderGeometry::RayResult(const AzFramework::RenderGeometry::RayRequest&));
|
||||
};
|
||||
} // namespace UnitTest
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace AzQtComponents
|
||||
QColor color;
|
||||
QString colorName(m_namedVariables.value(name));
|
||||
|
||||
bool colorSet = false;
|
||||
[[maybe_unused]] bool colorSet = false;
|
||||
if (QColor::isValidColor(colorName))
|
||||
{
|
||||
color.setNamedColor(colorName);
|
||||
|
||||
@@ -32,7 +32,8 @@ namespace AzQtComponents
|
||||
{
|
||||
if (QWidget* widget = item->widget())
|
||||
{
|
||||
toolbar->addWidget(widget);
|
||||
QAction* action = toolbar->addWidget(widget);
|
||||
action->setObjectName(widget->objectName());
|
||||
}
|
||||
else if (item->spacerItem())
|
||||
{
|
||||
|
||||
+1
-1
@@ -177,7 +177,7 @@ namespace AzToolsFramework
|
||||
auto data = index.data(AssetBrowserModel::Roles::EntryRole);
|
||||
if (data.canConvert<const AssetBrowserEntry*>())
|
||||
{
|
||||
bool isEnabled = (option.state & QStyle::State_Enabled) != 0;
|
||||
[[maybe_unused]] bool isEnabled = (option.state & QStyle::State_Enabled) != 0;
|
||||
|
||||
QStyle* style = option.widget ? option.widget->style() : QApplication::style();
|
||||
|
||||
|
||||
@@ -506,7 +506,7 @@ namespace AzToolsFramework
|
||||
//Remove all Links owned by the Template from TemplateToLinkIdsMap.
|
||||
Template& templateToDelete = findTemplateResult->get();
|
||||
const Template::Links& linkIdsToDelete = templateToDelete.GetLinks();
|
||||
bool result;
|
||||
[[maybe_unused]] bool result;
|
||||
for (auto linkId : linkIdsToDelete)
|
||||
{
|
||||
result = RemoveLinkIdFromTemplateToLinkIdsMap(linkId);
|
||||
@@ -774,7 +774,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
|
||||
Link& link = findLinkResult->get();
|
||||
bool result;
|
||||
[[maybe_unused]] bool result;
|
||||
result = RemoveLinkIdFromTemplateToLinkIdsMap(linkId, link);
|
||||
AZ_Assert(result,
|
||||
"Prefab - PrefabSystemComponent::RemoveLink - "
|
||||
|
||||
@@ -926,7 +926,7 @@ namespace AzToolsFramework
|
||||
const bool entityIsFromIgnoredSliceInstance = ignoreSliceInstance && ignoreSliceInstance->IsValid() && ignoreSliceInstance->GetReference()->GetSliceAsset().GetId() == instanceAddr.GetReference()->GetSliceAsset().GetId();
|
||||
if (!entityIsFromIgnoredSliceInstance)
|
||||
{
|
||||
bool foundTargetAncestor = false;
|
||||
[[maybe_unused]] bool foundTargetAncestor = false;
|
||||
|
||||
const AZ::SliceComponent::EntityList& entitiesInInstance = instanceAddr.GetInstance()->GetInstantiated()->m_entities;
|
||||
|
||||
|
||||
@@ -890,6 +890,7 @@ namespace AzToolsFramework
|
||||
|
||||
m_actionGoToEntitiesInViewport = new QAction(tr("Find in viewport"), this);
|
||||
m_actionGoToEntitiesInViewport->setShortcutContext(Qt::WidgetWithChildrenShortcut);
|
||||
m_actionGoToEntitiesInViewport->setShortcut(tr("Z"));
|
||||
connect(m_actionGoToEntitiesInViewport, &QAction::triggered, this, &EntityOutlinerWidget::GoToEntitiesInViewport);
|
||||
addAction(m_actionGoToEntitiesInViewport);
|
||||
}
|
||||
|
||||
+3
@@ -73,6 +73,9 @@ namespace AzToolsFramework::Prefab
|
||||
{
|
||||
// Push new Path
|
||||
m_breadcrumbsWidget->pushPath(m_prefabFocusPublicInterface->GetPrefabFocusPath(m_editorEntityContextId).c_str());
|
||||
|
||||
// If root instance is focused, disable the back button; else enable it.
|
||||
m_backButton->setEnabled(m_prefabFocusPublicInterface->GetPrefabFocusPathLength(m_editorEntityContextId) > 1);
|
||||
}
|
||||
|
||||
} // namespace AzToolsFramework::Prefab
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ namespace AzToolsFramework
|
||||
void PropertyEnumComboBoxCtrl::setValue(AZ::s64 value)
|
||||
{
|
||||
m_pComboBox->blockSignals(true);
|
||||
bool indexWasFound = false;
|
||||
[[maybe_unused]] bool indexWasFound = false;
|
||||
for (size_t enumValIndex = 0; enumValIndex < m_enumValues.size(); enumValIndex++)
|
||||
{
|
||||
if (m_enumValues[enumValIndex].first == value)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <AzFramework/Render/IntersectorInterface.h>
|
||||
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
|
||||
#include <AzToolsFramework/Viewport/ViewportMessages.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
@@ -66,15 +67,19 @@ namespace AzToolsFramework
|
||||
|
||||
AZ::Vector3 FindClosestPickIntersection(const AzFramework::RenderGeometry::RayRequest& rayRequest, const float defaultDistance)
|
||||
{
|
||||
AzFramework::RenderGeometry::RayResult renderGeometryIntersectionResult;
|
||||
// attempt a ray intersection with any visible mesh or terrain and return the intersection position if successful
|
||||
AZ::EBusReduceResult<AzFramework::RenderGeometry::RayResult, AzFramework::RenderGeometry::RayResultClosestAggregator> renderGeometryIntersectionResult;
|
||||
AzFramework::RenderGeometry::IntersectorBus::EventResult(
|
||||
renderGeometryIntersectionResult, AzToolsFramework::GetEntityContextId(),
|
||||
&AzFramework::RenderGeometry::IntersectorBus::Events::RayIntersect, rayRequest);
|
||||
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
|
||||
renderGeometryIntersectionResult,
|
||||
&AzFramework::Terrain::TerrainDataRequests::GetClosestIntersection,
|
||||
rayRequest);
|
||||
|
||||
// attempt a ray intersection with any visible mesh and return the intersection position if successful
|
||||
if (renderGeometryIntersectionResult)
|
||||
if (renderGeometryIntersectionResult.value)
|
||||
{
|
||||
return renderGeometryIntersectionResult.m_worldPosition;
|
||||
return renderGeometryIntersectionResult.value.m_worldPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -430,7 +430,7 @@ namespace UnitTest
|
||||
size_t nextIndex = 1;
|
||||
size_t slices = 0;
|
||||
size_t liveAllocs = 0;
|
||||
size_t totalAllocs = 0;
|
||||
[[maybe_unused]] size_t totalAllocs = 0;
|
||||
|
||||
auto cb = [&liveAllocs](void*, const AZ::Debug::AllocationInfo&, unsigned char)
|
||||
{
|
||||
|
||||
@@ -1952,8 +1952,8 @@ CarrierThread::ProcessConnections()
|
||||
|
||||
bool isHandshakeTimeOut = false;
|
||||
bool isConnectionTimeout = false;
|
||||
bool isBadTrafficConditions = false;
|
||||
bool isBadPackets = false;
|
||||
[[maybe_unused]] bool isBadTrafficConditions = false;
|
||||
[[maybe_unused]] bool isBadPackets = false;
|
||||
if (connection->m_isBadPackets)
|
||||
{
|
||||
isBadPackets = true;
|
||||
|
||||
@@ -544,7 +544,7 @@ void ApplicationManagerBase::InitConnectionManager()
|
||||
EBUS_EVENT(AssetProcessor::ConnectionBus, SendPerPlatform, 0, message, QString::fromUtf8(message.m_platform.c_str()));
|
||||
};
|
||||
|
||||
bool result = QObject::connect(GetAssetCatalog(), &AssetProcessor::AssetCatalog::SendAssetMessage, connectionAndChangeMessagesThreadContext, forwardMessageFunction, Qt::QueuedConnection);
|
||||
[[maybe_unused]] bool result = QObject::connect(GetAssetCatalog(), &AssetProcessor::AssetCatalog::SendAssetMessage, connectionAndChangeMessagesThreadContext, forwardMessageFunction, Qt::QueuedConnection);
|
||||
AZ_Assert(result, "Failed to connect to AssetCatalog signal");
|
||||
|
||||
//Application manager related stuff
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace AssetProcessor
|
||||
TNetResponse netResponse;
|
||||
netRequest.m_request = request;
|
||||
|
||||
AZ::u32 type;
|
||||
[[maybe_unused]] AZ::u32 type;
|
||||
QByteArray data;
|
||||
AZStd::binary_semaphore wait;
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace O3DE::ProjectManager
|
||||
o3deUserPath /= AZ::SettingsRegistryInterface::RegistryFolder;
|
||||
o3deUserPath /= "ProjectManager.setreg";
|
||||
|
||||
bool saved = false;
|
||||
[[maybe_unused]] bool saved = false;
|
||||
constexpr auto configurationMode =
|
||||
AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ protected:
|
||||
|
||||
sceneCoreModule = AZ::DynamicModuleHandle::Create("SceneCore");
|
||||
AZ_Assert(sceneCoreModule, "SceneBuilder unit tests failed to create SceneCore module.");
|
||||
bool loaded = sceneCoreModule->Load(false);
|
||||
[[maybe_unused]] bool loaded = sceneCoreModule->Load(false);
|
||||
AZ_Assert(loaded, "SceneBuilder unit tests failed to load SceneCore module.");
|
||||
auto init = sceneCoreModule->GetFunction<AZ::InitializeDynamicModuleFunction>(AZ::InitializeDynamicModuleFunctionName);
|
||||
AZ_Assert(init, "SceneBuilder unit tests failed to find the initialization function the SceneCore module.");
|
||||
|
||||
@@ -223,7 +223,7 @@ namespace AWSCore
|
||||
return;
|
||||
}
|
||||
|
||||
bool saved {};
|
||||
[[maybe_unused]] bool saved {};
|
||||
constexpr auto configurationMode =
|
||||
AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
|
||||
if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPathAWSPreference.c_str(), configurationMode))
|
||||
|
||||
@@ -120,9 +120,9 @@ namespace AssetValidation
|
||||
AZ::SimpleLcgRandom randomizer(seedValue);
|
||||
int lastTick = 0;
|
||||
AZStd::vector<AZ::Data::Asset<AZ::Data::AssetData>> heldAssets;
|
||||
AZStd::size_t heldCount{ 0 };
|
||||
AZ::u64 changeCount{ 0 };
|
||||
AZ::u64 blockCount{ 0 };
|
||||
[[maybe_unused]] AZStd::size_t heldCount{ 0 };
|
||||
[[maybe_unused]] AZ::u64 changeCount{ 0 };
|
||||
[[maybe_unused]] AZ::u64 blockCount{ 0 };
|
||||
AZ_TracePrintf("TestChangeAssets", "Beginning run with %zu assets\n", assetList.size());
|
||||
while (!forceStop && runMs < runTime)
|
||||
{
|
||||
|
||||
+1
-1
@@ -537,7 +537,7 @@ namespace AZ
|
||||
request.m_buffer = m_boxIndexBuffer.get();
|
||||
request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, m_boxIndices.size() * sizeof(uint16_t) };
|
||||
request.m_initialData = m_boxIndices.data();
|
||||
AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request);
|
||||
[[maybe_unused]] AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request);
|
||||
AZ_Error("DiffuseProbeGridFeatureProcessor", result == RHI::ResultCode::Success, "Failed to initialize box index buffer - error [%d]", result);
|
||||
|
||||
// create index buffer view
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace AZ
|
||||
// create the BLAS buffers for each sub-mesh, or re-use existing BLAS objects if they were already created.
|
||||
// Note: all sub-meshes must either create new BLAS objects or re-use existing ones, otherwise it's an error (it's the same model in both cases)
|
||||
// Note: the buffer is just reserved here, the BLAS is built in the RayTracingAccelerationStructurePass
|
||||
bool blasInstanceFound = false;
|
||||
[[maybe_unused]] bool blasInstanceFound = false;
|
||||
for (uint32_t subMeshIndex = 0; subMeshIndex < mesh.m_subMeshes.size(); ++subMeshIndex)
|
||||
{
|
||||
SubMesh& subMesh = mesh.m_subMeshes[subMeshIndex];
|
||||
|
||||
+1
-1
@@ -397,7 +397,7 @@ namespace AZ
|
||||
request.m_buffer = m_boxIndexBuffer.get();
|
||||
request.m_descriptor = AZ::RHI::BufferDescriptor{ AZ::RHI::BufferBindFlags::InputAssembly, m_boxIndices.size() * sizeof(uint16_t) };
|
||||
request.m_initialData = m_boxIndices.data();
|
||||
AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request);
|
||||
[[maybe_unused]] AZ::RHI::ResultCode result = m_bufferPool->InitBuffer(request);
|
||||
AZ_Error("ReflectionProbeFeatureProcessor", result == RHI::ResultCode::Success, "Failed to initialize box index buffer - error [%d]", result);
|
||||
|
||||
// create index buffer view
|
||||
|
||||
@@ -204,35 +204,56 @@ namespace AZ
|
||||
// do the enumeration for each view, keep track of the lowest lod for each entry,
|
||||
// and submit the appropriate dispatch item
|
||||
|
||||
//the [1][1] element of a perspective projection matrix stores cot(FovY/2) (equal to 2*nearPlaneDistance/nearPlaneHeight),
|
||||
//which is used to determine the (vertical) projected size in screen space
|
||||
const float yScale = viewToClip.GetElement(1, 1);
|
||||
const bool isPerspective = viewToClip.GetElement(3, 3) == 0.f;
|
||||
const Vector3 cameraPos = view->GetViewToWorldMatrix().GetTranslation();
|
||||
|
||||
const Vector3 pos = cullable.m_cullData.m_boundingSphere.GetCenter();
|
||||
|
||||
const float approxScreenPercentage = RPI::ModelLodUtils::ApproxScreenPercentage(
|
||||
pos, cullable.m_lodData.m_lodSelectionRadius, cameraPos, yScale, isPerspective);
|
||||
|
||||
for (size_t lodIndex = 0; lodIndex < cullable.m_lodData.m_lods.size(); ++lodIndex)
|
||||
switch (cullable.m_lodData.m_lodConfiguration.m_lodType)
|
||||
{
|
||||
const RPI::Cullable::LodData::Lod& lod = cullable.m_lodData.m_lods[lodIndex];
|
||||
|
||||
//Note that this supports overlapping lod ranges (to support cross-fading lods, for example)
|
||||
if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax)
|
||||
case RPI::Cullable::LodType::SpecificLod:
|
||||
{
|
||||
AZStd::lock_guard lock(m_dispatchItemMutex);
|
||||
auto lodIndex = cullable.m_lodData.m_lodConfiguration.m_lodOverride;
|
||||
m_skinningDispatches.insert(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem());
|
||||
for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy.m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++)
|
||||
{
|
||||
AZStd::lock_guard lock(m_dispatchItemMutex);
|
||||
m_skinningDispatches.insert(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem());
|
||||
for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy.m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++)
|
||||
const MorphTargetDispatchItem* dispatchItem = renderProxy.m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get();
|
||||
if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon)
|
||||
{
|
||||
const MorphTargetDispatchItem* dispatchItem = renderProxy.m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get();
|
||||
if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon)
|
||||
m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RPI::Cullable::LodType::ScreenCoverage:
|
||||
default:
|
||||
//the [1][1] element of a perspective projection matrix stores cot(FovY/2) (equal to 2*nearPlaneDistance/nearPlaneHeight),
|
||||
//which is used to determine the (vertical) projected size in screen space
|
||||
const float yScale = viewToClip.GetElement(1, 1);
|
||||
const bool isPerspective = viewToClip.GetElement(3, 3) == 0.f;
|
||||
const Vector3 cameraPos = view->GetViewToWorldMatrix().GetTranslation();
|
||||
|
||||
const Vector3 pos = cullable.m_cullData.m_boundingSphere.GetCenter();
|
||||
|
||||
const float approxScreenPercentage = RPI::ModelLodUtils::ApproxScreenPercentage(
|
||||
pos, cullable.m_lodData.m_lodSelectionRadius, cameraPos, yScale, isPerspective);
|
||||
|
||||
for (size_t lodIndex = 0; lodIndex < cullable.m_lodData.m_lods.size(); ++lodIndex)
|
||||
{
|
||||
const RPI::Cullable::LodData::Lod& lod = cullable.m_lodData.m_lods[lodIndex];
|
||||
|
||||
//Note that this supports overlapping lod ranges (to support cross-fading lods, for example)
|
||||
if (approxScreenPercentage >= lod.m_screenCoverageMin && approxScreenPercentage <= lod.m_screenCoverageMax)
|
||||
{
|
||||
AZStd::lock_guard lock(m_dispatchItemMutex);
|
||||
m_skinningDispatches.insert(&renderProxy.m_dispatchItemsByLod[lodIndex]->GetRHIDispatchItem());
|
||||
for (size_t morphTargetIndex = 0; morphTargetIndex < renderProxy.m_morphTargetDispatchItemsByLod[lodIndex].size(); morphTargetIndex++)
|
||||
{
|
||||
m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem());
|
||||
const MorphTargetDispatchItem* dispatchItem = renderProxy.m_morphTargetDispatchItemsByLod[lodIndex][morphTargetIndex].get();
|
||||
if (dispatchItem && dispatchItem->GetWeight() > AZ::Constants::FloatEpsilon)
|
||||
{
|
||||
m_morphTargetDispatches.insert(&dispatchItem->GetRHIDispatchItem());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ namespace AZ
|
||||
AZ_Assert(success, "PipelineStateEntry already exists in the pending cache.");
|
||||
}
|
||||
|
||||
ResultCode resultCode = ResultCode::InvalidArgument;
|
||||
[[maybe_unused]] ResultCode resultCode = ResultCode::InvalidArgument;
|
||||
|
||||
// Increment the pending compile count on the global entry, which tracks how many pipeline states
|
||||
// are currently being compiled across all threads.
|
||||
|
||||
@@ -120,7 +120,7 @@ namespace AZ
|
||||
AZ::RHI::BufferInitRequest scratchBufferRequest;
|
||||
scratchBufferRequest.m_buffer = buffers.m_scratchBuffer.get();
|
||||
scratchBufferRequest.m_descriptor = scratchBufferDescriptor;
|
||||
RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest);
|
||||
[[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest);
|
||||
AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create BLAS scratch buffer");
|
||||
|
||||
BufferMemoryView* scratchMemoryView = static_cast<Buffer*>(buffers.m_scratchBuffer.get())->GetBufferMemoryView();
|
||||
|
||||
@@ -170,7 +170,7 @@ namespace AZ
|
||||
createInfo.basePipelineHandle = nullptr;
|
||||
createInfo.basePipelineIndex = 0;
|
||||
|
||||
VkResult result = vkCreateRayTracingPipelinesKHR(device.GetNativeDevice(), nullptr, nullptr, 1, &createInfo, nullptr, &m_pipeline);
|
||||
[[maybe_unused]] VkResult result = vkCreateRayTracingPipelinesKHR(device.GetNativeDevice(), nullptr, nullptr, 1, &createInfo, nullptr, &m_pipeline);
|
||||
AZ_Assert(result == VK_SUCCESS, "vkCreateRayTracingPipelinesKHR failed");
|
||||
|
||||
// retrieve the shader handles
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace AZ
|
||||
AZ::RHI::BufferInitRequest shaderTableBufferRequest;
|
||||
shaderTableBufferRequest.m_buffer = shaderTableBuffer.get();
|
||||
shaderTableBufferRequest.m_descriptor = shaderTableBufferDescriptor;
|
||||
RHI::ResultCode resultCode = bufferPools.GetShaderTableBufferPool()->InitBuffer(shaderTableBufferRequest);
|
||||
[[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetShaderTableBufferPool()->InitBuffer(shaderTableBufferRequest);
|
||||
AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create shader table buffer");
|
||||
|
||||
BufferMemoryView* shaderTableMemoryView = static_cast<Buffer*>(shaderTableBuffer.get())->GetBufferMemoryView();
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace AZ
|
||||
AZ::RHI::BufferInitRequest tlasInstancesBufferRequest;
|
||||
tlasInstancesBufferRequest.m_buffer = buffers.m_tlasInstancesBuffer.get();
|
||||
tlasInstancesBufferRequest.m_descriptor = tlasInstancesBufferDescriptor;
|
||||
RHI::ResultCode resultCode = bufferPools.GetTlasInstancesBufferPool()->InitBuffer(tlasInstancesBufferRequest);
|
||||
[[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetTlasInstancesBufferPool()->InitBuffer(tlasInstancesBufferRequest);
|
||||
AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create TLAS instances buffer");
|
||||
|
||||
BufferMemoryView* tlasInstancesMemoryView = static_cast<Buffer*>(buffers.m_tlasInstancesBuffer.get())->GetBufferMemoryView();
|
||||
@@ -160,7 +160,7 @@ namespace AZ
|
||||
AZ::RHI::BufferInitRequest scratchBufferRequest;
|
||||
scratchBufferRequest.m_buffer = buffers.m_scratchBuffer.get();
|
||||
scratchBufferRequest.m_descriptor = scratchBufferDescriptor;
|
||||
RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest);
|
||||
[[maybe_unused]] RHI::ResultCode resultCode = bufferPools.GetScratchBufferPool()->InitBuffer(scratchBufferRequest);
|
||||
AZ_Assert(resultCode == RHI::ResultCode::Success, "failed to create TLAS scratch buffer");
|
||||
|
||||
BufferMemoryView* scratchMemoryView = static_cast<Buffer*>(buffers.m_scratchBuffer.get())->GetBufferMemoryView();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Name/Name.h>
|
||||
#include <AtomCore/std/containers/array_view.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
@@ -16,31 +17,38 @@ namespace AZ
|
||||
{
|
||||
class MaterialAsset;
|
||||
|
||||
//! Utility for building material property names consisting of a group name and a property sub-name.
|
||||
//! Represented as "[groupName].[propertyName]".
|
||||
//! The group name is optional, in which case the ID will just be "[propertyName]".
|
||||
//! Utility for building material property IDs.
|
||||
//! These IDs are represented like "groupA.groupB.[...].propertyName".
|
||||
//! The groups are optional, in which case the full property ID will just be like "propertyName".
|
||||
class MaterialPropertyId
|
||||
{
|
||||
public:
|
||||
static bool IsValidName(AZStd::string_view name);
|
||||
static bool IsValidName(const AZ::Name& name);
|
||||
|
||||
//! Creates a MaterialPropertyId from a full name string like "[groupName].[propertyName]" or just "[propertyName]"
|
||||
//! Creates a MaterialPropertyId from a full name string like "groupA.groupB.[...].propertyName" or just "propertyName".
|
||||
//! Also checks the name for validity.
|
||||
static MaterialPropertyId Parse(AZStd::string_view fullPropertyId);
|
||||
|
||||
MaterialPropertyId() = default;
|
||||
explicit MaterialPropertyId(AZStd::string_view propertyName);
|
||||
MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName);
|
||||
MaterialPropertyId(const Name& groupName, const Name& propertyName);
|
||||
explicit MaterialPropertyId(const AZStd::array_view<AZStd::string> names);
|
||||
|
||||
AZ_DEFAULT_COPY_MOVE(MaterialPropertyId);
|
||||
|
||||
const Name& GetGroupName() const;
|
||||
const Name& GetPropertyName() const;
|
||||
const Name& GetFullName() const;
|
||||
operator const Name&() const;
|
||||
|
||||
//! Returns a pointer to the full name ("[groupName].[propertyName]").
|
||||
//! Same as Name::GetCStr()
|
||||
//! This is included for convenience so it can be used for error messages in the same way an AZ::Name is used.
|
||||
const char* GetCStr() const;
|
||||
|
||||
//! Returns a string_view of the full name ("[groupName].[propertyName]").
|
||||
//! Same as Name::GetStringView()
|
||||
//! This is included for convenience so it can be used for string comparison in the same way an AZ::Name is used.
|
||||
AZStd::string_view GetStringView() const;
|
||||
|
||||
//! Returns a hash of the full name. This is needed for compatibility with NameIdReflectionMap.
|
||||
Name::Hash GetHash() const;
|
||||
@@ -52,8 +60,6 @@ namespace AZ
|
||||
|
||||
private:
|
||||
Name m_fullName;
|
||||
Name m_groupName;
|
||||
Name m_propertyName;
|
||||
};
|
||||
} // namespace RPI
|
||||
|
||||
|
||||
@@ -27,63 +27,84 @@ namespace AZ
|
||||
|
||||
bool MaterialPropertyId::IsValid() const
|
||||
{
|
||||
const bool groupNameIsValid = m_groupName.IsEmpty() || IsValidName(m_groupName);
|
||||
const bool propertyNameIsValid = IsValidName(m_propertyName);
|
||||
return groupNameIsValid && propertyNameIsValid;
|
||||
return !m_fullName.IsEmpty();
|
||||
}
|
||||
|
||||
MaterialPropertyId MaterialPropertyId::Parse(AZStd::string_view fullPropertyId)
|
||||
{
|
||||
AZStd::vector<AZStd::string> tokens;
|
||||
AzFramework::StringFunc::Tokenize(fullPropertyId.data(), tokens, '.', true, true);
|
||||
AzFramework::StringFunc::Tokenize(fullPropertyId, tokens, '.', true, true);
|
||||
|
||||
if (tokens.size() == 1)
|
||||
if (tokens.empty())
|
||||
{
|
||||
return MaterialPropertyId{"", tokens[0]};
|
||||
AZ_Error("MaterialPropertyId", false, "Property ID is empty.", fullPropertyId.data());
|
||||
return MaterialPropertyId{};
|
||||
}
|
||||
else if (tokens.size() == 2)
|
||||
|
||||
for (const auto& token : tokens)
|
||||
{
|
||||
return MaterialPropertyId{tokens[0], tokens[1]};
|
||||
if (!IsValidName(token))
|
||||
{
|
||||
AZ_Error("MaterialPropertyId", false, "Property ID '%.*s' is not a valid identifier.", AZ_STRING_ARG(fullPropertyId));
|
||||
return MaterialPropertyId{};
|
||||
}
|
||||
}
|
||||
|
||||
MaterialPropertyId id;
|
||||
id.m_fullName = fullPropertyId;
|
||||
return id;
|
||||
}
|
||||
|
||||
MaterialPropertyId::MaterialPropertyId(AZStd::string_view propertyName)
|
||||
{
|
||||
if (!IsValidName(propertyName))
|
||||
{
|
||||
AZ_Error("MaterialPropertyId", false, "Property name '%.*s' is not a valid identifier.", AZ_STRING_ARG(propertyName));
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("MaterialPropertyId", false, "Property ID '%s' is not a valid identifier.", fullPropertyId.data());
|
||||
return MaterialPropertyId{};
|
||||
m_fullName = propertyName;
|
||||
}
|
||||
}
|
||||
|
||||
MaterialPropertyId::MaterialPropertyId(AZStd::string_view groupName, AZStd::string_view propertyName)
|
||||
: MaterialPropertyId(Name{groupName}, Name{propertyName})
|
||||
{
|
||||
}
|
||||
|
||||
MaterialPropertyId::MaterialPropertyId(const Name& groupName, const Name& propertyName)
|
||||
{
|
||||
AZ_Error("MaterialPropertyId", groupName.IsEmpty() || IsValidName(groupName), "Group name '%s' is not a valid identifier.", groupName.GetCStr());
|
||||
AZ_Error("MaterialPropertyId", IsValidName(propertyName), "Property name '%s' is not a valid identifier.", propertyName.GetCStr());
|
||||
m_groupName = groupName;
|
||||
m_propertyName = propertyName;
|
||||
if (groupName.IsEmpty())
|
||||
if (!IsValidName(groupName))
|
||||
{
|
||||
m_fullName = m_propertyName.GetStringView();
|
||||
AZ_Error("MaterialPropertyId", false, "Group name '%.*s' is not a valid identifier.", AZ_STRING_ARG(groupName));
|
||||
}
|
||||
else if (!IsValidName(propertyName))
|
||||
{
|
||||
AZ_Error("MaterialPropertyId", false, "Property name '%.*s' is not a valid identifier.", AZ_STRING_ARG(propertyName));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fullName = AZStd::string::format("%s.%s", m_groupName.GetCStr(), m_propertyName.GetCStr());
|
||||
m_fullName = AZStd::string::format("%.*s.%.*s", AZ_STRING_ARG(groupName), AZ_STRING_ARG(propertyName));
|
||||
}
|
||||
}
|
||||
|
||||
const Name& MaterialPropertyId::GetGroupName() const
|
||||
|
||||
MaterialPropertyId::MaterialPropertyId(const Name& groupName, const Name& propertyName)
|
||||
: MaterialPropertyId(groupName.GetStringView(), propertyName.GetStringView())
|
||||
{
|
||||
return m_groupName;
|
||||
}
|
||||
|
||||
MaterialPropertyId::MaterialPropertyId(const AZStd::array_view<AZStd::string> names)
|
||||
{
|
||||
for (const auto& name : names)
|
||||
{
|
||||
if (!IsValidName(name))
|
||||
{
|
||||
AZ_Error("MaterialPropertyId", false, "'%s' is not a valid identifier.", name.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string fullName; // m_fullName is a Name, not a string, so we have to join into a local variable temporarily.
|
||||
AzFramework::StringFunc::Join(fullName, names.begin(), names.end(), ".");
|
||||
m_fullName = fullName;
|
||||
}
|
||||
|
||||
const Name& MaterialPropertyId::GetPropertyName() const
|
||||
{
|
||||
return m_propertyName;
|
||||
}
|
||||
|
||||
const Name& MaterialPropertyId::GetFullName() const
|
||||
MaterialPropertyId::operator const Name&() const
|
||||
{
|
||||
return m_fullName;
|
||||
}
|
||||
@@ -92,6 +113,11 @@ namespace AZ
|
||||
{
|
||||
return m_fullName.GetCStr();
|
||||
}
|
||||
|
||||
AZStd::string_view MaterialPropertyId::GetStringView() const
|
||||
{
|
||||
return m_fullName.GetStringView();
|
||||
}
|
||||
|
||||
Name::Hash MaterialPropertyId::GetHash() const
|
||||
{
|
||||
|
||||
@@ -340,16 +340,16 @@ namespace AZ
|
||||
if (result == MaterialUtils::GetImageAssetResult::Missing)
|
||||
{
|
||||
materialAssetCreator.ReportWarning(
|
||||
"Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(),
|
||||
"Material property '%s': Could not find the image '%s'", propertyId.GetCStr(),
|
||||
property.second.m_value.GetValue<AZStd::string>().data());
|
||||
}
|
||||
|
||||
imageAsset.SetAutoLoadBehavior(Data::AssetLoadBehavior::PreLoad);
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
|
||||
materialAssetCreator.SetPropertyValue(propertyId, imageAsset);
|
||||
}
|
||||
else
|
||||
{
|
||||
materialAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.second.m_value);
|
||||
materialAssetCreator.SetPropertyValue(propertyId, property.second.m_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ namespace AZ
|
||||
{
|
||||
if (action.m_operation == "rename")
|
||||
{
|
||||
if (action.m_renameFrom == propertyId.GetFullName().GetStringView())
|
||||
if (action.m_renameFrom == propertyId.GetStringView())
|
||||
{
|
||||
propertyId = MaterialPropertyId::Parse(action.m_renameTo);
|
||||
renamed = true;
|
||||
@@ -177,14 +177,19 @@ namespace AZ
|
||||
|
||||
// Do the search again with the new names
|
||||
|
||||
groupIter = m_propertyLayout.m_properties.find(propertyId.GetGroupName().GetStringView());
|
||||
if (groupIter != m_propertyLayout.m_properties.end())
|
||||
AZStd::vector<AZStd::string> tokens;
|
||||
AZ::StringFunc::Tokenize(propertyId.GetStringView(), tokens, ".", true, true);
|
||||
if (tokens.size() == 2)
|
||||
{
|
||||
for (const PropertyDefinition& property : groupIter->second)
|
||||
groupIter = m_propertyLayout.m_properties.find(tokens[0]);
|
||||
if (groupIter != m_propertyLayout.m_properties.end())
|
||||
{
|
||||
if (property.m_name == propertyId.GetPropertyName().GetStringView())
|
||||
for (const PropertyDefinition& property : groupIter->second)
|
||||
{
|
||||
return &property;
|
||||
if (property.m_name == tokens[1])
|
||||
{
|
||||
return &property;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -400,7 +405,7 @@ namespace AZ
|
||||
continue;
|
||||
}
|
||||
|
||||
materialTypeAssetCreator.BeginMaterialProperty(propertyId.GetFullName(), property.m_dataType);
|
||||
materialTypeAssetCreator.BeginMaterialProperty(propertyId, property.m_dataType);
|
||||
|
||||
if (property.m_dataType == MaterialPropertyDataType::Enum)
|
||||
{
|
||||
@@ -454,18 +459,18 @@ namespace AZ
|
||||
if (result == MaterialUtils::GetImageAssetResult::Missing)
|
||||
{
|
||||
materialTypeAssetCreator.ReportError(
|
||||
"Material property '%s': Could not find the image '%s'", propertyId.GetFullName().GetCStr(),
|
||||
"Material property '%s': Could not find the image '%s'", propertyId.GetCStr(),
|
||||
property.m_value.GetValue<AZStd::string>().data());
|
||||
}
|
||||
else
|
||||
{
|
||||
materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), imageAsset);
|
||||
materialTypeAssetCreator.SetPropertyValue(propertyId, imageAsset);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MaterialPropertyDataType::Enum:
|
||||
{
|
||||
MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName());
|
||||
MaterialPropertyIndex propertyIndex = materialTypeAssetCreator.GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId);
|
||||
const MaterialPropertyDescriptor* propertyDescriptor = materialTypeAssetCreator.GetMaterialPropertiesLayout()->GetPropertyDescriptor(propertyIndex);
|
||||
|
||||
AZ::Name enumName = AZ::Name(property.m_value.GetValue<AZStd::string>());
|
||||
@@ -476,12 +481,12 @@ namespace AZ
|
||||
}
|
||||
else
|
||||
{
|
||||
materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), enumValue);
|
||||
materialTypeAssetCreator.SetPropertyValue(propertyId, enumValue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
materialTypeAssetCreator.SetPropertyValue(propertyId.GetFullName(), property.m_value);
|
||||
materialTypeAssetCreator.SetPropertyValue(propertyId, property.m_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ namespace AZ
|
||||
|
||||
void Scene::RemoveRenderPipeline(const RenderPipelineId& pipelineId)
|
||||
{
|
||||
bool removed = false;
|
||||
[[maybe_unused]] bool removed = false;
|
||||
for (auto it = m_pipelines.begin(); it != m_pipelines.end(); ++it)
|
||||
{
|
||||
if (pipelineId == (*it)->GetId())
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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 <AzTest/AzTest.h>
|
||||
#include <Common/RPITestFixture.h>
|
||||
#include <Common/ErrorMessageFinder.h>
|
||||
#include <Atom/RPI.Edit/Material/MaterialPropertyId.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
using namespace AZ;
|
||||
using namespace RPI;
|
||||
|
||||
class MaterialPropertyIdTests
|
||||
: public RPITestFixture
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(MaterialPropertyIdTests, TestConstructWithPropertyName)
|
||||
{
|
||||
MaterialPropertyId id{"color"};
|
||||
EXPECT_TRUE(id.IsValid());
|
||||
EXPECT_STREQ(id.GetCStr(), "color");
|
||||
AZ::Name idCastedToName = id;
|
||||
EXPECT_EQ(idCastedToName, AZ::Name{"color"});
|
||||
}
|
||||
|
||||
TEST_F(MaterialPropertyIdTests, TestConstructWithPropertyName_BadName)
|
||||
{
|
||||
ErrorMessageFinder errorMessageFinder;
|
||||
errorMessageFinder.AddExpectedErrorMessage("not a valid identifier");
|
||||
|
||||
MaterialPropertyId id{"color?"};
|
||||
EXPECT_FALSE(id.IsValid());
|
||||
|
||||
errorMessageFinder.CheckExpectedErrorsFound();
|
||||
}
|
||||
|
||||
TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames)
|
||||
{
|
||||
MaterialPropertyId id{"baseColor", "factor"};
|
||||
EXPECT_TRUE(id.IsValid());
|
||||
EXPECT_STREQ(id.GetCStr(), "baseColor.factor");
|
||||
AZ::Name idCastedToName = id;
|
||||
EXPECT_EQ(idCastedToName, AZ::Name{"baseColor.factor"});
|
||||
}
|
||||
|
||||
TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames_BadGroupName)
|
||||
{
|
||||
ErrorMessageFinder errorMessageFinder;
|
||||
errorMessageFinder.AddExpectedErrorMessage("not a valid identifier");
|
||||
|
||||
MaterialPropertyId id{"layer1.baseColor", "factor"};
|
||||
EXPECT_FALSE(id.IsValid());
|
||||
|
||||
errorMessageFinder.CheckExpectedErrorsFound();
|
||||
}
|
||||
|
||||
TEST_F(MaterialPropertyIdTests, TestConstructWithTwoNames_BadPropertyName)
|
||||
{
|
||||
ErrorMessageFinder errorMessageFinder;
|
||||
errorMessageFinder.AddExpectedErrorMessage("not a valid identifier");
|
||||
|
||||
MaterialPropertyId id{"baseColor", ".factor"};
|
||||
EXPECT_FALSE(id.IsValid());
|
||||
|
||||
errorMessageFinder.CheckExpectedErrorsFound();
|
||||
}
|
||||
|
||||
TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleNames)
|
||||
{
|
||||
AZStd::vector<AZStd::string> names{"layer1", "clearCoat", "normal", "factor"};
|
||||
MaterialPropertyId id{names};
|
||||
EXPECT_TRUE(id.IsValid());
|
||||
EXPECT_STREQ(id.GetCStr(), "layer1.clearCoat.normal.factor");
|
||||
AZ::Name idCastedToName = id;
|
||||
EXPECT_EQ(idCastedToName, AZ::Name{"layer1.clearCoat.normal.factor"});
|
||||
}
|
||||
|
||||
TEST_F(MaterialPropertyIdTests, TestConstructWithMultipleNames_BadName)
|
||||
{
|
||||
ErrorMessageFinder errorMessageFinder;
|
||||
errorMessageFinder.AddExpectedErrorMessage("not a valid identifier");
|
||||
|
||||
AZStd::vector<AZStd::string> names{"layer1", "clear-coat", "normal", "factor"};
|
||||
MaterialPropertyId id{names};
|
||||
EXPECT_FALSE(id.IsValid());
|
||||
|
||||
errorMessageFinder.CheckExpectedErrorsFound();
|
||||
}
|
||||
|
||||
TEST_F(MaterialPropertyIdTests, TestParse)
|
||||
{
|
||||
MaterialPropertyId id = MaterialPropertyId::Parse("layer1.clearCoat.normal.factor");
|
||||
EXPECT_TRUE(id.IsValid());
|
||||
EXPECT_STREQ(id.GetCStr(), "layer1.clearCoat.normal.factor");
|
||||
AZ::Name idCastedToName = id;
|
||||
EXPECT_EQ(idCastedToName, AZ::Name{"layer1.clearCoat.normal.factor"});
|
||||
}
|
||||
|
||||
TEST_F(MaterialPropertyIdTests, TestParse_BadName)
|
||||
{
|
||||
ErrorMessageFinder errorMessageFinder;
|
||||
errorMessageFinder.AddExpectedErrorMessage("not a valid identifier");
|
||||
|
||||
MaterialPropertyId id = MaterialPropertyId::Parse("layer1.clearCoat.normal,factor");
|
||||
EXPECT_FALSE(id.IsValid());
|
||||
|
||||
errorMessageFinder.CheckExpectedErrorsFound();
|
||||
}
|
||||
|
||||
TEST_F(MaterialPropertyIdTests, TestNameValidity)
|
||||
{
|
||||
EXPECT_TRUE(MaterialPropertyId::IsValidName("a"));
|
||||
EXPECT_TRUE(MaterialPropertyId::IsValidName("z"));
|
||||
EXPECT_TRUE(MaterialPropertyId::IsValidName("A"));
|
||||
EXPECT_TRUE(MaterialPropertyId::IsValidName("Z"));
|
||||
EXPECT_TRUE(MaterialPropertyId::IsValidName("_"));
|
||||
EXPECT_TRUE(MaterialPropertyId::IsValidName("m_layer10bazBAZ"));
|
||||
EXPECT_FALSE(MaterialPropertyId::IsValidName(""));
|
||||
EXPECT_FALSE(MaterialPropertyId::IsValidName("1layer"));
|
||||
EXPECT_FALSE(MaterialPropertyId::IsValidName("base-color"));
|
||||
EXPECT_FALSE(MaterialPropertyId::IsValidName("base.color"));
|
||||
EXPECT_FALSE(MaterialPropertyId::IsValidName("base/color"));
|
||||
}
|
||||
}
|
||||
@@ -905,7 +905,7 @@ namespace UnitTest
|
||||
JsonTestResult loadResult = LoadTestDataFromJson(material, inputJson);
|
||||
auto materialAssetResult = material.CreateMaterialAsset(Uuid::CreateRandom(), "test.material", AZ::RPI::MaterialAssetProcessingMode::PreBake);
|
||||
EXPECT_TRUE(materialAssetResult);
|
||||
MaterialPropertyIndex propertyIndex = materialAssetResult.GetValue()->GetMaterialPropertiesLayout()->FindPropertyIndex(MaterialPropertyId{groupName, propertyName}.GetFullName());
|
||||
MaterialPropertyIndex propertyIndex = materialAssetResult.GetValue()->GetMaterialPropertiesLayout()->FindPropertyIndex(MaterialPropertyId{groupName, propertyName});
|
||||
CheckSimilar(expectedFinalValue, materialAssetResult.GetValue()->GetPropertyValues()[propertyIndex.GetIndex()].GetValue<PropertyTypeT>());
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ set(FILES
|
||||
Tests/Material/MaterialSourceDataTests.cpp
|
||||
Tests/Material/MaterialFunctorTests.cpp
|
||||
Tests/Material/MaterialFunctorSourceDataSerializerTests.cpp
|
||||
Tests/Material/MaterialPropertyIdTests.cpp
|
||||
Tests/Material/MaterialPropertyValueSourceDataTests.cpp
|
||||
Tests/Material/MaterialTests.cpp
|
||||
Tests/Model/ModelTests.cpp
|
||||
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/std/containers/vector.h>
|
||||
#endif
|
||||
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
class QListWidgetItem;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class AssetGridDialog;
|
||||
}
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
//! Widget for managing and selecting from a library of assets
|
||||
class AssetGridDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct SelectableAsset
|
||||
{
|
||||
AZ::Data::AssetId m_assetId;
|
||||
QString m_title;
|
||||
};
|
||||
|
||||
using SelectableAssetVector = AZStd::vector<SelectableAsset>;
|
||||
|
||||
AssetGridDialog(
|
||||
const QString& title,
|
||||
const SelectableAssetVector& selectableAssets,
|
||||
const AZ::Data::AssetId& selectedAsset,
|
||||
const QSize& tileSize,
|
||||
QWidget* parent = nullptr);
|
||||
|
||||
~AssetGridDialog();
|
||||
|
||||
Q_SIGNALS:
|
||||
void AssetSelected(const AZ::Data::AssetId& assetId);
|
||||
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(AssetGridDialog);
|
||||
|
||||
QListWidgetItem* CreateListItem(const SelectableAsset& selectableAsset);
|
||||
void SetupAssetList();
|
||||
void SetupSearchWidget();
|
||||
void SetupDialogButtons();
|
||||
void ApplySearchFilter();
|
||||
void ShowSearchMenu(const QPoint& pos);
|
||||
void SelectCurrentAsset();
|
||||
void SelectInitialAsset();
|
||||
|
||||
QSize m_tileSize;
|
||||
AZ::Data::AssetId m_initialSelectedAsset;
|
||||
QScopedPointer<Ui::AssetGridDialog> m_ui;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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 <AssetGridDialog/ui_AssetGridDialog.h>
|
||||
#include <AtomToolsFramework/AssetGridDialog/AssetGridDialog.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
#include <AzQtComponents/Components/Widgets/ElidingLabel.h>
|
||||
#include <AzQtComponents/Components/Widgets/LineEdit.h>
|
||||
#include <AzQtComponents/Components/Widgets/Text.h>
|
||||
#include <AzToolsFramework/AssetBrowser/Thumbnails/ProductThumbnail.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailContext.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailWidget.h>
|
||||
#include <AzToolsFramework/Thumbnails/ThumbnailerBus.h>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMenu>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
AssetGridDialog::AssetGridDialog(
|
||||
const QString& title,
|
||||
const SelectableAssetVector& selectableAssets,
|
||||
const AZ::Data::AssetId& selectedAsset,
|
||||
const QSize& tileSize,
|
||||
QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_tileSize(tileSize)
|
||||
, m_initialSelectedAsset(selectedAsset)
|
||||
, m_ui(new Ui::AssetGridDialog)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
QSignalBlocker signalBlocker(this);
|
||||
|
||||
setWindowTitle(title);
|
||||
|
||||
SetupAssetList();
|
||||
SetupSearchWidget();
|
||||
SetupDialogButtons();
|
||||
setModal(true);
|
||||
|
||||
QListWidgetItem* selectedItem = nullptr;
|
||||
for (const auto& selectableAsset : selectableAssets)
|
||||
{
|
||||
QListWidgetItem* item = CreateListItem(selectableAsset);
|
||||
if (!selectedItem || m_initialSelectedAsset == selectableAsset.m_assetId)
|
||||
{
|
||||
selectedItem = item;
|
||||
}
|
||||
}
|
||||
|
||||
m_ui->m_assetList->sortItems();
|
||||
|
||||
if (selectedItem)
|
||||
{
|
||||
m_ui->m_assetList->setCurrentItem(selectedItem);
|
||||
m_ui->m_assetList->scrollToItem(selectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
AssetGridDialog::~AssetGridDialog()
|
||||
{
|
||||
}
|
||||
|
||||
QListWidgetItem* AssetGridDialog::CreateListItem(const SelectableAsset& selectableAsset)
|
||||
{
|
||||
const int itemBorder = aznumeric_cast<int>(
|
||||
AtomToolsFramework::GetSettingOrDefault<AZ::u64>("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/ItemBorder", 4));
|
||||
const int itemSpacing = aznumeric_cast<int>(
|
||||
AtomToolsFramework::GetSettingOrDefault<AZ::u64>("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/ItemSpacing", 10));
|
||||
const int headerHeight = aznumeric_cast<int>(
|
||||
AtomToolsFramework::GetSettingOrDefault<AZ::u64>("/O3DE/Atom/AtomToolsFramework/AssetGridDialog/HeaderHeight", 15));
|
||||
|
||||
const QSize gridSize = m_ui->m_assetList->gridSize();
|
||||
m_ui->m_assetList->setGridSize(QSize(
|
||||
AZStd::max(gridSize.width(), m_tileSize.width() + itemSpacing),
|
||||
AZStd::max(gridSize.height(), m_tileSize.height() + itemSpacing + headerHeight)));
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem(m_ui->m_assetList);
|
||||
item->setData(Qt::DisplayRole, selectableAsset.m_title);
|
||||
item->setData(Qt::UserRole, QString(selectableAsset.m_assetId.ToString<AZStd::string>().c_str()));
|
||||
item->setSizeHint(m_tileSize + QSize(itemBorder, itemBorder + headerHeight));
|
||||
m_ui->m_assetList->addItem(item);
|
||||
|
||||
QWidget* itemWidget = new QWidget(m_ui->m_assetList);
|
||||
itemWidget->setLayout(new QVBoxLayout(itemWidget));
|
||||
itemWidget->layout()->setSpacing(0);
|
||||
itemWidget->layout()->setMargin(0);
|
||||
|
||||
AzQtComponents::ElidingLabel* header = new AzQtComponents::ElidingLabel(itemWidget);
|
||||
header->setText(selectableAsset.m_title);
|
||||
header->setFixedSize(QSize(m_tileSize.width(), headerHeight));
|
||||
header->setMargin(0);
|
||||
header->setStyleSheet("background-color: rgb(35, 35, 35)");
|
||||
AzQtComponents::Text::addPrimaryStyle(header);
|
||||
AzQtComponents::Text::addLabelStyle(header);
|
||||
itemWidget->layout()->addWidget(header);
|
||||
|
||||
AzToolsFramework::Thumbnailer::ThumbnailWidget* thumbnail = new AzToolsFramework::Thumbnailer::ThumbnailWidget(itemWidget);
|
||||
thumbnail->setFixedSize(m_tileSize);
|
||||
thumbnail->SetThumbnailKey(
|
||||
MAKE_TKEY(AzToolsFramework::AssetBrowser::ProductThumbnailKey, selectableAsset.m_assetId),
|
||||
AzToolsFramework::Thumbnailer::ThumbnailContext::DefaultContext);
|
||||
thumbnail->updateGeometry();
|
||||
itemWidget->layout()->addWidget(thumbnail);
|
||||
|
||||
m_ui->m_assetList->setItemWidget(item, itemWidget);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void AssetGridDialog::SetupAssetList()
|
||||
{
|
||||
m_ui->m_assetList->setFlow(QListView::LeftToRight);
|
||||
m_ui->m_assetList->setResizeMode(QListView::Adjust);
|
||||
m_ui->m_assetList->setGridSize(QSize(0, 0));
|
||||
m_ui->m_assetList->setWrapping(true);
|
||||
|
||||
QObject::connect(m_ui->m_assetList, &QListWidget::currentItemChanged, [this](){ SelectCurrentAsset(); });
|
||||
}
|
||||
|
||||
void AssetGridDialog::SetupSearchWidget()
|
||||
{
|
||||
m_ui->m_searchWidget->setReadOnly(false);
|
||||
m_ui->m_searchWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
AzQtComponents::LineEdit::applySearchStyle(m_ui->m_searchWidget);
|
||||
connect(m_ui->m_searchWidget, &QLineEdit::textChanged, this, [this](){ ApplySearchFilter(); });
|
||||
connect(m_ui->m_searchWidget, &QWidget::customContextMenuRequested, this, [this](const QPoint& pos){ ShowSearchMenu(pos); });
|
||||
}
|
||||
|
||||
void AssetGridDialog::SetupDialogButtons()
|
||||
{
|
||||
connect(m_ui->m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(m_ui->m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
connect(this, &QDialog::rejected, this, [this](){ SelectInitialAsset(); });
|
||||
}
|
||||
|
||||
void AssetGridDialog::ApplySearchFilter()
|
||||
{
|
||||
for (int index = 0; index < m_ui->m_assetList->count(); ++index)
|
||||
{
|
||||
QListWidgetItem* item = m_ui->m_assetList->item(index);
|
||||
const QString& title = item->data(Qt::DisplayRole).toString();
|
||||
const QString filter = m_ui->m_searchWidget->text();
|
||||
item->setHidden(!filter.isEmpty() && !title.contains(filter, Qt::CaseInsensitive));
|
||||
}
|
||||
}
|
||||
|
||||
void AssetGridDialog::ShowSearchMenu(const QPoint& pos)
|
||||
{
|
||||
QScopedPointer<QMenu> menu(m_ui->m_searchWidget->createStandardContextMenu());
|
||||
menu->setStyleSheet("background-color: #333333");
|
||||
menu->exec(m_ui->m_searchWidget->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
void AssetGridDialog::SelectCurrentAsset()
|
||||
{
|
||||
auto item = m_ui->m_assetList->currentItem();
|
||||
if (item)
|
||||
{
|
||||
AZ::Data::AssetId assetId = AZ::Data::AssetId::CreateString(item->data(Qt::UserRole).toString().toUtf8().constData());
|
||||
emit AssetSelected(assetId);
|
||||
}
|
||||
}
|
||||
|
||||
void AssetGridDialog::SelectInitialAsset()
|
||||
{
|
||||
emit AssetSelected(m_initialSelectedAsset);
|
||||
}
|
||||
} // namespace AtomToolsFramework
|
||||
|
||||
#include <AtomToolsFramework/AssetGridDialog/moc_AssetGridDialog.cpp>
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PresetBrowserDialog</class>
|
||||
<widget class="QWidget" name="PresetBrowserDialog">
|
||||
<class>AssetGridDialog</class>
|
||||
<widget class="QWidget" name="AssetGridDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
@@ -26,7 +26,7 @@
|
||||
<widget class="QLineEdit" name="m_searchWidget"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="m_presetList"/>
|
||||
<widget class="QListWidget" name="m_assetList"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
@@ -9,6 +9,7 @@
|
||||
set(FILES
|
||||
Include/AtomToolsFramework/Application/AtomToolsApplication.h
|
||||
Include/AtomToolsFramework/AssetBrowser/AtomToolsAssetBrowser.h
|
||||
Include/AtomToolsFramework/AssetGridDialog/AssetGridDialog.h
|
||||
Include/AtomToolsFramework/Communication/LocalServer.h
|
||||
Include/AtomToolsFramework/Communication/LocalSocket.h
|
||||
Include/AtomToolsFramework/Debug/TraceRecorder.h
|
||||
@@ -41,6 +42,8 @@ set(FILES
|
||||
Source/AssetBrowser/AtomToolsAssetBrowser.cpp
|
||||
Source/AssetBrowser/AtomToolsAssetBrowser.qrc
|
||||
Source/AssetBrowser/AtomToolsAssetBrowser.ui
|
||||
Source/AssetGridDialog/AssetGridDialog.cpp
|
||||
Source/AssetGridDialog/AssetGridDialog.ui
|
||||
Source/Communication/LocalServer.cpp
|
||||
Source/Communication/LocalSocket.cpp
|
||||
Source/Debug/TraceRecorder.cpp
|
||||
|
||||
@@ -589,15 +589,15 @@ namespace MaterialEditor
|
||||
|
||||
const MaterialPropertyId propertyId(groupName, propertyName);
|
||||
|
||||
const auto it = m_properties.find(propertyId.GetFullName());
|
||||
const auto it = m_properties.find(propertyId);
|
||||
if (it != m_properties.end() && propertyFilter(it->second))
|
||||
{
|
||||
MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue());
|
||||
if (propertyValue.IsValid())
|
||||
{
|
||||
if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyId.GetFullName(), propertyDefinition, propertyValue))
|
||||
if (!AtomToolsFramework::ConvertToExportFormat(exportPath, propertyId, propertyDefinition, propertyValue))
|
||||
{
|
||||
AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str());
|
||||
AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetCStr(), m_absolutePath.c_str());
|
||||
result = false;
|
||||
return false;
|
||||
}
|
||||
@@ -783,7 +783,7 @@ namespace MaterialEditor
|
||||
AtomToolsFramework::DynamicPropertyConfig propertyConfig;
|
||||
|
||||
// Assign id before conversion so it can be used in dynamic description
|
||||
propertyConfig.m_id = MaterialPropertyId(groupName, propertyName).GetCStr();
|
||||
propertyConfig.m_id = MaterialPropertyId(groupName, propertyName);
|
||||
|
||||
const auto& propertyIndex = m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyConfig.m_id);
|
||||
const bool propertyIndexInBounds = propertyIndex.IsValid() && propertyIndex.GetIndex() < m_materialAsset->GetPropertyValues().size();
|
||||
@@ -854,7 +854,7 @@ namespace MaterialEditor
|
||||
|
||||
propertyConfig = {};
|
||||
propertyConfig.m_dataType = AtomToolsFramework::DynamicPropertyType::String;
|
||||
propertyConfig.m_id = MaterialPropertyId(UvGroupName, shaderInput).GetCStr();
|
||||
propertyConfig.m_id = MaterialPropertyId(UvGroupName, shaderInput);
|
||||
propertyConfig.m_name = shaderInput;
|
||||
propertyConfig.m_displayName = shaderInput;
|
||||
propertyConfig.m_groupName = "UV Sets";
|
||||
|
||||
@@ -1,462 +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
|
||||
*
|
||||
*/
|
||||
|
||||
#undef RC_INVOKED
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
|
||||
#include <AzFramework/Components/NonUniformScaleComponent.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Entity/GameEntityContextBus.h>
|
||||
|
||||
#include <AtomCore/Instance/InstanceDatabase.h>
|
||||
|
||||
#include <Atom/RPI.Public/Image/StreamingImage.h>
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
#include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/WindowContext.h>
|
||||
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
||||
|
||||
#include <Atom/Component/DebugCamera/CameraComponent.h>
|
||||
#include <Atom/Component/DebugCamera/NoClipControllerComponent.h>
|
||||
#include <Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h>
|
||||
#include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/PostProcessing/PostProcessingConstants.h>
|
||||
|
||||
#include <Atom/Feature/Utils/LightingPreset.h>
|
||||
#include <Atom/Feature/Utils/ModelPreset.h>
|
||||
|
||||
#include <AtomLyIntegration/CommonFeatures/Grid/GridComponentConfig.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Grid/GridComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/ImageBasedLights/ImageBasedLightComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/ImageBasedLights/ImageBasedLightComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/PostProcess/PostFxLayerComponentConstants.h>
|
||||
|
||||
#include <Document/MaterialDocumentRequestBus.h>
|
||||
#include <Viewport/MaterialViewportRenderer.h>
|
||||
#include <Viewport/MaterialViewportRequestBus.h>
|
||||
#include <Viewport/MaterialViewportSettings.h>
|
||||
#include <Viewport/PerformanceMonitorRequestBus.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
static constexpr float DepthNear = 0.01f;
|
||||
|
||||
MaterialViewportRenderer::MaterialViewportRenderer(AZStd::shared_ptr<AZ::RPI::WindowContext> windowContext)
|
||||
: m_windowContext(windowContext)
|
||||
, m_viewportController(AZStd::make_shared<MaterialEditorViewportInputController>())
|
||||
{
|
||||
using namespace AZ;
|
||||
using namespace Data;
|
||||
|
||||
// Create and register a scene with all available feature processors
|
||||
AZ::RPI::SceneDescriptor sceneDesc;
|
||||
sceneDesc.m_nameId = AZ::Name("MaterialViewport");
|
||||
m_scene = AZ::RPI::Scene::CreateScene(sceneDesc);
|
||||
m_scene->EnableAllFeatureProcessors();
|
||||
|
||||
// Bind m_defaultScene to the GameEntityContext's AzFramework::Scene
|
||||
auto sceneSystem = AzFramework::SceneSystemInterface::Get();
|
||||
AZ_Assert(sceneSystem, "MaterialViewportRenderer was unable to get the scene system during construction.");
|
||||
AZStd::shared_ptr<AzFramework::Scene> mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName);
|
||||
|
||||
// This should never happen unless scene creation has changed.
|
||||
AZ_Assert(mainScene, "Main scenes missing during system component initialization");
|
||||
mainScene->SetSubsystem(m_scene);
|
||||
|
||||
// Create a render pipeline from the specified asset for the window context and add the pipeline to the scene
|
||||
AZ::Data::Asset<AZ::RPI::AnyAsset> pipelineAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::AnyAsset>(m_defaultPipelineAssetPath.c_str(), AZ::RPI::AssetUtils::TraceLevel::Error);
|
||||
m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineAsset, *m_windowContext.get());
|
||||
pipelineAsset.Release();
|
||||
m_scene->AddRenderPipeline(m_renderPipeline);
|
||||
|
||||
// As part of our initialization we need to create the BRDF texture generation pipeline
|
||||
AZ::RPI::RenderPipelineDescriptor pipelineDesc;
|
||||
pipelineDesc.m_mainViewTagName = "MainCamera";
|
||||
pipelineDesc.m_name = "BRDFTexturePipeline";
|
||||
pipelineDesc.m_rootPassTemplate = "BRDFTexturePipeline";
|
||||
pipelineDesc.m_executeOnce = true;
|
||||
|
||||
AZ::RPI::RenderPipelinePtr brdfTexturePipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc);
|
||||
m_scene->AddRenderPipeline(brdfTexturePipeline);
|
||||
|
||||
// Currently the scene has to be activated after render pipeline was added so some feature processors (i.e. imgui) can be initialized properly
|
||||
// with pipeline's pass information.
|
||||
m_scene->Activate();
|
||||
|
||||
AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene);
|
||||
|
||||
AzFramework::EntityContextId entityContextId;
|
||||
AzFramework::GameEntityContextRequestBus::BroadcastResult(entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId);
|
||||
|
||||
// Configure camera
|
||||
AzFramework::EntityContextRequestBus::EventResult(m_cameraEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "Cameraentity");
|
||||
AZ_Assert(m_cameraEntity != nullptr, "Failed to create camera entity.");
|
||||
|
||||
//Add debug camera and controller components
|
||||
AZ::Debug::CameraComponentConfig cameraConfig(m_windowContext);
|
||||
cameraConfig.m_fovY = AZ::Constants::HalfPi;
|
||||
cameraConfig.m_depthNear = DepthNear;
|
||||
m_cameraComponent = m_cameraEntity->CreateComponent(azrtti_typeid<AZ::Debug::CameraComponent>());
|
||||
m_cameraComponent->SetConfiguration(cameraConfig);
|
||||
m_cameraEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_cameraEntity->Activate();
|
||||
|
||||
// Connect camera to pipeline's default view after camera entity activated
|
||||
m_renderPipeline->SetDefaultViewFromEntity(m_cameraEntity->GetId());
|
||||
|
||||
// Configure tone mapper
|
||||
AzFramework::EntityContextRequestBus::EventResult(m_postProcessEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "postProcessEntity");
|
||||
AZ_Assert(m_postProcessEntity != nullptr, "Failed to create post process entity.");
|
||||
|
||||
m_postProcessEntity->CreateComponent(AZ::Render::PostFxLayerComponentTypeId);
|
||||
m_postProcessEntity->CreateComponent(AZ::Render::ExposureControlComponentTypeId);
|
||||
m_postProcessEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_postProcessEntity->Activate();
|
||||
|
||||
// Init directional light processor
|
||||
m_directionalLightFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::DirectionalLightFeatureProcessorInterface>();
|
||||
|
||||
// Init display mapper processor
|
||||
m_displayMapperFeatureProcessor = m_scene->GetFeatureProcessor<Render::DisplayMapperFeatureProcessorInterface>();
|
||||
|
||||
// Init Skybox
|
||||
m_skyboxFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::SkyBoxFeatureProcessorInterface>();
|
||||
m_skyboxFeatureProcessor->Enable(true);
|
||||
m_skyboxFeatureProcessor->SetSkyboxMode(AZ::Render::SkyBoxMode::Cubemap);
|
||||
|
||||
// Create IBL
|
||||
AzFramework::EntityContextRequestBus::EventResult(m_iblEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "IblEntity");
|
||||
AZ_Assert(m_iblEntity != nullptr, "Failed to create ibl entity.");
|
||||
|
||||
m_iblEntity->CreateComponent(Render::ImageBasedLightComponentTypeId);
|
||||
m_iblEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_iblEntity->Activate();
|
||||
|
||||
// Create model
|
||||
AzFramework::EntityContextRequestBus::EventResult(m_modelEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel");
|
||||
AZ_Assert(m_modelEntity != nullptr, "Failed to create model entity.");
|
||||
|
||||
m_modelEntity->CreateComponent(AZ::Render::MeshComponentTypeId);
|
||||
m_modelEntity->CreateComponent(AZ::Render::MaterialComponentTypeId);
|
||||
m_modelEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_modelEntity->Activate();
|
||||
|
||||
// Create shadow catcher
|
||||
AzFramework::EntityContextRequestBus::EventResult(m_shadowCatcherEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportShadowCatcher");
|
||||
AZ_Assert(m_shadowCatcherEntity != nullptr, "Failed to create shadow catcher entity.");
|
||||
m_shadowCatcherEntity->CreateComponent(AZ::Render::MeshComponentTypeId);
|
||||
m_shadowCatcherEntity->CreateComponent(AZ::Render::MaterialComponentTypeId);
|
||||
m_shadowCatcherEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_shadowCatcherEntity->CreateComponent(azrtti_typeid<AzFramework::NonUniformScaleComponent>());
|
||||
m_shadowCatcherEntity->Activate();
|
||||
|
||||
AZ::NonUniformScaleRequestBus::Event(m_shadowCatcherEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, AZ::Vector3{ 100, 100, 1.0 });
|
||||
|
||||
AZ::Data::AssetId shadowCatcherModelAssetId = RPI::AssetUtils::GetAssetIdForProductPath("materialeditor/viewportmodels/plane_1x1.azmodel", RPI::AssetUtils::TraceLevel::Error);
|
||||
AZ::Render::MeshComponentRequestBus::Event(m_shadowCatcherEntity->GetId(),
|
||||
&AZ::Render::MeshComponentRequestBus::Events::SetModelAssetId, shadowCatcherModelAssetId);
|
||||
|
||||
auto shadowCatcherMaterialAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::MaterialAsset>("materials/special/shadowcatcher.azmaterial", RPI::AssetUtils::TraceLevel::Error);
|
||||
if (shadowCatcherMaterialAsset)
|
||||
{
|
||||
m_shadowCatcherOpacityPropertyIndex = shadowCatcherMaterialAsset->GetMaterialTypeAsset()->GetMaterialPropertiesLayout()->FindPropertyIndex(AZ::Name{ "settings.opacity" });
|
||||
AZ_Error("MaterialViewportRenderer", m_shadowCatcherOpacityPropertyIndex.IsValid(), "Could not find opacity property");
|
||||
|
||||
m_shadowCatcherMaterial = AZ::RPI::Material::Create(shadowCatcherMaterialAsset);
|
||||
AZ_Error("MaterialViewportRenderer", m_shadowCatcherMaterial != nullptr, "Could not create shadow catcher material.");
|
||||
|
||||
AZ::Render::MaterialAssignmentMap shadowCatcherMaterials;
|
||||
auto& shadowCatcherMaterialAssignment = shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId];
|
||||
shadowCatcherMaterialAssignment.m_materialInstance = m_shadowCatcherMaterial;
|
||||
shadowCatcherMaterialAssignment.m_materialInstancePreCreated = true;
|
||||
|
||||
AZ::Render::MaterialComponentRequestBus::Event(m_shadowCatcherEntity->GetId(),
|
||||
&AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, shadowCatcherMaterials);
|
||||
}
|
||||
|
||||
// Create grid
|
||||
AzFramework::EntityContextRequestBus::EventResult(m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid");
|
||||
AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity.");
|
||||
|
||||
AZ::Render::GridComponentConfig gridConfig;
|
||||
gridConfig.m_gridSize = 4.0f;
|
||||
gridConfig.m_axisColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
gridConfig.m_primaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
gridConfig.m_secondaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId);
|
||||
gridComponent->SetConfiguration(gridConfig);
|
||||
|
||||
m_gridEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_gridEntity->Activate();
|
||||
|
||||
OnDocumentOpened(AZ::Uuid::CreateNull());
|
||||
|
||||
// Attempt to apply the default lighting preset
|
||||
AZ::Render::LightingPresetPtr lightingPreset;
|
||||
MaterialViewportRequestBus::BroadcastResult(lightingPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection);
|
||||
OnLightingPresetSelected(lightingPreset);
|
||||
|
||||
// Attempt to apply the default model preset
|
||||
AZ::Render::ModelPresetPtr modelPreset;
|
||||
MaterialViewportRequestBus::BroadcastResult(modelPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection);
|
||||
OnModelPresetSelected(modelPreset);
|
||||
|
||||
m_viewportController->Init(m_cameraEntity->GetId(), m_modelEntity->GetId(), m_iblEntity->GetId());
|
||||
|
||||
// Apply user settinngs restored since last run
|
||||
AZStd::intrusive_ptr<MaterialViewportSettings> viewportSettings =
|
||||
AZ::UserSettings::CreateFind<MaterialViewportSettings>(AZ::Crc32("MaterialViewportSettings"), AZ::UserSettings::CT_GLOBAL);
|
||||
|
||||
OnGridEnabledChanged(viewportSettings->m_enableGrid);
|
||||
OnShadowCatcherEnabledChanged(viewportSettings->m_enableShadowCatcher);
|
||||
OnAlternateSkyboxEnabledChanged(viewportSettings->m_enableAlternateSkybox);
|
||||
OnFieldOfViewChanged(viewportSettings->m_fieldOfView);
|
||||
OnDisplayMapperOperationTypeChanged(viewportSettings->m_displayMapperOperationType);
|
||||
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect();
|
||||
MaterialViewportNotificationBus::Handler::BusConnect();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
AZ::TransformNotificationBus::MultiHandler::BusConnect(m_cameraEntity->GetId());
|
||||
}
|
||||
|
||||
MaterialViewportRenderer::~MaterialViewportRenderer()
|
||||
{
|
||||
AZ::TransformNotificationBus::MultiHandler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
|
||||
MaterialViewportNotificationBus::Handler::BusDisconnect();
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
|
||||
AzFramework::EntityContextId entityContextId;
|
||||
AzFramework::GameEntityContextRequestBus::BroadcastResult(entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId);
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_iblEntity);
|
||||
m_iblEntity = nullptr;
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity);
|
||||
m_modelEntity = nullptr;
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_shadowCatcherEntity);
|
||||
m_shadowCatcherEntity = nullptr;
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_gridEntity);
|
||||
m_gridEntity = nullptr;
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_cameraEntity);
|
||||
m_cameraEntity = nullptr;
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_postProcessEntity);
|
||||
m_postProcessEntity = nullptr;
|
||||
|
||||
for (DirectionalLightHandle& handle : m_lightHandles)
|
||||
{
|
||||
m_directionalLightFeatureProcessor->ReleaseLight(handle);
|
||||
}
|
||||
m_lightHandles.clear();
|
||||
|
||||
auto sceneSystem = AzFramework::SceneSystemInterface::Get();
|
||||
AZ_Assert(sceneSystem, "MaterialViewportRenderer was unable to get the scene system during destruction.");
|
||||
AZStd::shared_ptr<AzFramework::Scene> mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName);
|
||||
// This should never happen unless scene creation has changed.
|
||||
AZ_Assert(mainScene, "Main scenes missing during system component destruction");
|
||||
mainScene->UnsetSubsystem(m_scene);
|
||||
|
||||
m_swapChainPass = nullptr;
|
||||
AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene);
|
||||
m_scene = nullptr;
|
||||
}
|
||||
|
||||
AZStd::shared_ptr<MaterialEditorViewportInputController> MaterialViewportRenderer::GetController()
|
||||
{
|
||||
return m_viewportController;
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnDocumentOpened(const AZ::Uuid& documentId)
|
||||
{
|
||||
AZ::Data::Instance<AZ::RPI::Material> materialInstance;
|
||||
MaterialDocumentRequestBus::EventResult(materialInstance, documentId, &MaterialDocumentRequestBus::Events::GetInstance);
|
||||
|
||||
AZ::Render::MaterialAssignmentMap materials;
|
||||
auto& materialAssignment = materials[AZ::Render::DefaultMaterialAssignmentId];
|
||||
materialAssignment.m_materialInstance = materialInstance;
|
||||
materialAssignment.m_materialInstancePreCreated = true;
|
||||
|
||||
AZ::Render::MaterialComponentRequestBus::Event(m_modelEntity->GetId(),
|
||||
&AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, materials);
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset)
|
||||
{
|
||||
if (!preset)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::Render::ImageBasedLightFeatureProcessorInterface* iblFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::ImageBasedLightFeatureProcessorInterface>();
|
||||
AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::PostProcessFeatureProcessorInterface>();
|
||||
|
||||
AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface = postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId())->GetOrCreateExposureControlSettingsInterface();
|
||||
|
||||
Camera::Configuration cameraConfig;
|
||||
Camera::CameraRequestBus::EventResult(cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration);
|
||||
|
||||
bool enableAlternateSkybox = false;
|
||||
MaterialViewportRequestBus::BroadcastResult(enableAlternateSkybox, &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled);
|
||||
|
||||
preset->ApplyLightingPreset(
|
||||
iblFeatureProcessor,
|
||||
m_skyboxFeatureProcessor,
|
||||
exposureControlSettingInterface,
|
||||
m_directionalLightFeatureProcessor,
|
||||
cameraConfig,
|
||||
m_lightHandles,
|
||||
m_shadowCatcherMaterial,
|
||||
m_shadowCatcherOpacityPropertyIndex,
|
||||
enableAlternateSkybox);
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset)
|
||||
{
|
||||
AZ::Render::LightingPresetPtr selectedPreset;
|
||||
MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection);
|
||||
if (selectedPreset == preset)
|
||||
{
|
||||
OnLightingPresetSelected(preset);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnModelPresetSelected(AZ::Render::ModelPresetPtr preset)
|
||||
{
|
||||
if (!preset)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!preset->m_modelAsset.GetId().IsValid())
|
||||
{
|
||||
AZ_Warning("MaterialViewportRenderer", false, "Attempting to set invalid model for preset: '%s'\n.", preset->m_displayName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (preset->m_modelAsset.GetId() == m_modelAssetId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::Render::MeshComponentRequestBus::Event(m_modelEntity->GetId(),
|
||||
&AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, preset->m_modelAsset);
|
||||
|
||||
m_modelAssetId = preset->m_modelAsset.GetId();
|
||||
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
AZ::Data::AssetBus::Handler::BusConnect(m_modelAssetId);
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnModelPresetChanged(AZ::Render::ModelPresetPtr preset)
|
||||
{
|
||||
AZ::Render::ModelPresetPtr selectedPreset;
|
||||
MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection);
|
||||
if (selectedPreset == preset)
|
||||
{
|
||||
OnModelPresetSelected(preset);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnShadowCatcherEnabledChanged(bool enable)
|
||||
{
|
||||
AZ::Render::MeshComponentRequestBus::Event(m_shadowCatcherEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetVisibility, enable);
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnGridEnabledChanged(bool enable)
|
||||
{
|
||||
if (m_gridEntity)
|
||||
{
|
||||
if (enable && m_gridEntity->GetState() == AZ::Entity::State::Init)
|
||||
{
|
||||
m_gridEntity->Activate();
|
||||
}
|
||||
else if (!enable && m_gridEntity->GetState() == AZ::Entity::State::Active)
|
||||
{
|
||||
m_gridEntity->Deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnAlternateSkyboxEnabledChanged(bool enable)
|
||||
{
|
||||
AZ_UNUSED(enable);
|
||||
AZ::Render::LightingPresetPtr selectedPreset;
|
||||
MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection);
|
||||
OnLightingPresetSelected(selectedPreset);
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnFieldOfViewChanged(float fieldOfView)
|
||||
{
|
||||
MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::SetFieldOfView, fieldOfView);
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType)
|
||||
{
|
||||
AZ::Render::DisplayMapperConfigurationDescriptor desc;
|
||||
desc.m_operationType = operationType;
|
||||
m_displayMapperFeatureProcessor->RegisterDisplayMapperConfiguration(desc);
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
if (m_modelAssetId == asset.GetId())
|
||||
{
|
||||
MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::Reset);
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect(asset.GetId());
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
||||
{
|
||||
m_renderPipeline->AddToRenderTickOnce();
|
||||
|
||||
PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::GatherMetrics);
|
||||
|
||||
if (m_shadowCatcherMaterial)
|
||||
{
|
||||
// Compile the m_shadowCatcherMaterial in OnTick because changes can only be compiled once per frame.
|
||||
// This is ignored when a compile isn't needed.
|
||||
m_shadowCatcherMaterial->Compile();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialViewportRenderer::OnTransformChanged(const AZ::Transform&, const AZ::Transform&)
|
||||
{
|
||||
const AZ::EntityId* currentBusId = AZ::TransformNotificationBus::GetCurrentBusId();
|
||||
if (m_cameraEntity && currentBusId && *currentBusId == m_cameraEntity->GetId() && m_directionalLightFeatureProcessor)
|
||||
{
|
||||
auto transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(
|
||||
transform,
|
||||
m_cameraEntity->GetId(),
|
||||
&AZ::TransformBus::Events::GetWorldTM);
|
||||
for (const DirectionalLightHandle& id : m_lightHandles)
|
||||
{
|
||||
m_directionalLightFeatureProcessor->SetCameraTransform(
|
||||
id, transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,114 +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 <Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <Viewport/InputController/MaterialEditorViewportInputController.h>
|
||||
#include <Viewport/MaterialViewportNotificationBus.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
class DisplayMapperFeatureProcessorInterface;
|
||||
}
|
||||
|
||||
class Entity;
|
||||
class Component;
|
||||
|
||||
namespace RPI
|
||||
{
|
||||
class SwapChainPass;
|
||||
class WindowContext;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
//! Provides backend logic for MaterialViewport
|
||||
//! Sets up a scene, camera, loads the model, and applies texture
|
||||
class MaterialViewportRenderer
|
||||
: public AZ::Data::AssetBus::Handler
|
||||
, public AZ::TickBus::Handler
|
||||
, public AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler
|
||||
, public MaterialViewportNotificationBus::Handler
|
||||
, public AZ::TransformNotificationBus::MultiHandler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(MaterialViewportRenderer, AZ::SystemAllocator, 0);
|
||||
|
||||
MaterialViewportRenderer(AZStd::shared_ptr<AZ::RPI::WindowContext> windowContext);
|
||||
~MaterialViewportRenderer();
|
||||
|
||||
AZStd::shared_ptr<MaterialEditorViewportInputController> GetController();
|
||||
|
||||
private:
|
||||
|
||||
// AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler interface overrides...
|
||||
void OnDocumentOpened(const AZ::Uuid& documentId) override;
|
||||
|
||||
// MaterialViewportNotificationBus::Handler interface overrides...
|
||||
void OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset) override;
|
||||
void OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) override;
|
||||
void OnModelPresetSelected(AZ::Render::ModelPresetPtr preset) override;
|
||||
void OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) override;
|
||||
void OnShadowCatcherEnabledChanged(bool enable) override;
|
||||
void OnGridEnabledChanged(bool enable) override;
|
||||
void OnAlternateSkyboxEnabledChanged(bool enable) override;
|
||||
void OnFieldOfViewChanged(float fieldOfView) override;
|
||||
void OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) override;
|
||||
|
||||
// AZ::Data::AssetBus::Handler interface overrides...
|
||||
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
|
||||
// AZ::TickBus::Handler interface overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
// AZ::TransformNotificationBus::MultiHandler overrides...
|
||||
void OnTransformChanged(const AZ::Transform&, const AZ::Transform&) override;
|
||||
|
||||
using DirectionalLightHandle = AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle;
|
||||
|
||||
AZ::Data::Instance<AZ::RPI::SwapChainPass> m_swapChainPass;
|
||||
AZStd::string m_defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset";
|
||||
AZStd::shared_ptr<AZ::RPI::WindowContext> m_windowContext;
|
||||
AZ::RPI::RenderPipelinePtr m_renderPipeline;
|
||||
AZ::RPI::ScenePtr m_scene;
|
||||
AZ::Render::DirectionalLightFeatureProcessorInterface* m_directionalLightFeatureProcessor = nullptr;
|
||||
AZ::Render::DisplayMapperFeatureProcessorInterface* m_displayMapperFeatureProcessor = nullptr;
|
||||
|
||||
AZ::Entity* m_cameraEntity = nullptr;
|
||||
AZ::Component* m_cameraComponent = nullptr;
|
||||
bool m_cameraNeedsFullReset = true;
|
||||
|
||||
AZ::Entity* m_postProcessEntity = nullptr;
|
||||
|
||||
AZ::Entity* m_modelEntity = nullptr;
|
||||
AZ::Data::AssetId m_modelAssetId;
|
||||
|
||||
AZ::Entity* m_gridEntity = nullptr;
|
||||
|
||||
AZ::Entity* m_shadowCatcherEntity = nullptr;
|
||||
AZ::Data::Instance<AZ::RPI::Material> m_shadowCatcherMaterial;
|
||||
AZ::RPI::MaterialPropertyIndex m_shadowCatcherOpacityPropertyIndex;
|
||||
|
||||
AZStd::vector<DirectionalLightHandle> m_lightHandles;
|
||||
|
||||
AZ::Entity* m_iblEntity = nullptr;
|
||||
AZ::Render::SkyBoxFeatureProcessorInterface* m_skyboxFeatureProcessor = nullptr;
|
||||
|
||||
AZStd::shared_ptr<MaterialEditorViewportInputController> m_viewportController;
|
||||
};
|
||||
} // namespace MaterialEditor
|
||||
@@ -6,29 +6,65 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#undef RC_INVOKED
|
||||
|
||||
#include <Atom/Component/DebugCamera/CameraComponent.h>
|
||||
#include <Atom/Component/DebugCamera/NoClipControllerComponent.h>
|
||||
#include <Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h>
|
||||
#include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/PostProcessing/PostProcessingConstants.h>
|
||||
#include <Atom/Feature/Utils/LightingPreset.h>
|
||||
#include <Atom/Feature/Utils/ModelPreset.h>
|
||||
#include <Atom/RHI/Device.h>
|
||||
#include <Atom/RHI/RHISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Image/StreamingImage.h>
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
#include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/ViewportContext.h>
|
||||
#include <Atom/RPI.Public/ViewportContextBus.h>
|
||||
#include <Atom/RPI.Public/WindowContext.h>
|
||||
|
||||
#include <Viewport/MaterialViewportRenderer.h>
|
||||
#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
|
||||
#include <AtomCore/Instance/InstanceDatabase.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Grid/GridComponentConfig.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Grid/GridComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/ImageBasedLights/ImageBasedLightComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/ImageBasedLights/ImageBasedLightComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlBus.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlComponentConstants.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/PostProcess/PostFxLayerComponentConstants.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzFramework/Components/NonUniformScaleComponent.h>
|
||||
#include <AzFramework/Components/TransformComponent.h>
|
||||
#include <AzFramework/Entity/GameEntityContextBus.h>
|
||||
#include <AzFramework/Viewport/ViewportControllerList.h>
|
||||
#include <Document/MaterialDocumentRequestBus.h>
|
||||
#include <Viewport/MaterialViewportRequestBus.h>
|
||||
#include <Viewport/MaterialViewportSettings.h>
|
||||
#include <Viewport/MaterialViewportWidget.h>
|
||||
#include <Viewport/PerformanceMonitorRequestBus.h>
|
||||
#include <Viewport/ui_MaterialViewportWidget.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QWindow>
|
||||
#include "Viewport/ui_MaterialViewportWidget.h"
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
#include <AzFramework/Viewport/ViewportControllerList.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
static constexpr float DepthNear = 0.01f;
|
||||
|
||||
MaterialViewportWidget::MaterialViewportWidget(QWidget* parent)
|
||||
: AtomToolsFramework::RenderViewportWidget(parent)
|
||||
, m_ui(new Ui::MaterialViewportWidget)
|
||||
, m_viewportController(AZStd::make_shared<MaterialEditorViewportInputController>())
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
@@ -38,7 +74,415 @@ namespace MaterialEditor
|
||||
const AZ::Name defaultContextName = viewportContextManager->GetDefaultViewportContextName();
|
||||
viewportContextManager->RenameViewportContext(GetViewportContext(), defaultContextName);
|
||||
|
||||
m_renderer = AZStd::make_unique<MaterialViewportRenderer>(GetViewportContext()->GetWindowContext());
|
||||
GetControllerList()->Add(m_renderer->GetController());
|
||||
// Create and register a scene with all available feature processors
|
||||
AZ::RPI::SceneDescriptor sceneDesc;
|
||||
sceneDesc.m_nameId = AZ::Name("MaterialViewport");
|
||||
m_scene = AZ::RPI::Scene::CreateScene(sceneDesc);
|
||||
m_scene->EnableAllFeatureProcessors();
|
||||
|
||||
// Bind m_defaultScene to the GameEntityContext's AzFramework::Scene
|
||||
auto sceneSystem = AzFramework::SceneSystemInterface::Get();
|
||||
AZ_Assert(sceneSystem, "MaterialViewportWidget was unable to get the scene system during construction.");
|
||||
AZStd::shared_ptr<AzFramework::Scene> mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName);
|
||||
|
||||
// This should never happen unless scene creation has changed.
|
||||
AZ_Assert(mainScene, "Main scenes missing during system component initialization");
|
||||
mainScene->SetSubsystem(m_scene);
|
||||
|
||||
// Create a render pipeline from the specified asset for the window context and add the pipeline to the scene
|
||||
AZ::Data::Asset<AZ::RPI::AnyAsset> pipelineAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::AnyAsset>(
|
||||
m_defaultPipelineAssetPath.c_str(), AZ::RPI::AssetUtils::TraceLevel::Error);
|
||||
m_renderPipeline = AZ::RPI::RenderPipeline::CreateRenderPipelineForWindow(pipelineAsset, *GetViewportContext()->GetWindowContext().get());
|
||||
pipelineAsset.Release();
|
||||
m_scene->AddRenderPipeline(m_renderPipeline);
|
||||
|
||||
// As part of our initialization we need to create the BRDF texture generation pipeline
|
||||
AZ::RPI::RenderPipelineDescriptor pipelineDesc;
|
||||
pipelineDesc.m_mainViewTagName = "MainCamera";
|
||||
pipelineDesc.m_name = "BRDFTexturePipeline";
|
||||
pipelineDesc.m_rootPassTemplate = "BRDFTexturePipeline";
|
||||
pipelineDesc.m_executeOnce = true;
|
||||
|
||||
AZ::RPI::RenderPipelinePtr brdfTexturePipeline = AZ::RPI::RenderPipeline::CreateRenderPipeline(pipelineDesc);
|
||||
m_scene->AddRenderPipeline(brdfTexturePipeline);
|
||||
|
||||
// Currently the scene has to be activated after render pipeline was added so some feature processors (i.e. imgui) can be
|
||||
// initialized properly with pipeline's pass information.
|
||||
m_scene->Activate();
|
||||
|
||||
AZ::RPI::RPISystemInterface::Get()->RegisterScene(m_scene);
|
||||
|
||||
AzFramework::EntityContextId entityContextId;
|
||||
AzFramework::GameEntityContextRequestBus::BroadcastResult(
|
||||
entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId);
|
||||
|
||||
// Configure camera
|
||||
AzFramework::EntityContextRequestBus::EventResult(
|
||||
m_cameraEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "Cameraentity");
|
||||
AZ_Assert(m_cameraEntity != nullptr, "Failed to create camera entity.");
|
||||
|
||||
// Add debug camera and controller components
|
||||
AZ::Debug::CameraComponentConfig cameraConfig(GetViewportContext()->GetWindowContext());
|
||||
cameraConfig.m_fovY = AZ::Constants::HalfPi;
|
||||
cameraConfig.m_depthNear = DepthNear;
|
||||
m_cameraComponent = m_cameraEntity->CreateComponent(azrtti_typeid<AZ::Debug::CameraComponent>());
|
||||
m_cameraComponent->SetConfiguration(cameraConfig);
|
||||
m_cameraEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_cameraEntity->Activate();
|
||||
|
||||
// Connect camera to pipeline's default view after camera entity activated
|
||||
m_renderPipeline->SetDefaultViewFromEntity(m_cameraEntity->GetId());
|
||||
|
||||
// Configure tone mapper
|
||||
AzFramework::EntityContextRequestBus::EventResult(
|
||||
m_postProcessEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "postProcessEntity");
|
||||
AZ_Assert(m_postProcessEntity != nullptr, "Failed to create post process entity.");
|
||||
|
||||
m_postProcessEntity->CreateComponent(AZ::Render::PostFxLayerComponentTypeId);
|
||||
m_postProcessEntity->CreateComponent(AZ::Render::ExposureControlComponentTypeId);
|
||||
m_postProcessEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_postProcessEntity->Activate();
|
||||
|
||||
// Init directional light processor
|
||||
m_directionalLightFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::DirectionalLightFeatureProcessorInterface>();
|
||||
|
||||
// Init display mapper processor
|
||||
m_displayMapperFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::DisplayMapperFeatureProcessorInterface>();
|
||||
|
||||
// Init Skybox
|
||||
m_skyboxFeatureProcessor = m_scene->GetFeatureProcessor<AZ::Render::SkyBoxFeatureProcessorInterface>();
|
||||
m_skyboxFeatureProcessor->Enable(true);
|
||||
m_skyboxFeatureProcessor->SetSkyboxMode(AZ::Render::SkyBoxMode::Cubemap);
|
||||
|
||||
// Create IBL
|
||||
AzFramework::EntityContextRequestBus::EventResult(
|
||||
m_iblEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "IblEntity");
|
||||
AZ_Assert(m_iblEntity != nullptr, "Failed to create ibl entity.");
|
||||
|
||||
m_iblEntity->CreateComponent(AZ::Render::ImageBasedLightComponentTypeId);
|
||||
m_iblEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_iblEntity->Activate();
|
||||
|
||||
// Create model
|
||||
AzFramework::EntityContextRequestBus::EventResult(
|
||||
m_modelEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportModel");
|
||||
AZ_Assert(m_modelEntity != nullptr, "Failed to create model entity.");
|
||||
|
||||
m_modelEntity->CreateComponent(AZ::Render::MeshComponentTypeId);
|
||||
m_modelEntity->CreateComponent(AZ::Render::MaterialComponentTypeId);
|
||||
m_modelEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_modelEntity->Activate();
|
||||
|
||||
// Create shadow catcher
|
||||
AzFramework::EntityContextRequestBus::EventResult(
|
||||
m_shadowCatcherEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportShadowCatcher");
|
||||
AZ_Assert(m_shadowCatcherEntity != nullptr, "Failed to create shadow catcher entity.");
|
||||
m_shadowCatcherEntity->CreateComponent(AZ::Render::MeshComponentTypeId);
|
||||
m_shadowCatcherEntity->CreateComponent(AZ::Render::MaterialComponentTypeId);
|
||||
m_shadowCatcherEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_shadowCatcherEntity->CreateComponent(azrtti_typeid<AzFramework::NonUniformScaleComponent>());
|
||||
m_shadowCatcherEntity->Activate();
|
||||
|
||||
AZ::NonUniformScaleRequestBus::Event(
|
||||
m_shadowCatcherEntity->GetId(), &AZ::NonUniformScaleRequests::SetScale, AZ::Vector3{ 100, 100, 1.0 });
|
||||
|
||||
AZ::Data::AssetId shadowCatcherModelAssetId = AZ::RPI::AssetUtils::GetAssetIdForProductPath(
|
||||
"materialeditor/viewportmodels/plane_1x1.azmodel", AZ::RPI::AssetUtils::TraceLevel::Error);
|
||||
AZ::Render::MeshComponentRequestBus::Event(
|
||||
m_shadowCatcherEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAssetId, shadowCatcherModelAssetId);
|
||||
|
||||
auto shadowCatcherMaterialAsset = AZ::RPI::AssetUtils::LoadAssetByProductPath<AZ::RPI::MaterialAsset>(
|
||||
"materials/special/shadowcatcher.azmaterial", AZ::RPI::AssetUtils::TraceLevel::Error);
|
||||
if (shadowCatcherMaterialAsset)
|
||||
{
|
||||
m_shadowCatcherOpacityPropertyIndex =
|
||||
shadowCatcherMaterialAsset->GetMaterialTypeAsset()->GetMaterialPropertiesLayout()->FindPropertyIndex(
|
||||
AZ::Name{ "settings.opacity" });
|
||||
AZ_Error("MaterialViewportWidget", m_shadowCatcherOpacityPropertyIndex.IsValid(), "Could not find opacity property");
|
||||
|
||||
m_shadowCatcherMaterial = AZ::RPI::Material::Create(shadowCatcherMaterialAsset);
|
||||
AZ_Error("MaterialViewportWidget", m_shadowCatcherMaterial != nullptr, "Could not create shadow catcher material.");
|
||||
|
||||
AZ::Render::MaterialAssignmentMap shadowCatcherMaterials;
|
||||
auto& shadowCatcherMaterialAssignment = shadowCatcherMaterials[AZ::Render::DefaultMaterialAssignmentId];
|
||||
shadowCatcherMaterialAssignment.m_materialInstance = m_shadowCatcherMaterial;
|
||||
shadowCatcherMaterialAssignment.m_materialInstancePreCreated = true;
|
||||
|
||||
AZ::Render::MaterialComponentRequestBus::Event(
|
||||
m_shadowCatcherEntity->GetId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides,
|
||||
shadowCatcherMaterials);
|
||||
}
|
||||
|
||||
// Create grid
|
||||
AzFramework::EntityContextRequestBus::EventResult(
|
||||
m_gridEntity, entityContextId, &AzFramework::EntityContextRequestBus::Events::CreateEntity, "ViewportGrid");
|
||||
AZ_Assert(m_gridEntity != nullptr, "Failed to create grid entity.");
|
||||
|
||||
AZ::Render::GridComponentConfig gridConfig;
|
||||
gridConfig.m_gridSize = 4.0f;
|
||||
gridConfig.m_axisColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
gridConfig.m_primaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
gridConfig.m_secondaryColor = AZ::Color(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
auto gridComponent = m_gridEntity->CreateComponent(AZ::Render::GridComponentTypeId);
|
||||
gridComponent->SetConfiguration(gridConfig);
|
||||
|
||||
m_gridEntity->CreateComponent(azrtti_typeid<AzFramework::TransformComponent>());
|
||||
m_gridEntity->Activate();
|
||||
|
||||
OnDocumentOpened(AZ::Uuid::CreateNull());
|
||||
|
||||
// Attempt to apply the default lighting preset
|
||||
AZ::Render::LightingPresetPtr lightingPreset;
|
||||
MaterialViewportRequestBus::BroadcastResult(lightingPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection);
|
||||
OnLightingPresetSelected(lightingPreset);
|
||||
|
||||
// Attempt to apply the default model preset
|
||||
AZ::Render::ModelPresetPtr modelPreset;
|
||||
MaterialViewportRequestBus::BroadcastResult(modelPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection);
|
||||
OnModelPresetSelected(modelPreset);
|
||||
|
||||
m_viewportController->Init(m_cameraEntity->GetId(), m_modelEntity->GetId(), m_iblEntity->GetId());
|
||||
|
||||
// Apply user settinngs restored since last run
|
||||
AZStd::intrusive_ptr<MaterialViewportSettings> viewportSettings =
|
||||
AZ::UserSettings::CreateFind<MaterialViewportSettings>(AZ::Crc32("MaterialViewportSettings"), AZ::UserSettings::CT_GLOBAL);
|
||||
|
||||
OnGridEnabledChanged(viewportSettings->m_enableGrid);
|
||||
OnShadowCatcherEnabledChanged(viewportSettings->m_enableShadowCatcher);
|
||||
OnAlternateSkyboxEnabledChanged(viewportSettings->m_enableAlternateSkybox);
|
||||
OnFieldOfViewChanged(viewportSettings->m_fieldOfView);
|
||||
OnDisplayMapperOperationTypeChanged(viewportSettings->m_displayMapperOperationType);
|
||||
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect();
|
||||
MaterialViewportNotificationBus::Handler::BusConnect();
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
AZ::TransformNotificationBus::MultiHandler::BusConnect(m_cameraEntity->GetId());
|
||||
|
||||
GetControllerList()->Add(m_viewportController);
|
||||
}
|
||||
|
||||
MaterialViewportWidget::~MaterialViewportWidget()
|
||||
{
|
||||
AZ::TransformNotificationBus::MultiHandler::BusDisconnect();
|
||||
AZ::TickBus::Handler::BusDisconnect();
|
||||
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
|
||||
MaterialViewportNotificationBus::Handler::BusDisconnect();
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
|
||||
AzFramework::EntityContextId entityContextId;
|
||||
AzFramework::GameEntityContextRequestBus::BroadcastResult(
|
||||
entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId);
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(
|
||||
entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_iblEntity);
|
||||
m_iblEntity = nullptr;
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(
|
||||
entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_modelEntity);
|
||||
m_modelEntity = nullptr;
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(
|
||||
entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_shadowCatcherEntity);
|
||||
m_shadowCatcherEntity = nullptr;
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(
|
||||
entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_gridEntity);
|
||||
m_gridEntity = nullptr;
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(
|
||||
entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_cameraEntity);
|
||||
m_cameraEntity = nullptr;
|
||||
|
||||
AzFramework::EntityContextRequestBus::Event(
|
||||
entityContextId, &AzFramework::EntityContextRequestBus::Events::DestroyEntity, m_postProcessEntity);
|
||||
m_postProcessEntity = nullptr;
|
||||
|
||||
for (DirectionalLightHandle& handle : m_lightHandles)
|
||||
{
|
||||
m_directionalLightFeatureProcessor->ReleaseLight(handle);
|
||||
}
|
||||
m_lightHandles.clear();
|
||||
|
||||
auto sceneSystem = AzFramework::SceneSystemInterface::Get();
|
||||
AZ_Assert(sceneSystem, "MaterialViewportWidget was unable to get the scene system during destruction.");
|
||||
AZStd::shared_ptr<AzFramework::Scene> mainScene = sceneSystem->GetScene(AzFramework::Scene::MainSceneName);
|
||||
// This should never happen unless scene creation has changed.
|
||||
AZ_Assert(mainScene, "Main scenes missing during system component destruction");
|
||||
mainScene->UnsetSubsystem(m_scene);
|
||||
|
||||
m_swapChainPass = nullptr;
|
||||
AZ::RPI::RPISystemInterface::Get()->UnregisterScene(m_scene);
|
||||
m_scene = nullptr;
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnDocumentOpened(const AZ::Uuid& documentId)
|
||||
{
|
||||
AZ::Data::Instance<AZ::RPI::Material> materialInstance;
|
||||
MaterialDocumentRequestBus::EventResult(materialInstance, documentId, &MaterialDocumentRequestBus::Events::GetInstance);
|
||||
|
||||
AZ::Render::MaterialAssignmentMap materials;
|
||||
auto& materialAssignment = materials[AZ::Render::DefaultMaterialAssignmentId];
|
||||
materialAssignment.m_materialInstance = materialInstance;
|
||||
materialAssignment.m_materialInstancePreCreated = true;
|
||||
|
||||
AZ::Render::MaterialComponentRequestBus::Event(
|
||||
m_modelEntity->GetId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialOverrides, materials);
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset)
|
||||
{
|
||||
if (!preset)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::Render::ImageBasedLightFeatureProcessorInterface* iblFeatureProcessor =
|
||||
m_scene->GetFeatureProcessor<AZ::Render::ImageBasedLightFeatureProcessorInterface>();
|
||||
AZ::Render::PostProcessFeatureProcessorInterface* postProcessFeatureProcessor =
|
||||
m_scene->GetFeatureProcessor<AZ::Render::PostProcessFeatureProcessorInterface>();
|
||||
|
||||
AZ::Render::ExposureControlSettingsInterface* exposureControlSettingInterface =
|
||||
postProcessFeatureProcessor->GetOrCreateSettingsInterface(m_postProcessEntity->GetId())
|
||||
->GetOrCreateExposureControlSettingsInterface();
|
||||
|
||||
Camera::Configuration cameraConfig;
|
||||
Camera::CameraRequestBus::EventResult(
|
||||
cameraConfig, m_cameraEntity->GetId(), &Camera::CameraRequestBus::Events::GetCameraConfiguration);
|
||||
|
||||
bool enableAlternateSkybox = false;
|
||||
MaterialViewportRequestBus::BroadcastResult(enableAlternateSkybox, &MaterialViewportRequestBus::Events::GetAlternateSkyboxEnabled);
|
||||
|
||||
preset->ApplyLightingPreset(
|
||||
iblFeatureProcessor, m_skyboxFeatureProcessor, exposureControlSettingInterface, m_directionalLightFeatureProcessor,
|
||||
cameraConfig, m_lightHandles, m_shadowCatcherMaterial, m_shadowCatcherOpacityPropertyIndex, enableAlternateSkybox);
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset)
|
||||
{
|
||||
AZ::Render::LightingPresetPtr selectedPreset;
|
||||
MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection);
|
||||
if (selectedPreset == preset)
|
||||
{
|
||||
OnLightingPresetSelected(preset);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnModelPresetSelected(AZ::Render::ModelPresetPtr preset)
|
||||
{
|
||||
if (!preset)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!preset->m_modelAsset.GetId().IsValid())
|
||||
{
|
||||
AZ_Warning(
|
||||
"MaterialViewportWidget", false, "Attempting to set invalid model for preset: '%s'\n.", preset->m_displayName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (preset->m_modelAsset.GetId() == m_modelAssetId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AZ::Render::MeshComponentRequestBus::Event(
|
||||
m_modelEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAsset, preset->m_modelAsset);
|
||||
|
||||
m_modelAssetId = preset->m_modelAsset.GetId();
|
||||
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
AZ::Data::AssetBus::Handler::BusConnect(m_modelAssetId);
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnModelPresetChanged(AZ::Render::ModelPresetPtr preset)
|
||||
{
|
||||
AZ::Render::ModelPresetPtr selectedPreset;
|
||||
MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetModelPresetSelection);
|
||||
if (selectedPreset == preset)
|
||||
{
|
||||
OnModelPresetSelected(preset);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnShadowCatcherEnabledChanged(bool enable)
|
||||
{
|
||||
AZ::Render::MeshComponentRequestBus::Event(
|
||||
m_shadowCatcherEntity->GetId(), &AZ::Render::MeshComponentRequestBus::Events::SetVisibility, enable);
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnGridEnabledChanged(bool enable)
|
||||
{
|
||||
if (m_gridEntity)
|
||||
{
|
||||
if (enable && m_gridEntity->GetState() == AZ::Entity::State::Init)
|
||||
{
|
||||
m_gridEntity->Activate();
|
||||
}
|
||||
else if (!enable && m_gridEntity->GetState() == AZ::Entity::State::Active)
|
||||
{
|
||||
m_gridEntity->Deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnAlternateSkyboxEnabledChanged(bool enable)
|
||||
{
|
||||
AZ_UNUSED(enable);
|
||||
AZ::Render::LightingPresetPtr selectedPreset;
|
||||
MaterialViewportRequestBus::BroadcastResult(selectedPreset, &MaterialViewportRequestBus::Events::GetLightingPresetSelection);
|
||||
OnLightingPresetSelected(selectedPreset);
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnFieldOfViewChanged(float fieldOfView)
|
||||
{
|
||||
MaterialEditorViewportInputControllerRequestBus::Broadcast(
|
||||
&MaterialEditorViewportInputControllerRequestBus::Handler::SetFieldOfView, fieldOfView);
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType)
|
||||
{
|
||||
AZ::Render::DisplayMapperConfigurationDescriptor desc;
|
||||
desc.m_operationType = operationType;
|
||||
m_displayMapperFeatureProcessor->RegisterDisplayMapperConfiguration(desc);
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
if (m_modelAssetId == asset.GetId())
|
||||
{
|
||||
MaterialEditorViewportInputControllerRequestBus::Broadcast(&MaterialEditorViewportInputControllerRequestBus::Handler::Reset);
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect(asset.GetId());
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnTick(float deltaTime, AZ::ScriptTimePoint time)
|
||||
{
|
||||
AtomToolsFramework::RenderViewportWidget::OnTick(deltaTime, time);
|
||||
|
||||
m_renderPipeline->AddToRenderTickOnce();
|
||||
|
||||
PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::GatherMetrics);
|
||||
|
||||
if (m_shadowCatcherMaterial)
|
||||
{
|
||||
// Compile the m_shadowCatcherMaterial in OnTick because changes can only be compiled once per frame.
|
||||
// This is ignored when a compile isn't needed.
|
||||
m_shadowCatcherMaterial->Compile();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialViewportWidget::OnTransformChanged(const AZ::Transform&, const AZ::Transform&)
|
||||
{
|
||||
const AZ::EntityId* currentBusId = AZ::TransformNotificationBus::GetCurrentBusId();
|
||||
if (m_cameraEntity && currentBusId && *currentBusId == m_cameraEntity->GetId() && m_directionalLightFeatureProcessor)
|
||||
{
|
||||
auto transform = AZ::Transform::CreateIdentity();
|
||||
AZ::TransformBus::EventResult(transform, m_cameraEntity->GetId(), &AZ::TransformBus::Events::GetWorldTM);
|
||||
for (const DirectionalLightHandle& id : m_lightHandles)
|
||||
{
|
||||
m_directionalLightFeatureProcessor->SetCameraTransform(id, transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace MaterialEditor
|
||||
|
||||
@@ -5,42 +5,115 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h>
|
||||
#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
|
||||
#include <Atom/RPI.Public/Base.h>
|
||||
#include <AtomCore/Instance/Instance.h>
|
||||
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
|
||||
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzFramework/Windowing/WindowBus.h>
|
||||
#include <Viewport/InputController/MaterialEditorViewportInputController.h>
|
||||
#include <Viewport/MaterialViewportNotificationBus.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QWidget>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
#endif
|
||||
|
||||
#include <AtomToolsFramework/Viewport/RenderViewportWidget.h>
|
||||
namespace AZ
|
||||
{
|
||||
namespace Render
|
||||
{
|
||||
class DisplayMapperFeatureProcessorInterface;
|
||||
}
|
||||
|
||||
class Entity;
|
||||
class Component;
|
||||
|
||||
namespace RPI
|
||||
{
|
||||
class SwapChainPass;
|
||||
class WindowContext;
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class MaterialViewportWidget;
|
||||
}
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
class WindowContext;
|
||||
}
|
||||
}
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
class MaterialViewportRenderer;
|
||||
|
||||
class MaterialViewportWidget
|
||||
: public AtomToolsFramework::RenderViewportWidget
|
||||
, public AZ::Data::AssetBus::Handler
|
||||
, public AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler
|
||||
, public MaterialViewportNotificationBus::Handler
|
||||
, public AZ::TransformNotificationBus::MultiHandler
|
||||
{
|
||||
public:
|
||||
MaterialViewportWidget(QWidget* parent = nullptr);
|
||||
~MaterialViewportWidget();
|
||||
|
||||
private:
|
||||
// AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler interface overrides...
|
||||
void OnDocumentOpened(const AZ::Uuid& documentId) override;
|
||||
|
||||
// MaterialViewportNotificationBus::Handler interface overrides...
|
||||
void OnLightingPresetSelected(AZ::Render::LightingPresetPtr preset) override;
|
||||
void OnLightingPresetChanged(AZ::Render::LightingPresetPtr preset) override;
|
||||
void OnModelPresetSelected(AZ::Render::ModelPresetPtr preset) override;
|
||||
void OnModelPresetChanged(AZ::Render::ModelPresetPtr preset) override;
|
||||
void OnShadowCatcherEnabledChanged(bool enable) override;
|
||||
void OnGridEnabledChanged(bool enable) override;
|
||||
void OnAlternateSkyboxEnabledChanged(bool enable) override;
|
||||
void OnFieldOfViewChanged(float fieldOfView) override;
|
||||
void OnDisplayMapperOperationTypeChanged(AZ::Render::DisplayMapperOperationType operationType) override;
|
||||
|
||||
// AZ::Data::AssetBus::Handler interface overrides...
|
||||
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
|
||||
// AZ::TickBus::Handler interface overrides...
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
// AZ::TransformNotificationBus::MultiHandler overrides...
|
||||
void OnTransformChanged(const AZ::Transform&, const AZ::Transform&) override;
|
||||
|
||||
using DirectionalLightHandle = AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle;
|
||||
|
||||
AZ::Data::Instance<AZ::RPI::SwapChainPass> m_swapChainPass;
|
||||
AZStd::string m_defaultPipelineAssetPath = "passes/MainRenderPipeline.azasset";
|
||||
AZ::RPI::RenderPipelinePtr m_renderPipeline;
|
||||
AZ::RPI::ScenePtr m_scene;
|
||||
AZ::Render::DirectionalLightFeatureProcessorInterface* m_directionalLightFeatureProcessor = {};
|
||||
AZ::Render::DisplayMapperFeatureProcessorInterface* m_displayMapperFeatureProcessor = {};
|
||||
|
||||
AZ::Entity* m_cameraEntity = {};
|
||||
AZ::Component* m_cameraComponent = {};
|
||||
|
||||
AZ::Entity* m_postProcessEntity = {};
|
||||
|
||||
AZ::Entity* m_modelEntity = {};
|
||||
AZ::Data::AssetId m_modelAssetId;
|
||||
|
||||
AZ::Entity* m_gridEntity = {};
|
||||
|
||||
AZ::Entity* m_shadowCatcherEntity = {};
|
||||
AZ::Data::Instance<AZ::RPI::Material> m_shadowCatcherMaterial;
|
||||
AZ::RPI::MaterialPropertyIndex m_shadowCatcherOpacityPropertyIndex;
|
||||
|
||||
AZStd::vector<DirectionalLightHandle> m_lightHandles;
|
||||
|
||||
AZ::Entity* m_iblEntity = {};
|
||||
AZ::Render::SkyBoxFeatureProcessorInterface* m_skyboxFeatureProcessor = {};
|
||||
|
||||
AZStd::shared_ptr<MaterialEditorViewportInputController> m_viewportController;
|
||||
|
||||
QScopedPointer<Ui::MaterialViewportWidget> m_ui;
|
||||
AZStd::unique_ptr<MaterialViewportRenderer> m_renderer;
|
||||
};
|
||||
} // namespace MaterialEditor
|
||||
|
||||
@@ -1,23 +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 <Window/HelpDialog/HelpDialog.h>
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
HelpDialog::HelpDialog(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_ui(new Ui::HelpDialogWidget)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
}
|
||||
|
||||
HelpDialog::~HelpDialog() = default;
|
||||
} // namespace MaterialEditor
|
||||
|
||||
#include <Window/HelpDialog/moc_HelpDialog.cpp>
|
||||
@@ -1,38 +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
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <AzCore/Memory/SystemAllocator.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QDialog>
|
||||
#include <Window/HelpDialog/ui_HelpDialog.h>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
#endif
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class HelpDialogWidget;
|
||||
}
|
||||
|
||||
namespace MaterialEditor
|
||||
{
|
||||
//! Displays help for Material Editor
|
||||
class HelpDialog
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
HelpDialog(QWidget* parent = nullptr);
|
||||
~HelpDialog();
|
||||
|
||||
QScopedPointer<Ui::HelpDialogWidget> m_ui;
|
||||
};
|
||||
} // namespace MaterialEditor
|
||||
@@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>HelpDialogWidget</class>
|
||||
<widget class="QDialog" name="HelpDialogWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>270</width>
|
||||
<height>210</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Material Editor Help</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="m_helpText">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Material Editor Controls</span></p><p><span style=" font-weight:600;">LMB</span> - pan camera</p><p><span style=" font-weight:600;">RMB</span> or <span style=" font-weight:600;">Alt+LMB</span> - orbit camera around target</p><p><span style=" font-weight:600;">MMB</span> or <span style=" font-weight:600;">Alt+MMB</span> - move camera on its xy plane</p><p><span style=" font-weight:600;">Alt+RMB</span> or <span style=" font-weight:600;">LMB+RMB</span> - dolly camera on its z axis</p><p><span style=" font-weight:600;">Ctrl+LMB</span> - rotate model</p><p><span style=" font-weight:600;">Shift+LMB</span> - rotate environment</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>HelpDialogWidget</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>HelpDialogWidget</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <Document/MaterialDocumentRequestBus.h>
|
||||
#include <Viewport/MaterialViewportWidget.h>
|
||||
#include <Window/CreateMaterialDialog/CreateMaterialDialog.h>
|
||||
#include <Window/HelpDialog/HelpDialog.h>
|
||||
#include <Window/MaterialEditorWindow.h>
|
||||
#include <Window/MaterialEditorWindowSettings.h>
|
||||
#include <Window/MaterialInspector/MaterialInspector.h>
|
||||
@@ -30,6 +29,7 @@ AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnin
|
||||
#include <QCloseEvent>
|
||||
#include <QDesktopServices>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QUrl>
|
||||
#include <QWindow>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
@@ -178,8 +178,22 @@ namespace MaterialEditor
|
||||
|
||||
void MaterialEditorWindow::OpenHelp()
|
||||
{
|
||||
HelpDialog dialog(this);
|
||||
dialog.exec();
|
||||
QMessageBox::information(
|
||||
this, windowTitle(),
|
||||
R"(<html><head/><body>
|
||||
<p><h3><u>Material Editor Controls</u></h3></p>
|
||||
<p><b>LMB</b> - pan camera</p>
|
||||
<p><b>RMB</b> or <b>Alt+LMB</b> - orbit camera around target</p>
|
||||
<p><b>MMB</b> or <b>Alt+MMB</b> - move camera on its xy plane</p>
|
||||
<p><b>Alt+RMB</b> or <b>LMB+RMB</b> - dolly camera on its z axis</p>
|
||||
<p><b>Ctrl+LMB</b> - rotate model</p>
|
||||
<p><b>Shift+LMB</b> - rotate environment</p>
|
||||
</body></html>)");
|
||||
}
|
||||
|
||||
void MaterialEditorWindow::OpenAbout()
|
||||
{
|
||||
QMessageBox::about(this, windowTitle(), QApplication::applicationName());
|
||||
}
|
||||
|
||||
void MaterialEditorWindow::closeEvent(QCloseEvent* closeEvent)
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace MaterialEditor
|
||||
bool GetOpenDocumentParams(AZStd::string& openPath) override;
|
||||
void OpenSettings() override;
|
||||
void OpenHelp() override;
|
||||
void OpenAbout() override;
|
||||
|
||||
void closeEvent(QCloseEvent* closeEvent) override;
|
||||
|
||||
|
||||
+2
-2
@@ -152,7 +152,7 @@ namespace MaterialEditor
|
||||
AtomToolsFramework::DynamicProperty property;
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(
|
||||
property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty,
|
||||
AZ::RPI::MaterialPropertyId(groupName, uvNamePair.m_shaderInput.ToString()).GetFullName());
|
||||
AZ::RPI::MaterialPropertyId(groupName, uvNamePair.m_shaderInput.ToString()));
|
||||
group.m_properties.push_back(property);
|
||||
|
||||
property.SetValue(property.GetConfig().m_parentValue);
|
||||
@@ -189,7 +189,7 @@ namespace MaterialEditor
|
||||
AtomToolsFramework::DynamicProperty property;
|
||||
AtomToolsFramework::AtomToolsDocumentRequestBus::EventResult(
|
||||
property, m_documentId, &AtomToolsFramework::AtomToolsDocumentRequestBus::Events::GetProperty,
|
||||
AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name).GetFullName());
|
||||
AZ::RPI::MaterialPropertyId(groupName, propertyDefinition.m_name));
|
||||
group.m_properties.push_back(property);
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user