Merge branch 'development' into animation/rhhong/RenderUtilOptions
Signed-off-by: rhhong <rhhong@amazon.com> # Conflicts: # Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.cpp # Gems/AtomLyIntegration/EMotionFXAtom/Code/Source/AtomActorDebugDraw.h
This commit is contained in:
@@ -185,7 +185,7 @@
|
||||
{
|
||||
"id": {
|
||||
"materialAssetId": {
|
||||
"guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
|
||||
"guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
|
||||
"subId": 803645540
|
||||
}
|
||||
}
|
||||
@@ -197,7 +197,7 @@
|
||||
"id": {
|
||||
"lodIndex": 0,
|
||||
"materialAssetId": {
|
||||
"guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
|
||||
"guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
|
||||
"subId": 803645540
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#
|
||||
|
||||
|
||||
# This script shows basic usage of LuaSymbolsReporterBus,
|
||||
# Which can be used to report all symbols available for
|
||||
# game scripting with Lua.
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
import azlmbr.bus as azbus
|
||||
import azlmbr.script as azscript
|
||||
import azlmbr.legacy.general as azgeneral
|
||||
|
||||
|
||||
def _dump_class_symbol(class_symbol: azlmbr.script.LuaClassSymbol):
|
||||
print(f"** {class_symbol}")
|
||||
print("Properties:")
|
||||
for property_symbol in class_symbol.properties:
|
||||
print(f" - {property_symbol}")
|
||||
print("Methods:")
|
||||
for method_symbol in class_symbol.methods:
|
||||
print(f" - {method_symbol}")
|
||||
|
||||
|
||||
def _dump_lua_classes():
|
||||
class_symbols = azscript.LuaSymbolsReporterBus(azbus.Broadcast,
|
||||
"GetListOfClasses")
|
||||
print("======== Classes ==========")
|
||||
sorted_classes_by_named = sorted(class_symbols, key=lambda class_symbol: class_symbol.name)
|
||||
for class_symbol in sorted_classes_by_named:
|
||||
_dump_class_symbol(class_symbol)
|
||||
print("\n\n")
|
||||
|
||||
|
||||
def _dump_lua_globals():
|
||||
global_properties = azscript.LuaSymbolsReporterBus(azbus.Broadcast,
|
||||
"GetListOfGlobalProperties")
|
||||
print("======== Global Properties ==========")
|
||||
sorted_properties_by_name = sorted(global_properties, key=lambda symbol: symbol.name)
|
||||
for property_symbol in sorted_properties_by_name:
|
||||
print(f"- {property_symbol}")
|
||||
print("\n\n")
|
||||
global_functions = azscript.LuaSymbolsReporterBus(azbus.Broadcast,
|
||||
"GetListOfGlobalFunctions")
|
||||
print("======== Global Functions ==========")
|
||||
sorted_functions_by_name = sorted(global_functions, key=lambda symbol: symbol.name)
|
||||
for function_symbol in sorted_functions_by_name:
|
||||
print(f"- {function_symbol}")
|
||||
print("\n\n")
|
||||
|
||||
|
||||
def _dump_lua_ebus(ebus_symbol: azlmbr.script.LuaEBusSymbol):
|
||||
print(f">> {ebus_symbol}")
|
||||
sorted_senders = sorted(ebus_symbol.senders, key=lambda symbol: symbol.name)
|
||||
for sender in sorted_senders:
|
||||
print(f" - {sender}")
|
||||
print("\n")
|
||||
|
||||
|
||||
def _dump_lua_ebuses():
|
||||
ebuses = azscript.LuaSymbolsReporterBus(azbus.Broadcast,
|
||||
"GetListOfEBuses")
|
||||
print("======== Ebus List ==========")
|
||||
sorted_ebuses_by_name = sorted(ebuses, key=lambda symbol: symbol.name)
|
||||
for ebus_symbol in sorted_ebuses_by_name:
|
||||
_dump_lua_ebus(ebus_symbol)
|
||||
print("\n\n")
|
||||
|
||||
|
||||
class WhatToDo:
|
||||
DumpClasses = "c"
|
||||
DumpGlobals = "g"
|
||||
DumpEBuses = "e"
|
||||
|
||||
if __name__ == "__main__":
|
||||
redirecting_stdout = False
|
||||
orig_stdout = sys.stdout
|
||||
if len(sys.argv) > 1:
|
||||
output_file_name = sys.argv[1]
|
||||
if not os.path.isabs(output_file_name):
|
||||
game_root_path = os.path.normpath(azgeneral.get_game_folder())
|
||||
output_file_name = os.path.join(game_root_path, output_file_name)
|
||||
try:
|
||||
file_obj = open(output_file_name, 'wt')
|
||||
sys.stdout = file_obj
|
||||
redirecting_stdout = True
|
||||
except Exception as e:
|
||||
print(f"Failed to open {output_file_name}: {e}")
|
||||
sys.exit(-1)
|
||||
|
||||
what_to_do = [action.lower() for action in sys.argv[2:]]
|
||||
|
||||
# If the user did not specify what to do, then let's dump
|
||||
# all the symbols.
|
||||
if len(what_to_do) < 1:
|
||||
what_to_do = [WhatToDo.DumpClasses, WhatToDo.DumpGlobals, WhatToDo.DumpEBuses]
|
||||
|
||||
for action in what_to_do:
|
||||
if action == WhatToDo.DumpClasses:
|
||||
_dump_lua_classes()
|
||||
elif action == WhatToDo.DumpGlobals:
|
||||
_dump_lua_globals()
|
||||
elif action == WhatToDo.DumpEBuses:
|
||||
_dump_lua_ebuses()
|
||||
|
||||
if redirecting_stdout:
|
||||
sys.stdout.close()
|
||||
sys.stdout = orig_stdout
|
||||
print(f" Lua Symbols Are available in: {output_file_name}")
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:93a7e033d9fb0fcac221647322bde03716643d789390f79078c4fcc37ecfd005
|
||||
size 68327
|
||||
+3111
File diff suppressed because it is too large
Load Diff
+3
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6e63a55a35c749a16a03e10a1f53a48bd426c61db80151de080235b14cf6b70d
|
||||
size 2479344
|
||||
@@ -21,8 +21,8 @@ from ly_test_tools.o3de.asset_processor import ASSET_PROCESSOR_PLATFORM_MAP
|
||||
from ..ap_fixtures.asset_processor_fixture import asset_processor as asset_processor
|
||||
from ..ap_fixtures.ap_setup_fixture import ap_setup_fixture as ap_setup_fixture
|
||||
from ..ap_fixtures.ap_config_backup_fixture import ap_config_backup_fixture as ap_config_backup_fixture
|
||||
from ..ap_fixtures.ap_config_default_platform_fixture import ap_config_default_platform_fixture as ap_config_default_platform_fixture
|
||||
|
||||
from ..ap_fixtures.ap_config_default_platform_fixture \
|
||||
import ap_config_default_platform_fixture as ap_config_default_platform_fixture
|
||||
|
||||
# Import LyShared
|
||||
import ly_test_tools.o3de.pipeline_utils as utils
|
||||
@@ -33,6 +33,7 @@ logger = logging.getLogger(__name__)
|
||||
# Helper: variables we will use for parameter values in the test:
|
||||
targetProjects = ["AutomatedTesting"]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@pytest.mark.SUITE_sandbox
|
||||
def local_resources(request, workspace, ap_setup_fixture):
|
||||
@@ -54,21 +55,21 @@ class BlackboxAssetTest:
|
||||
blackbox_fbx_tests = [
|
||||
pytest.param(
|
||||
BlackboxAssetTest(
|
||||
test_name= "OneMeshOneMaterial_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder= "OneMeshOneMaterial",
|
||||
test_name="OneMeshOneMaterial_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder="OneMeshOneMaterial",
|
||||
scene_debug_file="onemeshonematerial.dbgsg",
|
||||
assets = [
|
||||
assets=[
|
||||
asset_db_utils.DBSourceAsset(
|
||||
source_file_name = "OneMeshOneMaterial.fbx",
|
||||
uuid = b"8a9164adb84859be893e18aa819438e1",
|
||||
jobs = [
|
||||
source_file_name="OneMeshOneMaterial.fbx",
|
||||
uuid=b"8a9164adb84859be893e18aa819438e1",
|
||||
jobs=[
|
||||
asset_db_utils.DBJob(
|
||||
job_key= "Scene compilation",
|
||||
job_key="Scene compilation",
|
||||
builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3",
|
||||
status=4,
|
||||
error_count=0,
|
||||
warning_count=1,
|
||||
products = [
|
||||
products=[
|
||||
asset_db_utils.DBProduct(
|
||||
product_name='onemeshonematerial/onemeshonematerial.dbgsg',
|
||||
sub_id=1918494907,
|
||||
@@ -86,21 +87,21 @@ blackbox_fbx_tests = [
|
||||
BlackboxAssetTest(
|
||||
# Verifies that the soft naming convention feature with level of detail meshes works.
|
||||
# https://docs.aws.amazon.com/lumberyard/latest/userguide/char-fbx-importer-soft-naming.html
|
||||
test_name= "SoftNamingLOD_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder= "SoftNamingLOD",
|
||||
test_name="SoftNamingLOD_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder="SoftNamingLOD",
|
||||
scene_debug_file="lodtest.dbgsg",
|
||||
assets = [
|
||||
assets=[
|
||||
asset_db_utils.DBSourceAsset(
|
||||
source_file_name = "lodtest.fbx",
|
||||
uuid = b"44c8627fe2c25aae91fe3ff9547be3b9",
|
||||
jobs = [
|
||||
source_file_name="lodtest.fbx",
|
||||
uuid=b"44c8627fe2c25aae91fe3ff9547be3b9",
|
||||
jobs=[
|
||||
asset_db_utils.DBJob(
|
||||
job_key= "Scene compilation",
|
||||
job_key="Scene compilation",
|
||||
builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3",
|
||||
status=4,
|
||||
error_count=0,
|
||||
warning_count=22,
|
||||
products = [
|
||||
products=[
|
||||
asset_db_utils.DBProduct(
|
||||
product_name='softnaminglod/lodtest.dbgsg',
|
||||
sub_id=-632012261,
|
||||
@@ -118,21 +119,21 @@ blackbox_fbx_tests = [
|
||||
BlackboxAssetTest(
|
||||
# Verifies that the soft naming convention feature with physics proxies works.
|
||||
# https://docs.aws.amazon.com/lumberyard/latest/userguide/char-fbx-importer-soft-naming.html
|
||||
test_name= "SoftNamingPhysics_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder= "SoftNamingPhysics",
|
||||
test_name="SoftNamingPhysics_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder="SoftNamingPhysics",
|
||||
scene_debug_file="physicstest.dbgsg",
|
||||
assets = [
|
||||
assets=[
|
||||
asset_db_utils.DBSourceAsset(
|
||||
source_file_name = "physicstest.fbx",
|
||||
uuid = b"df957b7918cf5b029806c73f630fa1c8",
|
||||
jobs = [
|
||||
source_file_name="physicstest.fbx",
|
||||
uuid=b"df957b7918cf5b029806c73f630fa1c8",
|
||||
jobs=[
|
||||
asset_db_utils.DBJob(
|
||||
job_key= "Scene compilation",
|
||||
job_key="Scene compilation",
|
||||
builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3",
|
||||
status=4,
|
||||
error_count=0,
|
||||
warning_count=14,
|
||||
products = [
|
||||
products=[
|
||||
asset_db_utils.DBProduct(
|
||||
product_name='softnamingphysics/physicstest.dbgsg',
|
||||
sub_id=-740411732,
|
||||
@@ -152,21 +153,21 @@ blackbox_fbx_tests = [
|
||||
),
|
||||
pytest.param(
|
||||
BlackboxAssetTest(
|
||||
test_name= "MultipleMeshOneMaterial_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder= "TwoMeshOneMaterial",
|
||||
test_name="MultipleMeshOneMaterial_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder="TwoMeshOneMaterial",
|
||||
scene_debug_file="multiple_mesh_one_material.dbgsg",
|
||||
assets = [
|
||||
assets=[
|
||||
asset_db_utils.DBSourceAsset(
|
||||
source_file_name = "multiple_mesh_one_material.fbx",
|
||||
uuid = b"597618fd497659a1b197a015fe47aa95",
|
||||
jobs = [
|
||||
source_file_name="multiple_mesh_one_material.fbx",
|
||||
uuid=b"597618fd497659a1b197a015fe47aa95",
|
||||
jobs=[
|
||||
asset_db_utils.DBJob(
|
||||
job_key= "Scene compilation",
|
||||
job_key="Scene compilation",
|
||||
builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3",
|
||||
status=4,
|
||||
error_count=0,
|
||||
warning_count=2,
|
||||
products = [
|
||||
products=[
|
||||
asset_db_utils.DBProduct(
|
||||
product_name='twomeshonematerial/multiple_mesh_one_material.dbgsg',
|
||||
sub_id=2077268018,
|
||||
@@ -183,22 +184,22 @@ blackbox_fbx_tests = [
|
||||
pytest.param(
|
||||
BlackboxAssetTest(
|
||||
# Verifies whether multiple meshes can share linked materials
|
||||
test_name= "MultipleMeshLinkedMaterials_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder= "TwoMeshLinkedMaterials",
|
||||
scene_debug_file= "multiple_mesh_linked_materials.dbgsg",
|
||||
assets = [
|
||||
test_name="MultipleMeshLinkedMaterials_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder="TwoMeshLinkedMaterials",
|
||||
scene_debug_file="multiple_mesh_linked_materials.dbgsg",
|
||||
assets=[
|
||||
asset_db_utils.DBSourceAsset(
|
||||
source_file_name = "multiple_mesh_linked_materials.fbx",
|
||||
uuid = b"25d8301c2eef5dc7bded310db8ea608d",
|
||||
jobs = [
|
||||
source_file_name="multiple_mesh_linked_materials.fbx",
|
||||
uuid=b"25d8301c2eef5dc7bded310db8ea608d",
|
||||
jobs=[
|
||||
asset_db_utils.DBJob(
|
||||
job_key= "Scene compilation",
|
||||
platform= "pc",
|
||||
job_key="Scene compilation",
|
||||
platform="pc",
|
||||
builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3",
|
||||
status=4,
|
||||
error_count=0,
|
||||
warning_count=2,
|
||||
products= [
|
||||
products=[
|
||||
asset_db_utils.DBProduct(
|
||||
product_name='twomeshlinkedmaterials/multiple_mesh_linked_materials.dbgsg',
|
||||
sub_id=-1898461950,
|
||||
@@ -216,22 +217,22 @@ blackbox_fbx_tests = [
|
||||
pytest.param(
|
||||
BlackboxAssetTest(
|
||||
# Verifies a mesh with multiple materials
|
||||
test_name= "SingleMeshMultipleMaterials_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder= "OneMeshMultipleMaterials",
|
||||
test_name="SingleMeshMultipleMaterials_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder="OneMeshMultipleMaterials",
|
||||
scene_debug_file="single_mesh_multiple_materials.dbgsg",
|
||||
assets = [
|
||||
assets=[
|
||||
asset_db_utils.DBSourceAsset(
|
||||
source_file_name = "single_mesh_multiple_materials.fbx",
|
||||
uuid = b"f08fd585dfa35881b4bf86637da5e858",
|
||||
jobs = [
|
||||
source_file_name="single_mesh_multiple_materials.fbx",
|
||||
uuid=b"f08fd585dfa35881b4bf86637da5e858",
|
||||
jobs=[
|
||||
asset_db_utils.DBJob(
|
||||
job_key= "Scene compilation",
|
||||
platform= "pc",
|
||||
job_key="Scene compilation",
|
||||
platform="pc",
|
||||
builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3",
|
||||
status=4,
|
||||
error_count=0,
|
||||
warning_count=1,
|
||||
products = [
|
||||
products=[
|
||||
asset_db_utils.DBProduct(
|
||||
product_name='onemeshmultiplematerials/single_mesh_multiple_materials.dbgsg',
|
||||
sub_id=-262822238,
|
||||
@@ -277,21 +278,21 @@ blackbox_fbx_tests = [
|
||||
),
|
||||
pytest.param(
|
||||
BlackboxAssetTest(
|
||||
test_name= "MotionTest_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder= "Motion",
|
||||
test_name="MotionTest_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder="Motion",
|
||||
scene_debug_file="Jack_Idle_Aim_ZUp.dbgsg",
|
||||
assets = [
|
||||
assets=[
|
||||
asset_db_utils.DBSourceAsset(
|
||||
source_file_name = "Jack_Idle_Aim_ZUp.fbx",
|
||||
uuid = b"eda904ae0e145f8b973d57fc5809918b",
|
||||
jobs = [
|
||||
source_file_name="Jack_Idle_Aim_ZUp.fbx",
|
||||
uuid=b"eda904ae0e145f8b973d57fc5809918b",
|
||||
jobs=[
|
||||
asset_db_utils.DBJob(
|
||||
job_key= "Scene compilation",
|
||||
job_key="Scene compilation",
|
||||
builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3",
|
||||
status=4,
|
||||
error_count=0,
|
||||
warning_count=0,
|
||||
products = [
|
||||
products=[
|
||||
asset_db_utils.DBProduct(
|
||||
product_name='motion/jack_idle_aim_zup.dbgsg',
|
||||
sub_id=-517610290,
|
||||
@@ -307,29 +308,56 @@ blackbox_fbx_tests = [
|
||||
]
|
||||
),
|
||||
),
|
||||
pytest.param(
|
||||
BlackboxAssetTest(
|
||||
test_name="ShaderBall_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder="ShaderBall",
|
||||
scene_debug_file="shaderball.dbgsg",
|
||||
assets=[
|
||||
asset_db_utils.DBSourceAsset(
|
||||
source_file_name="shaderball.fbx",
|
||||
uuid=b"48181ba8038e5193997540fc8dffb06d",
|
||||
jobs=[
|
||||
asset_db_utils.DBJob(
|
||||
job_key="Scene compilation",
|
||||
builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3",
|
||||
status=4,
|
||||
error_count=0,
|
||||
warning_count=30,
|
||||
products=[
|
||||
asset_db_utils.DBProduct(
|
||||
product_name='shaderball/shaderball.dbgsg',
|
||||
sub_id=-1607815784,
|
||||
asset_type=b'07f289d14dc74c4094b40a53bbcb9f0b'),
|
||||
]
|
||||
),
|
||||
]
|
||||
)
|
||||
]
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
blackbox_fbx_special_tests = [
|
||||
pytest.param(
|
||||
BlackboxAssetTest(
|
||||
test_name= "MultipleMeshMultipleMaterial_MultipleAssetInfo_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder= "TwoMeshTwoMaterial",
|
||||
override_asset_folder = "OverrideAssetInfoForTwoMeshTwoMaterial",
|
||||
test_name="MultipleMeshMultipleMaterial_MultipleAssetInfo_RunAP_SuccessWithMatchingProducts",
|
||||
asset_folder="TwoMeshTwoMaterial",
|
||||
override_asset_folder="OverrideAssetInfoForTwoMeshTwoMaterial",
|
||||
scene_debug_file="multiple_mesh_multiple_material.dbgsg",
|
||||
override_scene_debug_file="multiple_mesh_multiple_material_override.dbgsg",
|
||||
assets = [
|
||||
assets=[
|
||||
asset_db_utils.DBSourceAsset(
|
||||
source_file_name = "multiple_mesh_multiple_material.fbx",
|
||||
uuid = b"b5915fb874af5c8a866ccabbddb57595",
|
||||
jobs = [
|
||||
source_file_name="multiple_mesh_multiple_material.fbx",
|
||||
uuid=b"b5915fb874af5c8a866ccabbddb57595",
|
||||
jobs=[
|
||||
asset_db_utils.DBJob(
|
||||
job_key="Scene compilation",
|
||||
builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3",
|
||||
status=4,
|
||||
error_count=0,
|
||||
warning_count=2,
|
||||
products = [
|
||||
products=[
|
||||
asset_db_utils.DBProduct(
|
||||
product_name='twomeshtwomaterial/multiple_mesh_multiple_material.dbgsg',
|
||||
sub_id=896980093,
|
||||
@@ -341,16 +369,16 @@ blackbox_fbx_special_tests = [
|
||||
],
|
||||
override_assets=[
|
||||
asset_db_utils.DBSourceAsset(
|
||||
source_file_name = "multiple_mesh_multiple_material.fbx",
|
||||
uuid = b"b5915fb874af5c8a866ccabbddb57595",
|
||||
jobs = [
|
||||
source_file_name="multiple_mesh_multiple_material.fbx",
|
||||
uuid=b"b5915fb874af5c8a866ccabbddb57595",
|
||||
jobs=[
|
||||
asset_db_utils.DBJob(
|
||||
job_key= "Scene compilation",
|
||||
job_key="Scene compilation",
|
||||
builder_guid=b"bd8bf65894854fe3830e8ec3a23c35f3",
|
||||
status=4,
|
||||
error_count=0,
|
||||
warning_count=2,
|
||||
products = [
|
||||
products=[
|
||||
asset_db_utils.DBProduct(
|
||||
product_name='twomeshtwomaterial/multiple_mesh_multiple_material.dbgsg',
|
||||
sub_id=896980093,
|
||||
@@ -378,29 +406,26 @@ class TestsFBX_AllPlatforms(object):
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("blackbox_param", blackbox_fbx_tests)
|
||||
def test_FBXBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace,
|
||||
ap_setup_fixture, asset_processor, project,
|
||||
blackbox_param):
|
||||
def test_FBXBlackboxTest_SourceFiles_Processed_ResultInExpectedProducts(self, workspace, ap_setup_fixture,
|
||||
asset_processor, project, blackbox_param):
|
||||
"""
|
||||
Please see run_fbx_test(...) for details
|
||||
|
||||
Please see run_fbx_test(...) for details
|
||||
Test Steps:
|
||||
1. Determine if blackbox is set to none
|
||||
2. Run FBX Test
|
||||
|
||||
"""
|
||||
|
||||
if blackbox_param == None:
|
||||
return
|
||||
self.run_fbx_test(workspace, ap_setup_fixture,
|
||||
asset_processor, project, blackbox_param)
|
||||
self.run_fbx_test(workspace, ap_setup_fixture, asset_processor, project, blackbox_param)
|
||||
|
||||
@pytest.mark.BAT
|
||||
@pytest.mark.SUITE_sandbox
|
||||
@pytest.mark.parametrize("blackbox_param", blackbox_fbx_special_tests)
|
||||
def test_FBXBlackboxTest_AssetInfoModified_AssetReprocessed_ResultInExpectedProducts(self,
|
||||
workspace, ap_setup_fixture,
|
||||
asset_processor, project,
|
||||
blackbox_param):
|
||||
def test_FBXBlackboxTest_AssetInfoModified_AssetReprocessed_ResultInExpectedProducts(
|
||||
self, workspace, ap_setup_fixture, asset_processor, project, blackbox_param):
|
||||
"""
|
||||
Please see run_fbx_test(...) for details
|
||||
|
||||
@@ -430,7 +455,7 @@ class TestsFBX_AllPlatforms(object):
|
||||
+ product.product_name
|
||||
|
||||
def run_fbx_test(self, workspace, ap_setup_fixture, asset_processor,
|
||||
project, blackbox_params: BlackboxAssetTest, overrideAsset = False):
|
||||
project, blackbox_params: BlackboxAssetTest, overrideAsset=False):
|
||||
"""
|
||||
These tests work by having the test case ingest the test data and determine the run pattern.
|
||||
Tests will process scene settings files and will additionally do a verification against a provided debug file
|
||||
@@ -469,21 +494,23 @@ class TestsFBX_AllPlatforms(object):
|
||||
expected_product_list.append(expected_product.product_name)
|
||||
|
||||
missing_assets, _ = utils.compare_assets_with_cache(expected_product_list,
|
||||
asset_processor.project_test_cache_folder())
|
||||
asset_processor.project_test_cache_folder())
|
||||
|
||||
assert not missing_assets, f'The following assets were expected to be in, but not found in cache: {str(missing_assets)}'
|
||||
assert not missing_assets, \
|
||||
f'The following assets were expected to be in, but not found in cache: {str(missing_assets)}'
|
||||
|
||||
# Load the asset database.
|
||||
db_path = os.path.join(asset_processor.temp_asset_root(), "Cache",
|
||||
"assetdb.sqlite")
|
||||
cache_root = os.path.dirname(os.path.join(asset_processor.temp_asset_root(), "Cache",
|
||||
ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform]))
|
||||
ASSET_PROCESSOR_PLATFORM_MAP[workspace.asset_processor_platform]))
|
||||
|
||||
if blackbox_params.scene_debug_file:
|
||||
scene_debug_file = blackbox_params.override_scene_debug_file if overrideAsset\
|
||||
scene_debug_file = blackbox_params.override_scene_debug_file if overrideAsset \
|
||||
else blackbox_params.scene_debug_file
|
||||
|
||||
debug_graph_path = os.path.join(asset_processor.project_test_cache_folder(), blackbox_params.scene_debug_file)
|
||||
debug_graph_path = os.path.join(asset_processor.project_test_cache_folder(),
|
||||
blackbox_params.scene_debug_file)
|
||||
expected_debug_graph_path = os.path.join(asset_processor.project_test_source_folder(), scene_debug_file)
|
||||
|
||||
logger.info(f"Parsing scene graph: {debug_graph_path}")
|
||||
|
||||
@@ -96,10 +96,6 @@ AzAssetBrowserWindow::AzAssetBrowserWindow(QWidget* parent)
|
||||
connect(
|
||||
m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this,
|
||||
&AzAssetBrowserWindow::SetTableViewVisibleAfterFilter);
|
||||
|
||||
connect(
|
||||
m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this,
|
||||
&AzAssetBrowserWindow::UpdateTableModelAfterFilter);
|
||||
connect(
|
||||
m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::selectionChangedSignal, this,
|
||||
&AzAssetBrowserWindow::SelectionChangedSlot);
|
||||
@@ -251,24 +247,6 @@ void AzAssetBrowserWindow::SetExpandedAssetBrowserMode()
|
||||
|
||||
m_assetBrowserDisplayState = AzAssetBrowser::AssetBrowserDisplayState::ExpandedMode;
|
||||
|
||||
disconnect(
|
||||
m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this,
|
||||
&AzAssetBrowserWindow::UpdateTableModelAfterFilter);
|
||||
disconnect(
|
||||
m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this,
|
||||
&AzAssetBrowserWindow::SetTableViewVisibleAfterFilter);
|
||||
|
||||
disconnect(
|
||||
m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::selectionChangedSignal, this,
|
||||
&AzAssetBrowserWindow::SelectionChangedSlot);
|
||||
disconnect(m_ui->m_assetBrowserTableViewWidget, &QAbstractItemView::doubleClicked, this, &AzAssetBrowserWindow::DoubleClickedItem);
|
||||
disconnect(
|
||||
m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::ClearStringFilter, m_ui->m_searchWidget,
|
||||
&AzAssetBrowser::SearchWidget::ClearStringFilter);
|
||||
disconnect(
|
||||
m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::ClearTypeFilter, m_ui->m_searchWidget,
|
||||
&AzAssetBrowser::SearchWidget::ClearTypeFilter);
|
||||
|
||||
if (m_ui->m_assetBrowserTableViewWidget->isVisible())
|
||||
{
|
||||
m_ui->m_assetBrowserTableViewWidget->setVisible(false);
|
||||
@@ -281,37 +259,9 @@ void AzAssetBrowserWindow::SetDefaultAssetBrowserMode()
|
||||
namespace AzAssetBrowser = AzToolsFramework::AssetBrowser;
|
||||
|
||||
m_assetBrowserDisplayState = AzAssetBrowser::AssetBrowserDisplayState::DefaultMode;
|
||||
|
||||
connect(
|
||||
m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this,
|
||||
&AzAssetBrowserWindow::SetTableViewVisibleAfterFilter);
|
||||
|
||||
connect(
|
||||
m_filterModel.data(), &AzAssetBrowser::AssetBrowserFilterModel::filterChanged, this,
|
||||
&AzAssetBrowserWindow::UpdateTableModelAfterFilter);
|
||||
connect(
|
||||
m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::selectionChangedSignal, this,
|
||||
&AzAssetBrowserWindow::SelectionChangedSlot);
|
||||
connect(m_ui->m_assetBrowserTableViewWidget, &QAbstractItemView::doubleClicked, this, &AzAssetBrowserWindow::DoubleClickedItem);
|
||||
connect(
|
||||
m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::ClearStringFilter, m_ui->m_searchWidget,
|
||||
&AzAssetBrowser::SearchWidget::ClearStringFilter);
|
||||
connect(
|
||||
m_ui->m_assetBrowserTableViewWidget, &AzAssetBrowser::AssetBrowserTableView::ClearTypeFilter, m_ui->m_searchWidget,
|
||||
&AzAssetBrowser::SearchWidget::ClearTypeFilter);
|
||||
|
||||
//If the filter is not empty we want to switch views and Update the model
|
||||
UpdateTableModelAfterFilter();
|
||||
SetTableViewVisibleAfterFilter();
|
||||
}
|
||||
|
||||
void AzAssetBrowserWindow::UpdateTableModelAfterFilter()
|
||||
{
|
||||
if (!m_ui->m_searchWidget->GetFilterString().isEmpty())
|
||||
{
|
||||
m_tableModel->UpdateTableModelMaps();
|
||||
}
|
||||
}
|
||||
|
||||
void AzAssetBrowserWindow::SetTableViewVisibleAfterFilter()
|
||||
{
|
||||
@@ -389,8 +339,8 @@ void AzAssetBrowserWindow::SelectionChangedSlot(const QItemSelection& /*selected
|
||||
UpdatePreview();
|
||||
}
|
||||
|
||||
// while its tempting to use Activated here, we dont actually want it to count as activation
|
||||
// just becuase on some OS clicking once is activation.
|
||||
// while its tempting to use Activated here, we don't actually want it to count as activation
|
||||
// just because on some OS clicking once is activation.
|
||||
void AzAssetBrowserWindow::DoubleClickedItem([[maybe_unused]] const QModelIndex& element)
|
||||
{
|
||||
namespace AzAssetBrowser = AzToolsFramework::AssetBrowser;
|
||||
|
||||
@@ -68,7 +68,6 @@ protected slots:
|
||||
void CreateSwitchViewMenu();
|
||||
void SetExpandedAssetBrowserMode();
|
||||
void SetDefaultAssetBrowserMode();
|
||||
void UpdateTableModelAfterFilter();
|
||||
void SetTableViewVisibleAfterFilter();
|
||||
|
||||
private:
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
#include <AzToolsFramework/Undo/UndoCacheInterface.h>
|
||||
#include <AzToolsFramework/Prefab/PrefabPublicInterface.h>
|
||||
#include <Entity/EntityUtilityComponent.h>
|
||||
#include <AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.h>
|
||||
|
||||
#include <QtWidgets/QMessageBox>
|
||||
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: 'QFileInfo::d_ptr': class 'QSharedDataPointer<QFileInfoPrivate>' needs to have dll-interface to be used by clients of class 'QFileInfo'
|
||||
@@ -273,7 +274,8 @@ namespace AzToolsFramework
|
||||
azrtti_typeid<Components::EditorEntitySearchComponent>(),
|
||||
azrtti_typeid<Components::EditorIntersectorComponent>(),
|
||||
azrtti_typeid<AzToolsFramework::SliceRequestComponent>(),
|
||||
azrtti_typeid<AzToolsFramework::EntityUtilityComponent>()
|
||||
azrtti_typeid<AzToolsFramework::EntityUtilityComponent>(),
|
||||
azrtti_typeid<AzToolsFramework::Script::LuaSymbolsReporterSystemComponent>(),
|
||||
});
|
||||
|
||||
return components;
|
||||
|
||||
+16
-26
@@ -24,24 +24,13 @@ namespace AzToolsFramework
|
||||
AZ_Assert(
|
||||
m_filterModel,
|
||||
"Error in AssetBrowserTableModel initialization, class expects source model to be an AssetBrowserFilterModel.");
|
||||
connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &AssetBrowserTableModel::UpdateTableModelMaps);
|
||||
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &AssetBrowserTableModel::UpdateTableModelMaps);
|
||||
connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &AssetBrowserTableModel::beginResetModel);
|
||||
connect(
|
||||
sourceModel, &QAbstractItemModel::modelReset, this,
|
||||
[this]()
|
||||
{
|
||||
{
|
||||
QSignalBlocker sb(this);
|
||||
UpdateTableModelMaps();
|
||||
}
|
||||
endResetModel();
|
||||
});
|
||||
connect(sourceModel, &QAbstractItemModel::layoutChanged, this, &AssetBrowserTableModel::UpdateTableModelMaps);
|
||||
connect(sourceModel, &QAbstractItemModel::dataChanged, this, &AssetBrowserTableModel::SourceDataChanged);
|
||||
|
||||
|
||||
QSortFilterProxyModel::setSourceModel(sourceModel);
|
||||
|
||||
connect(m_filterModel, &QAbstractItemModel::rowsInserted, this, &AssetBrowserTableModel::UpdateTableModelMaps);
|
||||
connect(m_filterModel, &QAbstractItemModel::rowsRemoved, this, &AssetBrowserTableModel::UpdateTableModelMaps);
|
||||
connect(m_filterModel, &QAbstractItemModel::layoutChanged, this, &AssetBrowserTableModel::UpdateTableModelMaps);
|
||||
connect(m_filterModel, &AssetBrowserFilterModel::filterChanged, this, &AssetBrowserTableModel::beginResetModel);
|
||||
connect(m_filterModel, &QAbstractItemModel::dataChanged, this, &AssetBrowserTableModel::SourceDataChanged);
|
||||
}
|
||||
|
||||
QModelIndex AssetBrowserTableModel::mapToSource(const QModelIndex& proxyIndex) const
|
||||
@@ -112,7 +101,7 @@ namespace AzToolsFramework
|
||||
|
||||
int AssetBrowserTableModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return !parent.isValid() ? m_indexMap.size() : sourceModel()->rowCount(parent);
|
||||
return !parent.isValid() ? m_indexMap.size() : 0;
|
||||
}
|
||||
|
||||
int AssetBrowserTableModel::BuildTableModelMap(
|
||||
@@ -162,28 +151,29 @@ namespace AzToolsFramework
|
||||
|
||||
AssetBrowserEntry* AssetBrowserTableModel::GetAssetEntry(QModelIndex index) const
|
||||
{
|
||||
if (index.isValid())
|
||||
{
|
||||
return static_cast<AssetBrowserEntry*>(index.internalPointer());
|
||||
}
|
||||
else
|
||||
if (!index.isValid())
|
||||
{
|
||||
AZ_Error("AssetBrowser", false, "Invalid Source Index provided to GetAssetEntry.");
|
||||
return nullptr;
|
||||
}
|
||||
return static_cast<AssetBrowserEntry*>(index.internalPointer());
|
||||
}
|
||||
|
||||
void AssetBrowserTableModel::UpdateTableModelMaps()
|
||||
{
|
||||
beginResetModel();
|
||||
emit layoutAboutToBeChanged();
|
||||
m_indexMap.clear();
|
||||
m_rowMap.clear();
|
||||
|
||||
if (!m_indexMap.isEmpty() || !m_rowMap.isEmpty())
|
||||
{
|
||||
m_indexMap.clear();
|
||||
m_rowMap.clear();
|
||||
}
|
||||
AzToolsFramework::EditorSettingsAPIBus::BroadcastResult(
|
||||
m_numberOfItemsDisplayed, &AzToolsFramework::EditorSettingsAPIBus::Handler::GetMaxNumberOfItemsShownInSearchView);
|
||||
|
||||
BuildTableModelMap(sourceModel());
|
||||
emit layoutChanged();
|
||||
endResetModel();
|
||||
}
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
+4
-2
@@ -21,7 +21,9 @@ namespace AzToolsFramework
|
||||
class AssetBrowserFilterModel;
|
||||
class AssetBrowserEntry;
|
||||
|
||||
class AssetBrowserTableModel : public QSortFilterProxyModel
|
||||
class AssetBrowserTableModel
|
||||
: public QSortFilterProxyModel
|
||||
, public AssetBrowserComponentNotificationBus::Handler
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -43,7 +45,7 @@ namespace AzToolsFramework
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role /* = Qt::DisplayRole */) const override;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
private:
|
||||
|
||||
AssetBrowserEntry* GetAssetEntry(QModelIndex index) const;
|
||||
int BuildTableModelMap(const QAbstractItemModel* model, const QModelIndex& parent = QModelIndex(), int row = 0);
|
||||
|
||||
|
||||
+21
-16
@@ -225,29 +225,36 @@ namespace AzToolsFramework
|
||||
const QModelIndex indexBelow = viewModel->index(index.row() + 1, index.column());
|
||||
const QModelIndex indexAbove = viewModel->index(index.row() - 1, index.column());
|
||||
|
||||
auto aboveEntry = qvariant_cast<const AssetBrowserEntry*>(indexBelow.data(AssetBrowserModel::Roles::EntryRole));
|
||||
auto belowEntry = qvariant_cast<const AssetBrowserEntry*>(indexAbove.data(AssetBrowserModel::Roles::EntryRole));
|
||||
auto belowEntry = qvariant_cast<const AssetBrowserEntry*>(indexBelow.data(AssetBrowserModel::Roles::EntryRole));
|
||||
auto aboveEntry = qvariant_cast<const AssetBrowserEntry*>(indexAbove.data(AssetBrowserModel::Roles::EntryRole));
|
||||
|
||||
auto aboveSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(aboveEntry);
|
||||
auto belowSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(belowEntry);
|
||||
auto aboveSourceEntry = azrtti_cast<const SourceAssetBrowserEntry*>(aboveEntry);
|
||||
|
||||
// if current index is the last entry in the view
|
||||
// or the index above it is a Source Entry and
|
||||
// the index below is invalid or is valid but it is also a source entry
|
||||
// then the current index is the only child.
|
||||
if (index.row() == viewModel->rowCount() - 1 ||
|
||||
(indexBelow.isValid() && aboveSourceEntry &&
|
||||
(!indexAbove.isValid() || (indexAbove.isValid() && belowSourceEntry))))
|
||||
// Last item and the above entry is a source entry
|
||||
// or indexBelow is a source entry and the index above is not
|
||||
if (viewModel->rowCount() > 0 && index.row() == viewModel->rowCount() - 1)
|
||||
{
|
||||
if (aboveSourceEntry)
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::OneChild, painter, branchIconTopLeft, iconSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::Last, painter, branchIconTopLeft, iconSize);
|
||||
}
|
||||
}
|
||||
else if (belowSourceEntry && aboveSourceEntry)
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::OneChild, painter, branchIconTopLeft, iconSize); // Draw One Child Icon
|
||||
}
|
||||
else if (indexBelow.isValid() && aboveSourceEntry) // The index above is a source entry
|
||||
else if (belowSourceEntry && !aboveSourceEntry)
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::Last, painter, branchIconTopLeft, iconSize); // Draw First child Icon
|
||||
DrawBranchPixMap(EntryBranchType::Last, painter, branchIconTopLeft, iconSize);
|
||||
}
|
||||
else if (indexAbove.isValid() && belowSourceEntry) // The index below is a source entry
|
||||
else if (aboveSourceEntry) // The index above is a source entry
|
||||
{
|
||||
DrawBranchPixMap(EntryBranchType::First, painter, branchIconTopLeft, iconSize); // Draw Last Child Icon
|
||||
DrawBranchPixMap(EntryBranchType::First, painter, branchIconTopLeft, iconSize); // Draw First Child Icon
|
||||
}
|
||||
else //the index above and below are also child entries
|
||||
{
|
||||
@@ -286,7 +293,6 @@ namespace AzToolsFramework
|
||||
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathLast;
|
||||
break;
|
||||
case AzToolsFramework::AssetBrowser::EntryBranchType::OneChild:
|
||||
default:
|
||||
absoluteIconPath = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / TreeIconPathOneChild;
|
||||
break;
|
||||
}
|
||||
@@ -311,5 +317,4 @@ namespace AzToolsFramework
|
||||
|
||||
} // namespace AssetBrowser
|
||||
} // namespace AzToolsFramework
|
||||
|
||||
#include "AssetBrowser/Views/moc_EntryDelegate.cpp"
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include <AzToolsFramework/AssetBrowser/AssetBrowserComponent.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemComponent.h>
|
||||
#include <AzToolsFramework/Entity/EntityUtilityComponent.h>
|
||||
#include <AzToolsFramework/Script/LuaSymbolsReporterSystemComponent.h>
|
||||
|
||||
AZ_DEFINE_BUDGET(AzToolsFramework);
|
||||
|
||||
@@ -106,6 +107,7 @@ namespace AzToolsFramework
|
||||
AzToolsFramework::Components::EditorIntersectorComponent::CreateDescriptor(),
|
||||
AzToolsFramework::AzToolsFrameworkConfigurationSystemComponent::CreateDescriptor(),
|
||||
AzToolsFramework::Components::EditorEntityUiSystemComponent::CreateDescriptor(),
|
||||
AzToolsFramework::Script::LuaSymbolsReporterSystemComponent::CreateDescriptor(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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 <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Script
|
||||
{
|
||||
struct LuaPropertySymbol
|
||||
{
|
||||
AZ_TYPE_INFO(LuaPropertySymbol, "{5AFB147F-50A4-4F00-9F82-D8D5BBC970D6}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_name;
|
||||
bool m_canRead;
|
||||
bool m_canWrite;
|
||||
|
||||
AZStd::string ToString() const;
|
||||
};
|
||||
|
||||
struct LuaMethodSymbol
|
||||
{
|
||||
AZ_TYPE_INFO(LuaMethodSymbol, "{7B074A36-C81D-46A0-8D2F-62E426EBE38A}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_name;
|
||||
AZStd::string m_debugArgumentInfo;
|
||||
|
||||
AZStd::string ToString() const;
|
||||
};
|
||||
|
||||
struct LuaClassSymbol
|
||||
{
|
||||
AZ_TYPE_INFO(LuaClassSymbol, "{5FBE5841-A8E1-44B6-BEDA-22302CF8DF5F}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_name;
|
||||
AZ::Uuid m_typeId;
|
||||
AZStd::vector<LuaPropertySymbol> m_properties;
|
||||
AZStd::vector<LuaMethodSymbol> m_methods;
|
||||
|
||||
AZStd::string ToString() const;
|
||||
};
|
||||
|
||||
struct LuaEBusSender
|
||||
{
|
||||
AZ_TYPE_INFO(LuaEBusSender, "{23EE4188-0924-49DB-BF3F-EB7AAB6D5E5C}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_name;
|
||||
AZStd::string m_debugArgumentInfo;
|
||||
AZStd::string m_category;
|
||||
|
||||
AZStd::string ToString() const;
|
||||
};
|
||||
|
||||
struct LuaEBusSymbol
|
||||
{
|
||||
AZ_TYPE_INFO(LuaEBusSymbol, "{381C5639-A916-4D2E-B825-50A3F2D93137}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZStd::string m_name;
|
||||
bool m_canBroadcast;
|
||||
bool m_canQueue;
|
||||
bool m_hasHandler;
|
||||
|
||||
AZStd::vector<LuaEBusSender> m_senders;
|
||||
|
||||
AZStd::string ToString() const;
|
||||
};
|
||||
|
||||
// This is an EBus useful to scrape classes, globals and EBuses exposed to game scripting
|
||||
// e.g: Lua.
|
||||
class LuaSymbolsReporterRequests
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(LuaSymbolsReporterRequests, "{3FF9A105-3159-49FF-8DC6-4948AE7B4AB8}");
|
||||
virtual ~LuaSymbolsReporterRequests() = default;
|
||||
// Put your public methods here
|
||||
|
||||
virtual const AZStd::vector<LuaClassSymbol>& GetListOfClasses() = 0;
|
||||
virtual const AZStd::vector<LuaPropertySymbol>& GetListOfGlobalProperties() = 0;
|
||||
virtual const AZStd::vector<LuaMethodSymbol>& GetListOfGlobalFunctions() = 0;
|
||||
virtual const AZStd::vector<LuaEBusSymbol>& GetListOfEBuses() = 0;
|
||||
|
||||
};
|
||||
|
||||
class LuaSymbolsReporterBusTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
|
||||
using LuaSymbolsReporterRequestBus = AZ::EBus<LuaSymbolsReporterRequests, LuaSymbolsReporterBusTraits>;
|
||||
|
||||
} // namespace Script
|
||||
} // namespace AzToolsFramework
|
||||
+475
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* 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 <AzCore/RTTI/BehaviorContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Script/ScriptSystemBus.h>
|
||||
#include <AzCore/Script/ScriptContextDebug.h>
|
||||
|
||||
#include "LuaSymbolsReporterSystemComponent.h"
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Script
|
||||
{
|
||||
AZStd::string LuaPropertySymbol::ToString() const
|
||||
{
|
||||
return AZStd::string::format("%s [%s/%s]",
|
||||
m_name.c_str(),
|
||||
m_canRead ? "R" : "_",
|
||||
m_canWrite ? "W" : "_");
|
||||
}
|
||||
|
||||
void LuaPropertySymbol::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
|
||||
if (behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<LuaPropertySymbol>()
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "script")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
|
||||
->Property("name", BehaviorValueProperty(&LuaPropertySymbol::m_name))
|
||||
->Property("canRead", BehaviorValueProperty(&LuaPropertySymbol::m_canRead))
|
||||
->Property("canWrite", BehaviorValueProperty(&LuaPropertySymbol::m_canWrite))
|
||||
->Method("ToString", &LuaPropertySymbol::ToString)
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string LuaMethodSymbol::ToString() const
|
||||
{
|
||||
return AZStd::string::format("%s(%s)", m_name.c_str(), m_debugArgumentInfo.c_str());
|
||||
}
|
||||
|
||||
void LuaMethodSymbol::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
|
||||
if (behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<LuaMethodSymbol>()
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "script")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
|
||||
->Property("name", BehaviorValueProperty(&LuaMethodSymbol::m_name))
|
||||
->Property("debugArgumentInfo", BehaviorValueProperty(&LuaMethodSymbol::m_debugArgumentInfo))
|
||||
->Method("ToString", &LuaMethodSymbol::ToString)
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string LuaClassSymbol::ToString() const
|
||||
{
|
||||
return AZStd::string::format("%s [%s]", m_name.c_str(), m_typeId.ToString<AZStd::string>().c_str());
|
||||
}
|
||||
|
||||
void LuaClassSymbol::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
|
||||
if (behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<LuaClassSymbol>()
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "script")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
|
||||
->Property("name", BehaviorValueProperty(&LuaClassSymbol::m_name))
|
||||
->Property("typeId", BehaviorValueProperty(&LuaClassSymbol::m_typeId))
|
||||
->Property("properties", BehaviorValueProperty(&LuaClassSymbol::m_properties))
|
||||
->Property("methods", BehaviorValueProperty(&LuaClassSymbol::m_methods))
|
||||
->Method("ToString", &LuaClassSymbol::ToString)
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string LuaEBusSender::ToString() const
|
||||
{
|
||||
return AZStd::string::format("%s(%s) - [%s]", m_name.c_str(), m_debugArgumentInfo.c_str(), m_category.c_str());
|
||||
}
|
||||
|
||||
void LuaEBusSender::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
|
||||
if (behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<LuaEBusSender>()
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "script")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
|
||||
->Property("name", BehaviorValueProperty(&LuaEBusSender::m_name))
|
||||
->Property("debugArgumentInfo", BehaviorValueProperty(&LuaEBusSender::m_debugArgumentInfo))
|
||||
->Property("category", BehaviorValueProperty(&LuaEBusSender::m_category))
|
||||
->Method("ToString", &LuaEBusSender::ToString)
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::string LuaEBusSymbol::ToString() const
|
||||
{
|
||||
auto boolToStr = +[](bool val) { return val ? "true" : "false"; };
|
||||
return AZStd::string::format("%s: canBroadcast(%s), canQueue(%s), hasHandler(%s)",
|
||||
m_name.c_str(),
|
||||
boolToStr(m_canBroadcast), boolToStr(m_canQueue), boolToStr(m_hasHandler));
|
||||
}
|
||||
|
||||
void LuaEBusSymbol::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
|
||||
if (behaviorContext)
|
||||
{
|
||||
behaviorContext->Class<LuaEBusSymbol>()
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "script")
|
||||
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::All)
|
||||
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
|
||||
->Property("name", BehaviorValueProperty(&LuaEBusSymbol::m_name))
|
||||
->Property("canBroadcast", BehaviorValueProperty(&LuaEBusSymbol::m_canBroadcast))
|
||||
->Property("canQueue", BehaviorValueProperty(&LuaEBusSymbol::m_canQueue))
|
||||
->Property("hasHandler", BehaviorValueProperty(&LuaEBusSymbol::m_hasHandler))
|
||||
->Property("senders", BehaviorValueProperty(&LuaEBusSymbol::m_senders))
|
||||
->Method("ToString", &LuaEBusSymbol::ToString)
|
||||
->Attribute(AZ::Script::Attributes::Operator, AZ::Script::Attributes::OperatorType::ToString)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
//! This local class helps us keeping private the sensitive data in LuaSymbolsReporterSystemComponent
|
||||
//! Used inside the function pointers for several AZ::SciptContextDebug::Enumerate* functions.
|
||||
class IntrusiveHelper
|
||||
{
|
||||
public:
|
||||
static AZStd::vector<LuaClassSymbol>& GetClassSymbols(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_cachedClassSymbols; }
|
||||
static AZStd::unordered_map<AZ::Uuid, size_t>& GetClassUuidToIndexMap(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_classUuidToIndexMap; }
|
||||
static AZStd::vector<LuaPropertySymbol>& GetGlobalPropertySymbols(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_cachedGlobalPropertySymbols; }
|
||||
static AZStd::vector<LuaMethodSymbol>& GetGlobalFunctionSymbols(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_cachedGlobalFunctionSymbols; }
|
||||
static AZStd::vector<LuaEBusSymbol>& GetEBusSymbols(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_cachedEbusSymbols; }
|
||||
static AZStd::unordered_map<AZStd::string, size_t>& GetEBusNameToIndexMap(LuaSymbolsReporterSystemComponent& symbolsReporter) { return symbolsReporter.m_ebusNameToIndexMap; }
|
||||
};
|
||||
|
||||
void LuaSymbolsReporterSystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
LuaPropertySymbol::Reflect(context);
|
||||
LuaMethodSymbol::Reflect(context);
|
||||
LuaClassSymbol::Reflect(context);
|
||||
LuaEBusSender::Reflect(context);
|
||||
LuaEBusSymbol::Reflect(context);
|
||||
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<LuaSymbolsReporterSystemComponent, AZ::Component>()
|
||||
->Version(0);
|
||||
|
||||
serializeContext->RegisterGenericType<AZStd::vector<LuaPropertySymbol>>();
|
||||
serializeContext->RegisterGenericType<AZStd::vector<LuaMethodSymbol>>();
|
||||
serializeContext->RegisterGenericType<AZStd::vector<LuaClassSymbol>>();
|
||||
serializeContext->RegisterGenericType<AZStd::vector<LuaEBusSender>>();
|
||||
serializeContext->RegisterGenericType<AZStd::vector<LuaEBusSymbol>>();
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behaviorContext->EBus<LuaSymbolsReporterRequestBus>("LuaSymbolsReporterBus")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "script")
|
||||
->Event("GetListOfClasses", &LuaSymbolsReporterRequests::GetListOfClasses)
|
||||
->Event("GetListOfGlobalProperties", &LuaSymbolsReporterRequests::GetListOfGlobalProperties)
|
||||
->Event("GetListOfGlobalFunctions", &LuaSymbolsReporterRequests::GetListOfGlobalFunctions)
|
||||
->Event("GetListOfEBuses", &LuaSymbolsReporterRequests::GetListOfEBuses)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void LuaSymbolsReporterSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
|
||||
{
|
||||
provided.push_back(AZ_CRC_CE("LuaSymbolsReporterSystemService"));
|
||||
}
|
||||
|
||||
void LuaSymbolsReporterSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
|
||||
{
|
||||
incompatible.push_back(AZ_CRC_CE("LuaSymbolsReporterSystemService"));
|
||||
}
|
||||
|
||||
void LuaSymbolsReporterSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
|
||||
{
|
||||
required.push_back(AZ_CRC_CE("ScriptService"));
|
||||
}
|
||||
|
||||
void LuaSymbolsReporterSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
|
||||
{
|
||||
// No dependent services.
|
||||
}
|
||||
|
||||
void LuaSymbolsReporterSystemComponent::Activate()
|
||||
{
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
|
||||
LuaSymbolsReporterRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void LuaSymbolsReporterSystemComponent::Deactivate()
|
||||
{
|
||||
LuaSymbolsReporterRequestBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
AZ::ScriptContext* LuaSymbolsReporterSystemComponent::InitScriptContext()
|
||||
{
|
||||
if (m_scriptContext)
|
||||
{
|
||||
return m_scriptContext;
|
||||
}
|
||||
|
||||
AZ::ScriptSystemRequestBus::BroadcastResult(m_scriptContext, &AZ::ScriptSystemRequests::GetContext, AZ::ScriptContextIds::DefaultScriptContextId);
|
||||
return m_scriptContext;
|
||||
}
|
||||
|
||||
void LuaSymbolsReporterSystemComponent::LoadGlobalSymbols()
|
||||
{
|
||||
auto scriptContext = InitScriptContext();
|
||||
if (!scriptContext)
|
||||
{
|
||||
AZ_Error(LogName, false, "Invalid scriptContext");
|
||||
return;
|
||||
}
|
||||
|
||||
scriptContext->EnableDebug();
|
||||
|
||||
auto debugContext = scriptContext->GetDebugContext();
|
||||
if (!debugContext)
|
||||
{
|
||||
AZ_Error(LogName, false, "Invalid debugContext from scriptContext");
|
||||
return;
|
||||
}
|
||||
|
||||
auto enumMethodFunc = +[]([[maybe_unused]] const AZ::Uuid* classTypeId, const char* methodName, const char* debugArgumentInfo, void* userData) -> bool
|
||||
{
|
||||
auto& mySelf = *reinterpret_cast<LuaSymbolsReporterSystemComponent*>(userData);
|
||||
auto& methodSymbols = IntrusiveHelper::GetGlobalFunctionSymbols(mySelf);
|
||||
methodSymbols.push_back({});
|
||||
auto& methodSymbol = methodSymbols.back();
|
||||
methodSymbol.m_name = methodName;
|
||||
if (debugArgumentInfo)
|
||||
{
|
||||
methodSymbol.m_debugArgumentInfo = debugArgumentInfo;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto enumPropertyFunc = +[]([[maybe_unused]] const AZ::Uuid* classTypeId, const char* propertyName, bool canRead, bool canWrite, void* userData) -> bool
|
||||
{
|
||||
auto& mySelf = *reinterpret_cast<LuaSymbolsReporterSystemComponent*>(userData);
|
||||
auto& propertySymbols = IntrusiveHelper::GetGlobalPropertySymbols(mySelf);
|
||||
propertySymbols.push_back({});
|
||||
auto& propertySymbol = propertySymbols.back();
|
||||
propertySymbol.m_name = propertyName;
|
||||
propertySymbol.m_canRead = canRead;
|
||||
propertySymbol.m_canWrite = canWrite;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
debugContext->EnumRegisteredGlobals(enumMethodFunc, enumPropertyFunc, this);
|
||||
|
||||
scriptContext->DisableDebug();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// LuaSymbolsReporterRequestBus::Handler
|
||||
const AZStd::vector<LuaClassSymbol>& LuaSymbolsReporterSystemComponent::GetListOfClasses()
|
||||
{
|
||||
if (!m_cachedClassSymbols.empty())
|
||||
{
|
||||
return m_cachedClassSymbols;
|
||||
}
|
||||
|
||||
auto scriptContext = InitScriptContext();
|
||||
if (!scriptContext)
|
||||
{
|
||||
return m_cachedClassSymbols;
|
||||
}
|
||||
|
||||
scriptContext->EnableDebug();
|
||||
|
||||
auto debugContext = scriptContext->GetDebugContext();
|
||||
if (!debugContext)
|
||||
{
|
||||
return m_cachedClassSymbols;
|
||||
}
|
||||
|
||||
auto enumClassFunc = +[](const char* className, const AZ::Uuid& classTypeId, void* userData) -> bool
|
||||
{
|
||||
auto& mySelf = *reinterpret_cast<LuaSymbolsReporterSystemComponent*>(userData);
|
||||
|
||||
auto& classSymbols = IntrusiveHelper::GetClassSymbols(mySelf);
|
||||
classSymbols.push_back({});
|
||||
auto& classSymbol = classSymbols.back();
|
||||
classSymbol.m_name = className;
|
||||
classSymbol.m_typeId = classTypeId;
|
||||
|
||||
auto& uuidToClassMap = IntrusiveHelper::GetClassUuidToIndexMap(mySelf);
|
||||
uuidToClassMap.emplace(classTypeId, classSymbols.size() - 1);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto enumMethodFunc = +[](const AZ::Uuid* classTypeId, const char* methodName, const char* debugArgumentInfo, void* userData) -> bool
|
||||
{
|
||||
auto& mySelf = *reinterpret_cast<LuaSymbolsReporterSystemComponent*>(userData);
|
||||
auto& classUuidToIndexMap = IntrusiveHelper::GetClassUuidToIndexMap(mySelf);
|
||||
auto itor = classUuidToIndexMap.find(*classTypeId);
|
||||
if (itor == classUuidToIndexMap.end())
|
||||
{
|
||||
AZ_Error(LogName, false, "Can not add method [%s] because class uuid [%s] is not registered", methodName, classTypeId->ToString<AZStd::string>().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto classIndex = itor->second;
|
||||
auto& classSymbols = IntrusiveHelper::GetClassSymbols(mySelf);
|
||||
auto& classSymbol = classSymbols[classIndex];
|
||||
classSymbol.m_methods.push_back({});
|
||||
auto& methodSymbol = classSymbol.m_methods.back();
|
||||
methodSymbol.m_name = methodName;
|
||||
if (debugArgumentInfo)
|
||||
{
|
||||
methodSymbol.m_debugArgumentInfo = debugArgumentInfo;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
auto enumPropertyFunc = +[](const AZ::Uuid* classTypeId, const char* propertyName, bool canRead, bool canWrite, void* userData) -> bool
|
||||
{
|
||||
auto& mySelf = *reinterpret_cast<LuaSymbolsReporterSystemComponent*>(userData);
|
||||
auto& classUuidToIndexMap = IntrusiveHelper::GetClassUuidToIndexMap(mySelf);
|
||||
auto itor = classUuidToIndexMap.find(*classTypeId);
|
||||
if (itor == classUuidToIndexMap.end())
|
||||
{
|
||||
AZ_Error(LogName, false, "Can not add property [%s] because class uuid [%s] is not registered", propertyName, classTypeId->ToString<AZStd::string>().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto classIndex = itor->second;
|
||||
auto& classSymbols = IntrusiveHelper::GetClassSymbols(mySelf);
|
||||
auto& classSymbol = classSymbols[classIndex];
|
||||
classSymbol.m_properties.push_back({});
|
||||
auto& propertySymbol = classSymbol.m_properties.back();
|
||||
propertySymbol.m_name = propertyName;
|
||||
propertySymbol.m_canRead = canRead;
|
||||
propertySymbol.m_canWrite = canWrite;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
debugContext->EnumRegisteredClasses(enumClassFunc, enumMethodFunc, enumPropertyFunc, this);
|
||||
|
||||
scriptContext->DisableDebug();
|
||||
|
||||
return m_cachedClassSymbols;
|
||||
}
|
||||
|
||||
const AZStd::vector<LuaPropertySymbol>& LuaSymbolsReporterSystemComponent::GetListOfGlobalProperties()
|
||||
{
|
||||
if (!m_cachedGlobalPropertySymbols.empty())
|
||||
{
|
||||
return m_cachedGlobalPropertySymbols;
|
||||
}
|
||||
|
||||
LoadGlobalSymbols();
|
||||
|
||||
return m_cachedGlobalPropertySymbols;
|
||||
}
|
||||
|
||||
const AZStd::vector<LuaMethodSymbol>& LuaSymbolsReporterSystemComponent::GetListOfGlobalFunctions()
|
||||
{
|
||||
if (!m_cachedGlobalFunctionSymbols.empty())
|
||||
{
|
||||
return m_cachedGlobalFunctionSymbols;
|
||||
}
|
||||
|
||||
LoadGlobalSymbols();
|
||||
|
||||
return m_cachedGlobalFunctionSymbols;
|
||||
}
|
||||
|
||||
const AZStd::vector<LuaEBusSymbol>& LuaSymbolsReporterSystemComponent::GetListOfEBuses()
|
||||
{
|
||||
if (!m_cachedEbusSymbols.empty())
|
||||
{
|
||||
return m_cachedEbusSymbols;
|
||||
}
|
||||
|
||||
auto scriptContext = InitScriptContext();
|
||||
if (!scriptContext)
|
||||
{
|
||||
return m_cachedEbusSymbols;
|
||||
}
|
||||
|
||||
scriptContext->EnableDebug();
|
||||
|
||||
auto debugContext = scriptContext->GetDebugContext();
|
||||
if (!debugContext)
|
||||
{
|
||||
return m_cachedEbusSymbols;
|
||||
}
|
||||
|
||||
auto enumEBusFunc = +[](const AZStd::string& ebusName, bool canBroadcast, bool canQueue, bool hasHandler, void* userData) -> bool
|
||||
{
|
||||
auto& mySelf = *reinterpret_cast<LuaSymbolsReporterSystemComponent*>(userData);
|
||||
|
||||
auto& ebusSymbols = IntrusiveHelper::GetEBusSymbols(mySelf);
|
||||
ebusSymbols.push_back({});
|
||||
auto& ebusSymbol = ebusSymbols.back();
|
||||
ebusSymbol.m_name = ebusName;
|
||||
ebusSymbol.m_canBroadcast = canBroadcast;
|
||||
ebusSymbol.m_canQueue = canQueue;
|
||||
ebusSymbol.m_hasHandler = hasHandler;
|
||||
|
||||
auto& nameToIndexMap = IntrusiveHelper::GetEBusNameToIndexMap(mySelf);
|
||||
nameToIndexMap.emplace(ebusName, ebusSymbols.size() - 1);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
auto enumEBusSenderFunc = +[](const AZStd::string& ebusName, const AZStd::string& senderName, const AZStd::string& debugArgumentInfo, const AZStd::string& category, void* userData) -> bool
|
||||
{
|
||||
auto& mySelf = *reinterpret_cast<LuaSymbolsReporterSystemComponent*>(userData);
|
||||
auto& nameToIndexMap = IntrusiveHelper::GetEBusNameToIndexMap(mySelf);
|
||||
auto itor = nameToIndexMap.find(ebusName);
|
||||
if (itor == nameToIndexMap.end())
|
||||
{
|
||||
AZ_Error(LogName, false, "Can not add ebus sender [%s] because ebus [%s] is not registered", senderName.c_str(), ebusName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ebusIndex = itor->second;
|
||||
auto& ebusSymbols = IntrusiveHelper::GetEBusSymbols(mySelf);
|
||||
auto& ebusSymbol = ebusSymbols[ebusIndex];
|
||||
|
||||
ebusSymbol.m_senders.push_back({});
|
||||
auto& ebusSender = ebusSymbol.m_senders.back();
|
||||
ebusSender.m_name = senderName;
|
||||
ebusSender.m_debugArgumentInfo = debugArgumentInfo;
|
||||
ebusSender.m_category = category;
|
||||
return true;
|
||||
};
|
||||
|
||||
debugContext->EnumRegisteredEBuses(enumEBusFunc, enumEBusSenderFunc, this);
|
||||
|
||||
scriptContext->DisableDebug();
|
||||
|
||||
return m_cachedEbusSymbols;
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} //namespace Script
|
||||
} // namespace AzToolsFramework
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 <AzCore/Script/ScriptContext.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
|
||||
#include <AzToolsFramework/Script/LuaSymbolsReporterBus.h>
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
namespace Script
|
||||
{
|
||||
/// System component for LuaSymbolsReporterRequestBus
|
||||
class LuaSymbolsReporterSystemComponent
|
||||
: public AZ::Component
|
||||
, public LuaSymbolsReporterRequestBus::Handler
|
||||
, private AzToolsFramework::EditorEvents::Bus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(LuaSymbolsReporterSystemComponent, "{DB8D95BA-FECF-4D81-A45C-8C05E706E2AC}");
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
static constexpr char LogName[] = "LuaSymbolsReporter";
|
||||
|
||||
LuaSymbolsReporterSystemComponent() = default;
|
||||
~LuaSymbolsReporterSystemComponent() = default;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// LuaSymbolsReporterRequestBus::Handler
|
||||
const AZStd::vector<LuaClassSymbol>& GetListOfClasses() override;
|
||||
const AZStd::vector<LuaPropertySymbol>& GetListOfGlobalProperties() override;
|
||||
const AZStd::vector<LuaMethodSymbol>& GetListOfGlobalFunctions() override;
|
||||
const AZStd::vector<LuaEBusSymbol>& GetListOfEBuses() override;
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
friend class IntrusiveHelper;
|
||||
|
||||
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
|
||||
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
|
||||
|
||||
// AZ::Component
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
|
||||
AZ::ScriptContext* InitScriptContext();
|
||||
void LoadGlobalSymbols();
|
||||
|
||||
AZ::ScriptContext* m_scriptContext = nullptr;
|
||||
|
||||
AZStd::vector<LuaClassSymbol> m_cachedClassSymbols;
|
||||
// The key is a class uuid, the value is the index in @m_cachedClassSymbols
|
||||
AZStd::unordered_map<AZ::Uuid, size_t> m_classUuidToIndexMap;
|
||||
|
||||
AZStd::vector<LuaPropertySymbol> m_cachedGlobalPropertySymbols;
|
||||
AZStd::vector<LuaMethodSymbol> m_cachedGlobalFunctionSymbols;
|
||||
|
||||
AZStd::vector<LuaEBusSymbol> m_cachedEbusSymbols;
|
||||
|
||||
// The key is the ebus name, the value is the index in @m_cachedEbusSymbols
|
||||
AZStd::unordered_map<AZStd::string, size_t> m_ebusNameToIndexMap;
|
||||
|
||||
};
|
||||
} // namespace Script
|
||||
} // namespace AzToolsFramework
|
||||
+33
-17
@@ -943,13 +943,15 @@ namespace AzToolsFramework
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const int count = rowCount(parent);
|
||||
AZ::EntityId newParentId = GetEntityFromIndex(parent);
|
||||
AZ::EntityId beforeEntityId = GetEntityFromIndex(index(row, 0, parent));
|
||||
AZ::EntityId beforeEntityId = (row >= 0 && row < count) ? GetEntityFromIndex(index(row, 0, parent)) : AZ::EntityId();
|
||||
EntityIdList topLevelEntityIds;
|
||||
topLevelEntityIds.reserve(entityIdListContainer.m_entityIds.size());
|
||||
ToolsApplicationRequestBus::Broadcast(&ToolsApplicationRequestBus::Events::FindTopLevelEntityIdsInactive, entityIdListContainer.m_entityIds, topLevelEntityIds);
|
||||
if (!ReparentEntities(newParentId, topLevelEntityIds, beforeEntityId))
|
||||
const auto appendActionForInvalid = newParentId.IsValid() && (row >= count) ? AppendEnd : AppendBeginning;
|
||||
if (!ReparentEntities(newParentId, topLevelEntityIds, beforeEntityId, appendActionForInvalid))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -1046,7 +1048,7 @@ namespace AzToolsFramework
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EntityOutlinerListModel::ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList &selectedEntityIds, const AZ::EntityId& beforeEntityId)
|
||||
bool EntityOutlinerListModel::ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList &selectedEntityIds, const AZ::EntityId& beforeEntityId, ReparentForInvalid forInvalid)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(AzToolsFramework);
|
||||
if (!CanReparentEntities(newParentId, selectedEntityIds))
|
||||
@@ -1056,10 +1058,18 @@ namespace AzToolsFramework
|
||||
|
||||
m_isFilterDirty = true;
|
||||
|
||||
ScopedUndoBatch undo("Reparent Entities");
|
||||
//capture child entity order before re-parent operation, which will automatically add order info if not present
|
||||
EntityOrderArray entityOrderArray = GetEntityChildOrder(newParentId);
|
||||
|
||||
//search for the insertion entity in the order array
|
||||
const auto beforeEntityItr = AZStd::find(entityOrderArray.begin(), entityOrderArray.end(), beforeEntityId);
|
||||
const bool hasInvalidIndex = beforeEntityItr == entityOrderArray.end();
|
||||
if (hasInvalidIndex && forInvalid == None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedUndoBatch undo("Reparent Entities");
|
||||
// The new parent is dirty due to sort change(s)
|
||||
undo.MarkEntityDirty(GetEntityIdForSortInfo(newParentId));
|
||||
|
||||
@@ -1088,9 +1098,7 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
//search for the insertion entity in the order array
|
||||
auto beforeEntityItr = AZStd::find(entityOrderArray.begin(), entityOrderArray.end(), beforeEntityId);
|
||||
|
||||
|
||||
//replace order info matching selection with bad values rather than remove to preserve layout
|
||||
for (auto& id : entityOrderArray)
|
||||
{
|
||||
@@ -1100,17 +1108,25 @@ namespace AzToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
if (newParentId.IsValid())
|
||||
//if adding to a valid parent entity, insert at the found entity location or at the head/tail depending on placeAtTail flag
|
||||
if (hasInvalidIndex)
|
||||
{
|
||||
//if adding to a valid parent entity, insert at the found entity location or at the head of the container
|
||||
auto insertItr = beforeEntityItr != entityOrderArray.end() ? beforeEntityItr : entityOrderArray.begin();
|
||||
entityOrderArray.insert(insertItr, processedEntityIds.begin(), processedEntityIds.end());
|
||||
}
|
||||
else
|
||||
switch(forInvalid)
|
||||
{
|
||||
case AppendEnd:
|
||||
entityOrderArray.insert(entityOrderArray.end(), processedEntityIds.begin(), processedEntityIds.end());
|
||||
break;
|
||||
case AppendBeginning:
|
||||
entityOrderArray.insert(entityOrderArray.begin(), processedEntityIds.begin(), processedEntityIds.end());
|
||||
break;
|
||||
default:
|
||||
AZ_Assert(false, "Unexpected type for ReparentForInvalid");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//if adding to an invalid parent entity (the root), insert at the found entity location or at the tail of the container
|
||||
auto insertItr = beforeEntityItr != entityOrderArray.end() ? beforeEntityItr : entityOrderArray.end();
|
||||
entityOrderArray.insert(insertItr, processedEntityIds.begin(), processedEntityIds.end());
|
||||
entityOrderArray.insert(beforeEntityItr, processedEntityIds.begin(), processedEntityIds.end());
|
||||
}
|
||||
|
||||
//remove placeholder entity ids
|
||||
|
||||
+8
-1
@@ -72,6 +72,13 @@ namespace AzToolsFramework
|
||||
ColumnCount //!< Total number of columns
|
||||
};
|
||||
|
||||
enum ReparentForInvalid
|
||||
{
|
||||
None, //!< For an invalid location the entity does not change location
|
||||
AppendEnd, //!< Append Item to end of target parent list
|
||||
AppendBeginning, //!< Append Item to the beginning of target parent list
|
||||
};
|
||||
|
||||
// Note: the ColumnSortIndex column isn't shown, hence the -1 and the need for a separate counter.
|
||||
// A wrong column count number causes refresh issues and hover mismatch on model update.
|
||||
static const int VisibleColumnCount = ColumnCount - 1;
|
||||
@@ -162,7 +169,7 @@ namespace AzToolsFramework
|
||||
|
||||
// Buffer Processing Slots - These are called using single-shot events when the buffers begin to fill.
|
||||
bool CanReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds) const;
|
||||
bool ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds, const AZ::EntityId& beforeEntityId = AZ::EntityId());
|
||||
bool ReparentEntities(const AZ::EntityId& newParentId, const EntityIdList& selectedEntityIds, const AZ::EntityId& beforeEntityId = AZ::EntityId(), ReparentForInvalid forInvalid = None);
|
||||
|
||||
//! Use the current filter setting and re-evaluate the filter.
|
||||
void InvalidateFilter();
|
||||
|
||||
@@ -770,6 +770,9 @@ set(FILES
|
||||
PythonTerminal/ScriptTermDialog.ui
|
||||
Input/QtEventToAzInputManager.h
|
||||
Input/QtEventToAzInputManager.cpp
|
||||
Script/LuaSymbolsReporterBus.h
|
||||
Script/LuaSymbolsReporterSystemComponent.h
|
||||
Script/LuaSymbolsReporterSystemComponent.cpp
|
||||
)
|
||||
|
||||
# Prevent the following files from being grouped in UNITY builds
|
||||
|
||||
@@ -34,6 +34,7 @@ ly_add_target(
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Source
|
||||
Platform/${PAL_PLATFORM_NAME}
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
3rdParty::Qt::Core
|
||||
|
||||
@@ -11,4 +11,6 @@ set(FILES
|
||||
ProjectBuilderWorker_linux.cpp
|
||||
ProjectUtils_linux.cpp
|
||||
ProjectManagerDefs_linux.cpp
|
||||
ProjectManager_Traits_Platform.h
|
||||
ProjectManager_Traits_Linux.h
|
||||
)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ProjectManager_Traits_Linux.h>
|
||||
@@ -11,4 +11,6 @@ set(FILES
|
||||
ProjectBuilderWorker_mac.cpp
|
||||
ProjectUtils_mac.cpp
|
||||
ProjectManagerDefs_mac.cpp
|
||||
ProjectManager_Traits_Platform.h
|
||||
ProjectManager_Traits_Mac.h
|
||||
)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR false
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ProjectManager_Traits_Mac.h>
|
||||
@@ -11,4 +11,6 @@ set(FILES
|
||||
ProjectBuilderWorker_windows.cpp
|
||||
ProjectUtils_windows.cpp
|
||||
ProjectManagerDefs_windows.cpp
|
||||
ProjectManager_Traits_Platform.h
|
||||
ProjectManager_Traits_Windows.h
|
||||
)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ProjectManager_Traits_Windows.h>
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR true
|
||||
@@ -9,7 +9,7 @@ QMainWindow {
|
||||
|
||||
#ScreensCtrl {
|
||||
min-width:1200px;
|
||||
min-height:800px;
|
||||
min-height:700px;
|
||||
}
|
||||
|
||||
QPushButton:focus {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <AzQtComponents/Utilities/HandleDpiAwareness.h>
|
||||
#include <AzQtComponents/Components/StyleManager.h>
|
||||
#include <AzQtComponents/Components/WindowDecorationWrapper.h>
|
||||
#include <ProjectManager_Traits_Platform.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
@@ -194,8 +195,12 @@ namespace O3DE::ProjectManager
|
||||
// set stylesheet after creating the main window or their styles won't get updated
|
||||
AzQtComponents::StyleManager::setStyleSheet(m_mainWindow.data(), QStringLiteral("style:ProjectManager.qss"));
|
||||
|
||||
// the decoration wrapper is intended to remember window positioning and sizing
|
||||
// the decoration wrapper is intended to remember window positioning and sizing
|
||||
#if AZ_TRAIT_PROJECT_MANAGER_CUSTOM_TITLEBAR
|
||||
auto wrapper = new AzQtComponents::WindowDecorationWrapper();
|
||||
#else
|
||||
auto wrapper = new AzQtComponents::WindowDecorationWrapper(AzQtComponents::WindowDecorationWrapper::OptionDisabled);
|
||||
#endif
|
||||
wrapper->setGuest(m_mainWindow.data());
|
||||
|
||||
// show the main window here to apply the stylesheet before restoring geometry or we
|
||||
|
||||
@@ -50,12 +50,12 @@ namespace AZ
|
||||
return scope;
|
||||
}
|
||||
|
||||
//! Sets the active context based on the provided PassHierarchyFilter. If the filter doesn't match exactly one pass, then do nothing.
|
||||
static ImGuiActiveContextScope FromPass(const RPI::PassHierarchyFilter& passHierarchyFilter)
|
||||
//! Sets the active context based on the provided pass hierarchy filter. If the filter doesn't match exactly one pass, then do nothing.
|
||||
static ImGuiActiveContextScope FromPass(const AZStd::vector<AZStd::string>& passHierarchy)
|
||||
{
|
||||
ImGuiActiveContextScope scope;
|
||||
scope.ConnectToImguiNotificationBus();
|
||||
ImGuiSystemRequestBus::BroadcastResult(scope.m_isEnabled, &ImGuiSystemRequests::PushActiveContextFromPass, passHierarchyFilter);
|
||||
ImGuiSystemRequestBus::BroadcastResult(scope.m_isEnabled, &ImGuiSystemRequests::PushActiveContextFromPass, passHierarchy);
|
||||
return scope;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,6 @@
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
class PassHierarchyFilter;
|
||||
}
|
||||
|
||||
namespace Render
|
||||
{
|
||||
class ImGuiPass;
|
||||
@@ -51,7 +46,7 @@ namespace AZ
|
||||
//! Pushes whichever ImGui pass is default on the top of the active context stack. Returns true/false for success/fail.
|
||||
virtual bool PushActiveContextFromDefaultPass() = 0;
|
||||
//! Pushes whichever ImGui pass is provided in passHierarchy on the top of the active context stack. Returns true/false for success/fail.
|
||||
virtual bool PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchy) = 0;
|
||||
virtual bool PushActiveContextFromPass(const AZStd::vector<AZStd::string>& passHierarchy) = 0;
|
||||
//! Pops the active context off the top of the active context stack. Returns true if there's a context to pop.
|
||||
virtual bool PopActiveContext() = 0;
|
||||
//! Gets the context at the top of the active context stack. Returns nullptr if the stack is emtpy.
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace AZ
|
||||
virtual bool CaptureScreenshotWithPreview(const AZStd::string& outputFilePath) = 0;
|
||||
|
||||
//! Save a buffer attachment or a image attachment binded to a pass's slot to a data file.
|
||||
//! @param passHierarchy For finding the pass by using PassHierarchyFilter
|
||||
//! @param passHierarchy For finding the pass by using a pass hierarchy filter. Check PassFilter::CreateWithPassHierarchy() function for detail
|
||||
//! @param slotName Name of the pass's slot. The attachment bound to this slot will be captured.
|
||||
//! @param option Only valid for an InputOutput attachment. Use PassAttachmentReadbackOption::Input to capture the input state
|
||||
//! and use PassAttachmentReadbackOption::Output to capture the output state
|
||||
|
||||
+32
-39
@@ -647,54 +647,46 @@ namespace AZ
|
||||
UpdateViewsOfCascadeSegments();
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass() {
|
||||
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("CascadedShadowmapsTemplate"));
|
||||
void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass()
|
||||
{
|
||||
m_cascadedShadowmapsPasses.clear();
|
||||
for (RPI::Pass* pass : passes)
|
||||
{
|
||||
if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline())
|
||||
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("CascadedShadowmapsTemplate"), GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
RPI::RenderPipeline* pipeline = pass->GetRenderPipeline();
|
||||
const RPI::RenderPipelineId pipelineId = pipeline->GetId();
|
||||
// This function can be called when the pipeline is not attached to the scene.
|
||||
// So we check it is attached to the scene.
|
||||
if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline)
|
||||
|
||||
CascadedShadowmapsPass* shadowPass = azrtti_cast<CascadedShadowmapsPass*>(pass);
|
||||
AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass.");
|
||||
if (pipeline->GetDefaultView())
|
||||
{
|
||||
CascadedShadowmapsPass* shadowPass = azrtti_cast<CascadedShadowmapsPass*>(pass);
|
||||
AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass.");
|
||||
if (pipeline->GetDefaultView())
|
||||
{
|
||||
m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass);
|
||||
}
|
||||
m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::CacheEsmShadowmapsPass()
|
||||
{
|
||||
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("EsmShadowmapsTemplate"));
|
||||
m_esmShadowmapsPasses.clear();
|
||||
for (RPI::Pass* pass : passes)
|
||||
{
|
||||
if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline())
|
||||
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
const RPI::RenderPipelineId pipelineId = pipeline->GetId();
|
||||
// checking the render pipeline is just removed from the scene.
|
||||
if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline)
|
||||
const RPI::RenderPipelineId pipelineId = pass->GetRenderPipeline()->GetId();
|
||||
|
||||
if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end())
|
||||
{
|
||||
if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end())
|
||||
EsmShadowmapsPass* esmPass = azrtti_cast<EsmShadowmapsPass*>(pass);
|
||||
AZ_Assert(esmPass, "It is not an EsmShadowmapPass.");
|
||||
if (esmPass->GetLightTypeName() == m_lightTypeName)
|
||||
{
|
||||
EsmShadowmapsPass* esmPass = azrtti_cast<EsmShadowmapsPass*>(pass);
|
||||
AZ_Assert(esmPass, "It is not an EsmShadowmapPass.");
|
||||
if (m_cascadedShadowmapsPasses.find(esmPass->GetRenderPipeline()->GetId()) != m_cascadedShadowmapsPasses.end() &&
|
||||
esmPass->GetLightTypeName() == m_lightTypeName)
|
||||
{
|
||||
m_esmShadowmapsPasses[pipelineId].push_back(esmPass);
|
||||
}
|
||||
m_esmShadowmapsPasses[pipelineId].push_back(esmPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
void DirectionalLightFeatureProcessor::PrepareCameraViews()
|
||||
@@ -1063,12 +1055,13 @@ namespace AZ
|
||||
|
||||
// if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view,
|
||||
// to filter out shadows from objects that are excluded from the cubemap
|
||||
RPI::PassClassFilter<RPI::EnvironmentCubeMapPass> passFilter;
|
||||
AZStd::vector<AZ::RPI::Pass*> cubeMapPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter);
|
||||
if (!cubeMapPasses.empty())
|
||||
{
|
||||
usageFlags |= RPI::View::UsageReflectiveCubeMap;
|
||||
}
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<RPI::EnvironmentCubeMapPass>();
|
||||
passFilter.SetOwenrScene(GetParentScene()); // only handles passes for this scene
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&usageFlags]([[maybe_unused]] RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
usageFlags |= RPI::View::UsageReflectiveCubeMap;
|
||||
return RPI::PassFilterExecutionFlow::StopVisitingPasses;
|
||||
});
|
||||
|
||||
segment.m_view = RPI::View::CreateView(viewName, usageFlags);
|
||||
}
|
||||
|
||||
+35
-22
@@ -80,35 +80,48 @@ namespace AZ
|
||||
}
|
||||
|
||||
// update the size multiplier on the DiffuseProbeGridDownsamplePass output
|
||||
AZStd::vector<Name> downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") };
|
||||
RPI::PassHierarchyFilter downsamplePassFilter(downsamplePassHierarchy);
|
||||
const AZStd::vector<RPI::Pass*>& downsamplePasses = RPI::PassSystemInterface::Get()->FindPasses(downsamplePassFilter);
|
||||
for (RPI::Pass* pass : downsamplePasses)
|
||||
// NOTE: The ownerScene wasn't added to both filters. This is because the passes from the non-owner scene may have invalid SRG values which could lead to
|
||||
// GPU error if the scene doesn't have this feature processor enabled.
|
||||
// For example, the ASV MultiScene sample may have TDR.
|
||||
{
|
||||
for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex)
|
||||
{
|
||||
RPI::Ptr<RPI::PassAttachment> outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment;
|
||||
RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers;
|
||||
AZStd::vector<Name> downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") };
|
||||
RPI::PassFilter downsamplePassFilter = RPI::PassFilter::CreateWithPassHierarchy(downsamplePassHierarchy);
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(
|
||||
downsamplePassFilter,
|
||||
[sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex)
|
||||
{
|
||||
RPI::Ptr<RPI::PassAttachment> outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment;
|
||||
RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers;
|
||||
|
||||
sizeMultipliers.m_widthMultiplier = sizeMultiplier;
|
||||
sizeMultipliers.m_heightMultiplier = sizeMultiplier;
|
||||
}
|
||||
sizeMultipliers.m_widthMultiplier = sizeMultiplier;
|
||||
sizeMultipliers.m_heightMultiplier = sizeMultiplier;
|
||||
}
|
||||
|
||||
// set the output scale on the PassSrg
|
||||
RPI::FullscreenTrianglePass* downsamplePass = static_cast<RPI::FullscreenTrianglePass*>(pass);
|
||||
auto constantIndex = downsamplePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_outputImageScale"));
|
||||
downsamplePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier));
|
||||
// set the output scale on the PassSrg
|
||||
RPI::FullscreenTrianglePass* downsamplePass = static_cast<RPI::FullscreenTrianglePass*>(pass);
|
||||
RHI::ShaderInputNameIndex outputImageScaleShaderInput = "m_outputImageScale";
|
||||
downsamplePass->GetShaderResourceGroup()->SetConstant(
|
||||
outputImageScaleShaderInput, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier));
|
||||
|
||||
// handle all downsample passes
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
// update the image scale on the DiffuseComposite pass
|
||||
AZStd::vector<Name> compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") };
|
||||
RPI::PassHierarchyFilter compositePassFilter(compositePassHierarchy);
|
||||
const AZStd::vector<RPI::Pass*>& compositePasses = RPI::PassSystemInterface::Get()->FindPasses(compositePassFilter);
|
||||
for (RPI::Pass* pass : compositePasses)
|
||||
{
|
||||
RPI::FullscreenTrianglePass* compositePass = static_cast<RPI::FullscreenTrianglePass*>(pass);
|
||||
auto constantIndex = compositePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_imageScale"));
|
||||
compositePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier));
|
||||
AZStd::vector<Name> compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") };
|
||||
RPI::PassFilter compositePassFilter = RPI::PassFilter::CreateWithPassHierarchy(compositePassHierarchy);
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(compositePassFilter, [sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
RPI::FullscreenTrianglePass* compositePass = static_cast<RPI::FullscreenTrianglePass*>(pass);
|
||||
RHI::ShaderInputNameIndex imageScaleShaderInput = "m_imageScale";
|
||||
compositePass->GetShaderResourceGroup()->SetConstant(imageScaleShaderInput, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier));
|
||||
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
}
|
||||
} // namespace Render
|
||||
|
||||
+6
-6
@@ -603,12 +603,12 @@ namespace AZ
|
||||
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
|
||||
if (device->GetFeatures().m_rayTracing == false)
|
||||
{
|
||||
RPI::PassHierarchyFilter updatePassFilter(AZ::Name("DiffuseProbeGridUpdatePass"));
|
||||
const AZStd::vector<RPI::Pass*>& updatePasses = RPI::PassSystemInterface::Get()->FindPasses(updatePassFilter);
|
||||
for (RPI::Pass* pass : updatePasses)
|
||||
{
|
||||
pass->SetEnabled(false);
|
||||
}
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("DiffuseProbeGridUpdatePass"), GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
pass->SetEnabled(false);
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
#include <ACES/Aces.h>
|
||||
#include <Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h>
|
||||
#include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
|
||||
#include <Atom/RPI.Public/Pass/PassUtils.h>
|
||||
#include <Atom/RPI.Public/Pass/PassFilter.h>
|
||||
#include <Atom/RPI.Public/Pass/PassFactory.h>
|
||||
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
|
||||
#include <Atom/RPI.Public/Pass/PassUtils.h>
|
||||
#include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/RPIUtils.h>
|
||||
@@ -66,22 +67,14 @@ namespace AZ
|
||||
{
|
||||
// Need to invalidate the CopyToSwapChain pass so that it updates the pipeline state in the event that
|
||||
// the swapchain format changed (for example, moving from LDR to HDR display)
|
||||
auto* passSystem = RPI::PassSystemInterface::Get();
|
||||
const Name fullscreenCopyTemplateName("FullscreenCopyTemplate");
|
||||
|
||||
if (passSystem->HasPassesForTemplateName(fullscreenCopyTemplateName))
|
||||
{
|
||||
const AZStd::vector<RPI::Pass*>& passes = passSystem->GetPassesForTemplateName(fullscreenCopyTemplateName);
|
||||
for (RPI::Pass* pass : passes)
|
||||
const Name copyToSwapChainPassName("CopyToSwapChain");
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(copyToSwapChainPassName, GetRenderPipeline());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
RPI::FullscreenTrianglePass* fullscreenTrianglePass = azrtti_cast<RPI::FullscreenTrianglePass*>(pass);
|
||||
const Name& passName = fullscreenTrianglePass->GetName();
|
||||
if (passName.GetStringView() == "CopyToSwapChain")
|
||||
{
|
||||
fullscreenTrianglePass->QueueForInitialization();
|
||||
}
|
||||
}
|
||||
}
|
||||
pass->QueueForInitialization();
|
||||
return RPI::PassFilterExecutionFlow::StopVisitingPasses;
|
||||
});
|
||||
|
||||
ConfigureDisplayParameters();
|
||||
}
|
||||
|
||||
|
||||
@@ -372,29 +372,25 @@ namespace AZ
|
||||
}
|
||||
m_latestCaptureInfo.clear();
|
||||
|
||||
// Find the pass first
|
||||
RPI::PassClassFilter<RPI::ImageAttachmentPreviewPass> passFilter;
|
||||
AZStd::vector<AZ::RPI::Pass*> foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter);
|
||||
|
||||
if (foundPasses.size() == 0)
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<RPI::ImageAttachmentPreviewPass>();
|
||||
AZ::RPI::ImageAttachmentPreviewPass* previewPass = azrtti_cast<AZ::RPI::ImageAttachmentPreviewPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(passFilter));
|
||||
if (!previewPass)
|
||||
{
|
||||
AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find an ImageAttachmentPreviewPass pass ");
|
||||
AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find an ImageAttachmentPreviewPass");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::RPI::ImageAttachmentPreviewPass* previewPass = azrtti_cast<AZ::RPI::ImageAttachmentPreviewPass*>(foundPasses[0]);
|
||||
bool result = previewPass->ReadbackOutput(m_readback);
|
||||
if (result)
|
||||
{
|
||||
m_state = State::Pending;
|
||||
m_result = FrameCaptureResult::None;
|
||||
SystemTickBus::Handler::BusConnect();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Warning("FrameCaptureSystemComponent", false, "CaptureScreenshotWithPreview. Failed to readback output from the ImageAttachmentPreviewPass");;
|
||||
}
|
||||
return result;
|
||||
|
||||
AZ_Warning("FrameCaptureSystemComponent", false, "CaptureScreenshotWithPreview. Failed to readback output from the ImageAttachmentPreviewPass");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FrameCaptureSystemComponent::CapturePassAttachment(const AZStd::vector<AZStd::string>& passHierarchy, const AZStd::string& slot,
|
||||
@@ -405,6 +401,12 @@ namespace AZ
|
||||
return false;
|
||||
}
|
||||
|
||||
if (passHierarchy.size() == 0)
|
||||
{
|
||||
AZ_Warning("FrameCaptureSystemComponent", false, "Empty data in passHierarchy");
|
||||
return false;
|
||||
}
|
||||
|
||||
InitReadback();
|
||||
|
||||
if (m_state != State::Idle)
|
||||
@@ -426,17 +428,15 @@ namespace AZ
|
||||
}
|
||||
m_latestCaptureInfo.clear();
|
||||
|
||||
// Find the pass first
|
||||
AZ::RPI::PassHierarchyFilter passFilter(passHierarchy);
|
||||
AZStd::vector<AZ::RPI::Pass*> foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter);
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchy);
|
||||
RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
|
||||
|
||||
if (foundPasses.size() == 0)
|
||||
if (!pass)
|
||||
{
|
||||
AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find pass from %s", passFilter.ToString().c_str());
|
||||
AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find pass from %s", passHierarchy[0].c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::RPI::Pass* pass = foundPasses[0];
|
||||
if (pass->ReadbackAttachment(m_readback, Name(slot), option))
|
||||
{
|
||||
m_state = State::Pending;
|
||||
@@ -444,6 +444,7 @@ namespace AZ
|
||||
SystemTickBus::Handler::BusConnect();
|
||||
return true;
|
||||
}
|
||||
|
||||
AZ_Warning("FrameCaptureSystemComponent", false, "Failed to readback the attachment bound to pass [%s] slot [%s]", pass->GetName().GetCStr(), slot.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -109,15 +109,15 @@ namespace AZ
|
||||
void ImGuiSystemComponent::ForAllImGuiPasses(PassFunction func)
|
||||
{
|
||||
ImGuiContext* contextToRestore = ImGui::GetCurrentContext();
|
||||
RPI::PassClassFilter<ImGuiPass> filter;
|
||||
auto imguiPasses = RPI::PassSystemInterface::Get()->FindPasses(filter);
|
||||
|
||||
for (RPI::Pass* pass : imguiPasses)
|
||||
{
|
||||
ImGuiPass* imguiPass = azrtti_cast<ImGuiPass*>(pass);
|
||||
ImGui::SetCurrentContext(imguiPass->GetContext());
|
||||
func(imguiPass);
|
||||
}
|
||||
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<ImGuiPass>();
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [func](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
ImGuiPass* imguiPass = azrtti_cast<ImGuiPass*>(pass);
|
||||
ImGui::SetCurrentContext(imguiPass->GetContext());
|
||||
func(imguiPass);
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
|
||||
ImGui::SetCurrentContext(contextToRestore);
|
||||
}
|
||||
@@ -169,29 +169,37 @@ namespace AZ
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ImGuiSystemComponent::PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchyFilter)
|
||||
bool ImGuiSystemComponent::PushActiveContextFromPass(const AZStd::vector<AZStd::string>& passHierarchyFilter)
|
||||
{
|
||||
AZStd::vector<AZ::RPI::Pass*> foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passHierarchyFilter);
|
||||
if (passHierarchyFilter.size() == 0)
|
||||
{
|
||||
AZ_Warning("ImGuiSystemComponent", false, "passHierarchyFilter is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::vector<ImGuiPass*> foundImGuiPasses;
|
||||
|
||||
for (RPI::Pass* pass : foundPasses)
|
||||
{
|
||||
ImGuiPass* imGuiPass = azrtti_cast<ImGuiPass*>(pass);
|
||||
if (imGuiPass)
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchyFilter);
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundImGuiPasses](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
foundImGuiPasses.push_back(imGuiPass);
|
||||
}
|
||||
}
|
||||
ImGuiPass* imGuiPass = azrtti_cast<ImGuiPass*>(pass);
|
||||
if (imGuiPass)
|
||||
{
|
||||
foundImGuiPasses.push_back(imGuiPass);
|
||||
}
|
||||
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
|
||||
if (foundImGuiPasses.size() == 0)
|
||||
{
|
||||
AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter.ToString().c_str());
|
||||
AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter[0].c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (foundImGuiPasses.size() > 1)
|
||||
{
|
||||
AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter.ToString().c_str());
|
||||
AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter[0].c_str());
|
||||
}
|
||||
|
||||
ImGuiContext* context = foundImGuiPasses.at(0)->GetContext();
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace AZ
|
||||
ImGuiPass* GetDefaultImGuiPass() override;
|
||||
|
||||
bool PushActiveContextFromDefaultPass() override;
|
||||
bool PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchy) override;
|
||||
bool PushActiveContextFromPass(const AZStd::vector<AZStd::string>& passHierarchy) override;
|
||||
bool PopActiveContext() override;
|
||||
ImGuiContext* GetActiveContext() override;
|
||||
|
||||
|
||||
+8
-12
@@ -15,6 +15,7 @@
|
||||
#include <AzFramework/Asset/AssetSystemBus.h>
|
||||
|
||||
#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
|
||||
#include <Atom/RPI.Public/Pass/PassFilter.h>
|
||||
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/RPIUtils.h>
|
||||
@@ -259,24 +260,19 @@ namespace AZ
|
||||
|
||||
// [GFX TODO][ATOM-3035]This function is temporary and will change with improvement to the draw list tag system
|
||||
void DepthOfFieldSettings::UpdateAutoFocusDepth(bool enabled)
|
||||
{
|
||||
auto* passSystem = AZ::RPI::PassSystemInterface::Get();
|
||||
{
|
||||
const Name TemplateNameReadBackFocusDepth = Name("DepthOfFieldReadBackFocusDepthTemplate");
|
||||
if (passSystem->HasPassesForTemplateName(TemplateNameReadBackFocusDepth))
|
||||
{
|
||||
const AZStd::vector<RPI::Pass*>& dofPasses = passSystem->GetPassesForTemplateName(TemplateNameReadBackFocusDepth);
|
||||
for (RPI::Pass* pass : dofPasses)
|
||||
// [GFX TODO][ATOM-4908] multiple camera should be distingushed.
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(TemplateNameReadBackFocusDepth, GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, enabled](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
auto* dofPass = azrtti_cast<AZ::Render::DepthOfFieldReadBackFocusDepthPass*>(pass);
|
||||
// Check this pass belongs to a render pipeline of the scene.
|
||||
// [GFX TODO][ATOM-4908] multiple camera should be distingushed.
|
||||
const RPI::RenderPipelineId pipelineId = dofPass->GetRenderPipeline()->GetId();
|
||||
if (enabled && GetParentScene()->GetRenderPipeline(pipelineId))
|
||||
if (enabled)
|
||||
{
|
||||
m_normalizedFocusDistanceForAutoFocus = dofPass->GetNormalizedFocusDistanceForAutoFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
void DepthOfFieldSettings::SetCameraEntityId(EntityId cameraEntityId)
|
||||
|
||||
+14
-13
@@ -10,6 +10,7 @@
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
#include <Atom/RPI.Public/Pass/PassFilter.h>
|
||||
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
|
||||
@@ -188,21 +189,21 @@ namespace AZ
|
||||
|
||||
void ExposureControlSettings::UpdateLuminanceHeatmap()
|
||||
{
|
||||
auto* passSystem = AZ::RPI::PassSystemInterface::Get();
|
||||
|
||||
// [GFX-TODO][ATOM-13194] Support multiple views for the luminance heatmap
|
||||
// [GFX-TODO][ATOM-13224] Remove UpdateLuminanceHeatmap and UpdateEyeAdaptationPass
|
||||
const RPI::Ptr<RPI::Pass> luminanceHeatmap = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHeatmapNameId);
|
||||
if (luminanceHeatmap)
|
||||
{
|
||||
luminanceHeatmap->SetEnabled(m_heatmapEnabled);
|
||||
}
|
||||
// [GFX-TODO][ATOM-13224] Remove UpdateLuminanceHeatmap and UpdateEyeAdaptationPass
|
||||
RPI::PassFilter heatmapPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHeatmapNameId, GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(heatmapPassFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
pass->SetEnabled(m_heatmapEnabled);
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
|
||||
const RPI::Ptr<RPI::Pass> histogramGenerator = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHistogramGeneratorNameId);
|
||||
if (histogramGenerator)
|
||||
{
|
||||
histogramGenerator->SetEnabled(m_heatmapEnabled);
|
||||
}
|
||||
RPI::PassFilter histogramPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHistogramGeneratorNameId, GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(histogramPassFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
pass->SetEnabled(m_heatmapEnabled);
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
void ExposureControlSettings::UpdateBuffer()
|
||||
|
||||
+8
-6
@@ -31,12 +31,14 @@ namespace AZ
|
||||
0,
|
||||
[](const uint8_t& value)
|
||||
{
|
||||
auto passes = RPI::PassSystem::Get()->FindPasses(RPI::PassClassFilter<LookModificationCompositePass>());
|
||||
for (auto* pass : passes)
|
||||
{
|
||||
LookModificationCompositePass* lookModPass = azrtti_cast<LookModificationCompositePass*>(pass);
|
||||
lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value));
|
||||
}
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<LookModificationCompositePass>();
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [value](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
LookModificationCompositePass* lookModPass = azrtti_cast<LookModificationCompositePass*>(pass);
|
||||
lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value));
|
||||
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
},
|
||||
ConsoleFunctorFlags::Null,
|
||||
"This can be increased to deal with particularly tricky luts. Range (0-2). 0 (default) - Standard linear sampling. 1 - 7 tap b-spline sampling. 2 - 19 tap b-spline sampling."
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <Atom/RHI/Factory.h>
|
||||
|
||||
#include <Atom/RPI.Public/Pass/PassFilter.h>
|
||||
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
@@ -71,26 +72,18 @@ namespace AZ
|
||||
|
||||
void SMAAFeatureProcessor::UpdateConvertToPerceptualPass()
|
||||
{
|
||||
auto* passSystem = AZ::RPI::PassSystemInterface::Get();
|
||||
|
||||
if (passSystem->HasPassesForTemplateName(m_convertToPerceptualColorPassTemplateNameId))
|
||||
{
|
||||
const AZStd::vector<RPI::Pass*>& convertToPerceptualColorPasses = passSystem->GetPassesForTemplateName(m_convertToPerceptualColorPassTemplateNameId);
|
||||
for (RPI::Pass* pass : convertToPerceptualColorPasses)
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_convertToPerceptualColorPassTemplateNameId, GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
pass->SetEnabled(m_data.m_enable);
|
||||
}
|
||||
}
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
void SMAAFeatureProcessor::UpdateEdgeDetectionPass()
|
||||
{
|
||||
auto* passSystem = AZ::RPI::PassSystemInterface::Get();
|
||||
|
||||
if (passSystem->HasPassesForTemplateName(m_edgeDetectioPassTemplateNameId))
|
||||
{
|
||||
const AZStd::vector<RPI::Pass*>& edgeDetectionPasses = passSystem->GetPassesForTemplateName(m_edgeDetectioPassTemplateNameId);
|
||||
for (RPI::Pass* pass : edgeDetectionPasses)
|
||||
{
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_edgeDetectioPassTemplateNameId, GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
auto* edgeDetectionPass = azrtti_cast<AZ::Render::SMAAEdgeDetectionPass*>(pass);
|
||||
|
||||
@@ -106,18 +99,14 @@ namespace AZ
|
||||
edgeDetectionPass->SetPredicationScale(m_data.m_predicationScale);
|
||||
edgeDetectionPass->SetPredicationStrength(m_data.m_predicationStrength);
|
||||
}
|
||||
}
|
||||
}
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
void SMAAFeatureProcessor::UpdateBlendingWeightCalculationPass()
|
||||
{
|
||||
auto* passSystem = AZ::RPI::PassSystemInterface::Get();
|
||||
|
||||
if (passSystem->HasPassesForTemplateName(m_blendingWeightCalculationPassTemplateNameId))
|
||||
{
|
||||
const AZStd::vector<RPI::Pass*>& blendingWeightCalculationPasses = passSystem->GetPassesForTemplateName(m_blendingWeightCalculationPassTemplateNameId);
|
||||
for (RPI::Pass* pass : blendingWeightCalculationPasses)
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_blendingWeightCalculationPassTemplateNameId, GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
auto* blendingWeightCalculationPass = azrtti_cast<AZ::Render::SMAABlendingWeightCalculationPass*>(pass);
|
||||
|
||||
@@ -130,18 +119,14 @@ namespace AZ
|
||||
blendingWeightCalculationPass->SetDiagonalDetectionEnable(m_data.m_enableDiagonalDetection);
|
||||
blendingWeightCalculationPass->SetCornerDetectionEnable(m_data.m_enableCornerDetection);
|
||||
}
|
||||
}
|
||||
}
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
void SMAAFeatureProcessor::UpdateNeighborhoodBlendingPass()
|
||||
{
|
||||
auto* passSystem = AZ::RPI::PassSystemInterface::Get();
|
||||
|
||||
if (passSystem->HasPassesForTemplateName(m_neighborhoodBlendingPassTemplateNameId))
|
||||
{
|
||||
const AZStd::vector<RPI::Pass*>& neighborhoodBlendingPasses = passSystem->GetPassesForTemplateName(m_neighborhoodBlendingPassTemplateNameId);
|
||||
for (RPI::Pass* pass : neighborhoodBlendingPasses)
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_neighborhoodBlendingPassTemplateNameId, GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
auto* neighborhoodBlendingPass = azrtti_cast<AZ::Render::SMAANeighborhoodBlendingPass*>(pass);
|
||||
|
||||
@@ -153,8 +138,8 @@ namespace AZ
|
||||
{
|
||||
neighborhoodBlendingPass->SetOutputMode(SMAAOutputMode::PassThrough);
|
||||
}
|
||||
}
|
||||
}
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
void SMAAFeatureProcessor::Render([[maybe_unused]] const SMAAFeatureProcessor::RenderPacket& packet)
|
||||
|
||||
@@ -377,14 +377,7 @@ namespace AZ
|
||||
|
||||
bool ProfilingCaptureSystemComponent::CapturePassTimestamp(const AZStd::string& outputFilePath)
|
||||
{
|
||||
// Find the root pass.
|
||||
AZStd::vector<RPI::Pass*> passes = FindPasses({ "Root" });
|
||||
if (passes.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RPI::Pass* root = passes[0];
|
||||
RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get();
|
||||
|
||||
// Enable all the Timestamp queries in passes.
|
||||
root->SetTimestampQueryEnabled(true);
|
||||
@@ -465,14 +458,7 @@ namespace AZ
|
||||
|
||||
bool ProfilingCaptureSystemComponent::CapturePassPipelineStatistics(const AZStd::string& outputFilePath)
|
||||
{
|
||||
// Find the root pass.
|
||||
AZStd::vector<RPI::Pass*> passes = FindPasses({ "Root" });
|
||||
if (passes.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RPI::Pass* root = passes[0];
|
||||
RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get();
|
||||
|
||||
// Enable all the PipelineStatistics queries in passes.
|
||||
root->SetPipelineStatisticsQueryEnabled(true);
|
||||
@@ -572,19 +558,6 @@ namespace AZ
|
||||
return passes;
|
||||
}
|
||||
|
||||
AZStd::vector<RPI::Pass*> ProfilingCaptureSystemComponent::FindPasses(AZStd::vector<AZStd::string>&& passHierarchy) const
|
||||
{
|
||||
// Find the pass first.
|
||||
RPI::PassHierarchyFilter passFilter(passHierarchy);
|
||||
AZStd::vector<AZ::RPI::Pass*> foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter);
|
||||
if (foundPasses.size() == 0)
|
||||
{
|
||||
AZ_Warning("ProfilingCaptureSystemComponent", false, "Failed to find pass from %s", passFilter.ToString().c_str());
|
||||
}
|
||||
|
||||
return foundPasses;
|
||||
}
|
||||
|
||||
void ProfilingCaptureSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
|
||||
{
|
||||
// Update the delayed captures
|
||||
|
||||
@@ -78,8 +78,6 @@ namespace AZ
|
||||
// Recursively collect all the passes from the root pass.
|
||||
AZStd::vector<const RPI::Pass*> CollectPassesRecursively(const RPI::Pass* root) const;
|
||||
|
||||
AZStd::vector<AZ::RPI::Pass*> FindPasses(AZStd::vector<AZStd::string>&& passHierarchy) const;
|
||||
|
||||
DelayedQueryCaptureHelper m_timestampCapture;
|
||||
DelayedQueryCaptureHelper m_cpuFrameTimeStatisticsCapture;
|
||||
DelayedQueryCaptureHelper m_pipelineStatisticsCapture;
|
||||
|
||||
+10
-9
@@ -28,16 +28,17 @@ namespace AZ
|
||||
|
||||
void ReflectionCopyFrameBufferPass::BuildInternal()
|
||||
{
|
||||
RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass"));
|
||||
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter);
|
||||
if (!passes.empty())
|
||||
{
|
||||
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(passes.front());
|
||||
Data::Instance<RPI::AttachmentImage>& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment();
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(pass);
|
||||
Data::Instance<RPI::AttachmentImage>& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment();
|
||||
|
||||
RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0);
|
||||
AttachImageToSlot(outputBinding.m_name, frameBufferAttachment);
|
||||
}
|
||||
RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0);
|
||||
AttachImageToSlot(outputBinding.m_name, frameBufferAttachment);
|
||||
|
||||
return RPI::PassFilterExecutionFlow::StopVisitingPasses;
|
||||
});
|
||||
|
||||
FullscreenTrianglePass::BuildInternal();
|
||||
}
|
||||
|
||||
+1
-1
@@ -150,7 +150,7 @@ namespace AZ
|
||||
auto transientImageDesc = RHI::ImageDescriptor::Create2D(imageBindFlags, mipSize.m_width, mipSize.m_height, RHI::Format::R16G16B16A16_FLOAT);
|
||||
|
||||
RPI::PassAttachment* transientPassAttachment = aznew RPI::PassAttachment();
|
||||
AZStd::string transientAttachmentName = AZStd::string::format("ReflectionScreenSpace_BlurImage%d", mip);
|
||||
AZStd::string transientAttachmentName = AZStd::string::format("%s.ReflectionScreenSpace_BlurImage%d", GetPathName().GetCStr(), mip);
|
||||
transientPassAttachment->m_name = transientAttachmentName;
|
||||
transientPassAttachment->m_path = transientAttachmentName;
|
||||
transientPassAttachment->m_lifetime = RHI::AttachmentLifetimeType::Transient;
|
||||
|
||||
+14
-12
@@ -33,20 +33,22 @@ namespace AZ
|
||||
return;
|
||||
}
|
||||
|
||||
RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass"));
|
||||
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter);
|
||||
if (!passes.empty())
|
||||
{
|
||||
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(passes.front());
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline());
|
||||
|
||||
// compute the max mip level based on the available mips in the previous frame image, and capping it
|
||||
// to stay within a range that has reasonable data
|
||||
const uint32_t MaxNumRoughnessMips = 8;
|
||||
uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1;
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(pass);
|
||||
|
||||
auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel"));
|
||||
m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel);
|
||||
}
|
||||
// compute the max mip level based on the available mips in the previous frame image, and capping it
|
||||
// to stay within a range that has reasonable data
|
||||
const uint32_t MaxNumRoughnessMips = 8;
|
||||
uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1;
|
||||
|
||||
auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel"));
|
||||
m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel);
|
||||
|
||||
return RPI::PassFilterExecutionFlow::StopVisitingPasses;
|
||||
});
|
||||
|
||||
FullscreenTrianglePass::CompileResources(context);
|
||||
}
|
||||
|
||||
@@ -313,52 +313,38 @@ namespace AZ::Render
|
||||
|
||||
void ProjectedShadowFeatureProcessor::CachePasses()
|
||||
{
|
||||
const AZStd::vector<RPI::RenderPipelineId> validPipelineIds = CacheProjectedShadowmapsPass();
|
||||
CacheEsmShadowmapsPass(validPipelineIds);
|
||||
CacheProjectedShadowmapsPass();
|
||||
CacheEsmShadowmapsPass();
|
||||
m_shadowmapPassNeedsUpdate = true;
|
||||
}
|
||||
|
||||
AZStd::vector<RPI::RenderPipelineId> ProjectedShadowFeatureProcessor::CacheProjectedShadowmapsPass()
|
||||
void ProjectedShadowFeatureProcessor::CacheProjectedShadowmapsPass()
|
||||
{
|
||||
const AZStd::vector<RPI::RenderPipelinePtr>& renderPipelines = GetParentScene()->GetRenderPipelines();
|
||||
const auto* passSystem = RPI::PassSystemInterface::Get();;
|
||||
const AZStd::vector<RPI::Pass*>& passes = passSystem->GetPassesForTemplateName(Name("ProjectedShadowmapsTemplate"));
|
||||
|
||||
AZStd::vector<RPI::RenderPipelineId> validPipelineIds;
|
||||
m_projectedShadowmapsPasses.clear();
|
||||
for (RPI::Pass* pass : passes)
|
||||
{
|
||||
ProjectedShadowmapsPass* shadowPass = static_cast<ProjectedShadowmapsPass*>(pass);
|
||||
for (const RPI::RenderPipelinePtr& pipeline : renderPipelines)
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("ProjectedShadowmapsTemplate"), GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
if (pipeline.get() == shadowPass->GetRenderPipeline())
|
||||
{
|
||||
m_projectedShadowmapsPasses.emplace_back(shadowPass);
|
||||
validPipelineIds.push_back(shadowPass->GetRenderPipeline()->GetId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return validPipelineIds;
|
||||
ProjectedShadowmapsPass* shadowPass = static_cast<ProjectedShadowmapsPass*>(pass);
|
||||
m_projectedShadowmapsPasses.emplace_back(shadowPass);
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass(const AZStd::vector<RPI::RenderPipelineId>& validPipelineIds)
|
||||
void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass()
|
||||
{
|
||||
const Name LightTypeName = Name("projected");
|
||||
|
||||
const auto* passSystem = RPI::PassSystemInterface::Get();
|
||||
const AZStd::vector<RPI::Pass*> passes = passSystem->GetPassesForTemplateName(Name("EsmShadowmapsTemplate"));
|
||||
|
||||
|
||||
m_esmShadowmapsPasses.clear();
|
||||
for (RPI::Pass* pass : passes)
|
||||
{
|
||||
EsmShadowmapsPass* esmPass = static_cast<EsmShadowmapsPass*>(pass);
|
||||
if (esmPass->GetRenderPipeline() &&
|
||||
AZStd::find(validPipelineIds.begin(), validPipelineIds.end(), esmPass->GetRenderPipeline()->GetId()) != validPipelineIds.end() &&
|
||||
esmPass->GetLightTypeName() == LightTypeName)
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene());
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, LightTypeName](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
m_esmShadowmapsPasses.emplace_back(esmPass);
|
||||
}
|
||||
}
|
||||
EsmShadowmapsPass* esmPass = static_cast<EsmShadowmapsPass*>(pass);
|
||||
if (esmPass->GetLightTypeName() == LightTypeName)
|
||||
{
|
||||
m_esmShadowmapsPasses.emplace_back(esmPass);
|
||||
}
|
||||
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
}
|
||||
|
||||
void ProjectedShadowFeatureProcessor::UpdateFilterParameters()
|
||||
|
||||
@@ -97,8 +97,8 @@ namespace AZ::Render
|
||||
|
||||
// Functions for caching the ProjectedShadowmapsPass and EsmShadowmapsPass.
|
||||
void CachePasses();
|
||||
AZStd::vector<RPI::RenderPipelineId> CacheProjectedShadowmapsPass();
|
||||
void CacheEsmShadowmapsPass(const AZStd::vector<RPI::RenderPipelineId>& validPipelineIds);
|
||||
void CacheProjectedShadowmapsPass();
|
||||
void CacheEsmShadowmapsPass();
|
||||
|
||||
//! Functions to update the parameter of Gaussian filter used in ESM.
|
||||
void UpdateFilterParameters();
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <MorphTargets/MorphTargetDispatchItem.h>
|
||||
|
||||
#include <Atom/RPI.Public/Model/ModelLodUtils.h>
|
||||
#include <Atom/RPI.Public/Pass/PassFilter.h>
|
||||
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
|
||||
#include <Atom/RPI.Public/RPIUtils.h>
|
||||
#include <Atom/RPI.Public/Shader/Shader.h>
|
||||
@@ -241,12 +242,12 @@ namespace AZ
|
||||
|
||||
void SkinnedMeshFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline)
|
||||
{
|
||||
InitSkinningAndMorphPass(pipeline->GetRootPass());
|
||||
InitSkinningAndMorphPass(pipeline.get());
|
||||
}
|
||||
|
||||
void SkinnedMeshFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline)
|
||||
{
|
||||
InitSkinningAndMorphPass(renderPipeline->GetRootPass());
|
||||
InitSkinningAndMorphPass(renderPipeline);
|
||||
}
|
||||
|
||||
void SkinnedMeshFeatureProcessor::OnBeginPrepareRender()
|
||||
@@ -289,9 +290,10 @@ namespace AZ
|
||||
return false;
|
||||
}
|
||||
|
||||
void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(const RPI::Ptr<RPI::ParentPass> pipelineRootPass)
|
||||
void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(RPI::RenderPipeline* renderPipeline)
|
||||
{
|
||||
RPI::Ptr<RPI::Pass> skinningPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "SkinningPass" });
|
||||
RPI::PassFilter skinPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name{ "SkinningPass" }, renderPipeline);
|
||||
RPI::Ptr<RPI::Pass> skinningPass = RPI::PassSystemInterface::Get()->FindFirstPass(skinPassFilter);
|
||||
if (skinningPass)
|
||||
{
|
||||
SkinnedMeshComputePass* skinnedMeshComputePass = azdynamic_cast<SkinnedMeshComputePass*>(skinningPass.get());
|
||||
@@ -310,7 +312,8 @@ namespace AZ
|
||||
}
|
||||
}
|
||||
|
||||
RPI::Ptr<RPI::Pass> morphTargetPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "MorphTargetPass" });
|
||||
RPI::PassFilter morphPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name{ "MorphTargetPass" }, renderPipeline);
|
||||
RPI::Ptr<RPI::Pass> morphTargetPass = RPI::PassSystemInterface::Get()->FindFirstPass(morphPassFilter);
|
||||
if (morphTargetPass)
|
||||
{
|
||||
MorphTargetComputePass* morphTargetComputePass = azdynamic_cast<MorphTargetComputePass*>(morphTargetPass.get());
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace AZ
|
||||
private:
|
||||
AZ_DISABLE_COPY_MOVE(SkinnedMeshFeatureProcessor);
|
||||
|
||||
void InitSkinningAndMorphPass(const RPI::Ptr<RPI::ParentPass> pipelineRootPass);
|
||||
void InitSkinningAndMorphPass(RPI::RenderPipeline* renderPipeline);
|
||||
|
||||
SkinnedMeshRenderProxyInterfaceHandle AcquireRenderProxyInterface(const SkinnedMeshRenderProxyDesc& desc) override;
|
||||
bool ReleaseRenderProxyInterface(SkinnedMeshRenderProxyInterfaceHandle& handle) override;
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Shader/DecomposeMsImage.azsl
|
||||
Shader/DecomposeMsImage.shader
|
||||
Shader/ImagePreview.azsl
|
||||
Shader/ImagePreview.shader
|
||||
Shaders/DecomposeMsImage.azsl
|
||||
Shaders/DecomposeMsImage.shader
|
||||
Shaders/ImagePreview.azsl
|
||||
Shaders/ImagePreview.shader
|
||||
ShaderLib/Atom/RPI/Math.azsli
|
||||
ShaderLib/Atom/RPI/TangentSpace.azsli
|
||||
ShaderLib/Atom/RPI/ShaderResourceGroups/DefaultDrawSrg.azsli
|
||||
|
||||
@@ -68,9 +68,6 @@ namespace AZ
|
||||
template<typename PassType>
|
||||
Ptr<PassType> FindChildPass() const;
|
||||
|
||||
//! Searches the tree for the first pass that has same pass name (Depth-first search). Return nullptr if none found.
|
||||
Ptr<Pass> FindPassByNameRecursive(const Name& passName) const;
|
||||
|
||||
//! Gets the list of children. Useful for validating hierarchies
|
||||
AZStd::array_view<Ptr<Pass>> GetChildren() const;
|
||||
|
||||
|
||||
@@ -139,6 +139,10 @@ namespace AZ
|
||||
//! Returns the number of output attachment bindings
|
||||
uint32_t GetOutputCount() const;
|
||||
|
||||
//! Returns the pass template which was used for create this pass.
|
||||
//! It may return nullptr if the pass wasn't create from a template
|
||||
const PassTemplate* GetPassTemplate() const;
|
||||
|
||||
//! Enable/disable this pass
|
||||
//! If the pass is disabled, it (and any children if it's a ParentPass) won't be rendered.
|
||||
void SetEnabled(bool enabled);
|
||||
|
||||
@@ -16,95 +16,85 @@ namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
// A base class for a filter which can be used to filter passes
|
||||
class Scene;
|
||||
class RenderPipeline;
|
||||
|
||||
class PassFilter
|
||||
{
|
||||
public:
|
||||
//! Whether the input pass matches with the filter
|
||||
virtual bool Matches(const Pass* pass) const = 0;
|
||||
static PassFilter CreateWithPassName(Name passName, const Scene* scene);
|
||||
static PassFilter CreateWithPassName(Name passName, const RenderPipeline* renderPipeline);
|
||||
|
||||
//! Return the pass' name if a pass name is used for the filter.
|
||||
//! Return nullptr if the filter doesn't have pass name used for matching
|
||||
virtual const Name* GetPassName() const = 0;
|
||||
//! Create a PassFilter with pass hierarchy information
|
||||
//! Filter for passes which have a matching name and also with ordered parents.
|
||||
//! For example, if the filter is initialized with
|
||||
//! pass name: "ShadowPass1"
|
||||
//! pass parents names: "MainPipeline", "Shadow"
|
||||
//! Passes with these names match the filter:
|
||||
//! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1"
|
||||
//! or "Root.MainPipeline.Shadow.ShadowPass1"
|
||||
//! or "MainPipeline.Shadow.Group1.ShadowPass1"
|
||||
//!
|
||||
//! Passes with these names wont match:
|
||||
//! "MainPipeline.ShadowPass1"
|
||||
//! or "Shadow.MainPipeline.ShadowPass1"
|
||||
static PassFilter CreateWithPassHierarchy(const AZStd::vector<Name>& passHierarchy);
|
||||
static PassFilter CreateWithPassHierarchy(const AZStd::vector<AZStd::string>& passHierarchy);
|
||||
static PassFilter CreateWithTemplateName(Name templateName, const Scene* scene);
|
||||
static PassFilter CreateWithTemplateName(Name templateName, const RenderPipeline* renderPipeline);
|
||||
template <typename PassClass>
|
||||
static PassFilter CreateWithPassClass();
|
||||
|
||||
//! Return this filter's info as a string
|
||||
virtual AZStd::string ToString() const = 0;
|
||||
};
|
||||
enum FilterOptions : uint32_t
|
||||
{
|
||||
Empty = 0,
|
||||
PassName = AZ_BIT(0),
|
||||
PassTemplateName = AZ_BIT(1),
|
||||
PassClass = AZ_BIT(2),
|
||||
PassHierarchy = AZ_BIT(3),
|
||||
OwnerScene = AZ_BIT(4),
|
||||
OwnerRenderPipeline = AZ_BIT(5)
|
||||
};
|
||||
|
||||
//! Filter for passes which have a matching name and also with ordered parents.
|
||||
//! For example, if the filter is initialized with
|
||||
//! pass name: "ShadowPass1"
|
||||
//! pass parents names: "MainPipeline", "Shadow"
|
||||
//! Passes with these names match the filter:
|
||||
//! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1"
|
||||
//! or "Root.MainPipeline.Shadow.ShadowPass1"
|
||||
//! or "MainPipeline.Shadow.Group1.ShadowPass1"
|
||||
//!
|
||||
//! Passes with these names wont match:
|
||||
//! "MainPipeline.ShadowPass1"
|
||||
//! or "Shadow.MainPipeline.ShadowPass1"
|
||||
class PassHierarchyFilter
|
||||
: public PassFilter
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PassHierarchyFilter, "{478F169F-BA97-4321-AC34-EDE823997159}", PassFilter);
|
||||
AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0);
|
||||
void SetOwenrScene(const Scene* scene);
|
||||
void SetOwenrRenderPipeline(const RenderPipeline* renderPipeline);
|
||||
void SetPassName(Name passName);
|
||||
void SetTemplateName(Name passTemplateName);
|
||||
void SetPassClass(TypeId passClassTypeId);
|
||||
|
||||
//! Construct filter with only pass name.
|
||||
PassHierarchyFilter(const Name& passName);
|
||||
const Name& GetPassName() const;
|
||||
const Name& GetPassTemplateName() const;
|
||||
|
||||
virtual ~PassHierarchyFilter() = default;
|
||||
uint32_t GetEnabledFilterOptions() const;
|
||||
|
||||
//! Construct filter with pass name and its parents' names in the order of the hierarchy
|
||||
//! This means k-th element is always an ancestor of the (k-1)-th element.
|
||||
//! And the last element is the pass name.
|
||||
PassHierarchyFilter(const AZStd::vector<Name>& passHierarchy);
|
||||
PassHierarchyFilter(const AZStd::vector<AZStd::string>& passHierarchy);
|
||||
//! Return true if the input pass matches the filter
|
||||
bool Matches(const Pass* pass) const;
|
||||
|
||||
// PassFilter overrides...
|
||||
bool Matches(const Pass* pass) const override;
|
||||
const Name* GetPassName() const override;
|
||||
AZStd::string ToString() const override;
|
||||
//! Return true if the input pass matches the filter with selected filter options
|
||||
//! The input filter options should be a subset of options returned by GetEnabledFilterOptions()
|
||||
//! This function is used to avoid extra checks for passes which was already filtered.
|
||||
//! Check PassLibrary::ForEachPass() function's implementation for more details
|
||||
bool Matches(const Pass* pass, uint32_t options) const;
|
||||
|
||||
private:
|
||||
PassHierarchyFilter() = delete;
|
||||
void UpdateFilterOptions();
|
||||
|
||||
AZStd::vector<Name> m_parentNames;
|
||||
Name m_passName;
|
||||
Name m_templateName;
|
||||
TypeId m_passClassTypeId = TypeId::CreateNull();
|
||||
AZStd::vector<Name> m_parentNames;
|
||||
const RenderPipeline* m_ownerRenderPipeline = nullptr;
|
||||
const Scene* m_ownerScene = nullptr;
|
||||
uint32_t m_filterOptions = 0;
|
||||
};
|
||||
|
||||
//! Filter for passes based on their class.
|
||||
template<typename PassClass>
|
||||
class PassClassFilter
|
||||
: public PassFilter
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PassClassFilter, "{AF6E3AD5-433A-462A-997A-F36D8A551D02}", PassFilter);
|
||||
AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0);
|
||||
PassClassFilter() = default;
|
||||
|
||||
// PassFilter overrides...
|
||||
bool Matches(const Pass* pass) const override;
|
||||
const Name* GetPassName() const override;
|
||||
AZStd::string ToString() const override;
|
||||
};
|
||||
|
||||
template<typename PassClass>
|
||||
bool PassClassFilter<PassClass>::Matches(const Pass* pass) const
|
||||
{
|
||||
return pass->RTTI_IsTypeOf(PassClass::RTTI_Type());
|
||||
}
|
||||
|
||||
template<typename PassClass>
|
||||
const Name* PassClassFilter<PassClass>::GetPassName() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename PassClass>
|
||||
AZStd::string PassClassFilter<PassClass>::ToString() const
|
||||
{
|
||||
return AZStd::string::format("PassClassFilter<%s>", PassClass::RTTI_TypeName());
|
||||
template <typename PassClass>
|
||||
PassFilter PassFilter::CreateWithPassClass()
|
||||
{
|
||||
PassFilter filter;
|
||||
filter.m_passClassTypeId = PassClass::RTTI_Type();
|
||||
filter.UpdateFilterOptions();
|
||||
return filter;
|
||||
}
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -84,8 +84,8 @@ namespace AZ
|
||||
bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath);
|
||||
bool LoadPassTemplateMappings(Data::Asset<AnyAsset> mappingAsset);
|
||||
|
||||
//! Returns a list of passes found in the pass name mapping using the provided pass filter
|
||||
AZStd::vector<Pass*> FindPasses(const PassFilter& passFilter) const;
|
||||
//! Visit each pass which matches the filter
|
||||
void ForEachPass(const PassFilter& passFilter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -92,13 +92,13 @@ namespace AZ
|
||||
|
||||
// PassSystemInterface library related functions...
|
||||
bool HasPassesForTemplateName(const Name& templateName) const override;
|
||||
const AZStd::vector<Pass*>& GetPassesForTemplateName(const Name& templateName) const override;
|
||||
bool AddPassTemplate(const Name& name, const AZStd::shared_ptr<PassTemplate>& passTemplate) override;
|
||||
const AZStd::shared_ptr<PassTemplate> GetPassTemplate(const Name& name) const override;
|
||||
void RemovePassFromLibrary(Pass* pass) override;
|
||||
void RegisterPass(Pass* pass) override;
|
||||
void UnregisterPass(Pass* pass) override;
|
||||
AZStd::vector<Pass*> FindPasses(const PassFilter& passFilter) const override;
|
||||
void ForEachPass(const PassFilter& filter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction) override;
|
||||
Pass* FindFirstPass(const PassFilter& filter) override;
|
||||
|
||||
private:
|
||||
// Returns the root of the pass tree hierarchy
|
||||
|
||||
@@ -75,6 +75,13 @@ namespace AZ
|
||||
u32 m_maxDrawItemsRenderedInAPass = 0;
|
||||
};
|
||||
|
||||
|
||||
enum PassFilterExecutionFlow : uint8_t
|
||||
{
|
||||
StopVisitingPasses,
|
||||
ContinueVisitingPasses,
|
||||
};
|
||||
|
||||
class PassSystemInterface
|
||||
{
|
||||
friend class Pass;
|
||||
@@ -186,9 +193,6 @@ namespace AZ
|
||||
//! Returns true if the pass factory contains passes created with the given template name
|
||||
virtual bool HasPassesForTemplateName(const Name& templateName) const = 0;
|
||||
|
||||
//! Get the passes created with the given template name.
|
||||
virtual const AZStd::vector<Pass*>& GetPassesForTemplateName(const Name& templateName) const = 0;
|
||||
|
||||
//! Adds a PassTemplate to the library
|
||||
virtual bool AddPassTemplate(const Name& name, const AZStd::shared_ptr<PassTemplate>& passTemplate) = 0;
|
||||
|
||||
@@ -197,9 +201,16 @@ namespace AZ
|
||||
|
||||
//! Removes all references to the given pass from the pass library
|
||||
virtual void RemovePassFromLibrary(Pass* pass) = 0;
|
||||
|
||||
//! Visit the matching passes from registered passes with specified filter
|
||||
//! The return value of the passFunction decides if the search continues or not
|
||||
//! Note: this function will find all the passes which match the pass filter even they are for render pipelines which are not added to a scene
|
||||
//! This function is fast if a pass name or a pass template name is specified.
|
||||
virtual void ForEachPass(const PassFilter& filter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction) = 0;
|
||||
|
||||
//! Find matching passes from registered passes with specified filter
|
||||
virtual AZStd::vector<Pass*> FindPasses(const PassFilter& passFilter) const = 0;
|
||||
//! Find the first matching pass from registered passes with specified filter
|
||||
//! Note: this function SHOULD ONLY be used when you are certain you only need to handle the first pass found
|
||||
virtual Pass* FindFirstPass(const PassFilter& filter) = 0;
|
||||
|
||||
private:
|
||||
// These functions are only meant to be used by the Pass class
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace AZ
|
||||
|
||||
//! The asset cache relative path of the only common shader asset for the RPI system that is used
|
||||
//! as means to load the layout for scene srg and view srg. This is used to create any RPI::Scene.
|
||||
AZStd::string m_commonSrgsShaderAssetPath = "shader/sceneandviewsrgs.azshader";
|
||||
AZStd::string m_commonSrgsShaderAssetPath = "shaders/sceneandviewsrgs.azshader";
|
||||
|
||||
ImageSystemDescriptor m_imageSystemDescriptor;
|
||||
GpuQuerySystemDescriptor m_gpuQuerySystemDescriptor;
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace AZ
|
||||
m_fence->Init(*device, RHI::FenceState::Reset);
|
||||
|
||||
// Load shader and srg
|
||||
const char* ShaderPath = "shader/decomposemsimage.azshader";
|
||||
const char* ShaderPath = "shaders/decomposemsimage.azshader";
|
||||
m_decomposeShader = LoadCriticalShader(ShaderPath);
|
||||
|
||||
if (m_decomposeShader == nullptr)
|
||||
|
||||
@@ -149,29 +149,6 @@ namespace AZ
|
||||
return index.IsValid() ? m_children[index.GetIndex()] : Ptr<Pass>(nullptr);
|
||||
}
|
||||
|
||||
Ptr<Pass> ParentPass::FindPassByNameRecursive(const Name& passName) const
|
||||
{
|
||||
for (const Ptr<Pass>& child : m_children)
|
||||
{
|
||||
if (child->GetName() == passName)
|
||||
{
|
||||
return child.get();
|
||||
}
|
||||
|
||||
ParentPass* asParent = child->AsParent();
|
||||
if (asParent)
|
||||
{
|
||||
auto pass = asParent->FindPassByNameRecursive(passName);
|
||||
if (pass)
|
||||
{
|
||||
return pass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Pass* ParentPass::FindPass(RHI::DrawListTag drawListTag) const
|
||||
{
|
||||
if (HasDrawListTag() && GetDrawListTag() == drawListTag)
|
||||
|
||||
@@ -238,6 +238,11 @@ namespace AZ
|
||||
return m_attachmentBindings[bindingIndex];
|
||||
}
|
||||
|
||||
const PassTemplate* Pass::GetPassTemplate() const
|
||||
{
|
||||
return m_template.get();
|
||||
}
|
||||
|
||||
void Pass::AddAttachmentBinding(PassAttachmentBinding attachmentBinding)
|
||||
{
|
||||
// Add the index of the binding to the input, output or input/output list based on the slot type
|
||||
|
||||
@@ -8,101 +8,264 @@
|
||||
|
||||
#include <Atom/RPI.Public/Pass/PassFilter.h>
|
||||
#include <Atom/RPI.Public/Pass/ParentPass.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
|
||||
namespace AZ
|
||||
{
|
||||
namespace RPI
|
||||
{
|
||||
PassHierarchyFilter::PassHierarchyFilter(const Name& passName)
|
||||
PassFilter PassFilter::CreateWithPassName(Name passName, const Scene* scene)
|
||||
{
|
||||
PassFilter filter;
|
||||
filter.m_passName = passName;
|
||||
filter.m_ownerScene = scene;
|
||||
filter.UpdateFilterOptions();
|
||||
return filter;
|
||||
}
|
||||
|
||||
PassFilter PassFilter::CreateWithPassName(Name passName, const RenderPipeline* renderPipeline)
|
||||
{
|
||||
PassFilter filter;
|
||||
filter.m_passName = passName;
|
||||
filter.m_ownerRenderPipeline = renderPipeline;
|
||||
filter.UpdateFilterOptions();
|
||||
return filter;
|
||||
}
|
||||
|
||||
PassFilter PassFilter::CreateWithTemplateName(Name templateName, const Scene* scene)
|
||||
{
|
||||
PassFilter filter;
|
||||
filter.m_templateName = templateName;
|
||||
filter.m_ownerScene = scene;
|
||||
filter.UpdateFilterOptions();
|
||||
return filter;
|
||||
}
|
||||
|
||||
PassFilter PassFilter::CreateWithTemplateName(Name templateName, const RenderPipeline* renderPipeline)
|
||||
{
|
||||
PassFilter filter;
|
||||
filter.m_templateName = templateName;
|
||||
filter.m_ownerRenderPipeline = renderPipeline;
|
||||
filter.UpdateFilterOptions();
|
||||
return filter;
|
||||
}
|
||||
|
||||
PassFilter PassFilter::CreateWithPassHierarchy(const AZStd::vector<Name>& passHierarchy)
|
||||
{
|
||||
PassFilter filter;
|
||||
if (passHierarchy.size() == 0)
|
||||
{
|
||||
AZ_Assert(false, "passHierarchy should have at least one element");
|
||||
return filter;
|
||||
}
|
||||
|
||||
filter.m_passName = passHierarchy.back();
|
||||
|
||||
filter.m_parentNames.resize(passHierarchy.size() - 1);
|
||||
for (uint32_t index = 0; index < filter.m_parentNames.size(); index++)
|
||||
{
|
||||
filter.m_parentNames[index] = passHierarchy[index];
|
||||
}
|
||||
filter.UpdateFilterOptions();
|
||||
return filter;
|
||||
}
|
||||
|
||||
PassFilter PassFilter::CreateWithPassHierarchy(const AZStd::vector<AZStd::string>& passHierarchy)
|
||||
{
|
||||
PassFilter filter;
|
||||
if (passHierarchy.size() == 0)
|
||||
{
|
||||
AZ_Assert(false, "passHierarchy should have at least one element");
|
||||
return filter;
|
||||
}
|
||||
|
||||
filter.m_passName = Name(passHierarchy.back());
|
||||
|
||||
filter.m_parentNames.resize(passHierarchy.size() - 1);
|
||||
for (uint32_t index = 0; index < filter.m_parentNames.size(); index++)
|
||||
{
|
||||
filter.m_parentNames[index] = Name(passHierarchy[index]);
|
||||
}
|
||||
filter.UpdateFilterOptions();
|
||||
return filter;
|
||||
}
|
||||
|
||||
void PassFilter::SetOwenrScene(const Scene* scene)
|
||||
{
|
||||
m_ownerScene = scene;
|
||||
UpdateFilterOptions();
|
||||
}
|
||||
|
||||
void PassFilter::SetOwenrRenderPipeline(const RenderPipeline* renderPipeline)
|
||||
{
|
||||
m_ownerRenderPipeline = renderPipeline;
|
||||
UpdateFilterOptions();
|
||||
}
|
||||
|
||||
void PassFilter::SetPassName(Name passName)
|
||||
{
|
||||
m_passName = passName;
|
||||
UpdateFilterOptions();
|
||||
}
|
||||
|
||||
PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector<AZStd::string>& passHierarchy)
|
||||
void PassFilter::SetTemplateName(Name passTemplateName)
|
||||
{
|
||||
if (passHierarchy.size() == 0)
|
||||
{
|
||||
AZ_Assert(false, "passHierarchy should have at least one element");
|
||||
return;
|
||||
}
|
||||
|
||||
m_passName = Name(passHierarchy.back());
|
||||
|
||||
m_parentNames.resize(passHierarchy.size() - 1);
|
||||
for (uint32_t index = 0; index < m_parentNames.size(); index++)
|
||||
{
|
||||
m_parentNames[index] = Name(passHierarchy[index]);
|
||||
}
|
||||
m_templateName = passTemplateName;
|
||||
UpdateFilterOptions();
|
||||
}
|
||||
|
||||
PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector<Name>& passHierarchy)
|
||||
void PassFilter::SetPassClass(TypeId passClassTypeId)
|
||||
{
|
||||
if (passHierarchy.size() == 0)
|
||||
{
|
||||
AZ_Assert(false, "passHierarchy should have at least one element");
|
||||
return;
|
||||
}
|
||||
|
||||
m_passName = passHierarchy.back();
|
||||
|
||||
m_parentNames.resize(passHierarchy.size() - 1);
|
||||
for (uint32_t index = 0; index < m_parentNames.size(); index++)
|
||||
{
|
||||
m_parentNames[index] = passHierarchy[index];
|
||||
}
|
||||
m_passClassTypeId = passClassTypeId;
|
||||
UpdateFilterOptions();
|
||||
}
|
||||
|
||||
bool PassHierarchyFilter::Matches(const Pass* pass) const
|
||||
const Name& PassFilter::GetPassName() const
|
||||
{
|
||||
if (pass->GetName() != m_passName)
|
||||
return m_passName;
|
||||
}
|
||||
|
||||
const Name& PassFilter::GetPassTemplateName() const
|
||||
{
|
||||
return m_templateName;
|
||||
}
|
||||
|
||||
uint32_t PassFilter::GetEnabledFilterOptions() const
|
||||
{
|
||||
return m_filterOptions;
|
||||
}
|
||||
|
||||
bool PassFilter::Matches(const Pass* pass) const
|
||||
{
|
||||
return Matches(pass, m_filterOptions);
|
||||
}
|
||||
|
||||
bool PassFilter::Matches(const Pass* pass, uint32_t options) const
|
||||
{
|
||||
AZ_Assert( (options&m_filterOptions) == options, "options should be a subset of m_filterOptions");
|
||||
|
||||
// return false if the pass doesn't have a pass template or the template's name is not matching
|
||||
if (options & FilterOptions::PassTemplateName && (!pass->GetPassTemplate() || pass->GetPassTemplate()->m_name != m_templateName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ParentPass* parent = pass->GetParent();
|
||||
|
||||
// search from the back of the array with the most close parent
|
||||
for (int32_t index = static_cast<int32_t>(m_parentNames.size() - 1); index >= 0; index--)
|
||||
if ((options & FilterOptions::PassName) && pass->GetName() != m_passName)
|
||||
{
|
||||
const Name& parentName = m_parentNames[index];
|
||||
while (parent)
|
||||
{
|
||||
if (parent->GetName() == parentName)
|
||||
{
|
||||
break;
|
||||
}
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// if parent is nullptr the it didn't find a parent has matching current parentName
|
||||
if (!parent)
|
||||
if ((options & FilterOptions::PassClass) && pass->RTTI_GetType() != m_passClassTypeId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((options & FilterOptions::OwnerRenderPipeline) && m_ownerRenderPipeline != pass->GetRenderPipeline())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the owner render pipeline was checked, the owner scene check can be skipped
|
||||
if (options & FilterOptions::OwnerScene)
|
||||
{
|
||||
if (pass->GetRenderPipeline())
|
||||
{
|
||||
// return false if the owner scene doesn't match
|
||||
if (m_ownerScene != pass->GetRenderPipeline()->GetScene())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// return false if the pass doesn't have an owner scene
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// move to next parent
|
||||
parent = parent->GetParent();
|
||||
if ((options & FilterOptions::PassHierarchy))
|
||||
{
|
||||
// Filter for passes which have a matching name and also with ordered parents.
|
||||
// For example, if the filter is initialized with
|
||||
// pass name: "ShadowPass1"
|
||||
// pass parents names: "MainPipeline", "Shadow"
|
||||
// Passes with these names match the filter:
|
||||
// "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1"
|
||||
// or "Root.MainPipeline.Shadow.ShadowPass1"
|
||||
// or "MainPipeline.Shadow.Group1.ShadowPass1"
|
||||
//
|
||||
// Passes with these names wont match:
|
||||
// "MainPipeline.ShadowPass1"
|
||||
// or "Shadow.MainPipeline.ShadowPass1"
|
||||
|
||||
ParentPass* parent = pass->GetParent();
|
||||
|
||||
// search from the back of the array with the most close parent
|
||||
for (int32_t index = static_cast<int32_t>(m_parentNames.size() - 1); index >= 0; index--)
|
||||
{
|
||||
const Name& parentName = m_parentNames[index];
|
||||
while (parent)
|
||||
{
|
||||
if (parent->GetName() == parentName)
|
||||
{
|
||||
break;
|
||||
}
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
|
||||
// if parent is nullptr the it didn't find a parent has matching current parentName
|
||||
if (!parent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// move to next parent
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const Name* PassHierarchyFilter::GetPassName() const
|
||||
void PassFilter::UpdateFilterOptions()
|
||||
{
|
||||
return &m_passName;
|
||||
}
|
||||
|
||||
AZStd::string PassHierarchyFilter::ToString() const
|
||||
{
|
||||
AZStd::string result = "PassHierarchyFilter";
|
||||
for (uint32_t index = 0; index < m_parentNames.size(); index++)
|
||||
m_filterOptions = FilterOptions::Empty;
|
||||
if (!m_passName.IsEmpty())
|
||||
{
|
||||
result += AZStd::string::format(" [%s]", m_parentNames[index].GetCStr());
|
||||
m_filterOptions |= FilterOptions::PassName;
|
||||
}
|
||||
if (!m_templateName.IsEmpty())
|
||||
{
|
||||
m_filterOptions |= FilterOptions::PassTemplateName;
|
||||
}
|
||||
if (m_parentNames.size() > 0)
|
||||
{
|
||||
m_filterOptions |= FilterOptions::PassHierarchy;
|
||||
}
|
||||
if (m_ownerRenderPipeline)
|
||||
{
|
||||
m_filterOptions |= FilterOptions::OwnerRenderPipeline;
|
||||
}
|
||||
if (m_ownerScene)
|
||||
{
|
||||
// If the OwnerRenderPipeline exists, we shouldn't need to filter owner scene
|
||||
// Validate the owner render pipeline belongs to the owner scene
|
||||
if (m_filterOptions & FilterOptions::OwnerRenderPipeline)
|
||||
{
|
||||
if (m_ownerRenderPipeline->GetScene() != m_ownerScene)
|
||||
{
|
||||
AZ_Warning("RPI", false, "The owner scene filter doesn't match owner render pipeline. It will be skipped.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_filterOptions |= FilterOptions::OwnerScene;
|
||||
}
|
||||
}
|
||||
if (!m_passClassTypeId.IsNull())
|
||||
{
|
||||
m_filterOptions |= FilterOptions::PassClass;
|
||||
}
|
||||
|
||||
result += AZStd::string::format(" [%s]", m_passName.GetCStr());
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
@@ -85,47 +85,80 @@ namespace AZ
|
||||
return (GetPassesForTemplate(templateName).size() > 0);
|
||||
}
|
||||
|
||||
AZStd::vector<Pass*> PassLibrary::FindPasses(const PassFilter& passFilter) const
|
||||
void PassLibrary::ForEachPass(const PassFilter& passFilter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction)
|
||||
{
|
||||
const Name* passName = passFilter.GetPassName();
|
||||
uint32_t filterOptions = passFilter.GetEnabledFilterOptions();
|
||||
|
||||
AZStd::vector<Pass*> result;
|
||||
|
||||
if (passName)
|
||||
// A lambda function which visits each pass in a pass list, if the pass matches the pass filter, then call the pass function
|
||||
auto visitList = [passFilter, passFunction](const AZStd::vector<Pass*>& passList, uint32_t options) -> PassFilterExecutionFlow
|
||||
{
|
||||
// If the pass' name is known, find passes with matching names first
|
||||
const auto constItr = m_passNameMapping.find(*passName);
|
||||
if (constItr == m_passNameMapping.end())
|
||||
if (passList.size() == 0)
|
||||
{
|
||||
return result;
|
||||
return PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
}
|
||||
|
||||
const AZStd::vector<Pass*>& passes = constItr->second;
|
||||
|
||||
for (Pass* pass : passes)
|
||||
// if there is not other filter options enabled, skip the filter and call pass functions directly
|
||||
if (options == PassFilter::FilterOptions::Empty)
|
||||
{
|
||||
if (passFilter.Matches(pass))
|
||||
for (Pass* pass : passList)
|
||||
{
|
||||
result.push_back(pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the filter doesn't know matching pass' name, need to go through all registered passes
|
||||
for (auto& namePasses : m_passNameMapping)
|
||||
{
|
||||
for (Pass* pass : namePasses.second)
|
||||
{
|
||||
if (passFilter.Matches(pass))
|
||||
// If user want to skip processing, return directly.
|
||||
if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses)
|
||||
{
|
||||
result.push_back(pass);
|
||||
return PassFilterExecutionFlow::StopVisitingPasses;
|
||||
}
|
||||
}
|
||||
return PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
}
|
||||
|
||||
// Check with the pass filter and call pass functions
|
||||
for (Pass* pass : passList)
|
||||
{
|
||||
if (passFilter.Matches(pass, options))
|
||||
{
|
||||
if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses)
|
||||
{
|
||||
return PassFilterExecutionFlow::StopVisitingPasses;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
};
|
||||
|
||||
// Check pass template name first
|
||||
if (filterOptions & PassFilter::FilterOptions::PassTemplateName)
|
||||
{
|
||||
auto entry = GetEntry(passFilter.GetPassTemplateName());
|
||||
if (!entry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
filterOptions &= ~(PassFilter::FilterOptions::PassTemplateName);
|
||||
visitList(entry->m_passes, filterOptions);
|
||||
return;
|
||||
}
|
||||
else if (filterOptions & PassFilter::FilterOptions::PassName)
|
||||
{
|
||||
const auto constItr = m_passNameMapping.find(passFilter.GetPassName());
|
||||
if (constItr == m_passNameMapping.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
filterOptions &= ~(PassFilter::FilterOptions::PassName);
|
||||
visitList(constItr->second, filterOptions);
|
||||
return;
|
||||
}
|
||||
|
||||
return result;
|
||||
// check againest every passes. This might be slow
|
||||
AZ_PROFILE_SCOPE(RPI, "PassLibrary::ForEachPass");
|
||||
for (auto& namePasses : m_passNameMapping)
|
||||
{
|
||||
if (visitList(namePasses.second, filterOptions) == PassFilterExecutionFlow::StopVisitingPasses)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add Functions...
|
||||
@@ -419,3 +452,4 @@ namespace AZ
|
||||
|
||||
} // namespace RPI
|
||||
} // namespace AZ
|
||||
|
||||
|
||||
@@ -456,11 +456,6 @@ namespace AZ
|
||||
return m_passLibrary.HasPassesForTemplate(templateName);
|
||||
}
|
||||
|
||||
const AZStd::vector<Pass*>& PassSystem::GetPassesForTemplateName(const Name& templateName) const
|
||||
{
|
||||
return m_passLibrary.GetPassesForTemplate(templateName);
|
||||
}
|
||||
|
||||
bool PassSystem::AddPassTemplate(const Name& name, const AZStd::shared_ptr<PassTemplate>& passTemplate)
|
||||
{
|
||||
return m_passLibrary.AddPassTemplate(name, passTemplate);
|
||||
@@ -487,10 +482,21 @@ namespace AZ
|
||||
RemovePassFromLibrary(pass);
|
||||
--m_passCounter;
|
||||
}
|
||||
|
||||
AZStd::vector<Pass*> PassSystem::FindPasses(const PassFilter& passFilter) const
|
||||
|
||||
void PassSystem::ForEachPass(const PassFilter& filter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction)
|
||||
{
|
||||
return m_passLibrary.FindPasses(passFilter);
|
||||
return m_passLibrary.ForEachPass(filter, passFunction);
|
||||
}
|
||||
|
||||
Pass* PassSystem::FindFirstPass(const PassFilter& filter)
|
||||
{
|
||||
Pass* foundPass = nullptr;
|
||||
m_passLibrary.ForEachPass(filter, [&foundPass](RPI::Pass* pass) ->PassFilterExecutionFlow
|
||||
{
|
||||
foundPass = pass;
|
||||
return PassFilterExecutionFlow::StopVisitingPasses;
|
||||
});
|
||||
return foundPass;
|
||||
}
|
||||
|
||||
SwapChainPass* PassSystem::FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const
|
||||
|
||||
@@ -244,7 +244,7 @@ namespace AZ
|
||||
m_needsShaderLoad = false;
|
||||
|
||||
// Load Shader
|
||||
const char* ShaderPath = "shader/imagepreview.azshader";
|
||||
const char* ShaderPath = "shaders/imagepreview.azshader";
|
||||
Data::Asset<ShaderAsset> shaderAsset = RPI::FindShaderAsset(ShaderPath);
|
||||
m_shader = Shader::FindOrCreate(shaderAsset);
|
||||
if (m_shader == nullptr)
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <Atom/RPI.Public/Pass/PassSystem.h>
|
||||
#include <Atom/RPI.Public/Pass/RasterPass.h>
|
||||
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
#include <Common/RPITestFixture.h>
|
||||
@@ -573,7 +575,7 @@ namespace UnitTest
|
||||
EXPECT_TRUE(pass != nullptr);
|
||||
}
|
||||
|
||||
TEST_F(PassTests, PassHierarchyFilter)
|
||||
TEST_F(PassTests, PassFilter_PassHierarchy)
|
||||
{
|
||||
m_data->AddPassTemplatesToLibrary();
|
||||
|
||||
@@ -587,62 +589,55 @@ namespace UnitTest
|
||||
parent2->AsParent()->AddChild(parent1);
|
||||
parent1->AsParent()->AddChild(pass);
|
||||
|
||||
{
|
||||
// Filter with only pass name
|
||||
PassHierarchyFilter filter(Name("pass1"));
|
||||
EXPECT_TRUE(filter.Matches(pass.get()));
|
||||
}
|
||||
|
||||
{
|
||||
// Filter with pass hierarchy which has only one element
|
||||
PassHierarchyFilter filter({ Name("pass1") });
|
||||
PassFilter filter = PassFilter::CreateWithPassHierarchy({Name("pass1")});
|
||||
EXPECT_TRUE(filter.Matches(pass.get()));
|
||||
}
|
||||
|
||||
{
|
||||
// Filter with empty pass hierarchy. Result one assert
|
||||
// Filter with empty pass hierarchy, triggers one assert
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
PassHierarchyFilter filter(AZStd::vector<Name>{});
|
||||
PassFilter filter = PassFilter::CreateWithPassHierarchy(AZStd::vector<Name>{});
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
|
||||
EXPECT_FALSE(filter.Matches(pass.get()));
|
||||
}
|
||||
|
||||
{
|
||||
// Filters with partial hierarchy by using string vector
|
||||
AZStd::vector<AZStd::string> passHierarchy1 = { "parent1", "pass1" };
|
||||
PassHierarchyFilter filter1(passHierarchy1);
|
||||
PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1);
|
||||
EXPECT_TRUE(filter1.Matches(pass.get()));
|
||||
|
||||
AZStd::vector<AZStd::string> passHierarchy2 = { "parent2", "pass1" };
|
||||
PassHierarchyFilter filter2(passHierarchy2);
|
||||
PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2);
|
||||
EXPECT_TRUE(filter2.Matches(pass.get()));
|
||||
|
||||
AZStd::vector<AZStd::string> passHierarchy3 = { "parent3", "parent2", "pass1" };
|
||||
PassHierarchyFilter filter3(passHierarchy3);
|
||||
PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3);
|
||||
EXPECT_TRUE(filter3.Matches(pass.get()));
|
||||
}
|
||||
|
||||
{
|
||||
// Filters with partial hierarchy by using Name vector
|
||||
AZStd::vector<Name> passHierarchy1 = { Name("parent1"), Name("pass1") };
|
||||
PassHierarchyFilter filter1(passHierarchy1);
|
||||
PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1);
|
||||
EXPECT_TRUE(filter1.Matches(pass.get()));
|
||||
|
||||
AZStd::vector<Name> passHierarchy2 = { Name("parent2"), Name("pass1")};
|
||||
PassHierarchyFilter filter2(passHierarchy2);
|
||||
PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2);
|
||||
EXPECT_TRUE(filter2.Matches(pass.get()));
|
||||
|
||||
AZStd::vector<Name> passHierarchy3 = { Name("parent3"), Name("parent2"), Name("pass1") };
|
||||
PassHierarchyFilter filter3(passHierarchy3);
|
||||
PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3);
|
||||
EXPECT_TRUE(filter3.Matches(pass.get()));
|
||||
}
|
||||
|
||||
{
|
||||
// Find non-leaf pass
|
||||
PassHierarchyFilter filter1(AZStd::vector<AZStd::string>{"parent3", "parent1"});
|
||||
PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector<AZStd::string>{"parent3", "parent1"});
|
||||
EXPECT_TRUE(filter1.Matches(parent1.get()));
|
||||
|
||||
PassHierarchyFilter filter2(Name("parent1"));
|
||||
|
||||
PassFilter filter2 = PassFilter::CreateWithPassHierarchy({ Name("parent1") });
|
||||
EXPECT_TRUE(filter2.Matches(parent1.get()));
|
||||
EXPECT_FALSE(filter2.Matches(pass.get()));
|
||||
}
|
||||
@@ -650,11 +645,131 @@ namespace UnitTest
|
||||
{
|
||||
// Failed to find pass
|
||||
// Mis-matching hierarchy
|
||||
PassHierarchyFilter filter1(AZStd::vector<AZStd::string>{"Parent1", "Parent3", "pass1"});
|
||||
PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector<AZStd::string>{"Parent1", "Parent3", "pass1"});
|
||||
EXPECT_FALSE(filter1.Matches(pass.get()));
|
||||
// Mis-matching name
|
||||
PassHierarchyFilter filter2(AZStd::vector<AZStd::string>{"Parent1", "pass1"});
|
||||
PassFilter filter2 = PassFilter::CreateWithPassHierarchy(AZStd::vector<AZStd::string>{"Parent1", "pass1"});
|
||||
EXPECT_FALSE(filter2.Matches(parent1.get()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(PassTests, PassFilter_Empty_Success)
|
||||
{
|
||||
m_data->AddPassTemplatesToLibrary();
|
||||
|
||||
// create a pass tree
|
||||
Ptr<Pass> pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
|
||||
Ptr<Pass> parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
|
||||
Ptr<Pass> parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2"));
|
||||
Ptr<Pass> parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3"));
|
||||
|
||||
parent3->AsParent()->AddChild(parent2);
|
||||
parent2->AsParent()->AddChild(parent1);
|
||||
parent1->AsParent()->AddChild(pass);
|
||||
|
||||
PassFilter filter;
|
||||
|
||||
// Any pass can match an empty filter
|
||||
EXPECT_TRUE(filter.Matches(pass.get()));
|
||||
EXPECT_TRUE(filter.Matches(parent1.get()));
|
||||
EXPECT_TRUE(filter.Matches(parent2.get()));
|
||||
EXPECT_TRUE(filter.Matches(parent3.get()));
|
||||
}
|
||||
|
||||
TEST_F(PassTests, PassFilter_PassClass_Success)
|
||||
{
|
||||
m_data->AddPassTemplatesToLibrary();
|
||||
|
||||
// create a pass tree
|
||||
Ptr<Pass> pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
|
||||
Ptr<Pass> depthPass = m_passSystem->CreatePassFromTemplate(Name("DepthPrePass"), Name("depthPass"));
|
||||
Ptr<Pass> parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
|
||||
|
||||
parent1->AsParent()->AddChild(pass);
|
||||
parent1->AsParent()->AddChild(depthPass);
|
||||
|
||||
PassFilter filter1 = PassFilter::CreateWithPassClass<Pass>();
|
||||
|
||||
EXPECT_TRUE(filter1.Matches(pass.get()));
|
||||
EXPECT_FALSE(filter1.Matches(parent1.get()));
|
||||
|
||||
PassFilter filter2 = PassFilter::CreateWithPassClass<ParentPass>();
|
||||
EXPECT_FALSE(filter2.Matches(pass.get()));
|
||||
EXPECT_TRUE(filter2.Matches(parent1.get()));
|
||||
}
|
||||
|
||||
TEST_F(PassTests, PassFilter_PassTemplate_Success)
|
||||
{
|
||||
m_data->AddPassTemplatesToLibrary();
|
||||
|
||||
// create a pass tree
|
||||
Ptr<Pass> childPass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
|
||||
Ptr<Pass> parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
|
||||
|
||||
PassFilter filter1 = PassFilter::CreateWithTemplateName(Name("Pass"), (Scene*) nullptr);
|
||||
// childPass doesn't have a template
|
||||
EXPECT_FALSE(filter1.Matches(childPass.get()));
|
||||
|
||||
PassFilter filter2 = PassFilter::CreateWithTemplateName(Name("ParentPass"), (Scene*) nullptr);
|
||||
EXPECT_TRUE(filter2.Matches(parent1.get()));
|
||||
}
|
||||
|
||||
TEST_F(PassTests, ForEachPass_PassTemplateFilter_Success)
|
||||
{
|
||||
m_data->AddPassTemplatesToLibrary();
|
||||
|
||||
// create a pass tree
|
||||
Ptr<Pass> pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
|
||||
Ptr<Pass> parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
|
||||
Ptr<Pass> parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2"));
|
||||
Ptr<Pass> parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3"));
|
||||
|
||||
parent3->AsParent()->AddChild(parent2);
|
||||
parent2->AsParent()->AddChild(parent1);
|
||||
parent1->AsParent()->AddChild(pass);
|
||||
|
||||
// Create render pipeline
|
||||
const RPI::PipelineViewTag viewTag{ "viewTag1" };
|
||||
RPI::RenderPipelineDescriptor desc;
|
||||
desc.m_mainViewTagName = viewTag.GetStringView();
|
||||
desc.m_name = "TestPipeline";
|
||||
RPI::RenderPipelinePtr pipeline = RPI::RenderPipeline::CreateRenderPipeline(desc);
|
||||
Ptr<Pass> parent4 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent4"));
|
||||
pipeline->GetRootPass()->AddChild(parent4);
|
||||
|
||||
Name templateName = Name("ParentPass");
|
||||
PassFilter filter1 = PassFilter::CreateWithTemplateName(templateName, (RenderPipeline*)nullptr);
|
||||
|
||||
int count = 0;
|
||||
m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow
|
||||
{
|
||||
EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName);
|
||||
count++;
|
||||
return PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
|
||||
// three from CreatePassFromTemplate() calls and one from Render Pipeline.
|
||||
EXPECT_TRUE(count == 4);
|
||||
|
||||
count = 0;
|
||||
m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow
|
||||
{
|
||||
EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName);
|
||||
count++;
|
||||
return PassFilterExecutionFlow::StopVisitingPasses;
|
||||
});
|
||||
EXPECT_TRUE(count == 1);
|
||||
|
||||
PassFilter filter2 = PassFilter::CreateWithTemplateName(templateName, pipeline.get());
|
||||
count = 0;
|
||||
m_passSystem->ForEachPass(filter2, [&count]([[maybe_unused]] RPI::Pass* pass) -> PassFilterExecutionFlow
|
||||
{
|
||||
count++;
|
||||
return PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
});
|
||||
|
||||
// only the ParentPass in the render pipeline was found
|
||||
EXPECT_TRUE(count == 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"Atom": {
|
||||
"RPI": {
|
||||
"Initialization": {
|
||||
"CommonSrgsShaderAssetPath": "shader/sceneandviewsrgs.azshader",
|
||||
"CommonSrgsShaderAssetPath": "shaders/sceneandviewsrgs.azshader",
|
||||
"ImageSystemDescriptor": {
|
||||
"AssetStreamingImagePoolSize": 2147483648, // 2 * 1024 * 1024 * 1024
|
||||
"SystemStreamingImagePoolSize": 134217728, // 128 * 1024 * 1024
|
||||
|
||||
@@ -581,7 +581,7 @@
|
||||
{
|
||||
"id": {
|
||||
"materialAssetId": {
|
||||
"guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
|
||||
"guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
|
||||
"subId": 803645540
|
||||
}
|
||||
}
|
||||
@@ -593,7 +593,7 @@
|
||||
"id": {
|
||||
"lodIndex": 0,
|
||||
"materialAssetId": {
|
||||
"guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
|
||||
"guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
|
||||
"subId": 803645540
|
||||
}
|
||||
}
|
||||
@@ -608,10 +608,10 @@
|
||||
"Configuration": {
|
||||
"ModelAsset": {
|
||||
"assetId": {
|
||||
"guid": "{935F694A-8639-515B-8133-81CDC7948E5B}",
|
||||
"subId": 277333723
|
||||
"guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
|
||||
"subId": 277889906
|
||||
},
|
||||
"assetHint": "objects/groudplane/groundplane_521x521m.azmodel"
|
||||
"assetHint": "objects/groudplane/groundplane_512x512m.azmodel"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -836,7 +836,7 @@
|
||||
</Class>
|
||||
<Class name="AZ::Render::MeshComponentController" field="Controller" type="{D0F35FAC-4194-4C89-9487-D000DDB8B272}">
|
||||
<Class name="AZ::Render::MeshComponentConfig" field="Configuration" version="1" type="{63737345-51B1-472B-9355-98F99993909B}">
|
||||
<Class name="Asset" field="ModelAsset" value="id={935F694A-8639-515B-8133-81CDC7948E5B}:1087c6db,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/groudplane/groundplane_521x521m.azmodel},loadBehavior=1" version="2" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
|
||||
<Class name="Asset" field="ModelAsset" value="id={0CD745C0-6AA8-569A-A68A-73A3270986C4}:10904372,type={2C7477B6-69C5-45BE-8163-BCD6A275B6D8},hint={objects/groudplane/groundplane_512x512m.azmodel},loadBehavior=1" version="2" type="{77A19D40-8731-4D3C-9041-1B43047366A4}"/>
|
||||
<Class name="AZ::s64" field="SortKey" value="0" type="{70D8A282-A1EA-462D-9D04-51EDE81FAC2F}"/>
|
||||
<Class name="unsigned char" field="LodOverride" value="255" type="{72B9409A-7D1A-4831-9CFE-FCB3FADD3426}"/>
|
||||
<Class name="bool" field="ExcludeFromReflectionCubeMaps" value="false" type="{A0CA880C-AFE4-43CB-926C-59AC48496112}"/>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <Atom/RPI.Public/View.h>
|
||||
#include <Atom/RPI.Public/Scene.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
#include <Atom/RPI.Public/Pass/PassFilter.h>
|
||||
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
|
||||
#include <Atom/RPI.Public/RPIUtils.h>
|
||||
#include <Atom/RPI.Public/Shader/Shader.h>
|
||||
@@ -142,12 +143,13 @@ namespace AZ
|
||||
EnablePasses(true);
|
||||
}
|
||||
|
||||
void HairFeatureProcessor::EnablePasses([[maybe_unused]] bool enable)
|
||||
void HairFeatureProcessor::EnablePasses(bool enable)
|
||||
{
|
||||
RPI::Ptr<RPI::Pass> desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName);
|
||||
if (desiredPass)
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene());
|
||||
RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
|
||||
if (pass)
|
||||
{
|
||||
desiredPass->SetEnabled(enable);
|
||||
pass->SetEnabled(enable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,10 +311,17 @@ namespace AZ
|
||||
m_forceClearRenderData = true;
|
||||
}
|
||||
|
||||
bool HairFeatureProcessor::HasHairParentPass()
|
||||
{
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene());
|
||||
RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
|
||||
return pass;
|
||||
}
|
||||
|
||||
void HairFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr renderPipeline)
|
||||
{
|
||||
// Proceed only if this is the main pipeline that contains the parent pass
|
||||
if (!renderPipeline.get()->GetRootPass()->FindPassByNameRecursive(HairParentPassName))
|
||||
if (!HasHairParentPass())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -323,10 +332,10 @@ namespace AZ
|
||||
m_forceRebuildRenderData = true;
|
||||
}
|
||||
|
||||
void HairFeatureProcessor::OnRenderPipelineRemoved(RPI::RenderPipeline* renderPipeline)
|
||||
void HairFeatureProcessor::OnRenderPipelineRemoved([[maybe_unused]] RPI::RenderPipeline* renderPipeline)
|
||||
{
|
||||
// Proceed only if this is the main pipeline that contains the parent pass
|
||||
if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName))
|
||||
if (!HasHairParentPass())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -338,7 +347,7 @@ namespace AZ
|
||||
void HairFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline)
|
||||
{
|
||||
// Proceed only if this is the main pipeline that contains the parent pass
|
||||
if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName))
|
||||
if (!HasHairParentPass())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -457,7 +466,8 @@ namespace AZ
|
||||
{
|
||||
m_computePasses[passName] = nullptr;
|
||||
|
||||
RPI::Ptr<RPI::Pass> desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(passName);
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(passName, m_renderPipeline);
|
||||
RPI::Ptr<RPI::Pass> desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
|
||||
if (desiredPass)
|
||||
{
|
||||
m_computePasses[passName] = static_cast<HairSkinningComputePass*>(desiredPass.get());
|
||||
@@ -478,8 +488,9 @@ namespace AZ
|
||||
bool HairFeatureProcessor::InitPPLLFillPass()
|
||||
{
|
||||
m_hairPPLLRasterPass = nullptr; // reset it to null, just in case it fails to load the assets properly
|
||||
|
||||
RPI::Ptr<RPI::Pass> desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairPPLLRasterPassName);
|
||||
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairPPLLRasterPassName, m_renderPipeline);
|
||||
RPI::Ptr<RPI::Pass> desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
|
||||
if (desiredPass)
|
||||
{
|
||||
m_hairPPLLRasterPass = static_cast<HairPPLLRasterPass*>(desiredPass.get());
|
||||
@@ -497,7 +508,8 @@ namespace AZ
|
||||
{
|
||||
m_hairPPLLResolvePass = nullptr; // reset it to null, just in case it fails to load the assets properly
|
||||
|
||||
RPI::Ptr<RPI::Pass> desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairPPLLResolvePassName);
|
||||
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairPPLLResolvePassName, m_renderPipeline);
|
||||
RPI::Ptr<RPI::Pass> desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
|
||||
if (desiredPass)
|
||||
{
|
||||
m_hairPPLLResolvePass = static_cast<HairPPLLResolvePass*>(desiredPass.get());
|
||||
@@ -518,8 +530,8 @@ namespace AZ
|
||||
m_hairShortCutGeometryDepthAlphaPass = nullptr;
|
||||
m_hairShortCutGeometryShadingPass = nullptr;
|
||||
|
||||
m_hairShortCutGeometryDepthAlphaPass = static_cast<HairShortCutGeometryDepthAlphaPass*>(
|
||||
m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryDepthAlphaPassName).get());
|
||||
RPI::PassFilter depthAlphaPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryDepthAlphaPassName, m_renderPipeline);
|
||||
m_hairShortCutGeometryDepthAlphaPass = static_cast<HairShortCutGeometryDepthAlphaPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(depthAlphaPassFilter));
|
||||
if (m_hairShortCutGeometryDepthAlphaPass)
|
||||
{
|
||||
m_hairShortCutGeometryDepthAlphaPass->SetFeatureProcessor(this);
|
||||
@@ -530,8 +542,8 @@ namespace AZ
|
||||
return false;
|
||||
}
|
||||
|
||||
m_hairShortCutGeometryShadingPass = static_cast<HairShortCutGeometryShadingPass*>(
|
||||
m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryShadingPassName).get());
|
||||
RPI::PassFilter shaderingPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryShadingPassName, m_renderPipeline);
|
||||
m_hairShortCutGeometryShadingPass = static_cast<HairShortCutGeometryShadingPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(shaderingPassFilter));
|
||||
if (m_hairShortCutGeometryShadingPass)
|
||||
{
|
||||
m_hairShortCutGeometryShadingPass->SetFeatureProcessor(this);
|
||||
|
||||
@@ -165,6 +165,8 @@ namespace AZ
|
||||
|
||||
void EnablePasses(bool enable);
|
||||
|
||||
bool HasHairParentPass();
|
||||
|
||||
//! The following will serve to register the FP in the Thumbnail system
|
||||
AZStd::vector<AZStd::string> m_hairFeatureProcessorRegistryName;
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"description": "",
|
||||
"materialType": "TerrainMacroMaterial.materialtype",
|
||||
"parentMaterial": "",
|
||||
"propertyLayoutVersion": 1,
|
||||
"properties": {
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
{
|
||||
"description": "A material for providing terrain with low-fidelity color and normals. This material will get blended with surface detail materials.",
|
||||
"version": 1,
|
||||
"propertyLayout": {
|
||||
"groups": [
|
||||
{
|
||||
"name": "baseColor",
|
||||
"displayName": "Base Color",
|
||||
"description": "Properties for configuring the surface reflected color for dielectrics or reflectance values for metals."
|
||||
},
|
||||
{
|
||||
"name": "normal",
|
||||
"displayName": "Normal",
|
||||
"description": "Properties related to configuring surface normal."
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"baseColor": [
|
||||
{
|
||||
"name": "textureMap",
|
||||
"displayName": "Texture",
|
||||
"description": "Base color of the macro material",
|
||||
"type": "Image"
|
||||
}
|
||||
],
|
||||
"normal": [
|
||||
{
|
||||
"name": "textureMap",
|
||||
"displayName": "Texture",
|
||||
"description": "Texture for defining surface normal direction. These will override normals generated from the geometry.",
|
||||
"type": "Image"
|
||||
},
|
||||
{
|
||||
"name": "flipX",
|
||||
"displayName": "Flip X Channel",
|
||||
"description": "Flip tangent direction for this normal map.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"name": "flipY",
|
||||
"displayName": "Flip Y Channel",
|
||||
"description": "Flip bitangent direction for this normal map.",
|
||||
"type": "Bool",
|
||||
"defaultValue": false
|
||||
},
|
||||
{
|
||||
"name": "factor",
|
||||
"displayName": "Factor",
|
||||
"description": "Strength factor for scaling the values",
|
||||
"type": "Float",
|
||||
"defaultValue": 1.0,
|
||||
"min": 0.0,
|
||||
"softMax": 2.0
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"shaders": [
|
||||
],
|
||||
"functors": [
|
||||
]
|
||||
}
|
||||
+95
-93
@@ -16,87 +16,65 @@
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
|
||||
#include <Atom/RPI.Public/Image/StreamingImage.h>
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
AZ::Data::AssetId TerrainMacroMaterialConfig::s_macroMaterialTypeAssetId{};
|
||||
bool TerrainMacroMaterialConfig::NormalMapAttributesAreReadOnly() const
|
||||
{
|
||||
return !m_macroNormalAsset.GetId().IsValid();
|
||||
}
|
||||
|
||||
void TerrainMacroMaterialConfig::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
if (serialize)
|
||||
if (auto* serialize = azrtti_cast<AZ::SerializeContext*>(context); serialize)
|
||||
{
|
||||
serialize->Class<TerrainMacroMaterialConfig, AZ::ComponentConfig>()
|
||||
->Version(1)
|
||||
->Field("MacroMaterial", &TerrainMacroMaterialConfig::m_materialAsset)
|
||||
;
|
||||
->Field("MacroColor", &TerrainMacroMaterialConfig::m_macroColorAsset)
|
||||
->Field("MacroNormal", &TerrainMacroMaterialConfig::m_macroNormalAsset)
|
||||
->Field("NormalFlipX", &TerrainMacroMaterialConfig::m_normalFlipX)
|
||||
->Field("NormalFlipY", &TerrainMacroMaterialConfig::m_normalFlipY)
|
||||
->Field("NormalFactor", &TerrainMacroMaterialConfig::m_normalFactor)
|
||||
;
|
||||
|
||||
// The edit context for this appears in EditorTerrainMacroMaterialComponent.cpp.
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Data::AssetId TerrainMacroMaterialConfig::GetTerrainMacroMaterialTypeAssetId()
|
||||
{
|
||||
// Get the Asset ID for the TerrainMacroMaterial material type and store it in a class static so that we don't have to look it
|
||||
// up again.
|
||||
if (!s_macroMaterialTypeAssetId.IsValid())
|
||||
{
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
s_macroMaterialTypeAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, TerrainMacroMaterialTypeAsset,
|
||||
azrtti_typeid<AZ::RPI::MaterialTypeAsset>(), false);
|
||||
AZ_Assert(s_macroMaterialTypeAssetId.IsValid(), "The asset '%s' couldn't be found.", TerrainMacroMaterialTypeAsset);
|
||||
}
|
||||
|
||||
return s_macroMaterialTypeAssetId;
|
||||
}
|
||||
|
||||
bool TerrainMacroMaterialConfig::IsMaterialTypeCorrect(const AZ::Data::AssetId& assetId)
|
||||
{
|
||||
// We'll verify that whatever material we try to load has this material type as a dependency, as a way to implicitly detect
|
||||
// that we're only trying to use terrain macro materials even before we load the asset.
|
||||
auto macroMaterialTypeAssetId = GetTerrainMacroMaterialTypeAssetId();
|
||||
|
||||
// Get the dependencies for the requested asset.
|
||||
AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> result;
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
result, &AZ::Data::AssetCatalogRequestBus::Events::GetDirectProductDependencies, assetId);
|
||||
|
||||
// If any of the dependencies match the TerrainMacroMaterial materialtype asset, then this should be the correct type of material.
|
||||
if (result)
|
||||
{
|
||||
for (auto& dependency : result.GetValue())
|
||||
if (auto* editContext = serialize->GetEditContext(); editContext)
|
||||
{
|
||||
if (dependency.m_assetId == macroMaterialTypeAssetId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
editContext
|
||||
->Class<TerrainMacroMaterialConfig>(
|
||||
"Terrain Macro Material Component", "Provide a terrain macro material for a region of the world")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_macroColorAsset, "Color Texture",
|
||||
"Terrain macro color texture for use by any terrain inside the bounding box on this entity.")
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_macroNormalAsset, "Normal Texture",
|
||||
"Texture for defining surface normal direction. These will override normals generated from the geometry.")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::AttributesAndValues)
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_normalFlipX, "Normal Flip X",
|
||||
"Flip tangent direction for this normal map.")
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &TerrainMacroMaterialConfig::NormalMapAttributesAreReadOnly)
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_normalFlipY, "Normal Flip Y",
|
||||
"Flip bitangent direction for this normal map.")
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &TerrainMacroMaterialConfig::NormalMapAttributesAreReadOnly)
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Slider, &TerrainMacroMaterialConfig::m_normalFactor, "Normal Factor",
|
||||
"Strength factor for scaling the normal map values.")
|
||||
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
|
||||
->Attribute(AZ::Edit::Attributes::Max, 10.0f)
|
||||
->Attribute(AZ::Edit::Attributes::SoftMin, 0.0f)
|
||||
->Attribute(AZ::Edit::Attributes::SoftMax, 2.0f)
|
||||
->Attribute(AZ::Edit::Attributes::ReadOnly, &TerrainMacroMaterialConfig::NormalMapAttributesAreReadOnly)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't have the expected dependency, so it must not be the right material type.
|
||||
return false;
|
||||
}
|
||||
|
||||
AZ::Outcome<void, AZStd::string> TerrainMacroMaterialConfig::ValidateMaterialAsset(void* newValue, const AZ::Uuid& valueType)
|
||||
{
|
||||
if (azrtti_typeid<AZ::Data::Asset<AZ::RPI::MaterialAsset>>() != valueType)
|
||||
{
|
||||
AZ_Assert(false, "Unexpected value type");
|
||||
return AZ::Failure(AZStd::string("Unexpectedly received something other than a material asset for the MacroMaterial!"));
|
||||
}
|
||||
|
||||
auto newMaterialAsset = *static_cast<AZ::Data::Asset<AZ::RPI::MaterialAsset>*>(newValue);
|
||||
|
||||
if (!IsMaterialTypeCorrect(newMaterialAsset.GetId()))
|
||||
{
|
||||
return AZ::Failure(AZStd::string::format(
|
||||
"The selected MacroMaterial ('%s') needs to use the TerrainMacroMaterial material type.",
|
||||
newMaterialAsset.GetHint().c_str()));
|
||||
}
|
||||
|
||||
return AZ::Success();
|
||||
}
|
||||
|
||||
|
||||
void TerrainMacroMaterialComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
|
||||
{
|
||||
services.push_back(AZ_CRC_CE("TerrainMacroMaterialProviderService"));
|
||||
@@ -133,25 +111,29 @@ namespace Terrain
|
||||
|
||||
void TerrainMacroMaterialComponent::Activate()
|
||||
{
|
||||
// Clear out our shape bounds and make sure the material is queued to load.
|
||||
// Clear out our shape bounds and make sure the texture assets are queued to load.
|
||||
m_cachedShapeBounds = AZ::Aabb::CreateNull();
|
||||
m_configuration.m_materialAsset.QueueLoad();
|
||||
m_configuration.m_macroColorAsset.QueueLoad();
|
||||
m_configuration.m_macroNormalAsset.QueueLoad();
|
||||
|
||||
// Don't mark our material as active until it's finished loading and is valid.
|
||||
m_macroMaterialActive = false;
|
||||
|
||||
// Listen for the material asset to complete loading.
|
||||
AZ::Data::AssetBus::Handler::BusConnect(m_configuration.m_materialAsset.GetId());
|
||||
// Listen for the texture assets to complete loading.
|
||||
AZ::Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_macroColorAsset.GetId());
|
||||
AZ::Data::AssetBus::MultiHandler::BusConnect(m_configuration.m_macroNormalAsset.GetId());
|
||||
}
|
||||
|
||||
void TerrainMacroMaterialComponent::Deactivate()
|
||||
{
|
||||
TerrainMacroMaterialRequestBus::Handler::BusDisconnect();
|
||||
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
m_configuration.m_materialAsset.Release();
|
||||
AZ::Data::AssetBus::MultiHandler::BusDisconnect();
|
||||
m_configuration.m_macroColorAsset.Release();
|
||||
m_configuration.m_macroNormalAsset.Release();
|
||||
|
||||
m_macroMaterialInstance.reset();
|
||||
m_colorImage.reset();
|
||||
m_normalImage.reset();
|
||||
|
||||
// Send out any notifications as appropriate based on the macro material destruction.
|
||||
HandleMaterialStateChange();
|
||||
@@ -195,12 +177,18 @@ namespace Terrain
|
||||
|
||||
void TerrainMacroMaterialComponent::HandleMaterialStateChange()
|
||||
{
|
||||
// We only want our component to appear active during the time that the macro material is loaded and valid. The logic below
|
||||
// We only want our component to appear active during the time that the macro material is fully loaded and valid. The logic below
|
||||
// will handle all transition possibilities to notify if we've become active, inactive, or just changed. We'll also only
|
||||
// keep a valid up-to-date copy of the shape bounds while the material is valid, since we don't need it any other time.
|
||||
|
||||
// Color and normal data is considered ready if it's finished loading or if we don't have a texture specified
|
||||
bool colorReady = m_colorImage || (!m_configuration.m_macroColorAsset.GetId().IsValid());
|
||||
bool normalReady = m_normalImage || (!m_configuration.m_macroNormalAsset.GetId().IsValid());
|
||||
// If we don't have color or normal data, then we don't have *any* useful data, so don't activate the macro material.
|
||||
bool hasAnyData = m_configuration.m_macroColorAsset.GetId().IsValid() || m_configuration.m_macroNormalAsset.GetId().IsValid();
|
||||
|
||||
bool wasPreviouslyActive = m_macroMaterialActive;
|
||||
bool isNowActive = (m_macroMaterialInstance != nullptr);
|
||||
bool isNowActive = colorReady && normalReady && hasAnyData;
|
||||
|
||||
// Set our state to active or inactive, based on whether or not the macro material instance is now valid.
|
||||
m_macroMaterialActive = isNowActive;
|
||||
@@ -226,9 +214,10 @@ namespace Terrain
|
||||
// Start listening for shape changes.
|
||||
LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(GetEntityId());
|
||||
|
||||
MacroMaterialData material = GetTerrainMacroMaterialData();
|
||||
|
||||
TerrainMacroMaterialNotificationBus::Broadcast(
|
||||
&TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialCreated, GetEntityId(), m_macroMaterialInstance,
|
||||
m_cachedShapeBounds);
|
||||
&TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialCreated, GetEntityId(), material);
|
||||
}
|
||||
else if (wasPreviouslyActive && !isNowActive)
|
||||
{
|
||||
@@ -246,30 +235,35 @@ namespace Terrain
|
||||
else
|
||||
{
|
||||
// We were active both before and after, so just send out a material changed event.
|
||||
MacroMaterialData material = GetTerrainMacroMaterialData();
|
||||
|
||||
TerrainMacroMaterialNotificationBus::Broadcast(
|
||||
&TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialChanged, GetEntityId(), m_macroMaterialInstance);
|
||||
&TerrainMacroMaterialNotificationBus::Events::OnTerrainMacroMaterialChanged, GetEntityId(), material);
|
||||
}
|
||||
}
|
||||
|
||||
void TerrainMacroMaterialComponent::OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset)
|
||||
{
|
||||
m_configuration.m_materialAsset = asset;
|
||||
|
||||
if (m_configuration.m_materialAsset.Get()->GetMaterialTypeAsset().GetId() ==
|
||||
TerrainMacroMaterialConfig::GetTerrainMacroMaterialTypeAssetId())
|
||||
if (asset.GetId() == m_configuration.m_macroColorAsset.GetId())
|
||||
{
|
||||
m_macroMaterialInstance = AZ::RPI::Material::FindOrCreate(m_configuration.m_materialAsset);
|
||||
m_configuration.m_macroColorAsset = asset;
|
||||
m_colorImage = AZ::RPI::StreamingImage::FindOrCreate(m_configuration.m_macroColorAsset);
|
||||
|
||||
// Clear the texture asset reference to make sure we don't prevent hot-reloading.
|
||||
m_configuration.m_macroColorAsset.Release();
|
||||
}
|
||||
else if (asset.GetId() == m_configuration.m_macroNormalAsset.GetId())
|
||||
{
|
||||
m_configuration.m_macroNormalAsset = asset;
|
||||
m_normalImage = AZ::RPI::StreamingImage::FindOrCreate(m_configuration.m_macroNormalAsset);
|
||||
|
||||
// Clear the texture asset reference to make sure we don't prevent hot-reloading.
|
||||
m_configuration.m_macroColorAsset.Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
AZ_Error("Terrain", false, "Material '%s' has the wrong material type.", m_configuration.m_materialAsset.GetHint().c_str());
|
||||
m_macroMaterialInstance.reset();
|
||||
}
|
||||
|
||||
// Clear the material asset reference to make sure we don't prevent hot-reloading.
|
||||
m_configuration.m_materialAsset.Release();
|
||||
|
||||
HandleMaterialStateChange();
|
||||
}
|
||||
|
||||
@@ -278,10 +272,18 @@ namespace Terrain
|
||||
OnAssetReady(asset);
|
||||
}
|
||||
|
||||
void TerrainMacroMaterialComponent::GetTerrainMacroMaterialData(
|
||||
AZ::Data::Instance<AZ::RPI::Material>& macroMaterial, AZ::Aabb& macroMaterialRegion)
|
||||
MacroMaterialData TerrainMacroMaterialComponent::GetTerrainMacroMaterialData()
|
||||
{
|
||||
macroMaterial = m_macroMaterialInstance;
|
||||
macroMaterialRegion = m_cachedShapeBounds;
|
||||
MacroMaterialData macroMaterial;
|
||||
|
||||
macroMaterial.m_entityId = GetEntityId();
|
||||
macroMaterial.m_bounds = m_cachedShapeBounds;
|
||||
macroMaterial.m_colorImage = m_colorImage;
|
||||
macroMaterial.m_normalImage = m_normalImage;
|
||||
macroMaterial.m_normalFactor = m_configuration.m_normalFactor;
|
||||
macroMaterial.m_normalFlipX = m_configuration.m_normalFlipX;
|
||||
macroMaterial.m_normalFlipY = m_configuration.m_normalFlipY;
|
||||
|
||||
return macroMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
+11
-14
@@ -11,10 +11,9 @@
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
|
||||
#include <LmbrCentral/Shape/ShapeComponentBus.h>
|
||||
#include <TerrainRenderer/TerrainMacroMaterialBus.h>
|
||||
|
||||
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
|
||||
|
||||
namespace LmbrCentral
|
||||
{
|
||||
@@ -32,23 +31,20 @@ namespace Terrain
|
||||
AZ_RTTI(TerrainMacroMaterialConfig, "{9DBAFFF0-FD20-4594-8884-E3266D8CCAC8}", AZ::ComponentConfig);
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
AZ::Data::Asset<AZ::RPI::MaterialAsset> m_materialAsset = { AZ::Data::AssetLoadBehavior::QueueLoad };
|
||||
|
||||
static AZ::Data::AssetId GetTerrainMacroMaterialTypeAssetId();
|
||||
static bool IsMaterialTypeCorrect(const AZ::Data::AssetId&);
|
||||
AZ::Outcome<void, AZStd::string> ValidateMaterialAsset(void* newValue, const AZ::Uuid& valueType);
|
||||
|
||||
private:
|
||||
static inline constexpr const char* TerrainMacroMaterialTypeAsset = "materials/terrain/terrainmacromaterial.azmaterialtype";
|
||||
static AZ::Data::AssetId s_macroMaterialTypeAssetId;
|
||||
bool NormalMapAttributesAreReadOnly() const;
|
||||
|
||||
AZ::Data::Asset<AZ::RPI::StreamingImageAsset> m_macroColorAsset = { AZ::Data::AssetLoadBehavior::QueueLoad };
|
||||
AZ::Data::Asset<AZ::RPI::StreamingImageAsset> m_macroNormalAsset = { AZ::Data::AssetLoadBehavior::QueueLoad };
|
||||
bool m_normalFlipX = false;
|
||||
bool m_normalFlipY = false;
|
||||
float m_normalFactor = 1.0f;
|
||||
};
|
||||
|
||||
class TerrainMacroMaterialComponent
|
||||
: public AZ::Component
|
||||
, public TerrainMacroMaterialRequestBus::Handler
|
||||
, private LmbrCentral::ShapeComponentNotificationsBus::Handler
|
||||
, private AZ::Data::AssetBus::Handler
|
||||
, private AZ::Data::AssetBus::MultiHandler
|
||||
{
|
||||
public:
|
||||
template<typename, typename>
|
||||
@@ -70,7 +66,7 @@ namespace Terrain
|
||||
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||
|
||||
void GetTerrainMacroMaterialData(AZ::Data::Instance<AZ::RPI::Material>& macroMaterial, AZ::Aabb& macroMaterialRegion) override;
|
||||
MacroMaterialData GetTerrainMacroMaterialData() override;
|
||||
|
||||
private:
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@@ -86,7 +82,8 @@ namespace Terrain
|
||||
|
||||
TerrainMacroMaterialConfig m_configuration;
|
||||
AZ::Aabb m_cachedShapeBounds;
|
||||
AZ::Data::Instance<AZ::RPI::Material> m_macroMaterialInstance;
|
||||
bool m_macroMaterialActive{ false };
|
||||
AZ::Data::Instance<AZ::RPI::Image> m_colorImage;
|
||||
AZ::Data::Instance<AZ::RPI::Image> m_normalImage;
|
||||
};
|
||||
}
|
||||
|
||||
+2
-31
@@ -17,36 +17,7 @@ namespace Terrain
|
||||
{
|
||||
BaseClassType::ReflectSubClass<EditorTerrainMacroMaterialComponent, BaseClassType>(
|
||||
context, 1,
|
||||
&LmbrCentral::EditorWrappedComponentBaseVersionConverter<typename BaseClassType::WrappedComponentType,
|
||||
typename BaseClassType::WrappedConfigType, 1>
|
||||
);
|
||||
|
||||
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
|
||||
|
||||
if (serializeContext)
|
||||
{
|
||||
AZ::EditContext* editContext = serializeContext->GetEditContext();
|
||||
|
||||
// The edit context for TerrainMacroMaterialConfig is specified here to make it easier to add custom filtering to the
|
||||
// asset picker for the material asset so that we can eventually only display materials that inherit from the proper
|
||||
// material type.
|
||||
if (editContext)
|
||||
{
|
||||
editContext
|
||||
->Class<TerrainMacroMaterialConfig>(
|
||||
"Terrain Macro Material Component", "Provide a terrain macro material for a region of the world")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly)
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &TerrainMacroMaterialConfig::m_materialAsset, "Macro Material",
|
||||
"Terrain macro material for use by any terrain inside the bounding box on this entity.")
|
||||
// This is disabled until ChangeValidate can support the Asset<T> type. :(
|
||||
//->Attribute(AZ::Edit::Attributes::ChangeValidate, &TerrainMacroMaterialConfig::ValidateMaterialAsset)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
&LmbrCentral::EditorWrappedComponentBaseVersionConverter<
|
||||
typename BaseClassType::WrappedComponentType, typename BaseClassType::WrappedConfigType, 1>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,13 +51,6 @@ namespace Terrain
|
||||
{
|
||||
// Terrain material
|
||||
static const char* const HeightmapImage("settings.heightmapImage");
|
||||
|
||||
// Macro material
|
||||
static const char* const MacroColorTextureMap("baseColor.textureMap");
|
||||
static const char* const MacroNormalTextureMap("normal.textureMap");
|
||||
static const char* const MacroNormalFlipX("normal.flipX");
|
||||
static const char* const MacroNormalFlipY("normal.flipY");
|
||||
static const char* const MacroNormalFactor("normal.factor");
|
||||
}
|
||||
|
||||
namespace ShaderInputs
|
||||
@@ -185,12 +178,11 @@ namespace Terrain
|
||||
m_areaData.m_heightmapUpdated = true;
|
||||
}
|
||||
|
||||
void TerrainFeatureProcessor::OnTerrainMacroMaterialCreated(AZ::EntityId entityId, MaterialInstance material, const AZ::Aabb& region)
|
||||
void TerrainFeatureProcessor::OnTerrainMacroMaterialCreated(AZ::EntityId entityId, const MacroMaterialData& newMaterialData)
|
||||
{
|
||||
MacroMaterialData& materialData = FindOrCreateMacroMaterial(entityId);
|
||||
materialData.m_bounds = region;
|
||||
|
||||
UpdateMacroMaterialData(materialData, material);
|
||||
UpdateMacroMaterialData(materialData, newMaterialData);
|
||||
|
||||
// Update all sectors in region.
|
||||
ForOverlappingSectors(materialData.m_bounds,
|
||||
@@ -203,20 +195,14 @@ namespace Terrain
|
||||
);
|
||||
}
|
||||
|
||||
void TerrainFeatureProcessor::OnTerrainMacroMaterialChanged(AZ::EntityId entityId, MaterialInstance macroMaterial)
|
||||
void TerrainFeatureProcessor::OnTerrainMacroMaterialChanged(AZ::EntityId entityId, const MacroMaterialData& newMaterialData)
|
||||
{
|
||||
if (macroMaterial)
|
||||
{
|
||||
MacroMaterialData& data = FindOrCreateMacroMaterial(entityId);
|
||||
UpdateMacroMaterialData(data, macroMaterial);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveMacroMaterial(entityId);
|
||||
}
|
||||
MacroMaterialData& data = FindOrCreateMacroMaterial(entityId);
|
||||
UpdateMacroMaterialData(data, newMaterialData);
|
||||
}
|
||||
|
||||
void TerrainFeatureProcessor::OnTerrainMacroMaterialRegionChanged(AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion)
|
||||
void TerrainFeatureProcessor::OnTerrainMacroMaterialRegionChanged(
|
||||
AZ::EntityId entityId, [[maybe_unused]] const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion)
|
||||
{
|
||||
MacroMaterialData& materialData = FindOrCreateMacroMaterial(entityId);
|
||||
for (SectorData& sectorData : m_sectorData)
|
||||
@@ -269,6 +255,7 @@ namespace Terrain
|
||||
}
|
||||
|
||||
m_areaData.m_macroMaterialsUpdated = true;
|
||||
RemoveMacroMaterial(entityId);
|
||||
}
|
||||
|
||||
void TerrainFeatureProcessor::UpdateTerrainData()
|
||||
@@ -382,42 +369,18 @@ namespace Terrain
|
||||
TerrainMacroMaterialRequestBus::EnumerateHandlers(
|
||||
[&](TerrainMacroMaterialRequests* handler)
|
||||
{
|
||||
MaterialInstance macroMaterial;
|
||||
AZ::Aabb bounds;
|
||||
handler->GetTerrainMacroMaterialData(macroMaterial, bounds);
|
||||
MacroMaterialData macroMaterial = handler->GetTerrainMacroMaterialData();
|
||||
AZ::EntityId entityId = *(Terrain::TerrainMacroMaterialRequestBus::GetCurrentBusId());
|
||||
OnTerrainMacroMaterialCreated(entityId, macroMaterial, bounds);
|
||||
OnTerrainMacroMaterialCreated(entityId, macroMaterial);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
TerrainMacroMaterialNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
void TerrainFeatureProcessor::UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, MaterialInstance material)
|
||||
void TerrainFeatureProcessor::UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, const MacroMaterialData& newMaterialData)
|
||||
{
|
||||
// Since we're using an actual macro material instance for now, get the values from it that we care about.
|
||||
const auto materialLayout = material->GetMaterialPropertiesLayout();
|
||||
|
||||
const AZ::RPI::MaterialPropertyIndex macroColorTextureMapIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroColorTextureMap));
|
||||
AZ_Error(TerrainFPName, macroColorTextureMapIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroColorTextureMap);
|
||||
|
||||
const AZ::RPI::MaterialPropertyIndex macroNormalTextureMapIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalTextureMap));
|
||||
AZ_Error(TerrainFPName, macroNormalTextureMapIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalTextureMap);
|
||||
|
||||
const AZ::RPI::MaterialPropertyIndex macroNormalFlipXIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalFlipX));
|
||||
AZ_Error(TerrainFPName, macroNormalFlipXIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalFlipX);
|
||||
|
||||
const AZ::RPI::MaterialPropertyIndex macroNormalFlipYIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalFlipY));
|
||||
AZ_Error(TerrainFPName, macroNormalFlipYIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalFlipY);
|
||||
|
||||
const AZ::RPI::MaterialPropertyIndex macroNormalFactorIndex = materialLayout->FindPropertyIndex(AZ::Name(MaterialInputs::MacroNormalFactor));
|
||||
AZ_Error(TerrainFPName, macroNormalFactorIndex.IsValid(), "Failed to find shader input constant %s.", MaterialInputs::MacroNormalFactor);
|
||||
|
||||
macroMaterialData.m_colorImage = material->GetPropertyValue(macroColorTextureMapIndex).GetValue<AZ::Data::Instance<AZ::RPI::Image>>();
|
||||
macroMaterialData.m_normalImage = material->GetPropertyValue(macroNormalTextureMapIndex).GetValue<AZ::Data::Instance<AZ::RPI::Image>>();
|
||||
macroMaterialData.m_normalFlipX = material->GetPropertyValue(macroNormalFlipXIndex).GetValue<bool>();
|
||||
macroMaterialData.m_normalFlipY = material->GetPropertyValue(macroNormalFlipYIndex).GetValue<bool>();
|
||||
macroMaterialData.m_normalFactor = material->GetPropertyValue(macroNormalFactorIndex).GetValue<float>();
|
||||
macroMaterialData = newMaterialData;
|
||||
|
||||
if (macroMaterialData.m_bounds.IsValid())
|
||||
{
|
||||
@@ -783,7 +746,7 @@ namespace Terrain
|
||||
// larger but this will limit how much is rendered.
|
||||
}
|
||||
|
||||
TerrainFeatureProcessor::MacroMaterialData* TerrainFeatureProcessor::FindMacroMaterial(AZ::EntityId entityId)
|
||||
MacroMaterialData* TerrainFeatureProcessor::FindMacroMaterial(AZ::EntityId entityId)
|
||||
{
|
||||
for (MacroMaterialData& data : m_macroMaterials.GetDataVector())
|
||||
{
|
||||
@@ -795,7 +758,7 @@ namespace Terrain
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TerrainFeatureProcessor::MacroMaterialData& TerrainFeatureProcessor::FindOrCreateMacroMaterial(AZ::EntityId entityId)
|
||||
MacroMaterialData& TerrainFeatureProcessor::FindOrCreateMacroMaterial(AZ::EntityId entityId)
|
||||
{
|
||||
MacroMaterialData* dataPtr = FindMacroMaterial(entityId);
|
||||
if (dataPtr != nullptr)
|
||||
|
||||
@@ -112,18 +112,6 @@ namespace Terrain
|
||||
AZStd::fixed_vector<uint16_t, MaxMaterialsPerSector> m_macroMaterials;
|
||||
};
|
||||
|
||||
struct MacroMaterialData
|
||||
{
|
||||
AZ::EntityId m_entityId;
|
||||
AZ::Aabb m_bounds = AZ::Aabb::CreateNull();
|
||||
|
||||
AZ::Data::Instance<AZ::RPI::Image> m_colorImage;
|
||||
AZ::Data::Instance<AZ::RPI::Image> m_normalImage;
|
||||
bool m_normalFlipX{ false };
|
||||
bool m_normalFlipY{ false };
|
||||
float m_normalFactor{ 0.0f };
|
||||
};
|
||||
|
||||
// AZ::RPI::MaterialReloadNotificationBus::Handler overrides...
|
||||
void OnMaterialReinitialized(const MaterialInstance& material) override;
|
||||
|
||||
@@ -132,8 +120,8 @@ namespace Terrain
|
||||
void OnTerrainDataChanged(const AZ::Aabb& dirtyRegion, TerrainDataChangedMask dataChangedMask) override;
|
||||
|
||||
// TerrainMacroMaterialNotificationBus overrides...
|
||||
void OnTerrainMacroMaterialCreated(AZ::EntityId entityId, MaterialInstance material, const AZ::Aabb& region) override;
|
||||
void OnTerrainMacroMaterialChanged(AZ::EntityId entityId, MaterialInstance material) override;
|
||||
void OnTerrainMacroMaterialCreated(AZ::EntityId entityId, const MacroMaterialData& material) override;
|
||||
void OnTerrainMacroMaterialChanged(AZ::EntityId entityId, const MacroMaterialData& material) override;
|
||||
void OnTerrainMacroMaterialRegionChanged(AZ::EntityId entityId, const AZ::Aabb& oldRegion, const AZ::Aabb& newRegion) override;
|
||||
void OnTerrainMacroMaterialDestroyed(AZ::EntityId entityId) override;
|
||||
|
||||
@@ -143,7 +131,7 @@ namespace Terrain
|
||||
|
||||
void UpdateTerrainData();
|
||||
void PrepareMaterialData();
|
||||
void UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, MaterialInstance material);
|
||||
void UpdateMacroMaterialData(MacroMaterialData& macroMaterialData, const MacroMaterialData& newMaterialData);
|
||||
|
||||
void ProcessSurfaces(const FeatureProcessor::RenderPacket& process);
|
||||
|
||||
|
||||
@@ -12,11 +12,22 @@
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
|
||||
#include <Atom/RPI.Public/Material/Material.h>
|
||||
#include <Atom/RPI.Reflect/Image/Image.h>
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
struct MacroMaterialData
|
||||
{
|
||||
AZ::EntityId m_entityId;
|
||||
AZ::Aabb m_bounds = AZ::Aabb::CreateNull();
|
||||
|
||||
AZ::Data::Instance<AZ::RPI::Image> m_colorImage;
|
||||
AZ::Data::Instance<AZ::RPI::Image> m_normalImage;
|
||||
bool m_normalFlipX{ false };
|
||||
bool m_normalFlipY{ false };
|
||||
float m_normalFactor{ 0.0f };
|
||||
};
|
||||
|
||||
/**
|
||||
* Request terrain macro material data.
|
||||
*/
|
||||
@@ -32,7 +43,7 @@ namespace Terrain
|
||||
virtual ~TerrainMacroMaterialRequests() = default;
|
||||
|
||||
// Get the terrain macro material and the region that it covers.
|
||||
virtual void GetTerrainMacroMaterialData(AZ::Data::Instance<AZ::RPI::Material>& macroMaterial, AZ::Aabb& macroMaterialRegion) = 0;
|
||||
virtual MacroMaterialData GetTerrainMacroMaterialData() = 0;
|
||||
};
|
||||
|
||||
using TerrainMacroMaterialRequestBus = AZ::EBus<TerrainMacroMaterialRequests>;
|
||||
@@ -51,14 +62,12 @@ namespace Terrain
|
||||
|
||||
virtual void OnTerrainMacroMaterialCreated(
|
||||
[[maybe_unused]] AZ::EntityId macroMaterialEntity,
|
||||
[[maybe_unused]] AZ::Data::Instance<AZ::RPI::Material> macroMaterial,
|
||||
[[maybe_unused]] const AZ::Aabb& macroMaterialRegion)
|
||||
[[maybe_unused]] const MacroMaterialData& macroMaterial)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void OnTerrainMacroMaterialChanged(
|
||||
[[maybe_unused]] AZ::EntityId macroMaterialEntity,
|
||||
[[maybe_unused]] AZ::Data::Instance<AZ::RPI::Material> macroMaterial)
|
||||
[[maybe_unused]] AZ::EntityId macroMaterialEntity, [[maybe_unused]] const MacroMaterialData& macroMaterial)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
ly_install_directory(
|
||||
DIRECTORIES
|
||||
AssetGem
|
||||
CustomTool
|
||||
PythonGem
|
||||
DefaultGem
|
||||
DefaultProject
|
||||
MinimalProject
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# {BEGIN_LICENSE}
|
||||
# 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
|
||||
#
|
||||
# {END_LICENSE}
|
||||
|
||||
set(o3de_gem_path ${CMAKE_CURRENT_LIST_DIR})
|
||||
set(o3de_gem_json ${o3de_gem_path}/gem.json)
|
||||
o3de_read_json_key(o3de_gem_name ${o3de_gem_json} "gem_name")
|
||||
o3de_restricted_path(${o3de_gem_json} o3de_gem_restricted_path)
|
||||
|
||||
add_subdirectory(Code)
|
||||
@@ -0,0 +1,14 @@
|
||||
# {BEGIN_LICENSE}
|
||||
# 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
|
||||
#
|
||||
# {END_LICENSE}
|
||||
|
||||
set(FILES
|
||||
Include/${Name}/${Name}Bus.h
|
||||
Source/${Name}ModuleInterface.h
|
||||
Source/${Name}EditorSystemComponent.cpp
|
||||
Source/${Name}EditorSystemComponent.h
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# {BEGIN_LICENSE}
|
||||
# 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
|
||||
#
|
||||
# {END_LICENSE}
|
||||
|
||||
set(FILES
|
||||
Source/${Name}EditorModule.cpp
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# {BEGIN_LICENSE}
|
||||
# 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
|
||||
#
|
||||
# {END_LICENSE}
|
||||
|
||||
set(FILES
|
||||
Tests/${Name}EditorTest.cpp
|
||||
)
|
||||
@@ -0,0 +1,76 @@
|
||||
# {BEGIN_LICENSE}
|
||||
# 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
|
||||
#
|
||||
# {END_LICENSE}
|
||||
|
||||
# Currently we are in the Code folder: ${CMAKE_CURRENT_LIST_DIR}
|
||||
# Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}
|
||||
# Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform
|
||||
# in which case it will see if that platform is present here or in the restricted folder.
|
||||
# i.e. It could here in our gem : Gems/${Name}/Code/Platform/<platorm_name> or
|
||||
# <restricted_folder>/<platform_name>/Gems/${Name}/Code
|
||||
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name})
|
||||
|
||||
# Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the
|
||||
# traits for this platform. Traits for a platform are defines for things like whether or not something in this gem
|
||||
# is supported by this platform.
|
||||
include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake)
|
||||
|
||||
|
||||
# If we are on a host platform, we want to add the host tools targets like the ${Name}.Editor target which
|
||||
# will also depend on ${Name}.Static
|
||||
if(PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
ly_add_target(
|
||||
NAME ${Name}.Editor.Static STATIC
|
||||
NAMESPACE Gem
|
||||
FILES_CMAKE
|
||||
${NameLower}_editor_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Source
|
||||
PUBLIC
|
||||
Include
|
||||
BUILD_DEPENDENCIES
|
||||
PUBLIC
|
||||
AZ::AzToolsFramework
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME ${Name}.Editor GEM_MODULE
|
||||
NAMESPACE Gem
|
||||
AUTOMOC
|
||||
FILES_CMAKE
|
||||
${NameLower}_editor_shared_files.cmake
|
||||
INCLUDE_DIRECTORIES
|
||||
PRIVATE
|
||||
Source
|
||||
PUBLIC
|
||||
Include
|
||||
BUILD_DEPENDENCIES
|
||||
PUBLIC
|
||||
Gem::${Name}.Editor.Static
|
||||
)
|
||||
|
||||
# By default, we will specify that the above target ${Name} would be used by
|
||||
# Tool and Builder type targets when this gem is enabled. If you don't want it
|
||||
# active in Tools or Builders by default, delete one of both of the following lines:
|
||||
ly_create_alias(NAME ${Name}.Tools NAMESPACE Gem TARGETS Gem::${Name}.Editor)
|
||||
ly_create_alias(NAME ${Name}.Builders NAMESPACE Gem TARGETS Gem::${Name}.Editor)
|
||||
|
||||
|
||||
endif()
|
||||
|
||||
################################################################################
|
||||
# Tests
|
||||
################################################################################
|
||||
# See if globally, tests are supported
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
# We globally support tests, see if we support tests on this platform for ${Name}.Static
|
||||
|
||||
# If we are a host platform we want to add tools test like editor tests here
|
||||
if(PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,40 @@
|
||||
// {BEGIN_LICENSE}
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
// {END_LICENSE}
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Interface/Interface.h>
|
||||
|
||||
namespace ${SanitizedCppName}
|
||||
{
|
||||
class ${SanitizedCppName}Requests
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(${SanitizedCppName}Requests, "{${Random_Uuid}}");
|
||||
virtual ~${SanitizedCppName}Requests() = default;
|
||||
// Put your public methods here
|
||||
};
|
||||
|
||||
class ${SanitizedCppName}BusTraits
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits overrides
|
||||
static constexpr AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
static constexpr AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
};
|
||||
|
||||
using ${SanitizedCppName}RequestBus = AZ::EBus<${SanitizedCppName}Requests, ${SanitizedCppName}BusTraits>;
|
||||
using ${SanitizedCppName}Interface = AZ::Interface<${SanitizedCppName}Requests>;
|
||||
|
||||
} // namespace ${SanitizedCppName}
|
||||
@@ -0,0 +1,15 @@
|
||||
# {BEGIN_LICENSE}
|
||||
# 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
|
||||
#
|
||||
# {END_LICENSE}
|
||||
|
||||
# Platform specific files for Linux
|
||||
# i.e. ../Source/Linux/${Name}Linux.cpp
|
||||
# ../Source/Linux/${Name}Linux.h
|
||||
# ../Include/Linux/${Name}Linux.h
|
||||
|
||||
set(FILES
|
||||
)
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# {BEGIN_LICENSE}
|
||||
# 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
|
||||
#
|
||||
# {END_LICENSE}
|
||||
|
||||
# Platform specific files for Linux
|
||||
# i.e. ../Source/Linux/${Name}Linux.cpp
|
||||
# ../Source/Linux/${Name}Linux.h
|
||||
# ../Include/Linux/${Name}Linux.h
|
||||
|
||||
set(FILES
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
# {BEGIN_LICENSE}
|
||||
# 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
|
||||
#
|
||||
# {END_LICENSE}
|
||||
|
||||
set(PAL_TRAIT_${NameUpper}_SUPPORTED TRUE)
|
||||
set(PAL_TRAIT_${NameUpper}_TEST_SUPPORTED TRUE)
|
||||
set(PAL_TRAIT_${NameUpper}_EDITOR_TEST_SUPPORTED TRUE)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user