Merge branch 'development' into cmake/SPEC-2513_w4267
This commit is contained in:
@@ -212,10 +212,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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2771,6 +2771,80 @@
|
||||
<source>VECTOR2_CREATEONE_OUTPUT0_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_NAME">
|
||||
<source>VECTOR2_DIRECTIONTO_NAME</source>
|
||||
<comment>Class/Bus: Vector2 Event/Method: DirectionTo</comment>
|
||||
<translation type="unfinished">Get Direction Vector</translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_TOOLTIP">
|
||||
<source>VECTOR2_DIRECTIONTO_TOOLTIP</source>
|
||||
<translation>Returns a direction vector between two points and the distance between them, by default the direction will be normalized, it may be optionally scaled using the Scale parameter if different from 1.0</translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_CATEGORY">
|
||||
<source>VECTOR2_DIRECTIONTO_CATEGORY</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_OUT_NAME">
|
||||
<source>VECTOR2_DIRECTIONTO_OUT_NAME</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_OUT_TOOLTIP">
|
||||
<source>VECTOR2_DIRECTIONTO_OUT_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTOL_IN_NAME">
|
||||
<source>VECTOR2_DIRECTIONTOL_IN_NAME</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_IN_TOOLTIP">
|
||||
<source>VECTOR2_DIRECTIONTO_IN_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_OUTPUT0_NAME">
|
||||
<source>VECTOR2_DIRECTIONTO_OUTPUT0_NAME</source>
|
||||
<comment>C++ Type: const Vector2</comment>
|
||||
<translation type="unfinished">Direction</translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_OUTPUT0_TOOLTIP">
|
||||
<source>VECTOR2_DIRECTIONTO_OUTPUT0_TOOLTIP</source>
|
||||
<translation>The direction between To and From normalized and optionally scaled</translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_OUTPUT1_NAME">
|
||||
<source>VECTOR2_DIRECTIONTO_OUTPUT1_NAME</source>
|
||||
<comment>C++ Type: float</comment>
|
||||
<translation type="unfinished">Distance</translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_OUTPUT1_TOOLTIP">
|
||||
<source>VECTOR2_DIRECTIONTO_OUTPUT1_TOOLTIP</source>
|
||||
<translation>The distance between To and From</translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_PARAM0_NAME">
|
||||
<source>VECTOR2_DIRECTIONTO_PARAM0_NAME</source>
|
||||
<comment>Simple Type: Vector2 C++ Type: Vector2*</comment>
|
||||
<translation type="unfinished">From</translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_PARAM0_TOOLTIP">
|
||||
<source>VECTOR2_DIRECTIONTO_PARAM0_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_PARAM1_NAME">
|
||||
<source>VECTOR2_DIRECTIONTO_PARAM1_NAME</source>
|
||||
<comment>Simple Type: Vector2 C++ Type: Vector2*</comment>
|
||||
<translation type="unfinished">To</translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_PARAM1_TOOLTIP">
|
||||
<source>VECTOR2_DIRECTIONTO_PARAM1_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_PARAM2_NAME">
|
||||
<source>VECTOR2_DIRECTIONTO_PARAM2_NAME</source>
|
||||
<comment>Simple Type: Vector2 C++ Type: Vector2*</comment>
|
||||
<translation type="unfinished">Scale</translation>
|
||||
</message>
|
||||
<message id="VECTOR2_DIRECTIONTO_PARAM2_TOOLTIP">
|
||||
<source>VECTOR2_DIRECTIONTO_PARAM2_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR2_GETPROJECTED_NAME">
|
||||
<source>VECTOR2_GETPROJECTED_NAME</source>
|
||||
<comment>Class/Bus: Vector2 Event/Method: GetProjected</comment>
|
||||
@@ -32262,6 +32336,80 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro
|
||||
<source>VECTOR4_GETRECIPROCAL_PARAM0_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_NAME">
|
||||
<source>VECTOR4_DIRECTIONTO_NAME</source>
|
||||
<comment>Class/Bus: Vector4 Event/Method: DirectionTo</comment>
|
||||
<translation type="unfinished">Get Direction Vector</translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_TOOLTIP">
|
||||
<source>VECTOR4_DIRECTIONTO_TOOLTIP</source>
|
||||
<translation>Returns a direction vector between two points and the distance between them, by default the direction will be normalized, it may be optionally scaled using the Scale parameter if different from 1.0</translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_CATEGORY">
|
||||
<source>VECTOR4_DIRECTIONTO_CATEGORY</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_OUT_NAME">
|
||||
<source>VECTOR4_DIRECTIONTO_OUT_NAME</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_OUT_TOOLTIP">
|
||||
<source>VECTOR4_DIRECTIONTO_OUT_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTOL_IN_NAME">
|
||||
<source>VECTOR4_DIRECTIONTOL_IN_NAME</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_IN_TOOLTIP">
|
||||
<source>VECTOR4_DIRECTIONTO_IN_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_OUTPUT0_NAME">
|
||||
<source>VECTOR4_DIRECTIONTO_OUTPUT0_NAME</source>
|
||||
<comment>C++ Type: const Vector4</comment>
|
||||
<translation type="unfinished">Direction</translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_OUTPUT0_TOOLTIP">
|
||||
<source>VECTOR4_DIRECTIONTO_OUTPUT0_TOOLTIP</source>
|
||||
<translation>The direction between To and From normalized and optionally scaled</translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_OUTPUT1_NAME">
|
||||
<source>VECTOR4_DIRECTIONTO_OUTPUT1_NAME</source>
|
||||
<comment>C++ Type: float</comment>
|
||||
<translation type="unfinished">Distance</translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_OUTPUT1_TOOLTIP">
|
||||
<source>VECTOR4_DIRECTIONTO_OUTPUT1_TOOLTIP</source>
|
||||
<translation>The distance between To and From</translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_PARAM0_NAME">
|
||||
<source>VECTOR4_DIRECTIONTO_PARAM0_NAME</source>
|
||||
<comment>Simple Type: Vector4 C++ Type: Vector4*</comment>
|
||||
<translation type="unfinished">From</translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_PARAM0_TOOLTIP">
|
||||
<source>VECTOR4_DIRECTIONTO_PARAM0_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_PARAM1_NAME">
|
||||
<source>VECTOR4_DIRECTIONTO_PARAM1_NAME</source>
|
||||
<comment>Simple Type: Vector4 C++ Type: Vector4*</comment>
|
||||
<translation type="unfinished">To</translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_PARAM1_TOOLTIP">
|
||||
<source>VECTOR4_DIRECTIONTO_PARAM1_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_PARAM2_NAME">
|
||||
<source>VECTOR4_DIRECTIONTO_PARAM2_NAME</source>
|
||||
<comment>Simple Type: Vector4 C++ Type: Vector4*</comment>
|
||||
<translation type="unfinished">Scale</translation>
|
||||
</message>
|
||||
<message id="VECTOR4_DIRECTIONTO_PARAM2_TOOLTIP">
|
||||
<source>VECTOR4_DIRECTIONTO_PARAM2_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR4_AXISX_NAME">
|
||||
<source>VECTOR4_AXISX_NAME</source>
|
||||
<comment>Class/Bus: Vector4 Event/Method: CreateAxisX</comment>
|
||||
@@ -37469,6 +37617,80 @@ An Entity can be selected by using the pick button, or by dragging an Entity fro
|
||||
<source>VECTOR3_GETRECIPROCAL_PARAM0_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_NAME">
|
||||
<source>VECTOR3_DIRECTIONTO_NAME</source>
|
||||
<comment>Class/Bus: Vector3 Event/Method: DirectionTo</comment>
|
||||
<translation type="unfinished">Get Direction Vector</translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_TOOLTIP">
|
||||
<source>VECTOR3_DIRECTIONTO_TOOLTIP</source>
|
||||
<translation>Returns a direction vector between two points and the distance between them, by default the direction will be normalized, it may be optionally scaled using the Scale parameter if different from 1.0</translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_CATEGORY">
|
||||
<source>VECTOR3_DIRECTIONTO_CATEGORY</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_OUT_NAME">
|
||||
<source>VECTOR3_DIRECTIONTO_OUT_NAME</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_OUT_TOOLTIP">
|
||||
<source>VECTOR3_DIRECTIONTO_OUT_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTOL_IN_NAME">
|
||||
<source>VECTOR3_DIRECTIONTOL_IN_NAME</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_IN_TOOLTIP">
|
||||
<source>VECTOR3_DIRECTIONTO_IN_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_OUTPUT0_NAME">
|
||||
<source>VECTOR3_DIRECTIONTO_OUTPUT0_NAME</source>
|
||||
<comment>C++ Type: const Vector3</comment>
|
||||
<translation type="unfinished">Direction</translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_OUTPUT0_TOOLTIP">
|
||||
<source>VECTOR3_DIRECTIONTO_OUTPUT0_TOOLTIP</source>
|
||||
<translation>The direction between To and From normalized and optionally scaled</translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_OUTPUT1_NAME">
|
||||
<source>VECTOR3_DIRECTIONTO_OUTPUT1_NAME</source>
|
||||
<comment>C++ Type: float</comment>
|
||||
<translation type="unfinished">Distance</translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_OUTPUT1_TOOLTIP">
|
||||
<source>VECTOR3_DIRECTIONTO_OUTPUT1_TOOLTIP</source>
|
||||
<translation>The distance between To and From</translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_PARAM0_NAME">
|
||||
<source>VECTOR3_DIRECTIONTO_PARAM0_NAME</source>
|
||||
<comment>Simple Type: Vector3 C++ Type: Vector3*</comment>
|
||||
<translation type="unfinished">From</translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_PARAM0_TOOLTIP">
|
||||
<source>VECTOR3_DIRECTIONTO_PARAM0_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_PARAM1_NAME">
|
||||
<source>VECTOR3_DIRECTIONTO_PARAM1_NAME</source>
|
||||
<comment>Simple Type: Vector3 C++ Type: Vector3*</comment>
|
||||
<translation type="unfinished">To</translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_PARAM1_TOOLTIP">
|
||||
<source>VECTOR3_DIRECTIONTO_PARAM1_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_PARAM2_NAME">
|
||||
<source>VECTOR3_DIRECTIONTO_PARAM2_NAME</source>
|
||||
<comment>Simple Type: Vector3 C++ Type: Vector3*</comment>
|
||||
<translation type="unfinished">Scale</translation>
|
||||
</message>
|
||||
<message id="VECTOR3_DIRECTIONTO_PARAM2_TOOLTIP">
|
||||
<source>VECTOR3_DIRECTIONTO_PARAM2_TOOLTIP</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message id="VECTOR3_PROJECT_NAME">
|
||||
<source>VECTOR3_PROJECT_NAME</source>
|
||||
<comment>Class/Bus: Vector3 Event/Method: Project</comment>
|
||||
|
||||
@@ -97,7 +97,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/asset_bundler_batch_tests.py
|
||||
EXCLUDE_TEST_RUN_TARGET_FROM_IDE
|
||||
TEST_SERIAL
|
||||
TIMEOUT 1500
|
||||
TIMEOUT 2400
|
||||
TEST_SUITE periodic
|
||||
RUNTIME_DEPENDENCIES
|
||||
AZ::AssetProcessor
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ class TestsAssetBuilder_WindowsAndMac(object):
|
||||
if listening_port:
|
||||
corrupted_slice_command.append(f'-port={listening_port}')
|
||||
if workspace.project:
|
||||
corrupted_slice_command.append(f'-gamename={workspace.project}')
|
||||
corrupted_slice_command.append(f'--project-path={workspace.project}')
|
||||
corrupted_slice_output = utils.safe_subprocess(corrupted_slice_command)
|
||||
|
||||
# Verify corrupted slice produced error
|
||||
|
||||
+7
-2
@@ -902,7 +902,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
second_input_arg = asset_lists_to_string(second_asset_list) # --secondAssetList
|
||||
output_arg = asset_lists_to_string(output_file) # --output
|
||||
|
||||
def generate_compare_command(platform_arg: str) -> object:
|
||||
def generate_compare_command(platform_arg: str, project_name : str) -> object:
|
||||
"""Creates a string containing a full Compare command. This string can be executed as-is."""
|
||||
cmd = [helper["bundler_batch"], "compare", f"--firstassetFile={first_input_arg}", f"--output={output_arg}"]
|
||||
if platform_arg is not None:
|
||||
@@ -918,6 +918,8 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
if comp_type == "4":
|
||||
# Extra arguments for pattern comparison
|
||||
cmd.extend([f"--filePatternType={pattern_type}", f"--filePattern={pattern}"])
|
||||
if workspace.project:
|
||||
cmd.append(f'--project-path={project_name}')
|
||||
return cmd
|
||||
# End generate_compare_command()
|
||||
|
||||
@@ -936,6 +938,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
# End verify_asset_list_contents()
|
||||
|
||||
def run_compare_command_and_verify(platform_arg: str, expect_pc_output: bool, expect_mac_output: bool) -> None:
|
||||
|
||||
# Expected asset list to equal result of comparison
|
||||
expected_pc_asset_list = None
|
||||
expected_mac_asset_list = None
|
||||
@@ -957,7 +960,7 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
output_mac_asset_list = helper.platform_file_name(last_output_arg, platform)
|
||||
|
||||
# Build execution command
|
||||
cmd = generate_compare_command(platform_arg)
|
||||
cmd = generate_compare_command(platform_arg, workspace.project)
|
||||
|
||||
# Execute command
|
||||
subprocess.check_call(cmd)
|
||||
@@ -992,10 +995,12 @@ class TestsAssetBundlerBatch_WindowsAndMac(object):
|
||||
f"--comparisonRulesFile={rule_file}",
|
||||
f"--comparisonType={args[1]}",
|
||||
r"--addComparison",
|
||||
f"--project-path={workspace.project}",
|
||||
]
|
||||
if args[1] == "4":
|
||||
# If pattern comparison, append a few extra arguments
|
||||
cmd.extend(["--filePatternType=0", "--filePattern=*.dat"])
|
||||
|
||||
subprocess.check_call(cmd)
|
||||
assert os.path.exists(rule_file), f"Rule file {args[0]} was not created at location: {rule_file}"
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
|
||||
TEST_SUITE main
|
||||
PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_MainSuite.py
|
||||
TEST_SERIAL
|
||||
TIMEOUT 400
|
||||
TIMEOUT 600
|
||||
RUNTIME_DEPENDENCIES
|
||||
AssetProcessor
|
||||
AutomatedTesting.Assets
|
||||
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
"""
|
||||
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
|
||||
|
||||
Hydra script that creates an entity, attaches the Light component to it for test verifications.
|
||||
The test verifies that each light type option is available and can be selected without errors.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.math as math
|
||||
import azlmbr.paths
|
||||
import azlmbr.legacy.general as general
|
||||
|
||||
sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
|
||||
|
||||
import editor_python_test_tools.hydra_editor_utils as hydra
|
||||
from atom_renderer.atom_utils.atom_component_helper import LIGHT_TYPES
|
||||
|
||||
LIGHT_TYPE_PROPERTY = 'Controller|Configuration|Light type'
|
||||
SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES = [
|
||||
("Controller|Configuration|Shadows|Enable shadow", True),
|
||||
("Controller|Configuration|Shadows|Shadowmap size", 0), # 256
|
||||
("Controller|Configuration|Shadows|Shadowmap size", 1), # 512
|
||||
("Controller|Configuration|Shadows|Shadowmap size", 2), # 1024
|
||||
("Controller|Configuration|Shadows|Shadowmap size", 3), # 2048
|
||||
("Controller|Configuration|Shadows|Shadow filter method", 1), # PCF
|
||||
("Controller|Configuration|Shadows|Filtering sample count", 4.0),
|
||||
("Controller|Configuration|Shadows|Filtering sample count", 64.0),
|
||||
("Controller|Configuration|Shadows|PCF method", 0), # Bicubic
|
||||
("Controller|Configuration|Shadows|PCF method", 1), # Boundary search
|
||||
("Controller|Configuration|Shadows|Shadow filter method", 2), # ECM
|
||||
("Controller|Configuration|Shadows|ESM exponent", 50),
|
||||
("Controller|Configuration|Shadows|ESM exponent", 5000),
|
||||
("Controller|Configuration|Shadows|Shadow filter method", 3), # ESM+PCF
|
||||
]
|
||||
QUAD_LIGHT_PROPERTIES = [
|
||||
("Controller|Configuration|Both directions", True),
|
||||
("Controller|Configuration|Fast approximation", True),
|
||||
]
|
||||
SIMPLE_POINT_LIGHT_PROPERTIES = [
|
||||
("Controller|Configuration|Attenuation radius|Mode", 0),
|
||||
("Controller|Configuration|Attenuation radius|Radius", 100.0),
|
||||
]
|
||||
SIMPLE_SPOT_LIGHT_PROPERTIES = [
|
||||
("Controller|Configuration|Shutters|Inner angle", 45.0),
|
||||
("Controller|Configuration|Shutters|Outer angle", 90.0),
|
||||
]
|
||||
|
||||
|
||||
def verify_required_component_property_value(entity_name, component, property_path, expected_property_value):
|
||||
"""
|
||||
Compares the property value of component against the expected_property_value.
|
||||
:param entity_name: name of the entity to use (for test verification purposes).
|
||||
:param component: component to check on a given entity for its current property value.
|
||||
:param property_path: the path to the property inside the component.
|
||||
:param expected_property_value: The value expected from the value inside property_path.
|
||||
:return: None, but prints to general.log() which the test uses to verify against.
|
||||
"""
|
||||
property_value = editor.EditorComponentAPIBus(
|
||||
bus.Broadcast, "GetComponentProperty", component, property_path).GetValue()
|
||||
general.log(f"{entity_name}_test: Property value is {property_value} "
|
||||
f"which matches {expected_property_value}")
|
||||
|
||||
|
||||
def run():
|
||||
"""
|
||||
Test Case - Light Component
|
||||
1. Creates a "light_entity" Entity and attaches a "Light" component to it.
|
||||
2. Updates the Light component to each light type option from the LIGHT_TYPES constant.
|
||||
3. The test will check the Editor log to ensure each light type was selected.
|
||||
4. Prints the string "Light component test (non-GPU) completed" after completion.
|
||||
|
||||
Tests will fail immediately if any of these log lines are found:
|
||||
1. Trace::Assert
|
||||
2. Trace::Error
|
||||
3. Traceback (most recent call last):
|
||||
|
||||
:return: None
|
||||
"""
|
||||
# Create a "light_entity" entity with "Light" component.
|
||||
light_entity_name = "light_entity"
|
||||
light_component = "Light"
|
||||
light_entity = hydra.Entity(light_entity_name)
|
||||
light_entity.create_entity(math.Vector3(-1.0, -2.0, 3.0), [light_component])
|
||||
general.log(
|
||||
f"{light_entity_name}_test: Component added to the entity: "
|
||||
f"{hydra.has_components(light_entity.id, [light_component])}")
|
||||
|
||||
# Populate the light_component_id_pair value so that it can be used to select all Light component options.
|
||||
light_component_id_pair = None
|
||||
component_type_id_list = azlmbr.editor.EditorComponentAPIBus(
|
||||
azlmbr.bus.Broadcast, 'FindComponentTypeIdsByEntityType', [light_component], 0)
|
||||
if len(component_type_id_list) < 1:
|
||||
general.log(f"ERROR: A component class with name {light_component} doesn't exist")
|
||||
light_component_id_pair = None
|
||||
elif len(component_type_id_list) > 1:
|
||||
general.log(f"ERROR: Found more than one component classes with same name: {light_component}")
|
||||
light_component_id_pair = None
|
||||
entity_component_id_pair = azlmbr.editor.EditorComponentAPIBus(
|
||||
azlmbr.bus.Broadcast, 'GetComponentOfType', light_entity.id, component_type_id_list[0])
|
||||
if entity_component_id_pair.IsSuccess():
|
||||
light_component_id_pair = entity_component_id_pair.GetValue()
|
||||
|
||||
# Test each Light component option can be selected and it's properties updated.
|
||||
# Point (sphere) light type checks.
|
||||
light_type_property_test(
|
||||
light_type=LIGHT_TYPES['sphere'],
|
||||
light_properties=SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES,
|
||||
light_component_id_pair=light_component_id_pair,
|
||||
light_entity_name=light_entity_name,
|
||||
light_entity=light_entity
|
||||
)
|
||||
|
||||
# Spot (disk) light type checks.
|
||||
light_type_property_test(
|
||||
light_type=LIGHT_TYPES['spot_disk'],
|
||||
light_properties=SPHERE_AND_SPOT_DISK_LIGHT_PROPERTIES,
|
||||
light_component_id_pair=light_component_id_pair,
|
||||
light_entity_name=light_entity_name,
|
||||
light_entity=light_entity
|
||||
)
|
||||
|
||||
# Capsule light type checks.
|
||||
azlmbr.editor.EditorComponentAPIBus(
|
||||
azlmbr.bus.Broadcast,
|
||||
'SetComponentProperty',
|
||||
light_component_id_pair,
|
||||
LIGHT_TYPE_PROPERTY,
|
||||
LIGHT_TYPES['capsule']
|
||||
)
|
||||
verify_required_component_property_value(
|
||||
entity_name=light_entity_name,
|
||||
component=light_entity.components[0],
|
||||
property_path=LIGHT_TYPE_PROPERTY,
|
||||
expected_property_value=LIGHT_TYPES['capsule']
|
||||
)
|
||||
|
||||
# Quad light type checks.
|
||||
light_type_property_test(
|
||||
light_type=LIGHT_TYPES['quad'],
|
||||
light_properties=QUAD_LIGHT_PROPERTIES,
|
||||
light_component_id_pair=light_component_id_pair,
|
||||
light_entity_name=light_entity_name,
|
||||
light_entity=light_entity
|
||||
)
|
||||
|
||||
# Polygon light type checks.
|
||||
azlmbr.editor.EditorComponentAPIBus(
|
||||
azlmbr.bus.Broadcast,
|
||||
'SetComponentProperty',
|
||||
light_component_id_pair,
|
||||
LIGHT_TYPE_PROPERTY,
|
||||
LIGHT_TYPES['polygon']
|
||||
)
|
||||
verify_required_component_property_value(
|
||||
entity_name=light_entity_name,
|
||||
component=light_entity.components[0],
|
||||
property_path=LIGHT_TYPE_PROPERTY,
|
||||
expected_property_value=LIGHT_TYPES['polygon']
|
||||
)
|
||||
|
||||
# Point (simple punctual) light type checks.
|
||||
light_type_property_test(
|
||||
light_type=LIGHT_TYPES['simple_point'],
|
||||
light_properties=SIMPLE_POINT_LIGHT_PROPERTIES,
|
||||
light_component_id_pair=light_component_id_pair,
|
||||
light_entity_name=light_entity_name,
|
||||
light_entity=light_entity
|
||||
)
|
||||
|
||||
# Spot (simple punctual) light type checks.
|
||||
light_type_property_test(
|
||||
light_type=LIGHT_TYPES['simple_spot'],
|
||||
light_properties=SIMPLE_SPOT_LIGHT_PROPERTIES,
|
||||
light_component_id_pair=light_component_id_pair,
|
||||
light_entity_name=light_entity_name,
|
||||
light_entity=light_entity
|
||||
)
|
||||
|
||||
general.log("Light component test (non-GPU) completed.")
|
||||
|
||||
|
||||
def light_type_property_test(light_type, light_properties, light_component_id_pair, light_entity_name, light_entity):
|
||||
"""
|
||||
Updates the current light type and modifies its properties, then verifies they are accurate to what was set.
|
||||
:param light_type: The type of light to update, must match a value in LIGHT_TYPES
|
||||
:param light_properties: List of tuples detailing properties to modify with update values.
|
||||
:param light_component_id_pair: Entity + component ID pair for updating the light component on a given entity.
|
||||
:param light_entity_name: the name of the Entity holding the light component.
|
||||
:param light_entity: the Entity object containing the light component.
|
||||
:return: None
|
||||
"""
|
||||
azlmbr.editor.EditorComponentAPIBus(
|
||||
azlmbr.bus.Broadcast,
|
||||
'SetComponentProperty',
|
||||
light_component_id_pair,
|
||||
LIGHT_TYPE_PROPERTY,
|
||||
light_type
|
||||
)
|
||||
verify_required_component_property_value(
|
||||
entity_name=light_entity_name,
|
||||
component=light_entity.components[0],
|
||||
property_path=LIGHT_TYPE_PROPERTY,
|
||||
expected_property_value=light_type
|
||||
)
|
||||
|
||||
for light_property in light_properties:
|
||||
light_entity.get_set_test(0, light_property[0], light_property[1])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
@@ -0,0 +1,19 @@
|
||||
"""
|
||||
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
|
||||
|
||||
File to assist with common hydra component functions or constants used across various Atom tests.
|
||||
"""
|
||||
|
||||
# Light type options for the Light component.
|
||||
LIGHT_TYPES = {
|
||||
'unknown': 0,
|
||||
'sphere': 1,
|
||||
'spot_disk': 2,
|
||||
'capsule': 3,
|
||||
'quad': 4,
|
||||
'polygon': 5,
|
||||
'simple_point': 6,
|
||||
'simple_spot': 7,
|
||||
}
|
||||
@@ -12,9 +12,10 @@ import os
|
||||
import pytest
|
||||
|
||||
import editor_python_test_tools.hydra_test_utils as hydra
|
||||
from atom_renderer.atom_utils.atom_component_helper import LIGHT_TYPES
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
EDITOR_TIMEOUT = 300
|
||||
EDITOR_TIMEOUT = 120
|
||||
TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts")
|
||||
|
||||
|
||||
@@ -180,3 +181,64 @@ class TestAtomEditorComponentsMain(object):
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
|
||||
def test_AtomEditorComponents_LightComponent(
|
||||
self, request, editor, workspace, project, launcher_platform, level):
|
||||
"""
|
||||
Please review the hydra script run by this test for more specific test info.
|
||||
Tests that the Light component has the expected property options available to it.
|
||||
"""
|
||||
cfg_args = [level]
|
||||
|
||||
expected_lines = [
|
||||
"light_entity Entity successfully created",
|
||||
"Entity has a Light component",
|
||||
"light_entity_test: Component added to the entity: True",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['sphere']} which matches {LIGHT_TYPES['sphere']}",
|
||||
"Controller|Configuration|Shadows|Enable shadow set to True",
|
||||
"light_entity Controller|Configuration|Shadows|Shadowmap size: SUCCESS",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 1", # PCF
|
||||
"Controller|Configuration|Shadows|Filtering sample count set to 4",
|
||||
"Controller|Configuration|Shadows|Filtering sample count set to 64",
|
||||
"Controller|Configuration|Shadows|PCF method set to 0",
|
||||
"Controller|Configuration|Shadows|PCF method set to 1",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 2", # ESM
|
||||
"Controller|Configuration|Shadows|ESM exponent set to 50.0",
|
||||
"Controller|Configuration|Shadows|ESM exponent set to 5000.0",
|
||||
"Controller|Configuration|Shadows|Shadow filter method set to 3", # ESM+PCF
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['spot_disk']} which matches {LIGHT_TYPES['spot_disk']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['capsule']} which matches {LIGHT_TYPES['capsule']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['quad']} which matches {LIGHT_TYPES['quad']}",
|
||||
"light_entity Controller|Configuration|Fast approximation: SUCCESS",
|
||||
"light_entity Controller|Configuration|Both directions: SUCCESS",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['polygon']} which matches {LIGHT_TYPES['polygon']}",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['simple_point']} "
|
||||
f"which matches {LIGHT_TYPES['simple_point']}",
|
||||
"Controller|Configuration|Attenuation radius|Mode set to 0",
|
||||
"Controller|Configuration|Attenuation radius|Radius set to 100.0",
|
||||
f"light_entity_test: Property value is {LIGHT_TYPES['simple_spot']} "
|
||||
f"which matches {LIGHT_TYPES['simple_spot']}",
|
||||
"Controller|Configuration|Shutters|Outer angle set to 45.0",
|
||||
"Controller|Configuration|Shutters|Outer angle set to 90.0",
|
||||
"light_entity_test: Component added to the entity: True",
|
||||
"Light component test (non-GPU) completed.",
|
||||
]
|
||||
|
||||
unexpected_lines = [
|
||||
"Trace::Assert",
|
||||
"Trace::Error",
|
||||
"Traceback (most recent call last):",
|
||||
]
|
||||
|
||||
hydra.launch_and_validate_results(
|
||||
request,
|
||||
TEST_DIRECTORY,
|
||||
editor,
|
||||
"hydra_AtomEditorComponents_LightComponent.py",
|
||||
timeout=EDITOR_TIMEOUT,
|
||||
expected_lines=expected_lines,
|
||||
unexpected_lines=unexpected_lines,
|
||||
halt_on_unexpected=True,
|
||||
null_renderer=True,
|
||||
cfg_args=cfg_args,
|
||||
)
|
||||
|
||||
+3
-2
@@ -64,7 +64,8 @@ def C15096740_Material_LibraryUpdatedCorrectly():
|
||||
|
||||
# Constants
|
||||
library_property_path = "Configuration|Physics Material|Library"
|
||||
default_material_path = "surfacetypemateriallibrary.physmaterial"
|
||||
|
||||
default_material_path = os.path.join("assets", "physics", "surfacetypemateriallibrary.physmaterial")
|
||||
new_material_path = os.path.join("physicssurfaces", "default_phys_materials.physmaterial")
|
||||
|
||||
helper.init_idle()
|
||||
@@ -82,7 +83,7 @@ def C15096740_Material_LibraryUpdatedCorrectly():
|
||||
default_asset = Asset.find_asset_by_path(default_material_path)
|
||||
test_component.set_component_property_value(library_property_path, default_asset.id)
|
||||
default_asset.id = test_component.get_component_property_value(library_property_path)
|
||||
Report.result(Tests.override_default_library, default_asset.get_path() == default_material_path)
|
||||
Report.result(Tests.override_default_library, default_asset.get_path() == default_material_path.replace(os.sep, '/'))
|
||||
|
||||
# 4) Switch it back again to the default material library.
|
||||
test_component.set_component_property_value(library_property_path, azasset.AssetId())
|
||||
|
||||
@@ -133,7 +133,7 @@ class Physmaterial_Editor:
|
||||
def _set_path(self):
|
||||
# type: (str) -> str
|
||||
if self.document_filename == None:
|
||||
self.document_filename = os.path.join(self.project_folder, "surfacetypemateriallibrary.physmaterial")
|
||||
self.document_filename = os.path.join(self.project_folder, "assets", "physics", "surfacetypemateriallibrary.physmaterial")
|
||||
else:
|
||||
for (root, directories, root_files) in os.walk(self.project_folder):
|
||||
for root_file in root_files:
|
||||
|
||||
@@ -0,0 +1,483 @@
|
||||
{
|
||||
"Type": "JsonSerialization",
|
||||
"Version": 1,
|
||||
"ClassName": "PassAsset",
|
||||
"ClassData": {
|
||||
"PassTemplate": {
|
||||
"Name": "MainPipeline",
|
||||
"PassClass": "ParentPass",
|
||||
"Slots": [
|
||||
{
|
||||
"Name": "SwapChainOutput",
|
||||
"SlotType": "InputOutput",
|
||||
"ScopeAttachmentUsage": "RenderTarget"
|
||||
}
|
||||
],
|
||||
"PassRequests": [
|
||||
{
|
||||
"Name": "MorphTargetPass",
|
||||
"TemplateName": "MorphTargetPassTemplate"
|
||||
},
|
||||
{
|
||||
"Name": "SkinningPass",
|
||||
"TemplateName": "SkinningPassTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "SkinnedMeshOutputStream",
|
||||
"AttachmentRef": {
|
||||
"Pass": "MorphTargetPass",
|
||||
"Attachment": "MorphTargetDeltaOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "RayTracingAccelerationStructurePass",
|
||||
"TemplateName": "RayTracingAccelerationStructurePassTemplate"
|
||||
},
|
||||
{
|
||||
"Name": "DiffuseProbeGridUpdatePass",
|
||||
"TemplateName": "DiffuseProbeGridUpdatePassTemplate",
|
||||
"ExecuteAfter": [
|
||||
"RayTracingAccelerationStructurePass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "DepthPrePass",
|
||||
"TemplateName": "DepthMSAAParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "SkinnedMeshes",
|
||||
"AttachmentRef": {
|
||||
"Pass": "SkinningPass",
|
||||
"Attachment": "SkinnedMeshOutputStream"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MotionVectorPass",
|
||||
"TemplateName": "MotionVectorParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "SkinnedMeshes",
|
||||
"AttachmentRef": {
|
||||
"Pass": "SkinningPass",
|
||||
"Attachment": "SkinnedMeshOutputStream"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "Depth",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "LightCullingPass",
|
||||
"TemplateName": "LightCullingParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "SkinnedMeshes",
|
||||
"AttachmentRef": {
|
||||
"Pass": "SkinningPass",
|
||||
"Attachment": "SkinnedMeshOutputStream"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthMSAA",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "DepthMSAA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ShadowPass",
|
||||
"TemplateName": "ShadowParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "SkinnedMeshes",
|
||||
"AttachmentRef": {
|
||||
"Pass": "SkinningPass",
|
||||
"Attachment": "SkinnedMeshOutputStream"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "OpaquePass",
|
||||
"TemplateName": "OpaqueParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "DirectionalShadowmap",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "DirectionalShadowmap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DirectionalESM",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "DirectionalESM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "ProjectedShadowmap",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "ProjectedShadowmap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "ProjectedESM",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "ProjectedESM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "TileLightData",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LightCullingPass",
|
||||
"Attachment": "TileLightData"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "LightListRemapped",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LightCullingPass",
|
||||
"Attachment": "LightListRemapped"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthLinear",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "DepthLinear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthStencil",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "DepthMSAA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "TransparentPass",
|
||||
"TemplateName": "TransparentParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "DirectionalShadowmap",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "DirectionalShadowmap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DirectionalESM",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "DirectionalESM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "ProjectedShadowmap",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "ProjectedShadowmap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "ProjectedESM",
|
||||
"AttachmentRef": {
|
||||
"Pass": "ShadowPass",
|
||||
"Attachment": "ProjectedESM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "TileLightData",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LightCullingPass",
|
||||
"Attachment": "TileLightData"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "LightListRemapped",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LightCullingPass",
|
||||
"Attachment": "LightListRemapped"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "InputLinearDepth",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "DepthLinear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthStencil",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "InputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "OpaquePass",
|
||||
"Attachment": "Output"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "DeferredFogPass",
|
||||
"TemplateName": "DeferredFogPassTemplate",
|
||||
"Enabled": false,
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "InputLinearDepth",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "DepthLinear"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "InputDepthStencil",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "RenderTargetInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "TransparentPass",
|
||||
"Attachment": "InputOutput"
|
||||
}
|
||||
}
|
||||
],
|
||||
"PassData": {
|
||||
"$type": "FullscreenTrianglePassData",
|
||||
"ShaderAsset": {
|
||||
"FilePath": "Shaders/ScreenSpace/DeferredFog.shader"
|
||||
},
|
||||
"PipelineViewTag": "MainCamera"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "ReflectionCopyFrameBufferPass",
|
||||
"TemplateName": "ReflectionCopyFrameBufferPassTemplate",
|
||||
"Enabled": false,
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "Input",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DeferredFogPass",
|
||||
"Attachment": "RenderTargetInputOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "PostProcessPass",
|
||||
"TemplateName": "PostProcessParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "LightingInput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DeferredFogPass",
|
||||
"Attachment": "RenderTargetInputOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "Depth",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "MotionVectors",
|
||||
"AttachmentRef": {
|
||||
"Pass": "MotionVectorPass",
|
||||
"Attachment": "MotionVectorOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "SwapChainOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AuxGeomPass",
|
||||
"TemplateName": "AuxGeomPassTemplate",
|
||||
"Enabled": true,
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "ColorInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "PostProcessPass",
|
||||
"Attachment": "Output"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
}
|
||||
],
|
||||
"PassData": {
|
||||
"$type": "RasterPassData",
|
||||
"DrawListTag": "auxgeom",
|
||||
"PipelineViewTag": "MainCamera"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Name": "DebugOverlayPass",
|
||||
"TemplateName": "DebugOverlayParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "TileLightData",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LightCullingPass",
|
||||
"Attachment": "TileLightData"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "RawLightingInput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "PostProcessPass",
|
||||
"Attachment": "RawLightingOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "LuminanceMipChainInput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "PostProcessPass",
|
||||
"Attachment": "LuminanceMipChainOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "InputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "AuxGeomPass",
|
||||
"Attachment": "ColorInputOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "LyShinePass",
|
||||
"TemplateName": "LyShineParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "ColorInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DebugOverlayPass",
|
||||
"Attachment": "InputOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "UIPass",
|
||||
"TemplateName": "UIParentTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "InputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "LyShinePass",
|
||||
"Attachment": "ColorInputOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "DepthInputOutput",
|
||||
"AttachmentRef": {
|
||||
"Pass": "DepthPrePass",
|
||||
"Attachment": "Depth"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "CopyToSwapChain",
|
||||
"TemplateName": "FullscreenCopyTemplate",
|
||||
"Connections": [
|
||||
{
|
||||
"LocalSlot": "Input",
|
||||
"AttachmentRef": {
|
||||
"Pass": "UIPass",
|
||||
"Attachment": "InputOutput"
|
||||
}
|
||||
},
|
||||
{
|
||||
"LocalSlot": "Output",
|
||||
"AttachmentRef": {
|
||||
"Pass": "Parent",
|
||||
"Attachment": "SwapChainOutput"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,9 +121,10 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}"
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
},
|
||||
"assetHint": "surfacetypemateriallibrary.physmaterial"
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,9 +109,10 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}"
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
},
|
||||
"assetHint": "surfacetypemateriallibrary.physmaterial"
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -121,9 +121,10 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}"
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
},
|
||||
"assetHint": "surfacetypemateriallibrary.physmaterial"
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,9 +121,10 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}"
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
},
|
||||
"assetHint": "surfacetypemateriallibrary.physmaterial"
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,9 +121,10 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}"
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
},
|
||||
"assetHint": "surfacetypemateriallibrary.physmaterial"
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,9 +103,10 @@
|
||||
},
|
||||
"MaterialLibrary": {
|
||||
"assetId": {
|
||||
"guid": "{3A055A3F-8CB7-5FEE-B437-EB365FACD0D4}"
|
||||
"guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
|
||||
},
|
||||
"assetHint": "surfacetypemateriallibrary.physmaterial"
|
||||
"loadBehavior": "QueueLoad",
|
||||
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,6 +338,8 @@ CConsoleSCB::CConsoleSCB(QWidget* parent)
|
||||
connect(findPreviousAction, &QAction::triggered, this, &CConsoleSCB::findPrevious);
|
||||
ui->findPrevButton->addAction(findPreviousAction);
|
||||
|
||||
GetIEditor()->RegisterNotifyListener(this);
|
||||
|
||||
connect(ui->button, &QPushButton::clicked, this, &CConsoleSCB::showVariableEditor);
|
||||
connect(ui->findButton, &QPushButton::clicked, this, &CConsoleSCB::toggleConsoleSearch);
|
||||
connect(ui->textEdit, &ConsoleTextEdit::searchBarRequested, this, [this]
|
||||
@@ -376,6 +378,8 @@ CConsoleSCB::~CConsoleSCB()
|
||||
{
|
||||
AzToolsFramework::EditorPreferencesNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
GetIEditor()->UnregisterNotifyListener(this);
|
||||
|
||||
s_consoleSCB = nullptr;
|
||||
CLogFile::AttachEditBox(nullptr);
|
||||
}
|
||||
@@ -1352,4 +1356,19 @@ CConsoleSCB* CConsoleSCB::GetCreatedInstance()
|
||||
return s_consoleSCB;
|
||||
}
|
||||
|
||||
void CConsoleSCB::OnEditorNotifyEvent(EEditorNotifyEvent event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case eNotify_OnBeginGameMode:
|
||||
if (gSettings.clearConsoleOnGameModeStart)
|
||||
{
|
||||
ui->textEdit->clear();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#include <Controls/moc_ConsoleSCB.cpp>
|
||||
|
||||
@@ -159,6 +159,7 @@ private:
|
||||
class CConsoleSCB
|
||||
: public QWidget
|
||||
, private AzToolsFramework::EditorPreferencesNotificationBus::Handler
|
||||
, public IEditorNotifyListener
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -187,6 +188,8 @@ private Q_SLOTS:
|
||||
void findNext();
|
||||
|
||||
private:
|
||||
void OnEditorNotifyEvent(EEditorNotifyEvent event) override;
|
||||
|
||||
QScopedPointer<Ui::Console> ui;
|
||||
int m_richEditTextLength;
|
||||
|
||||
|
||||
@@ -544,12 +544,12 @@ void LevelEditorMenuHandler::PopulateEditMenu(ActionManager::MenuWrapper& editMe
|
||||
|
||||
auto snapMenu = modifyMenu.AddMenu(tr("Snap"));
|
||||
|
||||
snapMenu.AddAction(ID_SNAPANGLE);
|
||||
snapMenu.AddAction(AzToolsFramework::SnapAngle);
|
||||
|
||||
auto transformModeMenu = modifyMenu.AddMenu(tr("Transform Mode"));
|
||||
transformModeMenu.AddAction(ID_EDITMODE_MOVE);
|
||||
transformModeMenu.AddAction(ID_EDITMODE_ROTATE);
|
||||
transformModeMenu.AddAction(ID_EDITMODE_SCALE);
|
||||
transformModeMenu.AddAction(AzToolsFramework::EditModeMove);
|
||||
transformModeMenu.AddAction(AzToolsFramework::EditModeRotate);
|
||||
transformModeMenu.AddAction(AzToolsFramework::EditModeScale);
|
||||
|
||||
editMenu.AddSeparator();
|
||||
|
||||
|
||||
+8
-73
@@ -375,9 +375,6 @@ void CCryEditApp::RegisterActionHandlers()
|
||||
});
|
||||
ON_COMMAND(ID_MOVE_OBJECT, OnMoveObject)
|
||||
ON_COMMAND(ID_RENAME_OBJ, OnRenameObj)
|
||||
ON_COMMAND(ID_EDITMODE_MOVE, OnEditmodeMove)
|
||||
ON_COMMAND(ID_EDITMODE_ROTATE, OnEditmodeRotate)
|
||||
ON_COMMAND(ID_EDITMODE_SCALE, OnEditmodeScale)
|
||||
ON_COMMAND(ID_UNDO, OnUndo)
|
||||
ON_COMMAND(ID_TOOLBAR_WIDGET_REDO, OnUndo) // Can't use the same ID, because for the menu we can't have a QWidgetAction, while for the toolbar we want one
|
||||
ON_COMMAND(ID_IMPORT_ASSET, OnOpenAssetImporter)
|
||||
@@ -2579,75 +2576,6 @@ void CCryEditApp::OnRenameObj()
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCryEditApp::OnEditmodeMove()
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
EditorTransformComponentSelectionRequestBus::Event(
|
||||
GetEntityContextId(),
|
||||
&EditorTransformComponentSelectionRequests::SetTransformMode,
|
||||
EditorTransformComponentSelectionRequests::Mode::Translation);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCryEditApp::OnEditmodeRotate()
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
EditorTransformComponentSelectionRequestBus::Event(
|
||||
GetEntityContextId(),
|
||||
&EditorTransformComponentSelectionRequests::SetTransformMode,
|
||||
EditorTransformComponentSelectionRequests::Mode::Rotation);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCryEditApp::OnEditmodeScale()
|
||||
{
|
||||
using namespace AzToolsFramework;
|
||||
EditorTransformComponentSelectionRequestBus::Event(
|
||||
GetEntityContextId(),
|
||||
&EditorTransformComponentSelectionRequests::SetTransformMode,
|
||||
EditorTransformComponentSelectionRequests::Mode::Scale);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCryEditApp::OnUpdateEditmodeMove(QAction* action)
|
||||
{
|
||||
Q_ASSERT(action->isCheckable());
|
||||
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode;
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
mode, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode);
|
||||
|
||||
action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Translation);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCryEditApp::OnUpdateEditmodeRotate(QAction* action)
|
||||
{
|
||||
Q_ASSERT(action->isCheckable());
|
||||
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode;
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
mode, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode);
|
||||
|
||||
action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Rotation);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void CCryEditApp::OnUpdateEditmodeScale(QAction* action)
|
||||
{
|
||||
Q_ASSERT(action->isCheckable());
|
||||
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode;
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
mode, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode);
|
||||
|
||||
action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Scale);
|
||||
}
|
||||
|
||||
void CCryEditApp::OnViewSwitchToGame()
|
||||
{
|
||||
if (IsInPreviewMode())
|
||||
@@ -2901,7 +2829,14 @@ void CCryEditApp::OpenProjectManager(const AZStd::string& screen)
|
||||
{
|
||||
// provide the current project path for in case we want to update the project
|
||||
AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath();
|
||||
const AZStd::string commandLineOptions = AZStd::string::format(" --screen %s --project-path %s", screen.c_str(), projectPath.c_str());
|
||||
#if !AZ_TRAIT_OS_PLATFORM_APPLE && !AZ_TRAIT_OS_USE_WINDOWS_FILE_PATHS
|
||||
const char* argumentQuoteString = R"(")";
|
||||
#else
|
||||
const char* argumentQuoteString = R"(\")";
|
||||
#endif
|
||||
const AZStd::string commandLineOptions = AZStd::string::format(R"( --screen %s --project-path %s%s%s)",
|
||||
screen.c_str(),
|
||||
argumentQuoteString, projectPath.c_str(), argumentQuoteString);
|
||||
bool launchSuccess = AzFramework::ProjectManager::LaunchProjectManager(commandLineOptions);
|
||||
if (!launchSuccess)
|
||||
{
|
||||
|
||||
@@ -208,12 +208,6 @@ public:
|
||||
void DeleteSelectedEntities(bool includeDescendants);
|
||||
void OnMoveObject();
|
||||
void OnRenameObj();
|
||||
void OnEditmodeMove();
|
||||
void OnEditmodeRotate();
|
||||
void OnEditmodeScale();
|
||||
void OnUpdateEditmodeMove(QAction* action);
|
||||
void OnUpdateEditmodeRotate(QAction* action);
|
||||
void OnUpdateEditmodeScale(QAction* action);
|
||||
void OnUndo();
|
||||
void OnOpenAssetImporter();
|
||||
void OnUpdateSelected(QAction* action);
|
||||
|
||||
+63
-84
@@ -108,21 +108,12 @@ namespace Internal
|
||||
// CCryEditDoc construction/destruction
|
||||
|
||||
CCryEditDoc::CCryEditDoc()
|
||||
: doc_validate_surface_types(0)
|
||||
: doc_validate_surface_types(nullptr)
|
||||
, m_modifiedModuleFlags(eModifiedNothing)
|
||||
// It assumes loaded levels have already been exported. Can be a big fat lie, though.
|
||||
// The right way would require us to save to the level folder the export status of the
|
||||
// level.
|
||||
, m_boLevelExported(true)
|
||||
, m_modified(false)
|
||||
, m_envProbeHeight(200.0f)
|
||||
, m_envProbeSliceRelativePath("EngineAssets/Slices/DefaultLevelSetup.slice")
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Set member variables to initial values
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
m_bLoadFailed = false;
|
||||
m_waterColor = QColor(0, 0, 255);
|
||||
|
||||
m_fogTemplate = GetIEditor()->FindTemplate("Fog");
|
||||
m_environmentTemplate = GetIEditor()->FindTemplate("Environment");
|
||||
@@ -136,7 +127,6 @@ CCryEditDoc::CCryEditDoc()
|
||||
m_environmentTemplate = XmlHelpers::CreateXmlNode("Environment");
|
||||
}
|
||||
|
||||
m_bDocumentReady = false;
|
||||
GetIEditor()->SetDocument(this);
|
||||
CLogFile::WriteLine("Document created");
|
||||
RegisterConsoleVariables();
|
||||
@@ -195,7 +185,7 @@ CCryEditDoc::DocumentEditingMode CCryEditDoc::GetEditMode() const
|
||||
|
||||
QString CCryEditDoc::GetActivePathName() const
|
||||
{
|
||||
return DocumentEditingMode() == CCryEditDoc::DocumentEditingMode::SliceEdit ? GetSlicePathName() : GetLevelPathName();
|
||||
return GetEditMode() == CCryEditDoc::DocumentEditingMode::SliceEdit ? GetSlicePathName() : GetLevelPathName();
|
||||
}
|
||||
|
||||
QString CCryEditDoc::GetTitle() const
|
||||
@@ -260,9 +250,9 @@ void CCryEditDoc::DeleteContents()
|
||||
GetIEditor()->FlushUndo();
|
||||
|
||||
// Notify listeners.
|
||||
for (std::list<IDocListener*>::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
|
||||
for (IDocListener* listener : m_listeners)
|
||||
{
|
||||
(*it)->OnCloseDocument();
|
||||
listener->OnCloseDocument();
|
||||
}
|
||||
|
||||
GetIEditor()->ResetViews();
|
||||
@@ -458,7 +448,7 @@ void CCryEditDoc::Load(TDocMultiArchive& arrXmlAr, const QString& szFilename)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Load water color.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
(*arrXmlAr[DMAS_GENERAL]).root->getAttr("WaterColor", m_waterColor);
|
||||
(*arrXmlAr[DMAS_GENERAL]).root->getAttr("WaterColor", m_waterColor);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Load View Settings
|
||||
@@ -507,9 +497,9 @@ void CCryEditDoc::Load(TDocMultiArchive& arrXmlAr, const QString& szFilename)
|
||||
CAutoLogTime logtime("Post Load");
|
||||
|
||||
// Notify listeners.
|
||||
for (std::list<IDocListener*>::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
|
||||
for (IDocListener* listener : m_listeners)
|
||||
{
|
||||
(*it)->OnLoadDocument();
|
||||
listener->OnLoadDocument();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -708,7 +698,8 @@ bool CCryEditDoc::SaveModified()
|
||||
return true;
|
||||
}
|
||||
|
||||
auto button = QMessageBox::question(AzToolsFramework::GetActiveWindow(), QString(), tr("Save changes to %1?").arg(GetTitle()), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
auto button = QMessageBox::question(AzToolsFramework::GetActiveWindow(), QString(), tr("Save changes to %1?").arg(GetTitle()),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
switch (button)
|
||||
{
|
||||
case QMessageBox::Cancel:
|
||||
@@ -933,8 +924,7 @@ bool CCryEditDoc::OnSaveDocument(const QString& lpszPathName)
|
||||
}
|
||||
|
||||
TSaveDocContext context;
|
||||
if (shouldSaveLevel &&
|
||||
BeforeSaveDocument(lpszPathName, context))
|
||||
if (shouldSaveLevel && BeforeSaveDocument(lpszPathName, context))
|
||||
{
|
||||
DoSaveDocument(lpszPathName, context);
|
||||
saveSuccess = AfterSaveDocument(lpszPathName, context);
|
||||
@@ -972,7 +962,7 @@ bool CCryEditDoc::BeforeSaveDocument(const QString& lpszPathName, TSaveDocContex
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool CCryEditDoc::HasLayerNameConflicts()
|
||||
bool CCryEditDoc::HasLayerNameConflicts() const
|
||||
{
|
||||
AZStd::vector<AZ::Entity*> editorEntities;
|
||||
AzToolsFramework::EditorEntityContextRequestBus::Broadcast(
|
||||
@@ -1004,43 +994,42 @@ bool CCryEditDoc::HasLayerNameConflicts()
|
||||
bool CCryEditDoc::DoSaveDocument(const QString& filename, TSaveDocContext& context)
|
||||
{
|
||||
bool& bSaved = context.bSaved;
|
||||
if (bSaved)
|
||||
if (!bSaved)
|
||||
{
|
||||
// Paranoia - we shouldn't get this far into the save routine without a level loaded (empty levelPath)
|
||||
// If nothing is loaded, we don't need to save anything
|
||||
if (filename.isEmpty())
|
||||
{
|
||||
bSaved = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save Tag Point locations to file if auto save of tag points disabled
|
||||
if (!gSettings.bAutoSaveTagPoints)
|
||||
{
|
||||
CCryEditApp::instance()->SaveTagLocations();
|
||||
}
|
||||
|
||||
QString normalizedPath = Path::ToUnixPath(filename);
|
||||
if (IsSliceFile(normalizedPath))
|
||||
{
|
||||
bSaved = SaveSlice(normalizedPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
bSaved = SaveLevel(normalizedPath);
|
||||
}
|
||||
|
||||
// Changes filename for this document.
|
||||
SetPathName(normalizedPath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Paranoia - we shouldn't get this far into the save routine without a level loaded (empty levelPath)
|
||||
// If nothing is loaded, we don't need to save anything
|
||||
if (filename.isEmpty())
|
||||
{
|
||||
bSaved = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save Tag Point locations to file if auto save of tag points disabled
|
||||
if (!gSettings.bAutoSaveTagPoints)
|
||||
{
|
||||
CCryEditApp::instance()->SaveTagLocations();
|
||||
}
|
||||
|
||||
QString normalizedPath = Path::ToUnixPath(filename);
|
||||
if (IsSliceFile(normalizedPath))
|
||||
{
|
||||
bSaved = SaveSlice(normalizedPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
bSaved = SaveLevel(normalizedPath);
|
||||
}
|
||||
|
||||
// Changes filename for this document.
|
||||
SetPathName(normalizedPath);
|
||||
return bSaved;
|
||||
}
|
||||
|
||||
bool CCryEditDoc::AfterSaveDocument([[maybe_unused]] const QString& lpszPathName, TSaveDocContext& context, bool bShowPrompt)
|
||||
{
|
||||
bool& bSaved = context.bSaved;
|
||||
bool bSaved = context.bSaved;
|
||||
|
||||
GetIEditor()->Notify(eNotify_OnEndSceneSave);
|
||||
|
||||
@@ -1067,8 +1056,7 @@ bool CCryEditDoc::AfterSaveDocument([[maybe_unused]] const QString& lpszPathName
|
||||
static void GetUserSettingsFile(const QString& levelFolder, QString& userSettings)
|
||||
{
|
||||
const char* pUserName = GetISystem()->GetUserName();
|
||||
QString fileName;
|
||||
fileName = QStringLiteral("%1_usersettings.editor_xml").arg(pUserName);
|
||||
QString fileName = QStringLiteral("%1_usersettings.editor_xml").arg(pUserName);
|
||||
userSettings = Path::Make(levelFolder, fileName);
|
||||
}
|
||||
|
||||
@@ -1182,9 +1170,9 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
|
||||
}
|
||||
|
||||
QString oldFilePath = QDir(oldLevelFolder).absoluteFilePath(sourceName);
|
||||
QString newFilePath = QDir(newLevelFolder).absoluteFilePath(sourceName);
|
||||
QString newFilePath = QDir(newLevelFolder).absoluteFilePath(destName);
|
||||
CFileUtil::CopyFile(oldFilePath, newFilePath);
|
||||
} while (findHandle = pIPak->FindNext(findHandle));
|
||||
} while ((findHandle = pIPak->FindNext(findHandle)));
|
||||
pIPak->FindClose(findHandle);
|
||||
}
|
||||
|
||||
@@ -1506,7 +1494,7 @@ bool CCryEditDoc::LoadEntitiesFromLevel(const QString& levelPakFile)
|
||||
{
|
||||
AZStd::vector<char> fileBuffer;
|
||||
fileBuffer.resize(entitiesFile.GetLength());
|
||||
if (fileBuffer.size() > 0)
|
||||
if (!fileBuffer.empty())
|
||||
{
|
||||
if (fileBuffer.size() == entitiesFile.ReadRaw(fileBuffer.begin(), fileBuffer.size()))
|
||||
{
|
||||
@@ -1910,7 +1898,7 @@ void CCryEditDoc::UnregisterListener(IDocListener* listener)
|
||||
m_listeners.remove(listener);
|
||||
}
|
||||
|
||||
void CCryEditDoc::LogLoadTime(int time)
|
||||
void CCryEditDoc::LogLoadTime(int time) const
|
||||
{
|
||||
QString appFilePath = QDir::toNativeSeparators(QCoreApplication::applicationFilePath());
|
||||
QString exePath = Path::GetPath(appFilePath);
|
||||
@@ -1922,21 +1910,18 @@ void CCryEditDoc::LogLoadTime(int time)
|
||||
SetFileAttributes(filename.toUtf8().data(), FILE_ATTRIBUTE_ARCHIVE);
|
||||
#endif
|
||||
|
||||
FILE* file = nullptr;
|
||||
azfopen(&file, filename.toUtf8().data(), "at");
|
||||
|
||||
if (file)
|
||||
QFile file(filename);
|
||||
if (!file.open(QFile::Append | QFile::Text))
|
||||
{
|
||||
char version[50];
|
||||
GetIEditor()->GetFileVersion().ToShortString(version, AZ_ARRAY_SIZE(version));
|
||||
|
||||
QString text;
|
||||
|
||||
time = time / 1000;
|
||||
text = QStringLiteral("\n[%1] Level %2 loaded in %3 seconds").arg(version, level).arg(time);
|
||||
fwrite(text.toUtf8().data(), text.toUtf8().length(), 1, file);
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
char version[50];
|
||||
GetIEditor()->GetFileVersion().ToShortString(version, AZ_ARRAY_SIZE(version));
|
||||
|
||||
time = time / 1000;
|
||||
QString text = QStringLiteral("\n[%1] Level %2 loaded in %3 seconds").arg(version, level).arg(time);
|
||||
file.write(text.toUtf8());
|
||||
}
|
||||
|
||||
void CCryEditDoc::SetDocumentReady(bool bReady)
|
||||
@@ -1944,7 +1929,7 @@ void CCryEditDoc::SetDocumentReady(bool bReady)
|
||||
m_bDocumentReady = bReady;
|
||||
}
|
||||
|
||||
void CCryEditDoc::GetMemoryUsage(ICrySizer* pSizer)
|
||||
void CCryEditDoc::GetMemoryUsage(ICrySizer* pSizer) const
|
||||
{
|
||||
{
|
||||
SIZER_COMPONENT_NAME(pSizer, "UndoManager(estimate)");
|
||||
@@ -2068,12 +2053,9 @@ void CCryEditDoc::InitEmptyLevel(int /*resolution*/, int /*unitSize*/, bool /*bU
|
||||
{
|
||||
// Notify listeners.
|
||||
std::list<IDocListener*> listeners = m_listeners;
|
||||
std::list<IDocListener*>::iterator it, next;
|
||||
for (it = listeners.begin(); it != listeners.end(); it = next)
|
||||
for (IDocListener* listener : listeners)
|
||||
{
|
||||
next = it;
|
||||
next++;
|
||||
(*it)->OnNewDocument();
|
||||
listener->OnNewDocument();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2134,25 +2116,23 @@ void CCryEditDoc::OnEnvironmentPropertyChanged(IVariable* pVar)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QString childValue;
|
||||
|
||||
if (pVar->GetDataType() == IVariable::DT_COLOR)
|
||||
{
|
||||
Vec3 value;
|
||||
pVar->Get(value);
|
||||
QString buff;
|
||||
QColor gammaColor = ColorLinearToGamma(ColorF(value.x, value.y, value.z));
|
||||
buff = QStringLiteral("%1,%2,%3").arg(gammaColor.red()).arg(gammaColor.green()).arg(gammaColor.blue());
|
||||
childNode->setAttr("value", buff.toUtf8().data());
|
||||
childValue = QStringLiteral("%1,%2,%3").arg(gammaColor.red()).arg(gammaColor.green()).arg(gammaColor.blue());
|
||||
}
|
||||
else
|
||||
{
|
||||
QString value;
|
||||
pVar->Get(value);
|
||||
childNode->setAttr("value", value.toUtf8().data());
|
||||
pVar->Get(childValue);
|
||||
}
|
||||
childNode->setAttr("value", childValue.toUtf8().data());
|
||||
}
|
||||
|
||||
QString CCryEditDoc::GetCryIndexPath(const LPCTSTR levelFilePath)
|
||||
QString CCryEditDoc::GetCryIndexPath(const LPCTSTR levelFilePath) const
|
||||
{
|
||||
QString levelPath = Path::GetPath(levelFilePath);
|
||||
QString levelName = Path::GetFileName(levelFilePath);
|
||||
@@ -2183,8 +2163,7 @@ BOOL CCryEditDoc::LoadXmlArchiveArray(TDocMultiArchive& arrXmlAr, const QString&
|
||||
}
|
||||
|
||||
CPakFile pakFile;
|
||||
bool loadFromPakSuccess;
|
||||
loadFromPakSuccess = xmlAr.LoadFromPak(levelPath, pakFile);
|
||||
bool loadFromPakSuccess = xmlAr.LoadFromPak(levelPath, pakFile);
|
||||
pIPak->ClosePack(absoluteLevelPath.toUtf8().data());
|
||||
if (!loadFromPakSuccess)
|
||||
{
|
||||
|
||||
+16
-14
@@ -91,7 +91,7 @@ public: // Create from serialization only
|
||||
// ClassWizard generated virtual function overrides
|
||||
virtual bool OnOpenDocument(const QString& lpszPathName);
|
||||
|
||||
const bool IsLevelLoadFailed() const { return m_bLoadFailed; }
|
||||
bool IsLevelLoadFailed() const { return m_bLoadFailed; }
|
||||
|
||||
//! Marks this document as having errors.
|
||||
void SetHasErrors() { m_hasErrors = true; }
|
||||
@@ -121,7 +121,7 @@ public: // Create from serialization only
|
||||
|
||||
CClouds* GetClouds() { return m_pClouds; }
|
||||
void SetWaterColor(const QColor& col) { m_waterColor = col; }
|
||||
QColor GetWaterColor() { return m_waterColor; }
|
||||
QColor GetWaterColor() const { return m_waterColor; }
|
||||
XmlNodeRef& GetFogTemplate() { return m_fogTemplate; }
|
||||
XmlNodeRef& GetEnvironmentTemplate() { return m_environmentTemplate; }
|
||||
void OnEnvironmentPropertyChanged(IVariable* pVar);
|
||||
@@ -129,7 +129,7 @@ public: // Create from serialization only
|
||||
void RegisterListener(IDocListener* listener);
|
||||
void UnregisterListener(IDocListener* listener);
|
||||
|
||||
void GetMemoryUsage(ICrySizer* pSizer);
|
||||
void GetMemoryUsage(ICrySizer* pSizer) const;
|
||||
|
||||
static bool IsBackupOrTempLevelSubdirectory(const QString& folderName);
|
||||
protected:
|
||||
@@ -161,14 +161,14 @@ protected:
|
||||
void SerializeFogSettings(CXmlArchive& xmlAr);
|
||||
virtual void SerializeViewSettings(CXmlArchive& xmlAr);
|
||||
void SerializeNameSelection(CXmlArchive& xmlAr);
|
||||
void LogLoadTime(int time);
|
||||
void LogLoadTime(int time) const;
|
||||
|
||||
struct TSaveDocContext
|
||||
{
|
||||
bool bSaved;
|
||||
};
|
||||
bool BeforeSaveDocument(const QString& lpszPathName, TSaveDocContext& context);
|
||||
bool HasLayerNameConflicts();
|
||||
bool HasLayerNameConflicts() const;
|
||||
bool DoSaveDocument(const QString& lpszPathName, TSaveDocContext& context);
|
||||
bool AfterSaveDocument(const QString& lpszPathName, TSaveDocContext& context, bool bShowPrompt = true);
|
||||
|
||||
@@ -180,7 +180,7 @@ protected:
|
||||
void OnStartLevelResourceList();
|
||||
static void OnValidateSurfaceTypesChanged(ICVar*);
|
||||
|
||||
QString GetCryIndexPath(const LPCTSTR levelFilePath);
|
||||
QString GetCryIndexPath(const LPCTSTR levelFilePath) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SliceEditorEntityOwnershipServiceNotificationBus::Handler
|
||||
@@ -188,24 +188,26 @@ protected:
|
||||
void OnSliceInstantiationFailed(const AZ::Data::AssetId& sliceAssetId, const AzFramework::SliceInstantiationTicket& /*ticket*/) override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool m_bLoadFailed;
|
||||
QColor m_waterColor;
|
||||
bool m_bLoadFailed = false;
|
||||
QColor m_waterColor = QColor(0, 0, 255);
|
||||
XmlNodeRef m_fogTemplate;
|
||||
XmlNodeRef m_environmentTemplate;
|
||||
CClouds* m_pClouds;
|
||||
std::list<IDocListener*> m_listeners;
|
||||
bool m_bDocumentReady;
|
||||
ICVar* doc_validate_surface_types;
|
||||
bool m_bDocumentReady = false;
|
||||
ICVar* doc_validate_surface_types = nullptr;
|
||||
int m_modifiedModuleFlags;
|
||||
bool m_boLevelExported;
|
||||
bool m_modified;
|
||||
// On construction, it assumes loaded levels have already been exported. Can be a big fat lie, though.
|
||||
// The right way would require us to save to the level folder the export status of the level.
|
||||
bool m_boLevelExported = true;
|
||||
bool m_modified = false;
|
||||
QString m_pathName;
|
||||
QString m_slicePathName;
|
||||
QString m_title;
|
||||
AZ::Data::AssetId m_envProbeSliceAssetId;
|
||||
float m_terrainSize;
|
||||
const char* m_envProbeSliceRelativePath;
|
||||
const float m_envProbeHeight;
|
||||
const char* m_envProbeSliceRelativePath = "EngineAssets/Slices/DefaultLevelSetup.slice";
|
||||
const float m_envProbeHeight = 200.0f;
|
||||
bool m_hasErrors = false; ///< This is used to warn the user that they may lose work when they go to save.
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ void CEditorPreferencesPage_General::Reflect(AZ::SerializeContext& serialize)
|
||||
->Field("PreviewPanel", &GeneralSettings::m_previewPanel)
|
||||
->Field("ApplyConfigSpec", &GeneralSettings::m_applyConfigSpec)
|
||||
->Field("EnableSourceControl", &GeneralSettings::m_enableSourceControl)
|
||||
->Field("ClearConsole", &GeneralSettings::m_clearConsoleOnGameModeStart)
|
||||
->Field("ConsoleBackgroundColorTheme", &GeneralSettings::m_consoleBackgroundColorTheme)
|
||||
->Field("AutoloadLastLevel", &GeneralSettings::m_autoLoadLastLevel)
|
||||
->Field("ShowTimeInConsole", &GeneralSettings::m_bShowTimeInConsole)
|
||||
@@ -77,6 +78,8 @@ void CEditorPreferencesPage_General::Reflect(AZ::SerializeContext& serialize)
|
||||
->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_previewPanel, "Show Geometry Preview Panel", "Show Geometry Preview Panel")
|
||||
->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_applyConfigSpec, "Hide objects by config spec", "Hide objects by config spec")
|
||||
->DataElement(AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_enableSourceControl, "Enable Source Control", "Enable Source Control")
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::CheckBox, &GeneralSettings::m_clearConsoleOnGameModeStart, "Clear Console at game startup", "Clear Console when game mode starts")
|
||||
->DataElement(AZ::Edit::UIHandlers::ComboBox, &GeneralSettings::m_consoleBackgroundColorTheme, "Console Background", "Console Background")
|
||||
->EnumAttribute(AzToolsFramework::ConsoleColorTheme::Light, "Light")
|
||||
->EnumAttribute(AzToolsFramework::ConsoleColorTheme::Dark, "Dark")
|
||||
@@ -142,6 +145,7 @@ void CEditorPreferencesPage_General::OnApply()
|
||||
gSettings.bPreviewGeometryWindow = m_generalSettings.m_previewPanel;
|
||||
gSettings.bApplyConfigSpecInEditor = m_generalSettings.m_applyConfigSpec;
|
||||
gSettings.enableSourceControl = m_generalSettings.m_enableSourceControl;
|
||||
gSettings.clearConsoleOnGameModeStart = m_generalSettings.m_clearConsoleOnGameModeStart;
|
||||
gSettings.consoleBackgroundColorTheme = m_generalSettings.m_consoleBackgroundColorTheme;
|
||||
gSettings.bShowTimeInConsole = m_generalSettings.m_bShowTimeInConsole;
|
||||
gSettings.bShowDashboardAtStartup = m_messaging.m_showDashboard;
|
||||
@@ -176,6 +180,7 @@ void CEditorPreferencesPage_General::InitializeSettings()
|
||||
m_generalSettings.m_previewPanel = gSettings.bPreviewGeometryWindow;
|
||||
m_generalSettings.m_applyConfigSpec = gSettings.bApplyConfigSpecInEditor;
|
||||
m_generalSettings.m_enableSourceControl = gSettings.enableSourceControl;
|
||||
m_generalSettings.m_clearConsoleOnGameModeStart = gSettings.clearConsoleOnGameModeStart;
|
||||
m_generalSettings.m_consoleBackgroundColorTheme = gSettings.consoleBackgroundColorTheme;
|
||||
m_generalSettings.m_bShowTimeInConsole = gSettings.bShowTimeInConsole;
|
||||
m_generalSettings.m_autoLoadLastLevel = gSettings.bAutoloadLastLevelAtStartup;
|
||||
|
||||
@@ -46,6 +46,7 @@ private:
|
||||
bool m_previewPanel;
|
||||
bool m_applyConfigSpec;
|
||||
bool m_enableSourceControl;
|
||||
bool m_clearConsoleOnGameModeStart;
|
||||
AzToolsFramework::ConsoleColorTheme m_consoleBackgroundColorTheme;
|
||||
bool m_autoLoadLastLevel;
|
||||
bool m_bShowTimeInConsole;
|
||||
|
||||
@@ -472,6 +472,12 @@ void EditorViewportWidget::Update()
|
||||
m_Camera.SetZRange(cameraState.m_nearClip, cameraState.m_farClip);
|
||||
}
|
||||
|
||||
// Ensure the FOV matches our internally stored setting if we're using the Editor camera
|
||||
if (!m_viewEntityId.IsValid() && !GetIEditor()->IsInGameMode())
|
||||
{
|
||||
SetFOV(GetFOV());
|
||||
}
|
||||
|
||||
// Reset the camera update flag now that we're finished updating our viewport context
|
||||
m_updateCameraPositionNextTick = false;
|
||||
|
||||
@@ -1234,6 +1240,13 @@ AZStd::shared_ptr<AtomToolsFramework::ModularViewportCameraController> CreateMod
|
||||
AzFramework::ViewportId viewportId)
|
||||
{
|
||||
auto controller = AZStd::make_shared<AtomToolsFramework::ModularViewportCameraController>();
|
||||
|
||||
controller->SetCameraPriorityBuilderCallback(
|
||||
[](AtomToolsFramework::CameraControllerPriorityFn& cameraControllerPriorityFn)
|
||||
{
|
||||
cameraControllerPriorityFn = AtomToolsFramework::DefaultCameraControllerPriority;
|
||||
});
|
||||
|
||||
controller->SetCameraPropsBuilderCallback(
|
||||
[](AzFramework::CameraProps& cameraProps)
|
||||
{
|
||||
@@ -2624,8 +2637,6 @@ void EditorViewportWidget::DestroyRenderContext()
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void EditorViewportWidget::SetDefaultCamera()
|
||||
{
|
||||
// Ensure the FOV matches our internally stored setting
|
||||
SetFOV(GetFOV());
|
||||
if (IsDefaultCamera())
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -566,7 +566,7 @@ void CGameEngine::SwitchToInGame()
|
||||
streamer->QueueRequest(flush);
|
||||
wait.acquire();
|
||||
}
|
||||
|
||||
|
||||
GetIEditor()->Notify(eNotify_OnBeginGameMode);
|
||||
|
||||
m_pISystem->GetIMovieSystem()->EnablePhysicsEvents(true);
|
||||
|
||||
@@ -46,6 +46,7 @@ AZ_POP_DISABLE_WARNING
|
||||
#include <AzToolsFramework/API/EditorAnimationSystemRequestBus.h>
|
||||
#include <AzToolsFramework/SourceControl/QtSourceControlNotificationHandler.h>
|
||||
#include <AzToolsFramework/PythonTerminal/ScriptTermDialog.h>
|
||||
#include <AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h>
|
||||
|
||||
// AzQtComponents
|
||||
#include <AzQtComponents/Buses/ShortcutDispatch.h>
|
||||
@@ -731,32 +732,84 @@ void MainWindow::InitActions()
|
||||
.SetStatusTip(tr("Restore saved state (Fetch)"));
|
||||
|
||||
// Modify actions
|
||||
am->AddAction(ID_EDITMODE_MOVE, tr("Move"))
|
||||
am->AddAction(AzToolsFramework::EditModeMove, tr("Move"))
|
||||
.SetIcon(Style::icon("Move"))
|
||||
.SetApplyHoverEffect()
|
||||
.SetShortcut(tr("1"))
|
||||
.SetToolTip(tr("Move (1)"))
|
||||
.SetCheckable(true)
|
||||
.SetStatusTip(tr("Select and move selected object(s)"))
|
||||
.RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateEditmodeMove);
|
||||
am->AddAction(ID_EDITMODE_ROTATE, tr("Rotate"))
|
||||
.RegisterUpdateCallback([](QAction* action)
|
||||
{
|
||||
Q_ASSERT(action->isCheckable());
|
||||
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode;
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
mode, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode);
|
||||
|
||||
action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Translation);
|
||||
})
|
||||
.Connect(
|
||||
&QAction::triggered,
|
||||
[]()
|
||||
{
|
||||
EditorTransformComponentSelectionRequestBus::Event(
|
||||
GetEntityContextId(), &EditorTransformComponentSelectionRequests::SetTransformMode,
|
||||
EditorTransformComponentSelectionRequests::Mode::Translation);
|
||||
});
|
||||
am->AddAction(AzToolsFramework::EditModeRotate, tr("Rotate"))
|
||||
.SetIcon(Style::icon("Translate"))
|
||||
.SetApplyHoverEffect()
|
||||
.SetShortcut(tr("2"))
|
||||
.SetToolTip(tr("Rotate (2)"))
|
||||
.SetCheckable(true)
|
||||
.SetStatusTip(tr("Select and rotate selected object(s)"))
|
||||
.RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateEditmodeRotate);
|
||||
am->AddAction(ID_EDITMODE_SCALE, tr("Scale"))
|
||||
.RegisterUpdateCallback([](QAction* action)
|
||||
{
|
||||
Q_ASSERT(action->isCheckable());
|
||||
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode;
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
mode, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode);
|
||||
|
||||
action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Rotation);
|
||||
})
|
||||
.Connect(
|
||||
&QAction::triggered,
|
||||
[]()
|
||||
{
|
||||
EditorTransformComponentSelectionRequestBus::Event(
|
||||
GetEntityContextId(), &EditorTransformComponentSelectionRequests::SetTransformMode,
|
||||
EditorTransformComponentSelectionRequests::Mode::Rotation);
|
||||
});
|
||||
am->AddAction(AzToolsFramework::EditModeScale, tr("Scale"))
|
||||
.SetIcon(Style::icon("Scale"))
|
||||
.SetApplyHoverEffect()
|
||||
.SetShortcut(tr("3"))
|
||||
.SetToolTip(tr("Scale (3)"))
|
||||
.SetCheckable(true)
|
||||
.SetStatusTip(tr("Select and scale selected object(s)"))
|
||||
.RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateEditmodeScale);
|
||||
.RegisterUpdateCallback([](QAction* action)
|
||||
{
|
||||
Q_ASSERT(action->isCheckable());
|
||||
|
||||
am->AddAction(ID_SNAP_TO_GRID, tr("Snap to grid"))
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequests::Mode mode;
|
||||
AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
|
||||
mode, AzToolsFramework::GetEntityContextId(),
|
||||
&AzToolsFramework::EditorTransformComponentSelectionRequests::GetTransformMode);
|
||||
|
||||
action->setChecked(mode == AzToolsFramework::EditorTransformComponentSelectionRequests::Mode::Scale);
|
||||
})
|
||||
.Connect( &QAction::triggered,[]()
|
||||
{
|
||||
EditorTransformComponentSelectionRequestBus::Event(
|
||||
GetEntityContextId(), &EditorTransformComponentSelectionRequests::SetTransformMode,
|
||||
EditorTransformComponentSelectionRequests::Mode::Scale);
|
||||
});
|
||||
|
||||
am->AddAction(AzToolsFramework::SnapToGrid, tr("Snap to grid"))
|
||||
.SetIcon(Style::icon("Grid"))
|
||||
.SetApplyHoverEffect()
|
||||
.SetShortcut(tr("G"))
|
||||
@@ -769,7 +822,7 @@ void MainWindow::InitActions()
|
||||
})
|
||||
.Connect(&QAction::triggered, []() { SandboxEditor::SetGridSnapping(!SandboxEditor::GridSnappingEnabled()); });
|
||||
|
||||
am->AddAction(ID_SNAPANGLE, tr("Snap angle"))
|
||||
am->AddAction(AzToolsFramework::SnapAngle, tr("Snap angle"))
|
||||
.SetIcon(Style::icon("Angle"))
|
||||
.SetApplyHoverEffect()
|
||||
.SetStatusTip(tr("Snap angle"))
|
||||
|
||||
@@ -59,11 +59,17 @@ namespace AzQtComponents
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class Ticker;
|
||||
}
|
||||
|
||||
namespace AzToolsFramework
|
||||
{
|
||||
class QtSourceControlNotificationHandler;
|
||||
|
||||
//! @name Reverse URLs.
|
||||
//! Used to identify common actions and override them when necessary.
|
||||
//@{
|
||||
constexpr inline AZ::Crc32 EditModeMove = AZ_CRC_CE("com.o3de.action.editor.editmode.move");
|
||||
constexpr inline AZ::Crc32 EditModeRotate = AZ_CRC_CE("com.o3de.action.editor.editmode.rotate");
|
||||
constexpr inline AZ::Crc32 EditModeScale = AZ_CRC_CE("com.o3de.action.editor.editmode.scale");
|
||||
constexpr inline AZ::Crc32 SnapToGrid = AZ_CRC_CE("com.o3de.action.editor.snaptogrid");
|
||||
constexpr inline AZ::Crc32 SnapAngle = AZ_CRC_CE("com.o3de.action.editor.snapangle");
|
||||
//@}
|
||||
}
|
||||
|
||||
#define MAINFRM_LAYOUT_NORMAL "NormalLayout"
|
||||
|
||||
@@ -82,7 +82,6 @@
|
||||
#define ID_TOOLS_CUSTOMIZEKEYBOARD 32914
|
||||
#define ID_EXPORT_INDOORS 32915
|
||||
#define ID_VIEW_CYCLE2DVIEWPORT 32916
|
||||
#define ID_SNAPANGLE 32917
|
||||
#define ID_PHYSICS_GETPHYSICSSTATE 32937
|
||||
#define ID_PHYSICS_RESETPHYSICSSTATE 32938
|
||||
#define ID_GAME_SYNCPLAYER 32941
|
||||
@@ -108,9 +107,6 @@
|
||||
#define ID_MOVE_OBJECT 33481
|
||||
#define ID_RENAME_OBJ 33483
|
||||
#define ID_FETCH 33496
|
||||
#define ID_EDITMODE_ROTATE 33506
|
||||
#define ID_EDITMODE_SCALE 33507
|
||||
#define ID_EDITMODE_MOVE 33508
|
||||
#define ID_SELECTION_DELETE 33512
|
||||
#define ID_EDIT_ESCAPE 33513
|
||||
#define ID_UNDO 33524
|
||||
@@ -137,7 +133,6 @@
|
||||
#define ID_ADDNODE 33570
|
||||
#define ID_ADDSCENETRACK 33573
|
||||
#define ID_FIND 33574
|
||||
#define ID_SNAP_TO_GRID 33575
|
||||
#define ID_TAG_LOC1 33576
|
||||
#define ID_TAG_LOC2 33577
|
||||
#define ID_TAG_LOC3 33578
|
||||
|
||||
@@ -189,6 +189,7 @@ SEditorSettings::SEditorSettings()
|
||||
|
||||
consoleBackgroundColorTheme = AzToolsFramework::ConsoleColorTheme::Dark;
|
||||
bShowTimeInConsole = false;
|
||||
clearConsoleOnGameModeStart = false;
|
||||
|
||||
enableSceneInspector = false;
|
||||
|
||||
@@ -527,6 +528,8 @@ void SEditorSettings::Save()
|
||||
|
||||
SaveValue("Settings", "ConsoleBackgroundColorThemeV2", (int)consoleBackgroundColorTheme);
|
||||
|
||||
SaveValue("Settings", "ClearConsoleOnGameModeStart", clearConsoleOnGameModeStart);
|
||||
|
||||
SaveValue("Settings", "ShowTimeInConsole", bShowTimeInConsole);
|
||||
|
||||
SaveValue("Settings", "EnableSceneInspector", enableSceneInspector);
|
||||
@@ -745,6 +748,8 @@ void SEditorSettings::Load()
|
||||
consoleBackgroundColorTheme = AzToolsFramework::ConsoleColorTheme::Dark;
|
||||
}
|
||||
|
||||
LoadValue("Settings", "ClearConsoleOnGameModeStart", clearConsoleOnGameModeStart);
|
||||
|
||||
LoadValue("Settings", "ShowTimeInConsole", bShowTimeInConsole);
|
||||
|
||||
LoadValue("Settings", "EnableSceneInspector", enableSceneInspector);
|
||||
@@ -1083,7 +1088,7 @@ void SEditorSettings::ConvertPath(const AZStd::string_view sourcePath, AZStd::st
|
||||
|
||||
AzToolsFramework::EditorSettingsAPIRequests::SettingOutcome SEditorSettings::GetValue(const AZStd::string_view path)
|
||||
{
|
||||
if (path.find("|") < 0)
|
||||
if (path.find("|") == AZStd::string_view::npos)
|
||||
{
|
||||
return { AZStd::string("Invalid Path - could not find separator \"|\"") };
|
||||
}
|
||||
@@ -1101,7 +1106,7 @@ AzToolsFramework::EditorSettingsAPIRequests::SettingOutcome SEditorSettings::Get
|
||||
|
||||
AzToolsFramework::EditorSettingsAPIRequests::SettingOutcome SEditorSettings::SetValue(const AZStd::string_view path, const AZStd::any& value)
|
||||
{
|
||||
if (path.find("|") < 0)
|
||||
if (path.find("|") == AZStd::string_view::npos)
|
||||
{
|
||||
return { AZStd::string("Invalid Path - could not find separator \"|\"") };
|
||||
}
|
||||
|
||||
@@ -380,6 +380,7 @@ AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
|
||||
|
||||
//! Source Control Enabling.
|
||||
bool enableSourceControl;
|
||||
bool clearConsoleOnGameModeStart;
|
||||
|
||||
//! Text editor.
|
||||
QString textEditorForScript;
|
||||
|
||||
@@ -953,13 +953,13 @@ void CViewportTitleDlg::CheckForCameraSpeedUpdate()
|
||||
void CViewportTitleDlg::OnGridSnappingToggled()
|
||||
{
|
||||
m_gridSizeActionWidget->setEnabled(m_enableGridSnappingAction->isChecked());
|
||||
MainWindow::instance()->GetActionManager()->GetAction(ID_SNAP_TO_GRID)->trigger();
|
||||
MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapToGrid)->trigger();
|
||||
}
|
||||
|
||||
void CViewportTitleDlg::OnAngleSnappingToggled()
|
||||
{
|
||||
m_angleSizeActionWidget->setEnabled(m_enableAngleSnappingAction->isChecked());
|
||||
MainWindow::instance()->GetActionManager()->GetAction(ID_SNAPANGLE)->trigger();
|
||||
MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->trigger();
|
||||
}
|
||||
|
||||
void CViewportTitleDlg::OnGridSpinBoxChanged(double value)
|
||||
@@ -974,14 +974,14 @@ void CViewportTitleDlg::OnAngleSpinBoxChanged(double value)
|
||||
|
||||
void CViewportTitleDlg::UpdateOverFlowMenuState()
|
||||
{
|
||||
bool gridSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(ID_SNAP_TO_GRID)->isChecked();
|
||||
bool gridSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapToGrid)->isChecked();
|
||||
{
|
||||
QSignalBlocker signalBlocker(m_enableGridSnappingAction);
|
||||
m_enableGridSnappingAction->setChecked(gridSnappingActive);
|
||||
}
|
||||
m_gridSizeActionWidget->setEnabled(gridSnappingActive);
|
||||
|
||||
bool angleSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(ID_SNAPANGLE)->isChecked();
|
||||
bool angleSnappingActive = MainWindow::instance()->GetActionManager()->GetAction(AzToolsFramework::SnapAngle)->isChecked();
|
||||
{
|
||||
QSignalBlocker signalBlocker(m_enableAngleSnappingAction);
|
||||
m_enableAngleSnappingAction->setChecked(angleSnappingActive);
|
||||
|
||||
@@ -211,7 +211,7 @@ namespace AZStd
|
||||
// 20.9.3.2, observer:
|
||||
constexpr rep count() const { return m_rep; }
|
||||
// 20.9.3.3, arithmetic:
|
||||
constexpr duration operator+() const { *this; }
|
||||
constexpr duration operator+() const { return *this; }
|
||||
constexpr duration operator-() const { return duration(-m_rep); }
|
||||
constexpr duration& operator++() { ++m_rep; return *this; }
|
||||
constexpr duration operator++(int) { return duration(m_rep++); }
|
||||
|
||||
@@ -1056,7 +1056,7 @@ namespace AZStd
|
||||
inline void insert(const iterator& pos, ForwardIterator first, ForwardIterator last, const AZStd::forward_iterator_tag&)
|
||||
{
|
||||
size_type size = AZStd::distance(first, last);
|
||||
AZSTD_CONTAINER_ASSERT(size >= 0, "AZStd::ring_buffer::insert - there are no elements to insert!");
|
||||
AZSTD_CONTAINER_ASSERT(first > last, "AZStd::ring_buffer::insert - there are no elements to insert!");
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace AZStd
|
||||
1610612741ul, 3221225473ul, 4294967291ul
|
||||
};
|
||||
|
||||
// Bucket size suitable to hold n elements.
|
||||
AZStd::size_t hash_next_bucket_size(AZStd::size_t n)
|
||||
{
|
||||
const AZStd::size_t* first = prime_list;
|
||||
|
||||
@@ -134,6 +134,7 @@ namespace AZStd
|
||||
void rehash(HashTable* table, size_type numBucketsMin)
|
||||
{
|
||||
size_type num_buckets = 0;
|
||||
|
||||
numBucketsMin = (AZStd::max)(numBucketsMin, (size_type)ceilf((float)m_list.size() / m_max_load_factor));
|
||||
|
||||
if (numBucketsMin != 0)
|
||||
@@ -143,7 +144,7 @@ namespace AZStd
|
||||
|
||||
if (num_buckets == m_numBuckets)
|
||||
{
|
||||
return; // no point
|
||||
return; // no need yet to rehash
|
||||
}
|
||||
m_numBuckets = num_buckets;
|
||||
|
||||
@@ -165,32 +166,43 @@ namespace AZStd
|
||||
while (!m_list.empty())
|
||||
{
|
||||
cur = m_list.begin();
|
||||
typename list_type::iterator insertIter, curEnd(cur);
|
||||
const typename HashTable::key_type& valueKey = Traits::key_from_value(*cur);
|
||||
|
||||
typename list_type::iterator newIter, iter(cur);
|
||||
size_type numValues = 1;
|
||||
for (++iter; iter != last && table->m_keyEqual(Traits::key_from_value(*cur), Traits::key_from_value(*iter)); ++iter, ++numValues)
|
||||
// Get the number of same consecutive elements in the table with same key,
|
||||
// this allows range insertion of elements at once
|
||||
for (++curEnd; curEnd != last && table->m_keyEqual(valueKey, Traits::key_from_value(*curEnd)); ++curEnd, ++numValues)
|
||||
{
|
||||
}
|
||||
;
|
||||
|
||||
const typename HashTable::key_type& valueKey = Traits::key_from_value(*cur);
|
||||
size_type newBucketIndex = table->bucket_from_hash(table->m_hasher(valueKey));
|
||||
|
||||
// newBucket.first holds the total number of elements in the bucket
|
||||
// newBucket.second contains the pointer to the first element in the bucket
|
||||
vector_value_type& newBucket = newBuckets[newBucketIndex];
|
||||
size_type numElements = newBucket.first;
|
||||
newIter = newBucket.second;
|
||||
insertIter = newBucket.second;
|
||||
|
||||
// If we don't have elements in the bucket yet, transfer the elements directly
|
||||
if (numElements == 0)
|
||||
{
|
||||
newList.splice(newList.begin(), m_list, cur, iter);
|
||||
newList.splice(newList.begin(), m_list, cur, curEnd);
|
||||
newBucket.second = newList.begin();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!table->find_insert_position(valueKey, table->m_keyEqual, newIter, numElements, integral_constant<bool, Traits::has_multi_elements>()))
|
||||
// Since there are elements already in the bucket, update `insertIter` to where the elements will need to be inserted.
|
||||
if (!table->find_insert_position(valueKey, table->m_keyEqual, insertIter, numElements, integral_constant<bool, Traits::has_multi_elements>()))
|
||||
{
|
||||
continue;
|
||||
// An element was found but we don't allow for duplicate elements in this table.
|
||||
// This happens when there was an insertion of two elements that are equal but have different hashes,
|
||||
// which is undefined behavior for a hash table: ISO C++ N4713, section 23.14.15 - 5.3
|
||||
AZ_Assert(false, "Found a duplicate element when rehashing. "
|
||||
"Review the hashing function for this type and make sure two equal elements always have the same hash");
|
||||
}
|
||||
|
||||
newList.splice(newIter, m_list, cur, iter);
|
||||
newList.splice(insertIter, m_list, cur, curEnd);
|
||||
}
|
||||
|
||||
newBucket.first += numValues;
|
||||
@@ -251,15 +263,15 @@ namespace AZStd
|
||||
m_vector.set_allocator(typename vector_type::allocator_type(&m_allocator));
|
||||
}
|
||||
|
||||
allocator_type m_allocator; ///< The single instance of the allocator shared between list and vector containers.
|
||||
list_type m_list; ///< List with elements.
|
||||
vector_type m_vector; ///< Buckets with list iterators.
|
||||
allocator_type m_allocator; //!< The single instance of the allocator shared between list and vector containers.
|
||||
list_type m_list; //!< List with elements.
|
||||
vector_type m_vector; //!< Buckets with list iterators.
|
||||
|
||||
private:
|
||||
vector_value_type* m_buckets; ///< Current buckets array. (can point to the m_vector or m_startBucket).
|
||||
size_type m_numBuckets; ///< Current number of buckets.
|
||||
float m_max_load_factor;
|
||||
vector_value_type m_startBucket; ///< Start bucket used for before we start dynamically allocate memory from m_vector.
|
||||
vector_value_type* m_buckets; //!< Current buckets array. (can point to the m_vector or m_startBucket).
|
||||
size_type m_numBuckets; //!< Current number of buckets.
|
||||
float m_max_load_factor; //!< Maximum load (elements/buckets) before rehashing.
|
||||
vector_value_type m_startBucket; //!< Start bucket used for before we start dynamically allocate memory from m_vector.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -321,8 +333,8 @@ namespace AZStd
|
||||
template<class HashTable>
|
||||
AZ_FORCE_INLINE void rehash(HashTable*, size_type) {}
|
||||
|
||||
vector_type m_vector; ///< Buckets with list iterators.
|
||||
list_type m_list; ///< List with elements.
|
||||
vector_type m_vector; //!< Buckets with list iterators.
|
||||
list_type m_list; //!< List with elements.
|
||||
};
|
||||
}
|
||||
|
||||
@@ -972,28 +984,32 @@ namespace AZStd
|
||||
rhs.clear();
|
||||
}
|
||||
|
||||
// find_insert_position sets insertIter to where the element should be inserted
|
||||
// and returns true if the element should be inserted, otherwise false
|
||||
template<class ComparableToKey, class KeyEq>
|
||||
bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& iter, size_type numElements, const true_type& /* is multi elements */)
|
||||
bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& insertIter, size_type numElements, const true_type& /* is multi elements */)
|
||||
{
|
||||
for (size_type i = 0; i < numElements; ++i, ++iter)
|
||||
for (size_type i = 0; i < numElements; ++i, ++insertIter)
|
||||
{
|
||||
if (keyEq(keyCmp, Traits::key_from_value(*iter)))
|
||||
if (keyEq(keyCmp, Traits::key_from_value(*insertIter)))
|
||||
{
|
||||
++iter;
|
||||
++insertIter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// always return true since multi elements (like multiset) allow repeated elements
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class ComparableToKey, class KeyEq>
|
||||
bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& iter, size_type numElements, const false_type& /* !is multi elements */)
|
||||
bool find_insert_position(const ComparableToKey& keyCmp, const KeyEq& keyEq, iterator& insertIter, size_type numElements, const false_type& /* !is multi elements */)
|
||||
{
|
||||
for (size_type i = 0; i < numElements; ++i, ++iter)
|
||||
for (size_type i = 0; i < numElements; ++i, ++insertIter)
|
||||
{
|
||||
if (keyEq(keyCmp, Traits::key_from_value(*iter)))
|
||||
if (keyEq(keyCmp, Traits::key_from_value(*insertIter)))
|
||||
{
|
||||
// Element already exists, it shouldn't be inserted as we don't allow more than one repeated element for this specialization
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ namespace AZStd
|
||||
T& m_v;
|
||||
constexpr addr_impl_ref(T& v)
|
||||
: m_v(v) {}
|
||||
constexpr addr_impl_ref& operator=(const addr_impl_ref& v) { m_v = v; }
|
||||
constexpr addr_impl_ref& operator=(const addr_impl_ref& v) { m_v = v; return *this; }
|
||||
constexpr operator T& () const { return m_v; }
|
||||
};
|
||||
|
||||
|
||||
@@ -287,6 +287,55 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(HashedContainers, HashTable_InsertionDuplicateOnRehash)
|
||||
{
|
||||
struct TwoPtrs
|
||||
{
|
||||
void* m_ptr1;
|
||||
void* m_ptr2;
|
||||
|
||||
bool operator==(const TwoPtrs& other) const
|
||||
{
|
||||
if (m_ptr1 == other.m_ptr1)
|
||||
{
|
||||
return m_ptr2 == other.m_ptr2;
|
||||
}
|
||||
else if (m_ptr1 == other.m_ptr2)
|
||||
{
|
||||
return m_ptr2 == other.m_ptr1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// This hashing function produces different hashes for two equal values,
|
||||
// which violates the requirement for hashing functions.
|
||||
// The test makes sure that this does not reproduce an issue that caused the insert() function to loop infinitely.
|
||||
struct TwoPtrsHasher
|
||||
{
|
||||
size_t operator()(const TwoPtrs& p) const
|
||||
{
|
||||
size_t hash{ 0 };
|
||||
AZStd::hash_combine(hash, p.m_ptr1, p.m_ptr2);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
using PairSet = AZStd::unordered_set<TwoPtrs, TwoPtrsHasher>;
|
||||
PairSet set;
|
||||
set.insert({ (void*)1, (void*)2 });
|
||||
set.insert({ (void*)3, (void*)4 });
|
||||
set.insert({ (void*)5, (void*)6 });
|
||||
set.insert({ (void*)7, (void*)8 });
|
||||
// Elements with different hashes, but equal
|
||||
set.insert({ (void*)0x000001ceddd9ca20, (void*)0x000001ceddd9cba0 }); // hash(148335135725641)
|
||||
set.insert({ (void*)0x000001ceddd9cba0, (void*)0x000001ceddd9ca20 }); // hash(148335135764189)
|
||||
AZ_TEST_START_TRACE_SUPPRESSION;
|
||||
// This will trigger the assertion of duplicated elements found
|
||||
// A bucket size of 23 since is where the collision between different hashes happens
|
||||
set.rehash(23);
|
||||
AZ_TEST_STOP_TRACE_SUPPRESSION(1); // 1 assertion
|
||||
}
|
||||
|
||||
TEST_F(HashedContainers, HashTable_Fixed)
|
||||
{
|
||||
array<int, 5> elements = {
|
||||
|
||||
@@ -1150,7 +1150,7 @@ namespace UnitTest
|
||||
#if AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
|
||||
#else
|
||||
TEST_F(AssetJobsFloodTest, ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
|
||||
TEST_F(AssetJobsFloodTest, DISABLED_ContainerFilterTest_ContainersWithAndWithoutFiltering_Success)
|
||||
#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_MANAGER_TESTS
|
||||
{
|
||||
m_assetHandlerAndCatalog->AssetCatalogRequestBus::Handler::BusConnect();
|
||||
|
||||
@@ -163,7 +163,11 @@ namespace AzFramework
|
||||
AZ_TracePrintfOnce("AssetSystemComponent", "Failed to find asset platform, setting 'pc'\n");
|
||||
outputConnectionSettings.m_assetPlatform = "pc";
|
||||
}
|
||||
outputConnectionSettings.m_assetPlatform = assetsPlatform;
|
||||
else
|
||||
{
|
||||
outputConnectionSettings.m_assetPlatform = assetsPlatform;
|
||||
}
|
||||
|
||||
if (outputConnectionSettings.m_assetPlatform.empty())
|
||||
{
|
||||
assetsPlatform = AzFramework::OSPlatformToDefaultAssetPlatform(AZ_TRAIT_OS_PLATFORM_CODENAME);
|
||||
|
||||
@@ -227,8 +227,10 @@ namespace AzFramework
|
||||
|
||||
EntitySpawnTicket::EntitySpawnTicket(EntitySpawnTicket&& rhs)
|
||||
: m_payload(rhs.m_payload)
|
||||
, m_id(rhs.m_id)
|
||||
{
|
||||
rhs.m_payload = nullptr;
|
||||
rhs.m_id = 0;
|
||||
}
|
||||
|
||||
EntitySpawnTicket::EntitySpawnTicket(AZ::Data::Asset<Spawnable> spawnable)
|
||||
|
||||
+1
-1
@@ -269,7 +269,7 @@ namespace AzFramework
|
||||
int numEnvironmentVars = 0;
|
||||
if (processLaunchInfo.m_environmentVariables)
|
||||
{
|
||||
const int numEnvironmentVars = processLaunchInfo.m_environmentVariables->size();
|
||||
numEnvironmentVars = processLaunchInfo.m_environmentVariables->size();
|
||||
// Adding one more as exec expects the array to have a nullptr as the last element
|
||||
environmentVariables = new char*[numEnvironmentVars + 1];
|
||||
for (int i = 0; i < numEnvironmentVars; i++)
|
||||
|
||||
@@ -366,6 +366,24 @@ namespace UnitTest
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(SpawnableEntitiesManagerTest, EntitySpawnTicket_Move_Works)
|
||||
{
|
||||
AzFramework::EntitySpawnTicket ticket1(*m_spawnableAsset);
|
||||
AzFramework::EntitySpawnTicket ticket2(*m_spawnableAsset);
|
||||
|
||||
const AzFramework::EntitySpawnTicket::Id ticket1Id = ticket1.GetId();
|
||||
const AzFramework::EntitySpawnTicket::Id ticket2Id = ticket2.GetId();
|
||||
|
||||
AzFramework::EntitySpawnTicket ticketMoveConstructor(AZStd::move(ticket1));
|
||||
EXPECT_TRUE(ticketMoveConstructor.IsValid());
|
||||
EXPECT_EQ(ticketMoveConstructor.GetId(), ticket1Id);
|
||||
|
||||
AzFramework::EntitySpawnTicket ticketMoveOperator;
|
||||
ticketMoveOperator = AZStd::move(ticket2);
|
||||
EXPECT_TRUE(ticketMoveOperator.IsValid());
|
||||
EXPECT_EQ(ticketMoveOperator.GetId(), ticket2Id);
|
||||
}
|
||||
|
||||
TEST_F(SpawnableEntitiesManagerTest, SpawnAllEntities_DeleteTicketBeforeCall_NoCrash)
|
||||
{
|
||||
{
|
||||
|
||||
@@ -103,6 +103,14 @@ namespace AzNetworking
|
||||
//! @return boolean true on success
|
||||
virtual bool Disconnect(ConnectionId connectionId, DisconnectReason reason) = 0;
|
||||
|
||||
//! Sets whether this connection interface can disconnect by virtue of a timeout
|
||||
//! @param timeoutEnabled If this connection interface will automatically disconnect due to a timeout
|
||||
virtual void SetTimeoutEnabled(bool timeoutEnabled) = 0;
|
||||
|
||||
//! Whether this connection interface will disconnect by virtue of a time out (does not account for cvars affecting all connections)
|
||||
//! @return boolean true if this connection will not disconnect on timeout (does not account for cvars affecting all connections)
|
||||
virtual bool IsTimeoutEnabled() const = 0;
|
||||
|
||||
//! Const access to the metrics tracked by this network interface.
|
||||
//! @return const reference to the metrics tracked by this network interface
|
||||
const NetworkInterfaceMetrics& GetMetrics() const;
|
||||
|
||||
@@ -174,6 +174,16 @@ namespace AzNetworking
|
||||
return connection->Disconnect(reason, TerminationEndpoint::Local);
|
||||
}
|
||||
|
||||
void TcpNetworkInterface::SetTimeoutEnabled(bool timeoutEnabled)
|
||||
{
|
||||
m_timeoutEnabled = timeoutEnabled;
|
||||
}
|
||||
|
||||
bool TcpNetworkInterface::IsTimeoutEnabled() const
|
||||
{
|
||||
return m_timeoutEnabled;
|
||||
}
|
||||
|
||||
void TcpNetworkInterface::QueueNewConnection(const PendingConnection& pendingConnection)
|
||||
{
|
||||
m_pendingConnections.PushBackItem(pendingConnection);
|
||||
@@ -306,7 +316,7 @@ namespace AzNetworking
|
||||
{
|
||||
tcpConnection->SendReliablePacket(CorePackets::HeartbeatPacket());
|
||||
}
|
||||
else if (net_TcpTimeoutConnections)
|
||||
else if (net_TcpTimeoutConnections && m_networkInterface.IsTimeoutEnabled())
|
||||
{
|
||||
tcpConnection->Disconnect(DisconnectReason::Timeout, TerminationEndpoint::Local);
|
||||
return TimeoutResult::Delete;
|
||||
|
||||
@@ -99,6 +99,8 @@ namespace AzNetworking
|
||||
bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override;
|
||||
bool StopListening() override;
|
||||
bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override;
|
||||
void SetTimeoutEnabled(bool timeoutEnabled) override;
|
||||
bool IsTimeoutEnabled() const override;
|
||||
//! @}
|
||||
|
||||
//! Queues a new incoming connection for this network interface.
|
||||
@@ -154,6 +156,7 @@ namespace AzNetworking
|
||||
AZ::Name m_name;
|
||||
TrustZone m_trustZone;
|
||||
uint16_t m_port = 0;
|
||||
bool m_timeoutEnabled = true;
|
||||
IConnectionListener& m_connectionListener;
|
||||
TcpConnectionSet m_connectionSet;
|
||||
TcpSocketManager m_tcpSocketManager;
|
||||
|
||||
@@ -397,6 +397,16 @@ namespace AzNetworking
|
||||
return connection->Disconnect(reason, TerminationEndpoint::Local);
|
||||
}
|
||||
|
||||
void UdpNetworkInterface::SetTimeoutEnabled(bool timeoutEnabled)
|
||||
{
|
||||
m_timeoutEnabled = timeoutEnabled;
|
||||
}
|
||||
|
||||
bool UdpNetworkInterface::IsTimeoutEnabled() const
|
||||
{
|
||||
return m_timeoutEnabled;
|
||||
}
|
||||
|
||||
bool UdpNetworkInterface::IsEncrypted() const
|
||||
{
|
||||
return m_socket->IsEncrypted();
|
||||
@@ -729,7 +739,7 @@ namespace AzNetworking
|
||||
{
|
||||
udpConnection->SendUnreliablePacket(CorePackets::HeartbeatPacket());
|
||||
}
|
||||
else if (net_UdpTimeoutConnections)
|
||||
else if (net_UdpTimeoutConnections && m_networkInterface.IsTimeoutEnabled())
|
||||
{
|
||||
udpConnection->Disconnect(DisconnectReason::Timeout, TerminationEndpoint::Local);
|
||||
return TimeoutResult::Delete;
|
||||
|
||||
@@ -104,6 +104,8 @@ namespace AzNetworking
|
||||
bool WasPacketAcked(ConnectionId connectionId, PacketId packetId) override;
|
||||
bool StopListening() override;
|
||||
bool Disconnect(ConnectionId connectionId, DisconnectReason reason) override;
|
||||
void SetTimeoutEnabled(bool timeoutEnabled) override;
|
||||
bool IsTimeoutEnabled() const override;
|
||||
//! @}
|
||||
|
||||
//! Returns true if this is an encrypted socket, false if not.
|
||||
@@ -179,6 +181,7 @@ namespace AzNetworking
|
||||
TrustZone m_trustZone;
|
||||
uint16_t m_port = 0;
|
||||
bool m_allowIncomingConnections = false;
|
||||
bool m_timeoutEnabled = true;
|
||||
IConnectionListener& m_connectionListener;
|
||||
UdpConnectionSet m_connectionSet;
|
||||
TimeoutQueue m_connectionTimeoutQueue;
|
||||
|
||||
+2
-9
@@ -72,15 +72,8 @@ namespace AzToolsFramework
|
||||
|
||||
if (m_rootInstance != nullptr)
|
||||
{
|
||||
// Need to save off the template id to remove the template after the instance is deleted.
|
||||
Prefab::TemplateId templateId = m_rootInstance->GetTemplateId();
|
||||
m_rootInstance.reset();
|
||||
if (templateId != Prefab::InvalidTemplateId)
|
||||
{
|
||||
// Remove the template here so that if we're in a Deactivate/Activate cycle, it can recreate the template/rootInstance
|
||||
// correctly
|
||||
m_prefabSystemComponent->RemoveTemplate(templateId);
|
||||
}
|
||||
m_prefabSystemComponent->RemoveAllTemplates();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +88,7 @@ namespace AzToolsFramework
|
||||
if (templateId != Prefab::InvalidTemplateId)
|
||||
{
|
||||
m_rootInstance->SetTemplateId(Prefab::InvalidTemplateId);
|
||||
m_prefabSystemComponent->RemoveTemplate(templateId);
|
||||
m_prefabSystemComponent->RemoveAllTemplates();
|
||||
}
|
||||
m_rootInstance->SetContainerEntityName("Level");
|
||||
}
|
||||
|
||||
+3
-1
@@ -245,7 +245,9 @@ namespace UnitTest
|
||||
m_instanceToTemplateInterface->GenerateDomForInstance(instanceDomBeforeUpdate, *firstInstance);
|
||||
|
||||
//remove instance from instance
|
||||
firstInstance->DetachNestedInstance(addedAlias);
|
||||
AZStd::unique_ptr<Instance> detachedInstance = firstInstance->DetachNestedInstance(addedAlias);
|
||||
ASSERT_TRUE(detachedInstance != nullptr);
|
||||
m_prefabSystemComponent->RemoveLink(detachedInstance->GetLinkId());
|
||||
|
||||
//create document with after change snapshot
|
||||
PrefabDom instanceDomAfterUpdate;
|
||||
|
||||
@@ -309,6 +309,7 @@ namespace UnitTest
|
||||
// and use the updated enclosing Instance to update the PrefabDom of Template.
|
||||
AZStd::unique_ptr<Instance> detachedInstance = newEnclosingInstance->DetachNestedInstance(nestedInstanceAliases.front());
|
||||
ASSERT_TRUE(detachedInstance);
|
||||
m_prefabSystemComponent->RemoveLink(detachedInstance->GetLinkId());
|
||||
|
||||
PrefabDom updatedTemplateDom;
|
||||
ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*newEnclosingInstance, updatedTemplateDom));
|
||||
|
||||
@@ -274,6 +274,7 @@ namespace UnitTest
|
||||
InstanceAlias aliasOfWheelInstanceToRetain = wheelInstanceAliasesUnderAxle.front();
|
||||
AZStd::unique_ptr<Instance> detachedInstance = axleInstance->DetachNestedInstance(wheelInstanceAliasesUnderAxle.back());
|
||||
ASSERT_TRUE(detachedInstance);
|
||||
m_prefabSystemComponent->RemoveLink(detachedInstance->GetLinkId());
|
||||
PrefabDom updatedAxleInstanceDom;
|
||||
ASSERT_TRUE(PrefabDomUtils::StoreInstanceInPrefabDom(*axleInstance, updatedAxleInstanceDom));
|
||||
m_prefabSystemComponent->UpdatePrefabTemplate(axleTemplateId, updatedAxleInstanceDom);
|
||||
|
||||
@@ -118,7 +118,9 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
if (m_configProjectProcess->exitCode() != 0 || !containsGeneratingDone)
|
||||
if (m_configProjectProcess->exitStatus() != QProcess::ExitStatus::NormalExit
|
||||
|| m_configProjectProcess->exitCode() != 0
|
||||
|| !containsGeneratingDone)
|
||||
{
|
||||
QString error = tr("Configuring project failed. See log for details.");
|
||||
QStringToAZTracePrint(error);
|
||||
@@ -180,7 +182,8 @@ namespace O3DE::ProjectManager
|
||||
}
|
||||
}
|
||||
|
||||
if (m_configProjectProcess->exitCode() != 0)
|
||||
if (m_configProjectProcess->exitStatus() != QProcess::ExitStatus::NormalExit
|
||||
|| m_configProjectProcess->exitCode() != 0)
|
||||
{
|
||||
QString error = tr("Building project failed. See log for details.");
|
||||
QStringToAZTracePrint(error);
|
||||
|
||||
@@ -265,6 +265,6 @@ namespace O3DE::ProjectManager
|
||||
void CreateProjectCtrl::ReinitGemCatalogForSelectedTemplate()
|
||||
{
|
||||
const QString projectTemplatePath = m_newProjectSettingsScreen->GetProjectTemplatePath();
|
||||
m_gemCatalogScreen->ReinitForProject(projectTemplatePath + "/Template", /*isNewProject=*/true);
|
||||
m_gemCatalogScreen->ReinitForProject(projectTemplatePath + "/Template");
|
||||
}
|
||||
} // namespace O3DE::ProjectManager
|
||||
|
||||
@@ -62,10 +62,10 @@ namespace O3DE::ProjectManager
|
||||
hLayout->addWidget(m_gemInspector);
|
||||
}
|
||||
|
||||
void GemCatalogScreen::ReinitForProject(const QString& projectPath, bool isNewProject)
|
||||
void GemCatalogScreen::ReinitForProject(const QString& projectPath)
|
||||
{
|
||||
m_gemModel->clear();
|
||||
FillModel(projectPath, isNewProject);
|
||||
FillModel(projectPath);
|
||||
|
||||
if (m_filterWidget)
|
||||
{
|
||||
@@ -88,18 +88,9 @@ namespace O3DE::ProjectManager
|
||||
});
|
||||
}
|
||||
|
||||
void GemCatalogScreen::FillModel(const QString& projectPath, bool isNewProject)
|
||||
void GemCatalogScreen::FillModel(const QString& projectPath)
|
||||
{
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> allGemInfosResult;
|
||||
if (isNewProject)
|
||||
{
|
||||
allGemInfosResult = PythonBindingsInterface::Get()->GetEngineGemInfos();
|
||||
}
|
||||
else
|
||||
{
|
||||
allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath);
|
||||
}
|
||||
|
||||
AZ::Outcome<QVector<GemInfo>, AZStd::string> allGemInfosResult = PythonBindingsInterface::Get()->GetAllGemInfos(projectPath);
|
||||
if (allGemInfosResult.IsSuccess())
|
||||
{
|
||||
// Add all available gems to the model.
|
||||
|
||||
@@ -28,13 +28,13 @@ namespace O3DE::ProjectManager
|
||||
~GemCatalogScreen() = default;
|
||||
ProjectManagerScreen GetScreenEnum() override;
|
||||
|
||||
void ReinitForProject(const QString& projectPath, bool isNewProject);
|
||||
void ReinitForProject(const QString& projectPath);
|
||||
bool EnableDisableGemsForProject(const QString& projectPath);
|
||||
|
||||
GemModel* GetGemModel() const { return m_gemModel; }
|
||||
|
||||
private:
|
||||
void FillModel(const QString& projectPath, bool isNewProject);
|
||||
void FillModel(const QString& projectPath);
|
||||
|
||||
GemListView* m_gemListView = nullptr;
|
||||
GemInspector* m_gemInspector = nullptr;
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace O3DE::ProjectManager
|
||||
QMessageBox::critical(m_parent, tr("Project Failed to Build!"), result);
|
||||
|
||||
m_projectInfo.m_buildFailed = true;
|
||||
m_projectInfo.m_logUrl = QUrl();
|
||||
m_projectInfo.m_logUrl = QUrl("file:///" + m_worker->GetLogFilePath());
|
||||
emit NotifyBuildProject(m_projectInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace O3DE::ProjectManager
|
||||
Update();
|
||||
|
||||
// Gather the available gems that will be shown in the gem catalog.
|
||||
m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path, /*isNewProject=*/false);
|
||||
m_gemCatalogScreen->ReinitForProject(m_projectInfo.m_path);
|
||||
}
|
||||
|
||||
void UpdateProjectCtrl::HandleGemsButton()
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace AZ
|
||||
UpdateViewToClipMatrix();
|
||||
}
|
||||
|
||||
void CameraComponent::SetOrthographic(bool orthographic)
|
||||
void CameraComponent::SetOrthographic([[maybe_unused]] bool orthographic)
|
||||
{
|
||||
AZ_Assert(!orthographic, "DebugCamera does not support orthographic projection");
|
||||
}
|
||||
|
||||
@@ -13,13 +13,7 @@
|
||||
"ScopeAttachmentUsage": "DepthStencil",
|
||||
"LoadStoreAction": {
|
||||
"ClearValue": {
|
||||
"Type": "DepthStencil",
|
||||
"Value": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
]
|
||||
"Type": "DepthStencil"
|
||||
},
|
||||
"LoadActionStencil": "Clear"
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace AZ
|
||||
if (auto* serialize = azrtti_cast<SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<ModelAssetBuilderComponent, SceneAPI::SceneCore::ExportingComponent>()
|
||||
->Version(29); // (updated to separate material slot ID from default material asset)
|
||||
->Version(30); // (updated to separate material slot ID from default material asset)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ namespace AZ
|
||||
}
|
||||
|
||||
m_pipelineState = m_shader->AcquirePipelineState(descriptor);
|
||||
}
|
||||
}
|
||||
m_dirty = false;
|
||||
}
|
||||
return m_pipelineState;
|
||||
|
||||
+61
-26
@@ -16,37 +16,62 @@
|
||||
|
||||
namespace AtomToolsFramework
|
||||
{
|
||||
class ModernViewportCameraControllerInstance;
|
||||
class ModularViewportCameraControllerInstance;
|
||||
|
||||
//! A function object to represent returning a camera controller priority.
|
||||
using CameraControllerPriorityFn =
|
||||
AZStd::function<AzFramework::ViewportControllerPriority(const AzFramework::CameraSystem& cameraSystem)>;
|
||||
|
||||
//! The default behavior for what priority the camera controller should respond to events at.
|
||||
//! @note This can change based on the state of the camera controller/system.
|
||||
AzFramework::ViewportControllerPriority DefaultCameraControllerPriority(const AzFramework::CameraSystem& cameraSystem);
|
||||
|
||||
//! Builder class to create and configure a ModularViewportCameraControllerInstance.
|
||||
class ModularViewportCameraController
|
||||
: public AzFramework::MultiViewportController<
|
||||
ModernViewportCameraControllerInstance, AzFramework::ViewportControllerPriority::DispatchToAllPriorities>
|
||||
ModularViewportCameraControllerInstance,
|
||||
AzFramework::ViewportControllerPriority::DispatchToAllPriorities>
|
||||
{
|
||||
public:
|
||||
friend ModularViewportCameraControllerInstance;
|
||||
|
||||
using CameraListBuilder = AZStd::function<void(AzFramework::Cameras&)>;
|
||||
using CameraPropsBuilder = AZStd::function<void(AzFramework::CameraProps&)>;
|
||||
using CameraPriorityBuilder = AZStd::function<void(CameraControllerPriorityFn&)>;
|
||||
|
||||
//! Sets the camera list builder callback used to populate new ModernViewportCameraControllerInstances
|
||||
//! Sets the camera list builder callback used to populate new ModularViewportCameraControllerInstances.
|
||||
void SetCameraListBuilderCallback(const CameraListBuilder& builder);
|
||||
//! Sets the camera props builder callback used to populate new ModernViewportCameraControllerInstances
|
||||
//! Sets the camera props builder callback used to populate new ModularViewportCameraControllerInstances.
|
||||
void SetCameraPropsBuilderCallback(const CameraPropsBuilder& builder);
|
||||
//! Sets up a camera list based on this controller's CameraListBuilderCallback
|
||||
void SetupCameras(AzFramework::Cameras& cameras);
|
||||
//! Sets up properties shared across all cameras
|
||||
void SetupCameraProperies(AzFramework::CameraProps& cameraProps);
|
||||
//! Sets the camera controller priority builder callback used to populate new ModularViewportCameraControllerInstances.
|
||||
void SetCameraPriorityBuilderCallback(const CameraPriorityBuilder& builder);
|
||||
|
||||
private:
|
||||
//! Sets up a camera list based on this controller's CameraListBuilderCallback.
|
||||
void SetupCameras(AzFramework::Cameras& cameras);
|
||||
//! Sets up properties shared across all cameras.
|
||||
void SetupCameraProperties(AzFramework::CameraProps& cameraProps);
|
||||
//! Sets up how the camera controller should decide at what priority level to respond to.
|
||||
void SetupCameraControllerPriority(CameraControllerPriorityFn& cameraPriorityFn);
|
||||
|
||||
//! Builder to generate a list of CameraInputs to run in the ModularViewportCameraControllerInstance.
|
||||
CameraListBuilder m_cameraListBuilder;
|
||||
//! Builder to define custom camera properties to use for things such as rotate and translate interpolation.
|
||||
CameraPropsBuilder m_cameraPropsBuilder;
|
||||
//! Builder to define what priority level the camera controller should respond to events at.
|
||||
CameraPriorityBuilder m_cameraControllerPriorityBuilder;
|
||||
};
|
||||
|
||||
class ModernViewportCameraControllerInstance final
|
||||
: public AzFramework::MultiViewportControllerInstanceInterface<ModularViewportCameraController>,
|
||||
public ModularViewportCameraControllerRequestBus::Handler,
|
||||
private AzFramework::ViewportDebugDisplayEventBus::Handler
|
||||
//! A customizable camera controller that can be configured to run a varying set of CameraInput instances.
|
||||
//! The controller can also be animated from its current transform to a new translation and orientation.
|
||||
class ModularViewportCameraControllerInstance final
|
||||
: public AzFramework::MultiViewportControllerInstanceInterface<ModularViewportCameraController>
|
||||
, public ModularViewportCameraControllerRequestBus::Handler
|
||||
, private AzFramework::ViewportDebugDisplayEventBus::Handler
|
||||
{
|
||||
public:
|
||||
explicit ModernViewportCameraControllerInstance(AzFramework::ViewportId viewportId, ModularViewportCameraController* controller);
|
||||
~ModernViewportCameraControllerInstance() override;
|
||||
explicit ModularViewportCameraControllerInstance(AzFramework::ViewportId viewportId, ModularViewportCameraController* controller);
|
||||
~ModularViewportCameraControllerInstance() override;
|
||||
|
||||
// MultiViewportControllerInstanceInterface overrides ...
|
||||
bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override;
|
||||
@@ -60,25 +85,35 @@ namespace AtomToolsFramework
|
||||
// AzFramework::ViewportDebugDisplayEventBus overrides ...
|
||||
void DisplayViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override;
|
||||
|
||||
//! The current mode the camera controller is in.
|
||||
enum class CameraMode
|
||||
{
|
||||
Control,
|
||||
Animation
|
||||
Control, //!< The camera is being driven by user input.
|
||||
Animation //!< The camera is being animated (interpolated) from one transform to another.
|
||||
};
|
||||
|
||||
AzFramework::Camera m_camera;
|
||||
AzFramework::Camera m_targetCamera;
|
||||
AzFramework::CameraSystem m_cameraSystem;
|
||||
AzFramework::CameraProps m_cameraProps;
|
||||
//! Encapsulates an animation (interpolation) between two transforms.
|
||||
struct CameraAnimation
|
||||
{
|
||||
//! The transform of the camera at the start of the animation.
|
||||
AZ::Transform m_transformStart = AZ::Transform::CreateIdentity();
|
||||
AZ::Transform m_transformEnd = AZ::Transform::CreateIdentity(); //!< The transform of the camera at the end of the animation.
|
||||
float m_time = 0.0f; //!< The interpolation amount between the start and end transforms (in the range 0.0 - 1.0).
|
||||
};
|
||||
|
||||
AZ::Transform m_transformStart = AZ::Transform::CreateIdentity();
|
||||
AZ::Transform m_transformEnd = AZ::Transform::CreateIdentity();
|
||||
float m_animationT = 0.0f;
|
||||
CameraMode m_cameraMode = CameraMode::Control;
|
||||
AzFramework::Camera m_camera; //!< The current camera state (pitch/yaw/position/look-distance).
|
||||
AzFramework::Camera m_targetCamera; //!< The target (next) camera state that m_camera is catching up to.
|
||||
AzFramework::CameraSystem m_cameraSystem; //!< The camera system responsible for managing all CameraInputs.
|
||||
AzFramework::CameraProps m_cameraProps; //!< Camera properties to control rotate and translate smoothness.
|
||||
CameraControllerPriorityFn m_priorityFn; //!< Controls at what priority the camera controller should respond to events.
|
||||
|
||||
CameraAnimation m_cameraAnimation; //!< Camera animation state (used during CameraMode::Animation).
|
||||
CameraMode m_cameraMode = CameraMode::Control; //!< The current mode the camera is operating in.
|
||||
AZStd::optional<AZ::Vector3> m_lookAtAfterInterpolation; //!< The look at point after an interpolation has finished.
|
||||
//!< Will be cleared when the view changes (camera looks away).
|
||||
bool m_updatingTransform = false;
|
||||
|
||||
//! Flag to prevent circular updates of the camera transform (while the viewport transform is being updated internally).
|
||||
bool m_updatingTransformInternally = false;
|
||||
//! Listen for camera view changes outside of the camera controller.
|
||||
AZ::RPI::ViewportContext::MatrixChangedEvent::Handler m_cameraViewMatrixChangeHandler;
|
||||
};
|
||||
} // namespace AtomToolsFramework
|
||||
|
||||
@@ -87,14 +87,12 @@ namespace AtomToolsFramework
|
||||
|
||||
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
auto targetName = GetBuildTargetName();
|
||||
|
||||
// this will put these methods into the 'azlmbr.AtomTools.general' module
|
||||
auto addGeneral = [targetName](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder)
|
||||
auto addGeneral = [](AZ::BehaviorContext::GlobalMethodBuilder methodBuilder)
|
||||
{
|
||||
methodBuilder->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Category, "Editor")
|
||||
->Attribute(AZ::Script::Attributes::Module, targetName);
|
||||
->Attribute(AZ::Script::Attributes::Module, "atomtools.general");
|
||||
};
|
||||
// The reflection here is based on patterns in CryEditPythonHandler::Reflect
|
||||
addGeneral(behaviorContext->Method(
|
||||
|
||||
+52
-37
@@ -68,6 +68,11 @@ namespace AtomToolsFramework
|
||||
m_cameraPropsBuilder = builder;
|
||||
}
|
||||
|
||||
void ModularViewportCameraController::SetCameraPriorityBuilderCallback(const CameraPriorityBuilder& builder)
|
||||
{
|
||||
m_cameraControllerPriorityBuilder = builder;
|
||||
}
|
||||
|
||||
void ModularViewportCameraController::SetupCameras(AzFramework::Cameras& cameras)
|
||||
{
|
||||
if (m_cameraListBuilder)
|
||||
@@ -76,7 +81,7 @@ namespace AtomToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void ModularViewportCameraController::SetupCameraProperies(AzFramework::CameraProps& cameraProps)
|
||||
void ModularViewportCameraController::SetupCameraProperties(AzFramework::CameraProps& cameraProps)
|
||||
{
|
||||
if (m_cameraPropsBuilder)
|
||||
{
|
||||
@@ -84,18 +89,43 @@ namespace AtomToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
ModernViewportCameraControllerInstance::ModernViewportCameraControllerInstance(
|
||||
void ModularViewportCameraController::SetupCameraControllerPriority(CameraControllerPriorityFn& cameraPriorityFn)
|
||||
{
|
||||
if (m_cameraControllerPriorityBuilder)
|
||||
{
|
||||
m_cameraControllerPriorityBuilder(cameraPriorityFn);
|
||||
}
|
||||
}
|
||||
|
||||
// what priority should the camera system respond to
|
||||
AzFramework::ViewportControllerPriority DefaultCameraControllerPriority(const AzFramework::CameraSystem& cameraSystem)
|
||||
{
|
||||
// ModernViewportCameraControllerInstance receives events at all priorities, when it is in 'exclusive' mode
|
||||
// or it is actively handling events (essentially when the camera system is 'active' and responding to inputs)
|
||||
// it should only respond to the highest priority
|
||||
if (cameraSystem.m_cameras.Exclusive() || cameraSystem.HandlingEvents())
|
||||
{
|
||||
return AzFramework::ViewportControllerPriority::Highest;
|
||||
}
|
||||
|
||||
// otherwise it should only respond to normal priority events
|
||||
return AzFramework::ViewportControllerPriority::Normal;
|
||||
}
|
||||
|
||||
ModularViewportCameraControllerInstance::ModularViewportCameraControllerInstance(
|
||||
const AzFramework::ViewportId viewportId, ModularViewportCameraController* controller)
|
||||
: MultiViewportControllerInstanceInterface<ModularViewportCameraController>(viewportId, controller)
|
||||
{
|
||||
controller->SetupCameras(m_cameraSystem.m_cameras);
|
||||
controller->SetupCameraProperies(m_cameraProps);
|
||||
controller->SetupCameraProperties(m_cameraProps);
|
||||
controller->SetupCameraControllerPriority(m_priorityFn);
|
||||
|
||||
if (auto viewportContext = RetrieveViewportContext(GetViewportId()))
|
||||
{
|
||||
auto handleCameraChange = [this, viewportContext](const AZ::Matrix4x4&)
|
||||
{
|
||||
if (!m_updatingTransform)
|
||||
// ignore these updates if the camera is being updated internally
|
||||
if (!m_updatingTransformInternally)
|
||||
{
|
||||
UpdateCameraFromTransform(m_targetCamera, viewportContext->GetCameraTransform());
|
||||
m_camera = m_targetCamera;
|
||||
@@ -111,30 +141,15 @@ namespace AtomToolsFramework
|
||||
ModularViewportCameraControllerRequestBus::Handler::BusConnect(viewportId);
|
||||
}
|
||||
|
||||
ModernViewportCameraControllerInstance::~ModernViewportCameraControllerInstance()
|
||||
ModularViewportCameraControllerInstance::~ModularViewportCameraControllerInstance()
|
||||
{
|
||||
ModularViewportCameraControllerRequestBus::Handler::BusDisconnect();
|
||||
AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
// what priority should the camera system respond to
|
||||
static AzFramework::ViewportControllerPriority GetPriority(const AzFramework::CameraSystem& cameraSystem)
|
||||
bool ModularViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
|
||||
{
|
||||
// ModernViewportCameraControllerInstance receives events at all priorities, when it is in 'exclusive' mode
|
||||
// or it is actively handling events (essentially when the camera system is 'active' and responding to inputs)
|
||||
// it should only respond to the highest priority
|
||||
if (cameraSystem.m_cameras.Exclusive() || cameraSystem.HandlingEvents())
|
||||
{
|
||||
return AzFramework::ViewportControllerPriority::Highest;
|
||||
}
|
||||
|
||||
// otherwise it should only respond to normal priority events
|
||||
return AzFramework::ViewportControllerPriority::Normal;
|
||||
}
|
||||
|
||||
bool ModernViewportCameraControllerInstance::HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event)
|
||||
{
|
||||
if (event.m_priority == GetPriority(m_cameraSystem))
|
||||
if (event.m_priority == m_priorityFn(m_cameraSystem))
|
||||
{
|
||||
return m_cameraSystem.HandleEvents(AzFramework::BuildInputEvent(event.m_inputChannel));
|
||||
}
|
||||
@@ -142,7 +157,7 @@ namespace AtomToolsFramework
|
||||
return false;
|
||||
}
|
||||
|
||||
void ModernViewportCameraControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
|
||||
void ModularViewportCameraControllerInstance::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event)
|
||||
{
|
||||
// only update for a single priority (normal is the default)
|
||||
if (event.m_priority != AzFramework::ViewportControllerPriority::Normal)
|
||||
@@ -152,7 +167,7 @@ namespace AtomToolsFramework
|
||||
|
||||
if (auto viewportContext = RetrieveViewportContext(GetViewportId()))
|
||||
{
|
||||
m_updatingTransform = true;
|
||||
m_updatingTransformInternally = true;
|
||||
|
||||
if (m_cameraMode == CameraMode::Control)
|
||||
{
|
||||
@@ -180,10 +195,12 @@ namespace AtomToolsFramework
|
||||
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
|
||||
};
|
||||
|
||||
const float transitionT = smootherStepFn(m_animationT);
|
||||
const auto& [transformStart, transformEnd, animationTime] = m_cameraAnimation;
|
||||
|
||||
const float transitionTime = smootherStepFn(animationTime);
|
||||
const AZ::Transform current = AZ::Transform::CreateFromQuaternionAndTranslation(
|
||||
m_transformStart.GetRotation().Slerp(m_transformEnd.GetRotation(), transitionT),
|
||||
m_transformStart.GetTranslation().Lerp(m_transformEnd.GetTranslation(), transitionT));
|
||||
transformStart.GetRotation().Slerp(transformEnd.GetRotation(), transitionTime),
|
||||
transformStart.GetTranslation().Lerp(transformEnd.GetTranslation(), transitionTime));
|
||||
|
||||
const AZ::Vector3 eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(current));
|
||||
m_camera.m_pitch = eulerAngles.GetX();
|
||||
@@ -191,21 +208,21 @@ namespace AtomToolsFramework
|
||||
m_camera.m_lookAt = current.GetTranslation();
|
||||
m_targetCamera = m_camera;
|
||||
|
||||
if (m_animationT >= 1.0f)
|
||||
if (animationTime >= 1.0f)
|
||||
{
|
||||
m_cameraMode = CameraMode::Control;
|
||||
}
|
||||
|
||||
m_animationT = AZ::GetClamp(m_animationT + event.m_deltaTime.count(), 0.0f, 1.0f);
|
||||
m_cameraAnimation.m_time = AZ::GetClamp(animationTime + event.m_deltaTime.count(), 0.0f, 1.0f);
|
||||
|
||||
viewportContext->SetCameraTransform(current);
|
||||
}
|
||||
|
||||
m_updatingTransform = false;
|
||||
m_updatingTransformInternally = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ModernViewportCameraControllerInstance::DisplayViewport(
|
||||
void ModularViewportCameraControllerInstance::DisplayViewport(
|
||||
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
|
||||
{
|
||||
if (const float alpha = AZStd::min(-m_camera.m_lookDist / 5.0f, 1.0f); alpha > AZ::Constants::FloatEpsilon)
|
||||
@@ -216,16 +233,14 @@ namespace AtomToolsFramework
|
||||
}
|
||||
}
|
||||
|
||||
void ModernViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance)
|
||||
void ModularViewportCameraControllerInstance::InterpolateToTransform(const AZ::Transform& worldFromLocal, const float lookAtDistance)
|
||||
{
|
||||
m_animationT = 0.0f;
|
||||
m_cameraMode = CameraMode::Animation;
|
||||
m_transformStart = m_camera.Transform();
|
||||
m_transformEnd = worldFromLocal;
|
||||
m_lookAtAfterInterpolation = m_transformEnd.GetTranslation() + m_transformEnd.GetBasisY() * lookAtDistance;
|
||||
m_cameraAnimation = CameraAnimation{ m_camera.Transform(), worldFromLocal, 0.0f };
|
||||
m_lookAtAfterInterpolation = worldFromLocal.GetTranslation() + worldFromLocal.GetBasisY() * lookAtDistance;
|
||||
}
|
||||
|
||||
AZStd::optional<AZ::Vector3> ModernViewportCameraControllerInstance::LookAtAfterInterpolation() const
|
||||
AZStd::optional<AZ::Vector3> ModularViewportCameraControllerInstance::LookAtAfterInterpolation() const
|
||||
{
|
||||
return m_lookAtAfterInterpolation;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
#include <AzCore/Utils/Utils.h>
|
||||
#include <AzFramework/Asset/AssetSystemComponent.h>
|
||||
#include <AzFramework/IO/LocalFileIO.h>
|
||||
#include <AzFramework/Network/AssetProcessorConnection.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
@@ -28,11 +27,11 @@
|
||||
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
|
||||
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
|
||||
#include <Atom/Document/MaterialDocumentModule.h>
|
||||
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
|
||||
#include <Atom/Viewport/MaterialViewportModule.h>
|
||||
#include <Atom/Window/MaterialEditorWindowFactoryRequestBus.h>
|
||||
#include <Atom/Window/MaterialEditorWindowModule.h>
|
||||
@@ -73,15 +72,14 @@ namespace MaterialEditor
|
||||
{
|
||||
QApplication::setApplicationName("O3DE Material Editor");
|
||||
|
||||
// The settings registry has been created at this point, so add the CMake target
|
||||
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(
|
||||
*AZ::SettingsRegistry::Get(), GetBuildTargetName());
|
||||
}
|
||||
|
||||
MaterialEditorApplication::~MaterialEditorApplication()
|
||||
{
|
||||
AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusDisconnect();
|
||||
MaterialEditorWindowNotificationBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void MaterialEditorApplication::CreateStaticModules(AZStd::vector<AZ::Module*>& outModules)
|
||||
@@ -122,7 +120,7 @@ namespace MaterialEditor
|
||||
&MaterialEditor::MaterialEditorWindowRequestBus::Handler::ActivateWindow);
|
||||
}
|
||||
|
||||
// Process command line options for opening one or more material documents on startup
|
||||
// Process command line options for opening one or more documents on startup
|
||||
size_t openDocumentCount = commandLine.GetNumMiscValues();
|
||||
for (size_t openDocumentIndex = 0; openDocumentIndex < openDocumentCount; ++openDocumentIndex)
|
||||
{
|
||||
|
||||
@@ -114,11 +114,11 @@ def SetCameraPitch(pitch):
|
||||
azlmbr.render.ArcBallControllerRequestBus(azlmbr.bus.Broadcast, 'SetPitch', pitch)
|
||||
|
||||
def IdleFrames(numFrames):
|
||||
azlmbr.materialeditor.general.idle_wait_frames(numFrames)
|
||||
azlmbr.atomtools.general.idle_wait_frames(numFrames)
|
||||
|
||||
def CaptureScreenshot(screenshotOutputPath):
|
||||
print("Capturing screenshot to " + screenshotOutputPath + " ...")
|
||||
return ScreenshotHelper(azlmbr.materialeditor.general.idle_wait_frames).capture_screenshot_blocking(screenshotOutputPath)
|
||||
return ScreenshotHelper(azlmbr.atomtools.general.idle_wait_frames).capture_screenshot_blocking(screenshotOutputPath)
|
||||
|
||||
def ResizeViewport(width, height):
|
||||
# This locks the size of the render target to the desired resolution
|
||||
|
||||
+27
-23
@@ -25,26 +25,27 @@
|
||||
#include <AzToolsFramework/UI/UICore/QTreeViewStateSaver.hxx>
|
||||
#include <AzToolsFramework/UI/UICore/QWidgetSavedState.h>
|
||||
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
#include <AtomToolsFramework/Util/Util.h>
|
||||
|
||||
#include <ShaderManagementConsoleApplication.h>
|
||||
#include <ShaderManagementConsole_Traits_Platform.h>
|
||||
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
||||
#include <Atom/RPI.Public/RPISystemInterface.h>
|
||||
|
||||
#include <Atom/Document/ShaderManagementConsoleDocumentModule.h>
|
||||
#include <Atom/Document/ShaderManagementConsoleDocumentSystemRequestBus.h>
|
||||
#include <Atom/Window/ShaderManagementConsoleWindowModule.h>
|
||||
#include <Atom/Window/ShaderManagementConsoleWindowRequestBus.h>
|
||||
|
||||
#include <ShaderManagementConsoleApplication.h>
|
||||
#include <ShaderManagementConsole_Traits_Platform.h>
|
||||
|
||||
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QObject>
|
||||
AZ_POP_DISABLE_WARNING
|
||||
|
||||
namespace ShaderManagementConsole
|
||||
{
|
||||
//! This function returns the build system target name of "ShaderManagementConsole
|
||||
AZStd::string ShaderManagementConsoleApplication::GetBuildTargetName() const
|
||||
{
|
||||
#if !defined(LY_CMAKE_TARGET)
|
||||
@@ -74,6 +75,11 @@ namespace ShaderManagementConsole
|
||||
*AZ::SettingsRegistry::Get(), GetBuildTargetName());
|
||||
}
|
||||
|
||||
ShaderManagementConsoleApplication::~ShaderManagementConsoleApplication()
|
||||
{
|
||||
ShaderManagementConsoleWindowNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void ShaderManagementConsoleApplication::CreateStaticModules(AZStd::vector<AZ::Module*>& outModules)
|
||||
{
|
||||
Base::CreateStaticModules(outModules);
|
||||
@@ -84,8 +90,6 @@ namespace ShaderManagementConsole
|
||||
void ShaderManagementConsoleApplication::OnShaderManagementConsoleWindowClosing()
|
||||
{
|
||||
ExitMainLoop();
|
||||
ShaderManagementConsoleWindowNotificationBus::Handler::BusDisconnect();
|
||||
AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void ShaderManagementConsoleApplication::Destroy()
|
||||
@@ -104,27 +108,19 @@ namespace ShaderManagementConsole
|
||||
return AZStd::vector<AZStd::string>({ "passes/", "config/" });
|
||||
}
|
||||
|
||||
void ShaderManagementConsoleApplication::ProcessCommandLine()
|
||||
void ShaderManagementConsoleApplication::ProcessCommandLine(const AZ::CommandLine& commandLine)
|
||||
{
|
||||
// Process command line options for running one or more python scripts on startup
|
||||
const AZStd::string runPythonScriptSwitchName = "runpython";
|
||||
size_t runPythonScriptCount = m_commandLine.GetNumSwitchValues(runPythonScriptSwitchName);
|
||||
for (size_t runPythonScriptIndex = 0; runPythonScriptIndex < runPythonScriptCount; ++runPythonScriptIndex)
|
||||
{
|
||||
const AZStd::string runPythonScriptPath = m_commandLine.GetSwitchValue(runPythonScriptSwitchName, runPythonScriptIndex);
|
||||
AZStd::vector<AZStd::string_view> runPythonArgs;
|
||||
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
|
||||
&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs, runPythonScriptPath, runPythonArgs);
|
||||
}
|
||||
|
||||
// Process command line options for opening one or more documents on startup
|
||||
size_t openDocumentCount = m_commandLine.GetNumMiscValues();
|
||||
size_t openDocumentCount = commandLine.GetNumMiscValues();
|
||||
for (size_t openDocumentIndex = 0; openDocumentIndex < openDocumentCount; ++openDocumentIndex)
|
||||
{
|
||||
const AZStd::string openDocumentPath = m_commandLine.GetMiscValue(openDocumentIndex);
|
||||
ShaderManagementConsoleDocumentSystemRequestBus::Broadcast(
|
||||
&ShaderManagementConsoleDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath);
|
||||
const AZStd::string openDocumentPath = commandLine.GetMiscValue(openDocumentIndex);
|
||||
|
||||
AZ_Printf(GetBuildTargetName().c_str(), "Opening document: %s", openDocumentPath.c_str());
|
||||
ShaderManagementConsoleDocumentSystemRequestBus::Broadcast(&ShaderManagementConsoleDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath);
|
||||
}
|
||||
|
||||
Base::ProcessCommandLine(commandLine);
|
||||
}
|
||||
|
||||
void ShaderManagementConsoleApplication::StartInternal()
|
||||
@@ -136,4 +132,12 @@ namespace ShaderManagementConsole
|
||||
ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Broadcast(
|
||||
&ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Handler::CreateShaderManagementConsoleWindow);
|
||||
}
|
||||
|
||||
void ShaderManagementConsoleApplication::Stop()
|
||||
{
|
||||
ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Broadcast(
|
||||
&ShaderManagementConsole::ShaderManagementConsoleWindowRequestBus::Handler::DestroyShaderManagementConsoleWindow);
|
||||
|
||||
Base::Stop();
|
||||
}
|
||||
} // namespace ShaderManagementConsole
|
||||
|
||||
+4
-3
@@ -26,12 +26,13 @@ namespace ShaderManagementConsole
|
||||
using Base = AtomToolsFramework::AtomToolsApplication;
|
||||
|
||||
ShaderManagementConsoleApplication(int* argc, char*** argv);
|
||||
virtual ~ShaderManagementConsoleApplication() = default;
|
||||
virtual ~ShaderManagementConsoleApplication();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AzFramework::Application
|
||||
void CreateStaticModules(AZStd::vector<AZ::Module*>& outModules) override;
|
||||
const char* GetCurrentConfigurationName() const override;
|
||||
void Stop() override;
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -44,9 +45,9 @@ namespace ShaderManagementConsole
|
||||
void Destroy() override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ProcessCommandLine();
|
||||
void ProcessCommandLine(const AZ::CommandLine& commandLine) override;
|
||||
void StartInternal() override;
|
||||
AZStd::string GetBuildTargetName() const override;
|
||||
AZStd::vector<AZStd::string> GetCriticalAssetFilters() const override;
|
||||
};
|
||||
};
|
||||
} // namespace ShaderManagementConsole
|
||||
|
||||
@@ -520,13 +520,14 @@ namespace AZ
|
||||
{
|
||||
AZStd::size_t sizeBeforeRemove = savedRegions.size();
|
||||
|
||||
auto firstRegionToKeep = AZStd::lower_bound(
|
||||
savedRegions.begin(), savedRegions.end(), deleteBeforeTick,
|
||||
[](const TimeRegion& region, AZStd::sys_time_t target)
|
||||
// Use erase_if over plain upper_bound + erase to avoid repeated shifts. erase requires a shift of all elements to the right
|
||||
// for each element that is erased, while erase_if squashes all removes into a single shift which significantly improves perf.
|
||||
AZStd::erase_if(
|
||||
savedRegions,
|
||||
[deleteBeforeTick](const TimeRegion& region)
|
||||
{
|
||||
return region.m_startTick < target;
|
||||
return region.m_startTick < deleteBeforeTick;
|
||||
});
|
||||
savedRegions.erase(savedRegions.begin(), firstRegionToKeep);
|
||||
|
||||
m_savedRegionCount -= sizeBeforeRemove - savedRegions.size();
|
||||
}
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
|
||||
#include <Atom/Features/PostProcessing/PostProcessUtil.azsli>
|
||||
|
||||
// Indicates whether to use pre-multiplied alpha
|
||||
option bool o_preMultiplyAlpha;
|
||||
|
||||
// If true pixels with an alpha value of less than 0.5 are clipped
|
||||
option bool o_alphaTest;
|
||||
|
||||
@@ -86,9 +83,9 @@ struct PSOutput
|
||||
float4 m_color : SV_Target0;
|
||||
};
|
||||
|
||||
float4 SampleTriangleTexture(int texIndex, float2 uv)
|
||||
float4 SampleTriangleTexture(uint texIndex, float2 uv)
|
||||
{
|
||||
if ((InstanceSrg::m_isClamp & (1 << texIndex)) != 0)
|
||||
if ((InstanceSrg::m_isClamp & (1U << texIndex)) != 0)
|
||||
{
|
||||
return InstanceSrg::m_texture[texIndex].Sample(InstanceSrg::m_clampSampler, uv);
|
||||
}
|
||||
@@ -120,14 +117,6 @@ PSOutput MainPS(VSOutput IN)
|
||||
resColor.xyz = LinearToSRGB(resColor.xyz);
|
||||
}
|
||||
|
||||
// Check for flag to premultiply alpha
|
||||
if (o_preMultiplyAlpha)
|
||||
{
|
||||
// premultiply the color by the alpha. This would not be required if we had full access to the separate alpha blend mode
|
||||
float preMult = resColor.w;
|
||||
resColor.xyz *= preMult;
|
||||
}
|
||||
|
||||
// If the o_modulate option is not None it means that the verts have two texture indicies. The second texture is used to
|
||||
// mask the first. This is used for gradient masks.
|
||||
if (o_modulate == Modulate::Alpha)
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
{
|
||||
"StableId": 1,
|
||||
"Options": {
|
||||
"o_preMultiplyAlpha": "false",
|
||||
"o_alphaTest": "false",
|
||||
"o_srgbWrite": "true",
|
||||
"o_modulate": "Modulate::None"
|
||||
@@ -13,11 +12,26 @@
|
||||
{
|
||||
"StableId": 2,
|
||||
"Options": {
|
||||
"o_preMultiplyAlpha": "false",
|
||||
"o_alphaTest": "true",
|
||||
"o_srgbWrite": "true",
|
||||
"o_alphaTest": "false",
|
||||
"o_srgbWrite": "false",
|
||||
"o_modulate": "Modulate::None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"StableId": 3,
|
||||
"Options": {
|
||||
"o_alphaTest": "true",
|
||||
"o_srgbWrite": "false",
|
||||
"o_modulate": "Modulate::None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"StableId": 4,
|
||||
"Options": {
|
||||
"o_alphaTest": "false",
|
||||
"o_srgbWrite": "false",
|
||||
"o_modulate": "Modulate::Alpha"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 <Asset/BlastChunksAsset.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
void BlastChunksAsset::SetModelAssetIds(const AZStd::vector<AZ::Data::AssetId>& modelAssetIds)
|
||||
{
|
||||
m_modelAssetIds = modelAssetIds;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::AssetId>& BlastChunksAsset::GetModelAssetIds() const
|
||||
{
|
||||
return m_modelAssetIds;
|
||||
}
|
||||
|
||||
void BlastChunksAsset::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<BlastChunksAsset, AZ::Data::AssetData>()
|
||||
->Version(1)
|
||||
->Field("modelAssetIds", &BlastChunksAsset::m_modelAssetIds);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Blast
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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/Asset/AssetCommon.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
//! The product asset file from a .blast_chunks file product asset file
|
||||
class BlastChunksAsset final
|
||||
: public AZ::Data::AssetData
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(BlastChunksAsset, "{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}", AZ::Data::AssetData);
|
||||
AZ_CLASS_ALLOCATOR(BlastChunksAsset, AZ::SystemAllocator, 0);
|
||||
|
||||
BlastChunksAsset() = default;
|
||||
~BlastChunksAsset() override = default;
|
||||
|
||||
void SetModelAssetIds(const AZStd::vector<AZ::Data::AssetId>& modelAssetIds);
|
||||
const AZStd::vector<AZ::Data::AssetId>& GetModelAssetIds() const;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
private:
|
||||
AZStd::vector<AZ::Data::AssetId> m_modelAssetIds;
|
||||
};
|
||||
} // namespace Blast
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Asset/BlastSliceAsset.h>
|
||||
#include <AzCore/RTTI/BehaviorContext.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
void BlastSliceAsset::SetMeshIdList(const AZStd::vector<AZ::Data::AssetId>& meshAssetIdList)
|
||||
{
|
||||
m_meshAssetIdList = meshAssetIdList;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::AssetId>& BlastSliceAsset::GetMeshIdList() const
|
||||
{
|
||||
return m_meshAssetIdList;
|
||||
}
|
||||
|
||||
void BlastSliceAsset::SetMaterialId(const AZ::Data::AssetId& materialAssetId)
|
||||
{
|
||||
m_materialAssetId = materialAssetId;
|
||||
}
|
||||
|
||||
const AZ::Data::AssetId& BlastSliceAsset::GetMaterialId() const
|
||||
{
|
||||
return m_materialAssetId;
|
||||
}
|
||||
|
||||
void BlastSliceAsset::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serializeContext->Class<BlastSliceAsset, AZ::Data::AssetData>()
|
||||
->Version(1)
|
||||
->Field("meshAssetIdList", &BlastSliceAsset::m_meshAssetIdList)
|
||||
->Field("materialAssetId", &BlastSliceAsset::m_materialAssetId);
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behavior = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behavior->Class<BlastSliceAsset>("BlastSliceAsset")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "blast")
|
||||
->Method("SetMeshIdList", &BlastSliceAsset::SetMeshIdList)
|
||||
->Method("GetMeshIdList", &BlastSliceAsset::GetMeshIdList)
|
||||
->Method("SetMaterialId", &BlastSliceAsset::SetMaterialId)
|
||||
->Method("GetMaterialId", &BlastSliceAsset::GetMaterialId)
|
||||
->Method(
|
||||
"GetAssetTypeId",
|
||||
[](BlastSliceAsset*)
|
||||
{
|
||||
return azrtti_typeid<BlastSliceAsset>();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Blast
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
//! The product asset file from a .blast_slice file product asset file
|
||||
class BlastSliceAsset final : public AZ::Data::AssetData
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(BlastSliceAsset, "{D04AAF07-EB12-4E50-8964-114A9B9C1FD1}", AZ::Data::AssetData);
|
||||
AZ_CLASS_ALLOCATOR(BlastSliceAsset, AZ::SystemAllocator, 0);
|
||||
|
||||
BlastSliceAsset() = default;
|
||||
~BlastSliceAsset() override = default;
|
||||
|
||||
void SetMeshIdList(const AZStd::vector<AZ::Data::AssetId>& meshAssetIdList);
|
||||
const AZStd::vector<AZ::Data::AssetId>& GetMeshIdList() const;
|
||||
|
||||
void SetMaterialId(const AZ::Data::AssetId& materialAssetId);
|
||||
const AZ::Data::AssetId& GetMaterialId() const;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
private:
|
||||
AZStd::vector<AZ::Data::AssetId> m_meshAssetIdList;
|
||||
AZ::Data::AssetId m_materialAssetId;
|
||||
};
|
||||
} // namespace Blast
|
||||
@@ -16,7 +16,6 @@
|
||||
#ifdef BLAST_EDITOR
|
||||
#include <Editor/EditorBlastFamilyComponent.h>
|
||||
#include <Editor/EditorBlastMeshDataComponent.h>
|
||||
#include <Editor/EditorBlastSliceAssetHandler.h>
|
||||
#include <Editor/EditorSystemComponent.h>
|
||||
#endif
|
||||
|
||||
@@ -40,8 +39,7 @@ namespace Blast
|
||||
#ifdef BLAST_EDITOR
|
||||
EditorSystemComponent::CreateDescriptor(),
|
||||
EditorBlastFamilyComponent::CreateDescriptor(),
|
||||
EditorBlastMeshDataComponent::CreateDescriptor(),
|
||||
BlastSliceAssetStorageComponent::CreateDescriptor(),
|
||||
EditorBlastMeshDataComponent::CreateDescriptor()
|
||||
#endif
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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 <Editor/EditorBlastMeshDataComponent.h>
|
||||
#include <Editor/EditorBlastChunksAssetHandler.h>
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/Serialization/ObjectStream.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
//
|
||||
// EditorBlastChunksAssetHandler
|
||||
//
|
||||
|
||||
EditorBlastChunksAssetHandler::~EditorBlastChunksAssetHandler()
|
||||
{
|
||||
Unregister();
|
||||
}
|
||||
|
||||
AZ::Data::AssetPtr EditorBlastChunksAssetHandler::CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type)
|
||||
{
|
||||
if (type != GetAssetType())
|
||||
{
|
||||
AZ_Error("Blast", type == GetAssetType(), "Invalid asset type! We only handle 'BlastChunksAsset'");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!CanHandleAsset(id))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return aznew BlastChunksAsset;
|
||||
}
|
||||
|
||||
AZ::Data::AssetHandler::LoadResult EditorBlastChunksAssetHandler::LoadAssetData(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
[[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB)
|
||||
{
|
||||
BlastChunksAsset* blastChunksAsset = asset.GetAs<BlastChunksAsset>();
|
||||
AZ_Error("blast", blastChunksAsset,
|
||||
"This should be a BlastChunksAsset type, as this is the only type we process!");
|
||||
if (!blastChunksAsset)
|
||||
{
|
||||
return LoadResult::Error;
|
||||
}
|
||||
|
||||
// get all products from the source scene asset
|
||||
bool found = false;
|
||||
AZStd::vector<AZ::Data::AssetInfo> productsAssetInfo;
|
||||
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
|
||||
found,
|
||||
&AzToolsFramework::AssetSystemRequestBus::Events::GetAssetsProducedBySourceUUID,
|
||||
asset.Get()->GetId().m_guid,
|
||||
productsAssetInfo);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
AZ_Error("blast",
|
||||
found,
|
||||
"Could not find asset models produced by source asset ID %s, verify the output product model assets.",
|
||||
asset.Get()->GetId().m_guid.ToString<AZStd::string>().c_str());
|
||||
return LoadResult::Error;
|
||||
}
|
||||
|
||||
// find all model assets
|
||||
AZStd::vector<AZ::Data::AssetId> modelAssetIdList;
|
||||
for (const AZ::Data::AssetInfo& assetInfo : productsAssetInfo)
|
||||
{
|
||||
if (azrtti_typeid<AZ::RPI::ModelAsset>() == assetInfo.m_assetType)
|
||||
{
|
||||
modelAssetIdList.push_back(assetInfo.m_assetId);
|
||||
}
|
||||
}
|
||||
blastChunksAsset->SetModelAssetIds(modelAssetIdList);
|
||||
|
||||
return LoadResult::LoadComplete;
|
||||
}
|
||||
|
||||
void EditorBlastChunksAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr)
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
void EditorBlastChunksAssetHandler::GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes)
|
||||
{
|
||||
assetTypes.push_back(azrtti_typeid<BlastChunksAsset>());
|
||||
}
|
||||
|
||||
void EditorBlastChunksAssetHandler::Register()
|
||||
{
|
||||
AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!");
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(this, azrtti_typeid<BlastChunksAsset>());
|
||||
AZ::AssetTypeInfoBus::Handler::BusConnect(azrtti_typeid<BlastChunksAsset>());
|
||||
}
|
||||
|
||||
void EditorBlastChunksAssetHandler::Unregister()
|
||||
{
|
||||
AZ::AssetTypeInfoBus::Handler::BusDisconnect(azrtti_typeid<BlastChunksAsset>());
|
||||
if (AZ::Data::AssetManager::IsReady())
|
||||
{
|
||||
AZ::Data::AssetManager::Instance().UnregisterHandler(this);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Data::AssetType EditorBlastChunksAssetHandler::GetAssetType() const
|
||||
{
|
||||
return azrtti_typeid<BlastChunksAsset>();
|
||||
}
|
||||
|
||||
const char* EditorBlastChunksAssetHandler::GetAssetTypeDisplayName() const
|
||||
{
|
||||
return "Blast Chunks Asset";
|
||||
}
|
||||
|
||||
const char* EditorBlastChunksAssetHandler::GetGroup() const
|
||||
{
|
||||
return "Blast";
|
||||
}
|
||||
|
||||
const char* EditorBlastChunksAssetHandler::GetBrowserIcon() const
|
||||
{
|
||||
return "Icons/Components/Box.png";
|
||||
}
|
||||
|
||||
void EditorBlastChunksAssetHandler::GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions)
|
||||
{
|
||||
extensions.push_back("blast_chunks");
|
||||
}
|
||||
|
||||
} // namespace Blast
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 <Asset/BlastChunksAsset.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Asset/AssetTypeInfoBus.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
class EditorBlastChunksAssetHandler final
|
||||
: public AZ::Data::AssetHandler
|
||||
, public AZ::AssetTypeInfoBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(EditorBlastChunksAssetHandler, AZ::SystemAllocator, 0);
|
||||
|
||||
~EditorBlastChunksAssetHandler() override;
|
||||
|
||||
// AZ::Data::AssetHandler
|
||||
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override;
|
||||
LoadResult LoadAssetData(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
const AZ::Data::AssetFilterCB& assetLoadFilterCB) override;
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override;
|
||||
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override;
|
||||
|
||||
// AZ::AssetTypeInfoBus::Handler
|
||||
AZ::Data::AssetType GetAssetType() const override;
|
||||
const char* GetAssetTypeDisplayName() const override;
|
||||
const char* GetGroup() const override;
|
||||
const char* GetBrowserIcon() const override;
|
||||
void GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions) override;
|
||||
|
||||
void Register();
|
||||
void Unregister();
|
||||
};
|
||||
} // namespace Blast
|
||||
@@ -45,10 +45,10 @@ namespace Blast
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<EditorBlastMeshDataComponent, AzToolsFramework::Components::EditorComponentBase>()
|
||||
->Version(4)
|
||||
->Version(5)
|
||||
->Field("Show Mesh Assets", &EditorBlastMeshDataComponent::m_showMeshAssets)
|
||||
->Field("Mesh Assets", &EditorBlastMeshDataComponent::m_meshAssets)
|
||||
->Field("Blast Slice", &EditorBlastMeshDataComponent::m_blastSliceAsset);
|
||||
->Field("Blast Chunks", &EditorBlastMeshDataComponent::m_blastChunksAsset);
|
||||
|
||||
if (AZ::EditContext* ec = serialize->GetEditContext())
|
||||
{
|
||||
@@ -77,9 +77,9 @@ namespace Blast
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, false)
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorBlastMeshDataComponent::OnMeshAssetsChanged)
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &EditorBlastMeshDataComponent::m_blastSliceAsset, "Blast Slice",
|
||||
"Slice override to fill out meshes and material")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorBlastMeshDataComponent::OnSliceAssetChanged);
|
||||
AZ::Edit::UIHandlers::Default, &EditorBlastMeshDataComponent::m_blastChunksAsset, "Blast Chunks",
|
||||
"Manifest override to fill out meshes and material")
|
||||
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorBlastMeshDataComponent::OnBlastChunksAssetChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,23 +107,27 @@ namespace Blast
|
||||
UnregisterModel();
|
||||
}
|
||||
|
||||
void EditorBlastMeshDataComponent::OnSliceAssetChanged()
|
||||
void EditorBlastMeshDataComponent::OnBlastChunksAssetChanged()
|
||||
{
|
||||
if (!m_blastSliceAsset.GetId().IsValid())
|
||||
if (!m_blastChunksAsset.GetId().IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using namespace AZ::Data;
|
||||
const AssetId blastAssetId = m_blastChunksAsset.GetId();
|
||||
m_blastChunksAsset = AssetManager::Instance().GetAsset<BlastChunksAsset>(blastAssetId, AssetLoadBehavior::QueueLoad);
|
||||
m_blastChunksAsset.BlockUntilLoadComplete();
|
||||
|
||||
const AssetId blastAssetId = m_blastSliceAsset.GetId();
|
||||
m_blastSliceAsset =
|
||||
AssetManager::Instance().GetAsset<BlastSliceAsset>(blastAssetId, AssetLoadBehavior::QueueLoad);
|
||||
m_blastSliceAsset.BlockUntilLoadComplete();
|
||||
if (!m_blastChunksAsset.Get() || m_blastChunksAsset.Get()->GetModelAssetIds().empty())
|
||||
{
|
||||
AZ_Warning("blast", false, "Blast Chunk Asset does not contain any models.")
|
||||
return;
|
||||
}
|
||||
|
||||
// load up the new mesh list
|
||||
m_meshAssets.clear();
|
||||
for (const auto& meshId : m_blastSliceAsset.Get()->GetMeshIdList())
|
||||
for (const auto& meshId : m_blastChunksAsset.Get()->GetModelAssetIds())
|
||||
{
|
||||
auto meshAsset = AssetManager::Instance().GetAsset<AZ::RPI::ModelAsset>(meshId, AssetLoadBehavior::QueueLoad);
|
||||
if (meshAsset)
|
||||
@@ -135,8 +139,8 @@ namespace Blast
|
||||
UnregisterModel();
|
||||
RegisterModel();
|
||||
|
||||
AzToolsFramework::ToolsApplicationEvents::Bus::Broadcast(
|
||||
&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree);
|
||||
using namespace AzToolsFramework;
|
||||
ToolsApplicationEvents::Bus::Broadcast(&ToolsApplicationEvents::InvalidatePropertyDisplay, Refresh_EntireTree);
|
||||
}
|
||||
|
||||
void EditorBlastMeshDataComponent::OnMeshAssetsChanged()
|
||||
@@ -205,9 +209,9 @@ namespace Blast
|
||||
gameEntity->CreateComponent<BlastMeshDataComponent>(m_meshAssets);
|
||||
}
|
||||
|
||||
const AZ::Data::Asset<BlastSliceAsset>& EditorBlastMeshDataComponent::GetBlastSliceAsset() const
|
||||
const AZ::Data::Asset<BlastChunksAsset>& EditorBlastMeshDataComponent::GetBlastChunksAsset() const
|
||||
{
|
||||
return m_blastSliceAsset;
|
||||
return m_blastChunksAsset;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::RPI::ModelAsset>>& EditorBlastMeshDataComponent::GetMeshAssets() const
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Asset/BlastSliceAsset.h>
|
||||
#include <Asset/BlastChunksAsset.h>
|
||||
#include <Atom/Feature/Mesh/MeshFeatureProcessorInterface.h>
|
||||
#include <Atom/RPI.Public/Model/Model.h>
|
||||
#include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
|
||||
@@ -43,14 +43,14 @@ namespace Blast
|
||||
// EditorComponentBase
|
||||
void BuildGameEntity(AZ::Entity* gameEntity) override;
|
||||
|
||||
const AZ::Data::Asset<BlastSliceAsset>& GetBlastSliceAsset() const;
|
||||
const AZ::Data::Asset<BlastChunksAsset>& GetBlastChunksAsset() const;
|
||||
const AZStd::vector<AZ::Data::Asset<AZ::RPI::ModelAsset>>& GetMeshAssets() const;
|
||||
|
||||
void OnMaterialsUpdated(const AZ::Render::MaterialAssignmentMap& materials) override;
|
||||
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
|
||||
|
||||
private:
|
||||
void OnSliceAssetChanged();
|
||||
void OnBlastChunksAssetChanged();
|
||||
void OnMeshAssetsChanged();
|
||||
AZ::Crc32 GetMeshAssetsVisibility() const;
|
||||
void OnMeshAssetsVisibilityChanged();
|
||||
@@ -62,7 +62,7 @@ namespace Blast
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Reflected data
|
||||
bool m_showMeshAssets = false;
|
||||
AZ::Data::Asset<BlastSliceAsset> m_blastSliceAsset;
|
||||
AZ::Data::Asset<BlastChunksAsset> m_blastChunksAsset;
|
||||
AZStd::vector<AZ::Data::Asset<AZ::RPI::ModelAsset>> m_meshAssets;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -1,345 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Editor/EditorBlastMeshDataComponent.h>
|
||||
#include <Editor/EditorBlastSliceAssetHandler.h>
|
||||
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/GenericStreams.h>
|
||||
#include <AzCore/Serialization/ObjectStream.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/Serialization/Utils.h>
|
||||
#include <AzCore/Slice/SliceComponent.h>
|
||||
#include <AzCore/StringFunc/StringFunc.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <SceneAPI/SceneCore/Containers/RuleContainer.h>
|
||||
#include <SceneAPI/SceneCore/Containers/SceneManifest.h>
|
||||
#include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h>
|
||||
#include <SceneAPI/SceneData/Groups/MeshGroup.h>
|
||||
#include <SceneAPI/SceneData/ManifestBase/SceneNodeSelectionList.h>
|
||||
#include <SceneAPI/SceneData/Rules/MaterialRule.h>
|
||||
|
||||
#include <GFxFramework/MaterialIO/Material.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
// BlastSliceAssetStorageComponent
|
||||
|
||||
void BlastSliceAssetStorageComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
using namespace AZ::Edit;
|
||||
|
||||
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
serialize->Class<BlastSliceAssetStorageComponent, AzToolsFramework::Components::EditorComponentBase>()
|
||||
->Version(2)
|
||||
->Field("Mesh Data", &BlastSliceAssetStorageComponent::m_meshAssetIdList)
|
||||
->Field("Mesh Path List", &BlastSliceAssetStorageComponent::m_meshAssetPathList);
|
||||
|
||||
if (AZ::EditContext* ec = serialize->GetEditContext())
|
||||
{
|
||||
ec->Class<BlastSliceAssetStorageComponent>(
|
||||
"Blast Slice Storage Component", "Used process blast slice data")
|
||||
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
|
||||
->Attribute(AZ::Edit::Attributes::Category, "Physics")
|
||||
->Attribute(AZ::Edit::Attributes::Icon, "Icons/Components/Box.png")
|
||||
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Box.png")
|
||||
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
|
||||
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
|
||||
->Attribute(AZ::Edit::Attributes::AddableByUser, false)
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &BlastSliceAssetStorageComponent::m_meshAssetIdList, "Mesh Data",
|
||||
"Slice data to fill out the mesh list")
|
||||
->DataElement(
|
||||
AZ::Edit::UIHandlers::Default, &BlastSliceAssetStorageComponent::m_meshAssetPathList,
|
||||
"Mesh Paths", "The mesh path list");
|
||||
}
|
||||
}
|
||||
|
||||
if (AZ::BehaviorContext* behavior = azrtti_cast<AZ::BehaviorContext*>(context))
|
||||
{
|
||||
behavior->Class<BlastSliceAssetStorageComponent>("BlastSliceAssetStorageComponent")
|
||||
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
|
||||
->Attribute(AZ::Script::Attributes::Module, "blast")
|
||||
->Method("GenerateAssetInfo", &BlastSliceAssetStorageComponent::GenerateAssetInfo)
|
||||
->Method("WriteMaterialFile", &BlastSliceAssetStorageComponent::WriteMaterialFile);
|
||||
}
|
||||
}
|
||||
|
||||
bool BlastSliceAssetStorageComponent::GenerateAssetInfo(
|
||||
const AZStd::vector<AZStd::string>& chunkNames, AZStd::string_view blastFilename,
|
||||
AZStd::string_view assetinfoFilename)
|
||||
{
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(
|
||||
serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
if (serializeContext == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
using namespace AZ::SceneAPI::Containers;
|
||||
using namespace AZ::SceneAPI::SceneData;
|
||||
|
||||
AZStd::string filename;
|
||||
AZ::StringFunc::Path::Split(blastFilename.data(), nullptr, nullptr, &filename, nullptr);
|
||||
|
||||
AZStd::any sceneManifestPointer(serializeContext->CreateAny(azrtti_typeid<SceneManifest>()));
|
||||
SceneManifest* sceneManifest = AZStd::any_cast<SceneManifest>(&sceneManifestPointer);
|
||||
|
||||
AZStd::vector<AZStd::any> meshGroupData;
|
||||
meshGroupData.reserve(chunkNames.size());
|
||||
|
||||
AZStd::vector<AZStd::any> materialRuleData;
|
||||
materialRuleData.reserve(chunkNames.size());
|
||||
|
||||
for (const AZStd::string& chunkName : chunkNames)
|
||||
{
|
||||
meshGroupData.emplace_back(serializeContext->CreateAny(azrtti_typeid<MeshGroup>()));
|
||||
AZStd::any& meshGroupPointer = meshGroupData.back();
|
||||
MeshGroup* meshGroup = AZStd::any_cast<MeshGroup>(&meshGroupPointer);
|
||||
|
||||
// make selection list
|
||||
meshGroup->GetSceneNodeSelectionList().RemoveSelectedNode("RootNode");
|
||||
for (const AZStd::string& node : chunkNames)
|
||||
{
|
||||
meshGroup->GetSceneNodeSelectionList().RemoveSelectedNode(
|
||||
AZStd::string::format("RootNode.%s", node.c_str()));
|
||||
}
|
||||
meshGroup->GetSceneNodeSelectionList().AddSelectedNode(
|
||||
AZStd::string::format("RootNode.%s", chunkName.c_str()));
|
||||
|
||||
// create a default material for the mesh group
|
||||
materialRuleData.emplace_back(serializeContext->CreateAny(azrtti_typeid<MaterialRule>()));
|
||||
AZStd::any& materialRulePointer = materialRuleData.back();
|
||||
MaterialRule* materialRule = AZStd::any_cast<MaterialRule>(&materialRulePointer);
|
||||
|
||||
// override the deleter since the AZStd::any will clean up later on
|
||||
AZStd::shared_ptr<MaterialRule> materialRuleEntry = AZStd::shared_ptr<MaterialRule>(
|
||||
materialRule,
|
||||
[](auto)
|
||||
{
|
||||
});
|
||||
meshGroup->GetRuleContainer().AddRule(materialRuleEntry);
|
||||
|
||||
// construct the asset name for the chunk's mesh group
|
||||
AZStd::string meshGroupName(filename);
|
||||
meshGroupName.append("-");
|
||||
meshGroupName.append(chunkName);
|
||||
// TODO: Uncomment lines below as part of SPEC-3542
|
||||
// meshGroup->OverrideId(AZ::Uuid::CreateName(meshGroupName.c_str()));
|
||||
// meshGroup->SetName(AZStd::move(meshGroupName));
|
||||
|
||||
// override the deleter since the AZStd::any will clean up later on
|
||||
AZStd::shared_ptr<MeshGroup> meshGroupEntry = AZStd::shared_ptr<MeshGroup>(
|
||||
meshGroup,
|
||||
[](auto)
|
||||
{
|
||||
});
|
||||
sceneManifest->AddEntry(AZStd::move(meshGroupEntry));
|
||||
}
|
||||
|
||||
return sceneManifest->SaveToFile(assetinfoFilename.data());
|
||||
}
|
||||
|
||||
bool BlastSliceAssetStorageComponent::WriteMaterialFile(
|
||||
AZStd::string_view materialGroupName, const AZStd::vector<AZStd::string>& materialNames,
|
||||
AZStd::string_view materialFilename)
|
||||
{
|
||||
AZ::GFxFramework::MaterialGroup group;
|
||||
for (const auto& texture : materialNames)
|
||||
{
|
||||
auto mat = AZStd::make_shared<AZ::GFxFramework::Material>();
|
||||
mat->SetName(texture);
|
||||
mat->SetTexture(AZ::GFxFramework::TextureMapType::Diffuse, "EngineAssets/Textures/white.dds");
|
||||
group.AddMaterial(mat);
|
||||
}
|
||||
group.SetMtlName(materialGroupName);
|
||||
return group.WriteMtlFile(materialFilename.data());
|
||||
}
|
||||
|
||||
//
|
||||
// EditorBlastSliceAssetHandler
|
||||
//
|
||||
|
||||
EditorBlastSliceAssetHandler::~EditorBlastSliceAssetHandler()
|
||||
{
|
||||
Unregister();
|
||||
}
|
||||
|
||||
AZ::Data::AssetPtr EditorBlastSliceAssetHandler::CreateAsset(
|
||||
const AZ::Data::AssetId& id, const AZ::Data::AssetType& type)
|
||||
{
|
||||
if (type != GetAssetType())
|
||||
{
|
||||
AZ_Error("Blast", type == GetAssetType(), "Invalid asset type! We only handle 'BlastAsset'");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (!CanHandleAsset(id))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return aznew BlastSliceAsset;
|
||||
}
|
||||
|
||||
AZ::Data::AssetHandler::LoadResult EditorBlastSliceAssetHandler::LoadAssetData(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>& asset, AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
const AZ::Data::AssetFilterCB& assetLoadFilterCB)
|
||||
{
|
||||
BlastSliceAsset* blastSliceAssetData = asset.GetAs<BlastSliceAsset>();
|
||||
AZ_Error(
|
||||
"blast", blastSliceAssetData,
|
||||
"This should be a BlastSliceAsset type, as this is the only type we process!");
|
||||
AZ::SerializeContext* serializeContext = nullptr;
|
||||
AZ::ComponentApplicationBus::BroadcastResult(
|
||||
serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
|
||||
if (blastSliceAssetData && serializeContext)
|
||||
{
|
||||
AZ::ObjectStream::FilterDescriptor filter(assetLoadFilterCB);
|
||||
AZStd::unique_ptr<AZ::Entity> baseEntity(
|
||||
AZ::Utils::LoadObjectFromStream<AZ::Entity>(*stream, serializeContext, filter));
|
||||
AZ_Error("Blast", baseEntity, "Could not load slice root entity {asset id}");
|
||||
if (!baseEntity)
|
||||
{
|
||||
return LoadResult::Error;
|
||||
}
|
||||
|
||||
auto&& sliceComponent = baseEntity->FindComponent<AZ::SliceComponent>();
|
||||
AZ_Error("Blast", sliceComponent, "blast_slice entity missing SliceComponent!");
|
||||
if (sliceComponent == nullptr)
|
||||
{
|
||||
return LoadResult::Error;
|
||||
}
|
||||
|
||||
AZStd::vector<AZ::Entity*> enityList;
|
||||
sliceComponent->GetEntities(enityList);
|
||||
for (auto&& entity : enityList)
|
||||
{
|
||||
// the base element type to store Blast mesh data is the BlastSliceAssetStorageComponent
|
||||
auto&& blastSliceAssetStorage = entity->FindComponent<BlastSliceAssetStorageComponent>();
|
||||
if (blastSliceAssetStorage)
|
||||
{
|
||||
if (blastSliceAssetStorage->GetMeshData().empty() == false)
|
||||
{
|
||||
blastSliceAssetData->SetMeshIdList(blastSliceAssetStorage->GetMeshData());
|
||||
return LoadResult::LoadComplete;
|
||||
}
|
||||
else if (blastSliceAssetStorage->GetMeshPathList().empty() == false)
|
||||
{
|
||||
AZStd::vector<AZ::Data::AssetId> meshAssetIdList;
|
||||
meshAssetIdList.reserve(blastSliceAssetStorage->GetMeshPathList().size());
|
||||
|
||||
for (auto&& assetPath : blastSliceAssetStorage->GetMeshPathList())
|
||||
{
|
||||
AZ::Data::AssetId meshAssetId;
|
||||
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
|
||||
meshAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
|
||||
assetPath.c_str(), AZ::Data::s_invalidAssetType, false);
|
||||
|
||||
if (meshAssetId.IsValid())
|
||||
{
|
||||
meshAssetIdList.emplace_back(meshAssetId);
|
||||
}
|
||||
}
|
||||
blastSliceAssetData->SetMeshIdList(meshAssetIdList);
|
||||
return LoadResult::LoadComplete;
|
||||
}
|
||||
}
|
||||
|
||||
// back up logic to load blast data for the EditorBlastMeshDataComponent
|
||||
auto&& meshDataComponent = entity->FindComponent<EditorBlastMeshDataComponent>();
|
||||
if (meshDataComponent)
|
||||
{
|
||||
auto&& innerBlastSliceAsset = meshDataComponent->GetBlastSliceAsset();
|
||||
if (innerBlastSliceAsset.IsReady())
|
||||
{
|
||||
blastSliceAssetData->SetMeshIdList(innerBlastSliceAsset.Get()->GetMeshIdList());
|
||||
blastSliceAssetData->SetMaterialId(innerBlastSliceAsset.Get()->GetMaterialId());
|
||||
return LoadResult::LoadComplete;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto&& meshDataList = meshDataComponent->GetMeshAssets();
|
||||
AZStd::vector<AZ::Data::AssetId> meshAssetIdList;
|
||||
meshAssetIdList.reserve(meshDataList.size());
|
||||
for (auto&& meshData : meshDataList)
|
||||
{
|
||||
AZ::RPI::ModelAsset* meshAsset = meshData.Get();
|
||||
if (meshAsset)
|
||||
{
|
||||
meshAssetIdList.push_back(meshAsset->GetId());
|
||||
}
|
||||
}
|
||||
blastSliceAssetData->SetMeshIdList(meshAssetIdList);
|
||||
return LoadResult::LoadComplete;
|
||||
}
|
||||
}
|
||||
}
|
||||
AZ_Error(
|
||||
"Blast", false, "blast_slice assetId:%s missing EditorBlastMeshDataComponent!",
|
||||
asset->GetId().ToString<AZStd::string>().c_str());
|
||||
}
|
||||
return LoadResult::Error;
|
||||
}
|
||||
|
||||
void EditorBlastSliceAssetHandler::DestroyAsset(AZ::Data::AssetPtr ptr)
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
void EditorBlastSliceAssetHandler::GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes)
|
||||
{
|
||||
assetTypes.push_back(azrtti_typeid<BlastSliceAsset>());
|
||||
}
|
||||
|
||||
void EditorBlastSliceAssetHandler::Register()
|
||||
{
|
||||
AZ_Assert(AZ::Data::AssetManager::IsReady(), "Asset manager isn't ready!");
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(this, azrtti_typeid<BlastSliceAsset>());
|
||||
AZ::AssetTypeInfoBus::Handler::BusConnect(azrtti_typeid<BlastSliceAsset>());
|
||||
}
|
||||
|
||||
void EditorBlastSliceAssetHandler::Unregister()
|
||||
{
|
||||
AZ::AssetTypeInfoBus::Handler::BusDisconnect(azrtti_typeid<BlastSliceAsset>());
|
||||
if (AZ::Data::AssetManager::IsReady())
|
||||
{
|
||||
AZ::Data::AssetManager::Instance().UnregisterHandler(this);
|
||||
}
|
||||
}
|
||||
|
||||
AZ::Data::AssetType EditorBlastSliceAssetHandler::GetAssetType() const
|
||||
{
|
||||
return azrtti_typeid<BlastSliceAsset>();
|
||||
}
|
||||
|
||||
const char* EditorBlastSliceAssetHandler::GetAssetTypeDisplayName() const
|
||||
{
|
||||
return "Blast Slice Asset";
|
||||
}
|
||||
|
||||
const char* EditorBlastSliceAssetHandler::GetGroup() const
|
||||
{
|
||||
return "Blast";
|
||||
}
|
||||
|
||||
const char* EditorBlastSliceAssetHandler::GetBrowserIcon() const
|
||||
{
|
||||
return "Icons/Components/Box.png";
|
||||
}
|
||||
|
||||
void EditorBlastSliceAssetHandler::GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions)
|
||||
{
|
||||
extensions.push_back("blast_slice");
|
||||
}
|
||||
|
||||
} // namespace Blast
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <Asset/BlastSliceAsset.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Asset/AssetTypeInfoBus.h>
|
||||
#include <AzCore/Serialization/EditContext.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
//! Used to create store asset references (i.e. ids) to fill out the EditorBlastMeshDataComponent
|
||||
class BlastSliceAssetStorageComponent final : public AzToolsFramework::Components::EditorComponentBase
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(
|
||||
BlastSliceAssetStorageComponent, "{696C7E62-1EA4-41E2-B4F6-7BD0D30888DC}",
|
||||
AzToolsFramework::Components::EditorComponentBase);
|
||||
|
||||
~BlastSliceAssetStorageComponent() override = default;
|
||||
|
||||
static void Reflect(AZ::ReflectContext* context);
|
||||
|
||||
const AZStd::vector<AZ::Data::AssetId>& GetMeshData() const
|
||||
{
|
||||
return m_meshAssetIdList;
|
||||
}
|
||||
|
||||
void SetMeshData(const AZStd::vector<AZ::Data::AssetId>& meshAssetIdList)
|
||||
{
|
||||
m_meshAssetIdList = meshAssetIdList;
|
||||
}
|
||||
|
||||
const AZStd::vector<AZStd::string>& GetMeshPathList() const
|
||||
{
|
||||
return m_meshAssetPathList;
|
||||
}
|
||||
|
||||
void SetMeshPathList(const AZStd::vector<AZStd::string>& meshAssetPathList)
|
||||
{
|
||||
m_meshAssetPathList = meshAssetPathList;
|
||||
}
|
||||
|
||||
private:
|
||||
// AZ::Component interface implementation
|
||||
void Activate() override {}
|
||||
void Deactivate() override {}
|
||||
|
||||
// EditorComponentBase
|
||||
void BuildGameEntity([[maybe_unused]] AZ::Entity* gameEntity) override {}
|
||||
|
||||
// Script API
|
||||
bool GenerateAssetInfo(
|
||||
const AZStd::vector<AZStd::string>& chunkNames,
|
||||
AZStd::string_view blastFilename,
|
||||
AZStd::string_view assetinfoFilename);
|
||||
|
||||
bool WriteMaterialFile(
|
||||
AZStd::string_view materialGroupName,
|
||||
const AZStd::vector<AZStd::string>& materialNames,
|
||||
AZStd::string_view materialFilename);
|
||||
|
||||
AZStd::vector<AZ::Data::AssetId> m_meshAssetIdList;
|
||||
AZStd::vector<AZStd::string> m_meshAssetPathList;
|
||||
};
|
||||
|
||||
class EditorBlastSliceAssetHandler final
|
||||
: public AZ::Data::AssetHandler
|
||||
, public AZ::AssetTypeInfoBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_CLASS_ALLOCATOR(EditorBlastSliceAssetHandler, AZ::SystemAllocator, 0);
|
||||
|
||||
~EditorBlastSliceAssetHandler() override;
|
||||
|
||||
// AZ::Data::AssetHandler
|
||||
AZ::Data::AssetPtr CreateAsset(const AZ::Data::AssetId& id, const AZ::Data::AssetType& type) override;
|
||||
LoadResult LoadAssetData(
|
||||
const AZ::Data::Asset<AZ::Data::AssetData>& asset, AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
const AZ::Data::AssetFilterCB& assetLoadFilterCB) override;
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override;
|
||||
void GetHandledAssetTypes(AZStd::vector<AZ::Data::AssetType>& assetTypes) override;
|
||||
|
||||
// AZ::AssetTypeInfoBus::Handler
|
||||
AZ::Data::AssetType GetAssetType() const override;
|
||||
const char* GetAssetTypeDisplayName() const override;
|
||||
const char* GetGroup() const override;
|
||||
const char* GetBrowserIcon() const override;
|
||||
void GetAssetTypeExtensions(AZStd::vector<AZStd::string>& extensions) override;
|
||||
|
||||
void Register();
|
||||
void Unregister();
|
||||
};
|
||||
} // namespace Blast
|
||||
@@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Asset/BlastSliceAsset.h>
|
||||
#include <Asset/BlastChunksAsset.h>
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <Editor/EditorSystemComponent.h>
|
||||
#include <Editor/EditorWindow.h>
|
||||
@@ -16,7 +16,7 @@ namespace Blast
|
||||
{
|
||||
void EditorSystemComponent::Reflect(AZ::ReflectContext* context)
|
||||
{
|
||||
BlastSliceAsset::Reflect(context);
|
||||
BlastChunksAsset::Reflect(context);
|
||||
|
||||
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
|
||||
{
|
||||
@@ -26,14 +26,14 @@ namespace Blast
|
||||
|
||||
void EditorSystemComponent::Activate()
|
||||
{
|
||||
m_editorBlastSliceAssetHandler = AZStd::make_unique<EditorBlastSliceAssetHandler>();
|
||||
m_editorBlastSliceAssetHandler->Register();
|
||||
m_editorBlastChunksAssetHandler = AZStd::make_unique<EditorBlastChunksAssetHandler>();
|
||||
m_editorBlastChunksAssetHandler->Register();
|
||||
|
||||
auto assetCatalog = AZ::Data::AssetCatalogRequestBus::FindFirstHandler();
|
||||
if (assetCatalog)
|
||||
{
|
||||
assetCatalog->EnableCatalogForAsset(azrtti_typeid<BlastSliceAsset>());
|
||||
assetCatalog->AddExtension("blast_slice");
|
||||
assetCatalog->EnableCatalogForAsset(azrtti_typeid<BlastChunksAsset>());
|
||||
assetCatalog->AddExtension("blast_chunks");
|
||||
}
|
||||
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
|
||||
@@ -46,7 +46,7 @@ namespace Blast
|
||||
void EditorSystemComponent::Deactivate()
|
||||
{
|
||||
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
|
||||
m_editorBlastSliceAssetHandler.reset();
|
||||
m_editorBlastChunksAssetHandler.reset();
|
||||
}
|
||||
|
||||
// This will be called when the IEditor instance is ready
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <AzCore/Component/TickBus.h>
|
||||
#include <AzToolsFramework/Entity/EditorEntityContextBus.h>
|
||||
#include <Editor/EditorBlastSliceAssetHandler.h>
|
||||
#include <Editor/EditorBlastChunksAssetHandler.h>
|
||||
|
||||
namespace Blast
|
||||
{
|
||||
@@ -39,7 +39,7 @@ namespace Blast
|
||||
required.push_back(AZ_CRC("BlastService", 0x75beae2d));
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<EditorBlastSliceAssetHandler> m_editorBlastSliceAssetHandler;
|
||||
AZStd::unique_ptr<EditorBlastChunksAssetHandler> m_editorBlastChunksAssetHandler;
|
||||
|
||||
// AZ::Component
|
||||
void Activate() override;
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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 <Editor/EditorBlastChunksAssetHandler.h>
|
||||
#include <Editor/EditorBlastMeshDataComponent.h>
|
||||
#include <Asset/BlastChunksAsset.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <AzCore/UnitTest/MockComponentApplication.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
MockComponentApplication::MockComponentApplication()
|
||||
{
|
||||
AZ::ComponentApplicationBus::Handler::BusConnect();
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Register(this);
|
||||
}
|
||||
|
||||
MockComponentApplication::~MockComponentApplication()
|
||||
{
|
||||
AZ::Interface<AZ::ComponentApplicationRequests>::Unregister(this);
|
||||
AZ::ComponentApplicationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
class MockAssetCatalogRequestBusHandler final
|
||||
: public AZ::Data::AssetCatalogRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
MockAssetCatalogRequestBusHandler()
|
||||
{
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
virtual ~MockAssetCatalogRequestBusHandler()
|
||||
{
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
MOCK_METHOD3(GetAssetIdByPath, AZ::Data::AssetId(const char*, const AZ::Data::AssetType&, bool));
|
||||
MOCK_METHOD1(GetAssetInfoById, AZ::Data::AssetInfo(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(AddAssetType, void(const AZ::Data::AssetType&));
|
||||
MOCK_METHOD1(AddDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(AddExtension, void(const char*));
|
||||
MOCK_METHOD0(ClearCatalog, void());
|
||||
MOCK_METHOD5(CreateBundleManifest, bool(const AZStd::string&, const AZStd::vector<AZStd::string>&, const AZStd::string&, int, const AZStd::vector<AZStd::string>&));
|
||||
MOCK_METHOD2(CreateDeltaCatalog, bool(const AZStd::vector<AZStd::string>&, const AZStd::string&));
|
||||
MOCK_METHOD0(DisableCatalog, void());
|
||||
MOCK_METHOD1(EnableCatalogForAsset, void(const AZ::Data::AssetType&));
|
||||
MOCK_METHOD3(EnumerateAssets, void(BeginAssetEnumerationCB, AssetEnumerationCB, EndAssetEnumerationCB));
|
||||
MOCK_METHOD1(GenerateAssetIdTEMP, AZ::Data::AssetId(const char*));
|
||||
MOCK_METHOD1(GetAllProductDependencies, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD3(GetAllProductDependenciesFilter, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&, const AZStd::unordered_set<AZ::Data::AssetId>&, const AZStd::vector<AZStd::string>&));
|
||||
MOCK_METHOD1(GetAssetPathById, AZStd::string(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(GetDirectProductDependencies, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(GetHandledAssetTypes, void(AZStd::vector<AZ::Data::AssetType>&));
|
||||
MOCK_METHOD0(GetRegisteredAssetPaths, AZStd::vector<AZStd::string>());
|
||||
MOCK_METHOD2(InsertDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>, size_t));
|
||||
MOCK_METHOD2(InsertDeltaCatalogBefore, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>, AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(LoadCatalog, bool(const char*));
|
||||
MOCK_METHOD2(RegisterAsset, void(const AZ::Data::AssetId&, AZ::Data::AssetInfo&));
|
||||
MOCK_METHOD1(RemoveDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(SaveCatalog, bool(const char*));
|
||||
MOCK_METHOD0(StartMonitoringAssets, void());
|
||||
MOCK_METHOD0(StopMonitoringAssets, void());
|
||||
MOCK_METHOD1(UnregisterAsset, void(const AZ::Data::AssetId&));
|
||||
};
|
||||
|
||||
class MockAssetManager
|
||||
: public AZ::Data::AssetManager
|
||||
{
|
||||
public:
|
||||
MockAssetManager(const AZ::Data::AssetManager::Descriptor& desc) :
|
||||
AssetManager(desc)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class EditorBlastChunkAssetHandlerTestFixture
|
||||
: public AllocatorsTestFixture
|
||||
{
|
||||
public:
|
||||
AZStd::unique_ptr<UnitTest::MockComponentApplication> m_mockComponentApplicationBusHandler;
|
||||
AZStd::unique_ptr<MockAssetCatalogRequestBusHandler> m_mockAssetCatalogRequestBusHandler;
|
||||
AZStd::unique_ptr<MockAssetManager> m_mockAssetManager;
|
||||
|
||||
void SetUp() override final
|
||||
{
|
||||
AllocatorsTestFixture::SetUp();
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
|
||||
m_mockComponentApplicationBusHandler = AZStd::make_unique<UnitTest::MockComponentApplication>();
|
||||
m_mockAssetCatalogRequestBusHandler = AZStd::make_unique<MockAssetCatalogRequestBusHandler>();
|
||||
m_mockAssetManager = AZStd::make_unique<MockAssetManager>(AZ::Data::AssetManager::Descriptor{});
|
||||
|
||||
AZ::Data::AssetManager::SetInstance(m_mockAssetManager.get());
|
||||
}
|
||||
|
||||
void TearDown() override final
|
||||
{
|
||||
m_mockAssetManager.release();
|
||||
AZ::Data::AssetManager::Destroy();
|
||||
|
||||
m_mockAssetCatalogRequestBusHandler.reset();
|
||||
m_mockComponentApplicationBusHandler.reset();
|
||||
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
|
||||
AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(EditorBlastChunkAssetHandlerTestFixture, EditorBlastChunkAssetHandler_AssetManager_Registered)
|
||||
{
|
||||
Blast::EditorBlastChunksAssetHandler handler;
|
||||
handler.Register();
|
||||
EXPECT_NE(nullptr, AZ::Data::AssetManager::Instance().GetHandler(azrtti_typeid<Blast::BlastChunksAsset>()));
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastChunkAssetHandlerTestFixture, EditorBlastChunkAssetHandler_AssetTypeInfoBus_Responds)
|
||||
{
|
||||
auto assetId = azrtti_typeid<Blast::BlastChunksAsset>();
|
||||
|
||||
Blast::EditorBlastChunksAssetHandler handler;
|
||||
handler.Register();
|
||||
|
||||
AZ::Data::AssetType assetType = AZ::Uuid::CreateNull();
|
||||
AZ::AssetTypeInfoBus::EventResult(assetType, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetType);
|
||||
EXPECT_NE(AZ::Uuid::CreateNull(), assetType);
|
||||
|
||||
const char* displayName = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(displayName, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeDisplayName);
|
||||
EXPECT_STREQ("Blast Chunks Asset", displayName);
|
||||
|
||||
const char* group = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(group, assetId, &AZ::AssetTypeInfoBus::Events::GetGroup);
|
||||
EXPECT_STREQ("Blast", group);
|
||||
|
||||
const char* icon = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(icon, assetId, &AZ::AssetTypeInfoBus::Events::GetBrowserIcon);
|
||||
EXPECT_STREQ("Icons/Components/Box.png", icon);
|
||||
|
||||
AZStd::vector<AZStd::string> extensions;
|
||||
AZ::AssetTypeInfoBus::Event(assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeExtensions, extensions);
|
||||
ASSERT_EQ(1, extensions.size());
|
||||
ASSERT_EQ("blast_chunks", extensions[0]);
|
||||
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastChunkAssetHandlerTestFixture, EditorBlastChunkAssetHandler_AssetHandler_Ready)
|
||||
{
|
||||
auto assetType = azrtti_typeid<Blast::BlastChunksAsset>();
|
||||
auto&& assetManager = AZ::Data::AssetManager::Instance();
|
||||
|
||||
Blast::EditorBlastChunksAssetHandler handler;
|
||||
handler.Register();
|
||||
EXPECT_EQ(&handler, assetManager.GetHandler(assetType));
|
||||
|
||||
// create and release an instance of the BlastChunkAsset asset type
|
||||
{
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
|
||||
EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetInfoById(_))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(AZ::Data::AssetInfo{}));
|
||||
|
||||
auto assetPtr = assetManager.CreateAsset<Blast::BlastChunksAsset>(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0));
|
||||
EXPECT_NE(nullptr, assetPtr.Get());
|
||||
EXPECT_EQ(azrtti_typeid<Blast::BlastChunksAsset>(), assetPtr.GetType());
|
||||
}
|
||||
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,377 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Editor/EditorBlastSliceAssetHandler.h>
|
||||
#include <Editor/EditorBlastMeshDataComponent.h>
|
||||
#include <Asset/BlastSliceAsset.h>
|
||||
|
||||
#include <AzCore/UnitTest/MockComponentApplication.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class MockComponentApplicationBusHandler final
|
||||
//: public MockComponentApplication
|
||||
: public AZ::ComponentApplicationBus::Handler
|
||||
{
|
||||
public:
|
||||
MockComponentApplicationBusHandler()
|
||||
{
|
||||
AZ::ComponentApplicationBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
virtual ~MockComponentApplicationBusHandler()
|
||||
{
|
||||
AZ::ComponentApplicationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
MOCK_METHOD0(Destroy, void());
|
||||
MOCK_METHOD1(RegisterComponentDescriptor, void(const AZ::ComponentDescriptor*));
|
||||
MOCK_METHOD1(UnregisterComponentDescriptor, void(const AZ::ComponentDescriptor*));
|
||||
MOCK_METHOD1(RemoveEntity, bool(AZ::Entity*));
|
||||
MOCK_METHOD1(DeleteEntity, bool(const AZ::EntityId&));
|
||||
MOCK_METHOD1(GetEntityName, AZStd::string(const AZ::EntityId&));
|
||||
MOCK_METHOD1(AddEntity, bool(AZ::Entity*));
|
||||
MOCK_METHOD1(FindEntity, AZ::Entity*(const AZ::EntityId&));
|
||||
MOCK_METHOD1(EnumerateEntities, void(const ComponentApplicationRequests::EntityCallback&));
|
||||
MOCK_METHOD0(GetApplication, AZ::ComponentApplication* ());
|
||||
MOCK_METHOD0(GetSerializeContext, AZ::SerializeContext* ());
|
||||
MOCK_METHOD0(GetBehaviorContext, AZ::BehaviorContext* ());
|
||||
MOCK_METHOD0(GetJsonRegistrationContext, AZ::JsonRegistrationContext* ());
|
||||
MOCK_METHOD0(GetAppRoot, const char* ());
|
||||
MOCK_CONST_METHOD0(GetExecutableFolder, const char* ());
|
||||
MOCK_METHOD0(GetDrillerManager, AZ::Debug::DrillerManager* ());
|
||||
MOCK_METHOD0(GetTickDeltaTime, float());
|
||||
MOCK_METHOD1(Tick, void(float));
|
||||
MOCK_METHOD0(TickSystem, void());
|
||||
MOCK_CONST_METHOD0(GetRequiredSystemComponents, AZ::ComponentTypeList());
|
||||
MOCK_METHOD1(ResolveModulePath, void(AZ::OSString&));
|
||||
MOCK_METHOD0(CreateSerializeContext, void());
|
||||
MOCK_METHOD0(DestroySerializeContext, void());
|
||||
MOCK_METHOD0(CreateBehaviorContext, void());
|
||||
MOCK_METHOD0(DestroyBehaviorContext, void());
|
||||
MOCK_METHOD0(RegisterCoreComponents, void());
|
||||
MOCK_METHOD1(AddSystemComponents, void(AZ::Entity*));
|
||||
MOCK_METHOD0(ReflectSerialize, void());
|
||||
MOCK_METHOD1(Reflect, void(AZ::ReflectContext*));
|
||||
MOCK_CONST_METHOD0(GetBinFolder, const char* ());
|
||||
};
|
||||
|
||||
class MockAssetCatalogRequestBusHandler final
|
||||
: public AZ::Data::AssetCatalogRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
MockAssetCatalogRequestBusHandler()
|
||||
{
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusConnect();
|
||||
}
|
||||
|
||||
virtual ~MockAssetCatalogRequestBusHandler()
|
||||
{
|
||||
AZ::Data::AssetCatalogRequestBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
MOCK_METHOD3(GetAssetIdByPath, AZ::Data::AssetId(const char*, const AZ::Data::AssetType&, bool));
|
||||
MOCK_METHOD1(GetAssetInfoById, AZ::Data::AssetInfo(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(AddAssetType, void(const AZ::Data::AssetType&));
|
||||
MOCK_METHOD1(AddDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(AddExtension, void(const char*));
|
||||
MOCK_METHOD0(ClearCatalog, void());
|
||||
MOCK_METHOD5(CreateBundleManifest, bool(const AZStd::string&, const AZStd::vector<AZStd::string>&, const AZStd::string&, int, const AZStd::vector<AZStd::string>&));
|
||||
MOCK_METHOD2(CreateDeltaCatalog, bool(const AZStd::vector<AZStd::string>&, const AZStd::string&));
|
||||
MOCK_METHOD0(DisableCatalog, void());
|
||||
MOCK_METHOD1(EnableCatalogForAsset, void(const AZ::Data::AssetType&));
|
||||
MOCK_METHOD3(EnumerateAssets, void(BeginAssetEnumerationCB, AssetEnumerationCB, EndAssetEnumerationCB));
|
||||
MOCK_METHOD1(GenerateAssetIdTEMP, AZ::Data::AssetId(const char*));
|
||||
MOCK_METHOD1(GetAllProductDependencies, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD3(GetAllProductDependenciesFilter, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&, const AZStd::unordered_set<AZ::Data::AssetId>&, const AZStd::vector<AZStd::string>&));
|
||||
MOCK_METHOD1(GetAssetPathById, AZStd::string(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(GetDirectProductDependencies, AZ::Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string>(const AZ::Data::AssetId&));
|
||||
MOCK_METHOD1(GetHandledAssetTypes, void(AZStd::vector<AZ::Data::AssetType>&));
|
||||
MOCK_METHOD0(GetRegisteredAssetPaths, AZStd::vector<AZStd::string>());
|
||||
MOCK_METHOD2(InsertDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>, size_t));
|
||||
MOCK_METHOD2(InsertDeltaCatalogBefore, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>, AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(LoadCatalog, bool(const char*));
|
||||
MOCK_METHOD2(RegisterAsset, void(const AZ::Data::AssetId&, AZ::Data::AssetInfo&));
|
||||
MOCK_METHOD1(RemoveDeltaCatalog, bool(AZStd::shared_ptr<AzFramework::AssetRegistry>));
|
||||
MOCK_METHOD1(SaveCatalog, bool(const char*));
|
||||
MOCK_METHOD0(StartMonitoringAssets, void());
|
||||
MOCK_METHOD0(StopMonitoringAssets, void());
|
||||
MOCK_METHOD1(UnregisterAsset, void(const AZ::Data::AssetId&));
|
||||
};
|
||||
|
||||
class MockAssetManager
|
||||
: public AZ::Data::AssetManager
|
||||
{
|
||||
public:
|
||||
MockAssetManager(const AZ::Data::AssetManager::Descriptor& desc) :
|
||||
AssetManager(desc)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class EditorBlastSliceAssetHandlerTestFixture
|
||||
: public AllocatorsTestFixture
|
||||
{
|
||||
public:
|
||||
AZStd::unique_ptr<MockComponentApplicationBusHandler> m_mockComponentApplicationBusHandler;
|
||||
//AZStd::unique_ptr<UnitTest::MockComponentApplication> m_mockComponentApplicationBusHandler;
|
||||
AZStd::unique_ptr<MockAssetCatalogRequestBusHandler> m_mockAssetCatalogRequestBusHandler;
|
||||
AZStd::unique_ptr<MockAssetManager> m_mockAssetManager;
|
||||
AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
|
||||
const AZ::ComponentDescriptor* m_sliceComponentDescriptor = nullptr;
|
||||
|
||||
void SetUpSliceComponents()
|
||||
{
|
||||
m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
|
||||
|
||||
AZ::Entity::Reflect(m_serializeContext.get());
|
||||
Blast::BlastSliceAssetStorageComponent::Reflect(m_serializeContext.get());
|
||||
AzToolsFramework::Components::EditorComponentBase::Reflect(m_serializeContext.get());
|
||||
|
||||
m_sliceComponentDescriptor = AZ::SliceComponent::CreateDescriptor();
|
||||
m_sliceComponentDescriptor->Reflect(m_serializeContext.get());
|
||||
}
|
||||
|
||||
void TearDownSliceComponents()
|
||||
{
|
||||
delete m_sliceComponentDescriptor;
|
||||
m_serializeContext.reset();
|
||||
}
|
||||
|
||||
void SetUp() override final
|
||||
{
|
||||
AllocatorsTestFixture::SetUp();
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Create();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
|
||||
m_mockComponentApplicationBusHandler = AZStd::make_unique<MockComponentApplicationBusHandler>();
|
||||
m_mockAssetCatalogRequestBusHandler = AZStd::make_unique<MockAssetCatalogRequestBusHandler>();
|
||||
m_mockAssetManager = AZStd::make_unique<MockAssetManager>(AZ::Data::AssetManager::Descriptor{});
|
||||
|
||||
AZ::Data::AssetManager::SetInstance(m_mockAssetManager.get());
|
||||
}
|
||||
|
||||
void TearDown() override final
|
||||
{
|
||||
AZ::Data::AssetManager::SetInstance(nullptr);
|
||||
|
||||
m_mockAssetManager.reset();
|
||||
m_mockAssetCatalogRequestBusHandler.reset();
|
||||
m_mockComponentApplicationBusHandler.reset();
|
||||
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
|
||||
AZ::AllocatorInstance<AZ::PoolAllocator>::Destroy();
|
||||
AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
|
||||
void SaveSliceAssetToStream(AZ::Entity* sliceAssetEntity, AZStd::vector<char>& buffer)
|
||||
{
|
||||
buffer.clear();
|
||||
AZ::IO::ByteContainerStream<AZStd::vector<char>> stream(&buffer);
|
||||
AZ::ObjectStream* objStream = AZ::ObjectStream::Create(&stream, *m_serializeContext.get(), AZ::ObjectStream::ST_XML);
|
||||
objStream->WriteClass(sliceAssetEntity);
|
||||
EXPECT_TRUE(objStream->Finalize());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetManager_Registered)
|
||||
{
|
||||
Blast::EditorBlastSliceAssetHandler handler;
|
||||
handler.Register();
|
||||
EXPECT_NE(nullptr, AZ::Data::AssetManager::Instance().GetHandler(azrtti_typeid<Blast::BlastSliceAsset>()));
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, BlastSliceAssetStorageComponent_Behavior_Registered)
|
||||
{
|
||||
AZ::BehaviorContext behaviorContext;
|
||||
Blast::BlastSliceAssetStorageComponent::Reflect(&behaviorContext);
|
||||
|
||||
auto classEntry = behaviorContext.m_classes.find("BlastSliceAssetStorageComponent");
|
||||
EXPECT_NE(behaviorContext.m_classes.end(), classEntry);
|
||||
AZ::BehaviorClass* behaviorClass = classEntry->second;
|
||||
auto methodEntry = behaviorClass->m_methods.find("GenerateAssetInfo");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), methodEntry);
|
||||
AZ::BehaviorMethod* behaviorMethod = methodEntry->second;
|
||||
EXPECT_EQ(4, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAssetStorageComponent>());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(1)->m_typeId, azrtti_typeid<AZStd::vector<AZStd::string>>());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(2)->m_typeId, azrtti_typeid<AZStd::string_view>());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(3)->m_typeId, azrtti_typeid<AZStd::string_view>());
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, BlastSliceAsset_Behavior_Registered)
|
||||
{
|
||||
AZ::BehaviorContext behaviorContext;
|
||||
Blast::BlastSliceAsset::Reflect(&behaviorContext);
|
||||
|
||||
auto classEntry = behaviorContext.m_classes.find("BlastSliceAsset");
|
||||
EXPECT_NE(behaviorContext.m_classes.end(), classEntry);
|
||||
AZ::BehaviorClass* behaviorClass = classEntry->second;
|
||||
|
||||
auto setMeshIdListEntry = behaviorClass->m_methods.find("SetMeshIdList");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), setMeshIdListEntry);
|
||||
{
|
||||
AZ::BehaviorMethod* behaviorMethod = setMeshIdListEntry->second;
|
||||
EXPECT_EQ(2, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAsset>());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(1)->m_typeId, azrtti_typeid<AZStd::vector<AZ::Data::AssetId>>());
|
||||
}
|
||||
|
||||
auto getMeshIdListEntry = behaviorClass->m_methods.find("GetMeshIdList");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), getMeshIdListEntry);
|
||||
{
|
||||
AZ::BehaviorMethod* behaviorMethod = getMeshIdListEntry->second;
|
||||
EXPECT_EQ(1, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAsset>());
|
||||
EXPECT_EQ(behaviorMethod->GetResult()->m_typeId, azrtti_typeid<AZStd::vector<AZ::Data::AssetId>>());
|
||||
}
|
||||
|
||||
auto setMaterialIdEntry = behaviorClass->m_methods.find("SetMaterialId");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), setMaterialIdEntry);
|
||||
{
|
||||
AZ::BehaviorMethod* behaviorMethod = setMaterialIdEntry->second;
|
||||
EXPECT_EQ(2, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAsset>());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(1)->m_typeId, azrtti_typeid<AZ::Data::AssetId>());
|
||||
}
|
||||
|
||||
auto getMaterialIdEntry = behaviorClass->m_methods.find("GetMaterialId");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), getMaterialIdEntry);
|
||||
{
|
||||
AZ::BehaviorMethod* behaviorMethod = getMaterialIdEntry->second;
|
||||
EXPECT_EQ(1, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAsset>());
|
||||
EXPECT_EQ(behaviorMethod->GetResult()->m_typeId, azrtti_typeid<AZ::Data::AssetId>());
|
||||
}
|
||||
|
||||
auto getAssetTypeIdEntry = behaviorClass->m_methods.find("GetAssetTypeId");
|
||||
EXPECT_NE(behaviorClass->m_methods.end(), getAssetTypeIdEntry);
|
||||
{
|
||||
AZ::BehaviorMethod* behaviorMethod = getAssetTypeIdEntry->second;
|
||||
EXPECT_EQ(1, behaviorMethod->GetNumArguments());
|
||||
EXPECT_EQ(behaviorMethod->GetArgument(0)->m_typeId, azrtti_typeid<Blast::BlastSliceAsset>());
|
||||
EXPECT_EQ(behaviorMethod->GetResult()->m_typeId, azrtti_typeid<AZ::TypeId>());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetTypeInfoBus_Responds)
|
||||
{
|
||||
auto assetId = azrtti_typeid<Blast::BlastSliceAsset>();
|
||||
|
||||
Blast::EditorBlastSliceAssetHandler handler;
|
||||
handler.Register();
|
||||
|
||||
AZ::Data::AssetType assetType = AZ::Uuid::CreateNull();
|
||||
AZ::AssetTypeInfoBus::EventResult(assetType, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetType);
|
||||
EXPECT_NE(AZ::Uuid::CreateNull(), assetType);
|
||||
|
||||
const char* displayName = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(displayName, assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeDisplayName);
|
||||
EXPECT_STREQ("Blast Slice Asset", displayName);
|
||||
|
||||
const char* group = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(group, assetId, &AZ::AssetTypeInfoBus::Events::GetGroup);
|
||||
EXPECT_STREQ("Blast", group);
|
||||
|
||||
const char* icon = nullptr;
|
||||
AZ::AssetTypeInfoBus::EventResult(icon, assetId, &AZ::AssetTypeInfoBus::Events::GetBrowserIcon);
|
||||
EXPECT_STREQ("Editor/Icons/Components/Box.png", icon);
|
||||
|
||||
AZStd::vector<AZStd::string> extensions;
|
||||
AZ::AssetTypeInfoBus::Event(assetId, &AZ::AssetTypeInfoBus::Events::GetAssetTypeExtensions, extensions);
|
||||
ASSERT_EQ(1, extensions.size());
|
||||
ASSERT_EQ("blast_slice", extensions[0]);
|
||||
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetHandler_Ready)
|
||||
{
|
||||
auto assetType = azrtti_typeid<Blast::BlastSliceAsset>();
|
||||
auto&& assetManager = AZ::Data::AssetManager::Instance();
|
||||
|
||||
Blast::EditorBlastSliceAssetHandler handler;
|
||||
handler.Register();
|
||||
EXPECT_EQ(&handler, assetManager.GetHandler(assetType));
|
||||
|
||||
// create and release an instance of the BlastSliceAsset asset type
|
||||
{
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
|
||||
EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetInfoById(_))
|
||||
.Times(1)
|
||||
.WillRepeatedly(Return(AZ::Data::AssetInfo{}));
|
||||
|
||||
auto assetPtr = assetManager.CreateAsset<Blast::BlastSliceAsset>(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0));
|
||||
EXPECT_NE(nullptr, assetPtr.Get());
|
||||
EXPECT_EQ(azrtti_typeid<Blast::BlastSliceAsset>(), assetPtr.GetType());
|
||||
}
|
||||
|
||||
handler.Unregister();
|
||||
}
|
||||
|
||||
TEST_F(EditorBlastSliceAssetHandlerTestFixture, EditorBlastSliceAssetHandler_AssetHandler_LoadsAssetData)
|
||||
{
|
||||
SetUpSliceComponents();
|
||||
|
||||
AZStd::vector<AZStd::string> meshAssetPathList = { "/foo/path/thing.cgf", "/foo/path/that.cgf" };
|
||||
AZ::Entity* storageEntity = aznew AZ::Entity();
|
||||
auto* blastStorage = storageEntity->CreateComponent<Blast::BlastSliceAssetStorageComponent>();
|
||||
blastStorage->SetMeshPathList(meshAssetPathList);
|
||||
|
||||
AZ::Entity sliceEntity;
|
||||
AZ::SliceComponent* slice = sliceEntity.CreateComponent<AZ::SliceComponent>();
|
||||
slice->AddEntity(storageEntity);
|
||||
|
||||
AZStd::vector<char> buffer;
|
||||
SaveSliceAssetToStream(&sliceEntity, buffer);
|
||||
|
||||
// Load a slice with the BlastSliceAssetStorageComponent
|
||||
Blast::EditorBlastSliceAssetHandler handler;
|
||||
handler.Register();
|
||||
{
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
|
||||
EXPECT_CALL(*m_mockComponentApplicationBusHandler, GetSerializeContext)
|
||||
.Times(1)
|
||||
.WillOnce(Return(m_serializeContext.get()));
|
||||
|
||||
EXPECT_CALL(*m_mockComponentApplicationBusHandler, FindEntity(_))
|
||||
.Times(1)
|
||||
.WillOnce(Return(&sliceEntity));
|
||||
|
||||
EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetIdByPath(_,_,_))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0)));
|
||||
|
||||
EXPECT_CALL(*m_mockAssetCatalogRequestBusHandler, GetAssetInfoById(_))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(AZ::Data::AssetInfo{}));
|
||||
|
||||
auto&& assetManager = AZ::Data::AssetManager::Instance();
|
||||
auto assetPtr = assetManager.CreateAsset<Blast::BlastSliceAsset>(AZ::Data::AssetId(AZ::Uuid::CreateRandom(), 0));
|
||||
|
||||
AZ::IO::ByteContainerStream<AZStd::vector<char>> stream(&buffer);
|
||||
stream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
|
||||
|
||||
const AZ::Data::AssetFilterCB assetLoadFilterCB{};
|
||||
bool loaded = handler.LoadAssetData(assetPtr, &stream, assetLoadFilterCB);
|
||||
EXPECT_TRUE(loaded);
|
||||
}
|
||||
handler.Unregister();
|
||||
|
||||
TearDownSliceComponents();
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ set(FILES
|
||||
Source/Editor/EditorBlastFamilyComponent.cpp
|
||||
Source/Editor/EditorBlastMeshDataComponent.cpp
|
||||
Source/Editor/EditorBlastMeshDataComponent.h
|
||||
Source/Editor/EditorBlastSliceAssetHandler.h
|
||||
Source/Editor/EditorBlastSliceAssetHandler.cpp
|
||||
Source/Editor/EditorBlastChunksAssetHandler.h
|
||||
Source/Editor/EditorBlastChunksAssetHandler.cpp
|
||||
Source/Editor/EditorSystemComponent.h
|
||||
Source/Editor/EditorSystemComponent.cpp
|
||||
Editor/ConfigurationWidget.h
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
# Tests/Editor/EditorBlastSliceAssetHandlerTest.cpp
|
||||
# Disabled until SPEC-7904 is fixed Tests/Editor/EditorBlastChunksAssetHandlerTest.cpp
|
||||
Tests/Editor/EditorTestMain.cpp
|
||||
)
|
||||
|
||||
@@ -26,8 +26,8 @@ set(FILES
|
||||
Source/Asset/BlastAsset.cpp
|
||||
Source/Asset/BlastAssetHandler.h
|
||||
Source/Asset/BlastAssetHandler.cpp
|
||||
Source/Asset/BlastSliceAsset.h
|
||||
Source/Asset/BlastSliceAsset.cpp
|
||||
Source/Asset/BlastChunksAsset.h
|
||||
Source/Asset/BlastChunksAsset.cpp
|
||||
Source/Components/BlastFamilyComponent.h
|
||||
Source/Components/BlastFamilyComponent.cpp
|
||||
Source/Components/BlastFamilyComponentNotificationBusHandler.h
|
||||
|
||||
@@ -1,323 +0,0 @@
|
||||
"""
|
||||
Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
def install_user_site():
|
||||
import os
|
||||
import sys
|
||||
import azlmbr.paths
|
||||
executableBinFolder = azlmbr.paths.executableFolder
|
||||
|
||||
# the PyAssImp module checks the Windows PATH for the assimp DLL file
|
||||
if os.name == "nt":
|
||||
os.environ['PATH'] = os.environ['PATH'] + os.pathsep + executableBinFolder
|
||||
|
||||
# PyAssImp module needs to find the shared library for assimp to load; "posix" handles Mac and Linux
|
||||
if os.name == "posix":
|
||||
if 'LD_LIBRARY_PATH' in os.environ:
|
||||
os.environ['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH'] + os.pathsep + executableBinFolder
|
||||
else:
|
||||
os.environ['LD_LIBRARY_PATH'] = executableBinFolder
|
||||
|
||||
# add the user site packages folder to find the pyassimp egg link
|
||||
import site
|
||||
for item in sys.path:
|
||||
if (item.find('site-packages') != -1):
|
||||
site.addsitedir(item)
|
||||
|
||||
install_user_site()
|
||||
import pyassimp
|
||||
|
||||
import azlmbr.asset
|
||||
import azlmbr.asset.builder
|
||||
import azlmbr.asset.entity
|
||||
import azlmbr.blast
|
||||
import azlmbr.bus as bus
|
||||
import azlmbr.editor as editor
|
||||
import azlmbr.entity
|
||||
import azlmbr.math
|
||||
import os
|
||||
import traceback
|
||||
import binascii
|
||||
import sys
|
||||
|
||||
# the UUID must be unique amongst all the asset builders in Python or otherwise
|
||||
# a collision of builders will happen preventing one from running
|
||||
busIdString = '{CF5C74D1-9ED4-4851-85B1-9B15090DBEC7}'
|
||||
busId = azlmbr.math.Uuid_CreateString(busIdString, 0)
|
||||
handler = None
|
||||
jobKeyName = 'Blast Chunk Assets'
|
||||
sceneManifestType = azlmbr.math.Uuid_CreateString('{9274AD17-3212-4651-9F3B-7DCCB080E467}', 0)
|
||||
dccMaterialType = azlmbr.math.Uuid_CreateString('{C88469CF-21E7-41EB-96FD-BF14FBB05EDC}', 0)
|
||||
|
||||
|
||||
def log_exception_traceback():
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
data = traceback.format_exception(exc_type, exc_value, exc_tb)
|
||||
print(str(data))
|
||||
|
||||
|
||||
def get_source_fbx_filename(request):
|
||||
fullPath = os.path.join(request.watchFolder, request.sourceFile)
|
||||
basePath, filePart = os.path.split(fullPath)
|
||||
filename = os.path.splitext(filePart)[0] + '.fbx'
|
||||
filename = os.path.join(basePath, filename)
|
||||
return filename
|
||||
|
||||
|
||||
def raise_error(message):
|
||||
raise RuntimeError(f'[ERROR]: {message}')
|
||||
|
||||
|
||||
def generate_asset_info(chunkNames, request):
|
||||
import azlmbr.blast
|
||||
|
||||
# write out an object stream with the extension of .fbx.assetinfo.generated
|
||||
basePath, sceneFile = os.path.split(request.sourceFile)
|
||||
assetinfoFilename = os.path.splitext(sceneFile)[0] + '.fbx.assetinfo.generated'
|
||||
assetinfoFilename = os.path.join(basePath, assetinfoFilename)
|
||||
assetinfoFilename = assetinfoFilename.replace('\\', '/').lower()
|
||||
outputFilename = os.path.join(request.tempDirPath, assetinfoFilename)
|
||||
|
||||
storage = azlmbr.blast.BlastSliceAssetStorageComponent()
|
||||
if (storage.GenerateAssetInfo(chunkNames, request.sourceFile, outputFilename)):
|
||||
product = azlmbr.asset.builder.JobProduct(assetinfoFilename, sceneManifestType, 1)
|
||||
product.dependenciesHandled = True
|
||||
return product
|
||||
raise_error('Failed to generate assetinfo.generated')
|
||||
|
||||
|
||||
def export_fbx_manifest(request):
|
||||
output = []
|
||||
fbxFilename = get_source_fbx_filename(request)
|
||||
sceneAsset = pyassimp.load(fbxFilename)
|
||||
with sceneAsset as scene:
|
||||
rootNode = scene.mRootNode.contents
|
||||
for index in range(0, rootNode.mNumChildren):
|
||||
child = rootNode.mChildren[index]
|
||||
childNode = child.contents
|
||||
childNodeName = bytes.decode(childNode.mName.data)
|
||||
output.append(str(childNodeName))
|
||||
return output
|
||||
|
||||
|
||||
def convert_to_asset_paths(fbxFilename, gameRoot, chunkNameList):
|
||||
realtivePath = fbxFilename[len(gameRoot) + 1:]
|
||||
realtivePath = os.path.splitext(realtivePath)[0]
|
||||
output = []
|
||||
for chunk in chunkNameList:
|
||||
assetPath = realtivePath + '-' + chunk + '.cgf'
|
||||
assetPath = assetPath.replace('\\', '/')
|
||||
assetPath = assetPath.lower()
|
||||
output.append(assetPath)
|
||||
return output
|
||||
|
||||
|
||||
# creates a single job to compile for each platform
|
||||
def create_jobs(request):
|
||||
fbxSidecarFilename = get_source_fbx_filename(request)
|
||||
if (os.path.exists(fbxSidecarFilename) is False):
|
||||
print('[WARN] Sidecar FBX file {} is missing for blast file {}'.format(fbxSidecarFilename, request.sourceFile))
|
||||
return azlmbr.asset.builder.CreateJobsResponse()
|
||||
|
||||
# see if the FBX file already has a .assetinfo source asset, if so then do not create a job
|
||||
if (os.path.exists(f'{fbxSidecarFilename}.assetinfo')):
|
||||
response = azlmbr.asset.builder.CreateJobsResponse()
|
||||
response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess
|
||||
return response
|
||||
|
||||
# create job descriptor for each platform
|
||||
jobDescriptorList = []
|
||||
for platformInfo in request.enabledPlatforms:
|
||||
jobDesc = azlmbr.asset.builder.JobDescriptor()
|
||||
jobDesc.jobKey = jobKeyName
|
||||
jobDesc.priority = 12 # higher than the 'Scene compilation' or 'fbx'
|
||||
jobDesc.set_platform_identifier(platformInfo.identifier)
|
||||
jobDescriptorList.append(jobDesc)
|
||||
|
||||
response = azlmbr.asset.builder.CreateJobsResponse()
|
||||
response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess
|
||||
response.createJobOutputs = jobDescriptorList
|
||||
return response
|
||||
|
||||
# handler to create jobs for a source asset
|
||||
|
||||
|
||||
def on_create_jobs(args):
|
||||
try:
|
||||
request = args[0]
|
||||
return create_jobs(request)
|
||||
except:
|
||||
log_exception_traceback()
|
||||
return azlmbr.asset.builder.CreateJobsResponse()
|
||||
|
||||
|
||||
def generate_blast_slice_asset(chunkNameList, request):
|
||||
# get list of relative chunk paths
|
||||
fbxFilename = get_source_fbx_filename(request)
|
||||
assetPaths = convert_to_asset_paths(fbxFilename, request.watchFolder, chunkNameList)
|
||||
|
||||
outcome = azlmbr.asset.entity.PythonBuilderRequestBus(bus.Broadcast, 'CreateEditorEntity', 'BlastData')
|
||||
if (outcome.IsSuccess() is False):
|
||||
raise_error('could not create an editor entity')
|
||||
blastDataEntityId = outcome.GetValue()
|
||||
|
||||
# create a component for the editor entity
|
||||
gameType = azlmbr.entity.EntityType().Game
|
||||
blastMeshDataTypeIdList = editor.EditorComponentAPIBus(bus.Broadcast, 'FindComponentTypeIdsByEntityType', ["Blast Slice Storage Component"], gameType)
|
||||
componentOutcome = editor.EditorComponentAPIBus(bus.Broadcast, 'AddComponentOfType', blastDataEntityId, blastMeshDataTypeIdList[0])
|
||||
if (componentOutcome.IsSuccess() is False):
|
||||
raise_error('failed to add component (Blast Slice Storage Component) to the blast_slice')
|
||||
|
||||
# build the blast slice using the chunk asset paths
|
||||
blastMeshComponentId = componentOutcome.GetValue()[0]
|
||||
outcome = editor.EditorComponentAPIBus(bus.Broadcast, 'BuildComponentPropertyTreeEditor', blastMeshComponentId)
|
||||
if(outcome.IsSuccess() is False):
|
||||
raise_error(f'failed to create Property Tree Editor for component ({blastMeshComponentId})')
|
||||
pte = outcome.GetValue()
|
||||
pte.set_visible_enforcement(True)
|
||||
pte.set_value('Mesh Paths', assetPaths)
|
||||
|
||||
# write out an object stream with the extension of .blast_slice
|
||||
basePath, sceneFile = os.path.split(request.sourceFile)
|
||||
blastFilename = os.path.splitext(sceneFile)[0] + '.blast_slice'
|
||||
blastFilename = os.path.join(basePath, blastFilename)
|
||||
blastFilename = blastFilename.replace('\\', '/').lower()
|
||||
tempFilename = os.path.join(request.tempDirPath, blastFilename)
|
||||
entityList = [blastDataEntityId]
|
||||
makeDynamic = False
|
||||
outcome = azlmbr.asset.entity.PythonBuilderRequestBus(bus.Broadcast, 'WriteSliceFile', tempFilename, entityList, makeDynamic)
|
||||
if (outcome.IsSuccess() is False):
|
||||
raise_error(f'WriteSliceFile failed for blast_slice file ({blastFilename})')
|
||||
|
||||
# return a job product
|
||||
blastSliceAsset = azlmbr.blast.BlastSliceAsset()
|
||||
subId = binascii.crc32(blastFilename.encode('utf8'))
|
||||
product = azlmbr.asset.builder.JobProduct(blastFilename, blastSliceAsset.GetAssetTypeId(), subId)
|
||||
product.dependenciesHandled = True
|
||||
return product
|
||||
|
||||
|
||||
def read_in_string(data, dataLength):
|
||||
stringData = ''
|
||||
for idx in range(4, dataLength - 1):
|
||||
char = bytes.decode(data[idx])
|
||||
if (str.isascii(char)):
|
||||
stringData += char
|
||||
return stringData
|
||||
|
||||
|
||||
def import_material_info(fbxFilename):
|
||||
_, group_name = os.path.split(fbxFilename)
|
||||
group_name = os.path.splitext(group_name)[0]
|
||||
output = {}
|
||||
output['group_name'] = group_name
|
||||
output['material_name_list'] = []
|
||||
sceneAsset = pyassimp.load(fbxFilename)
|
||||
with sceneAsset as scene:
|
||||
for materialIndex in range(0, scene.mNumMaterials):
|
||||
material = scene.mMaterials[materialIndex].contents
|
||||
for materialPropertyIdx in range(0, material.mNumProperties):
|
||||
materialProperty = material.mProperties[materialPropertyIdx].contents
|
||||
materialPropertyName = bytes.decode(materialProperty.mKey.data)
|
||||
if (materialPropertyName.endswith('mat.name') and materialProperty.mType is 3):
|
||||
stringData = read_in_string(materialProperty.mData, materialProperty.mDataLength)
|
||||
output['material_name_list'].append(stringData)
|
||||
return output
|
||||
|
||||
|
||||
def write_material_file(sourceFile, destFolder):
|
||||
# preserve source MTL files
|
||||
rootPath, materialSourceFile = os.path.split(sourceFile)
|
||||
materialSourceFile = os.path.splitext(materialSourceFile)[0] + '.mtl'
|
||||
materialSourceFile = os.path.join(rootPath, materialSourceFile)
|
||||
if (os.path.exists(materialSourceFile)):
|
||||
print(f'{materialSourceFile} source already exists')
|
||||
return None
|
||||
|
||||
# auto-generate a DCC material file
|
||||
info = import_material_info(sourceFile)
|
||||
materialGroupName = info['group_name']
|
||||
materialNames = info['material_name_list']
|
||||
materialFilename = materialGroupName + '.dccmtl.generated'
|
||||
subId = binascii.crc32(materialFilename.encode('utf8'))
|
||||
materialFilename = os.path.join(destFolder, materialFilename)
|
||||
storage = azlmbr.blast.BlastSliceAssetStorageComponent()
|
||||
storage.WriteMaterialFile(materialGroupName, materialNames, materialFilename)
|
||||
product = azlmbr.asset.builder.JobProduct(materialFilename, dccMaterialType, subId)
|
||||
product.dependenciesHandled = True
|
||||
return product
|
||||
|
||||
|
||||
def process_fbx_file(request):
|
||||
# fill out response object
|
||||
response = azlmbr.asset.builder.ProcessJobResponse()
|
||||
productOutputs = []
|
||||
|
||||
# write out DCCMTL file as a product (if needed)
|
||||
materialProduct = write_material_file(get_source_fbx_filename(request), request.tempDirPath)
|
||||
if (materialProduct is not None):
|
||||
productOutputs.append(materialProduct)
|
||||
|
||||
# prepare output folder
|
||||
basePath, _ = os.path.split(request.sourceFile)
|
||||
outputPath = os.path.join(request.tempDirPath, basePath)
|
||||
os.makedirs(outputPath)
|
||||
|
||||
# parse FBX for chunk names
|
||||
chunkNameList = export_fbx_manifest(request)
|
||||
|
||||
# create assetinfo generated (is product)
|
||||
productOutputs.append(generate_asset_info(chunkNameList, request))
|
||||
|
||||
# write out the blast_slice object stream
|
||||
productOutputs.append(generate_blast_slice_asset(chunkNameList, request))
|
||||
|
||||
response.outputProducts = productOutputs
|
||||
response.resultCode = azlmbr.asset.builder.ProcessJobResponse_Success
|
||||
response.dependenciesHandled = True
|
||||
return response
|
||||
|
||||
|
||||
# using the incoming 'request' find the type of job via 'jobKey' to determine what to do
|
||||
def on_process_job(args):
|
||||
try:
|
||||
request = args[0]
|
||||
if (request.jobDescription.jobKey.startswith(jobKeyName)):
|
||||
return process_fbx_file(request)
|
||||
|
||||
return azlmbr.asset.builder.ProcessJobResponse()
|
||||
except:
|
||||
log_exception_traceback()
|
||||
return azlmbr.asset.builder.ProcessJobResponse()
|
||||
|
||||
# register asset builder
|
||||
def register_asset_builder():
|
||||
assetPattern = azlmbr.asset.builder.AssetBuilderPattern()
|
||||
assetPattern.pattern = '*.blast'
|
||||
assetPattern.type = azlmbr.asset.builder.AssetBuilderPattern_Wildcard
|
||||
|
||||
builderDescriptor = azlmbr.asset.builder.AssetBuilderDesc()
|
||||
builderDescriptor.name = "Blast Gem"
|
||||
builderDescriptor.patterns = [assetPattern]
|
||||
builderDescriptor.busId = busId
|
||||
builderDescriptor.version = 5
|
||||
|
||||
outcome = azlmbr.asset.builder.PythonAssetBuilderRequestBus(azlmbr.bus.Broadcast, 'RegisterAssetBuilder', builderDescriptor)
|
||||
if outcome.IsSuccess():
|
||||
# created the asset builder to hook into the notification bus
|
||||
handler = azlmbr.asset.builder.PythonBuilderNotificationBusHandler()
|
||||
handler.connect(busId)
|
||||
handler.add_callback('OnCreateJobsRequest', on_create_jobs)
|
||||
handler.add_callback('OnProcessJobRequest', on_process_job)
|
||||
return handler
|
||||
|
||||
|
||||
# create the asset builder handler
|
||||
try:
|
||||
handler = register_asset_builder()
|
||||
except:
|
||||
handler = None
|
||||
log_exception_traceback()
|
||||
@@ -0,0 +1,290 @@
|
||||
"""
|
||||
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 a Python Asset Builder script examines each .blast file to see if an
|
||||
associated .fbx file needs to be processed by exporting all of its chunks
|
||||
into a scene manifest
|
||||
|
||||
This is also a SceneAPI script that executes from a foo.fbx.assetinfo scene
|
||||
manifest that writes out asset chunk data for .blast files
|
||||
"""
|
||||
import os, traceback, binascii, sys, json, pathlib
|
||||
import azlmbr.math
|
||||
import azlmbr.asset
|
||||
import azlmbr.asset.entity
|
||||
import azlmbr.asset.builder
|
||||
import azlmbr.bus
|
||||
|
||||
#
|
||||
# Python Asset Builder
|
||||
#
|
||||
busId = azlmbr.math.Uuid_CreateString('{D4FA20E3-8EF4-44A3-A045-AAE6C1CCAAAB}', 0)
|
||||
jobKeyName = 'Blast Chunk Assets'
|
||||
|
||||
def log_exception_traceback():
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
data = traceback.format_exception(exc_type, exc_value, exc_tb)
|
||||
print(str(data))
|
||||
|
||||
def raise_error(message):
|
||||
print (f'ERROR - {message}');
|
||||
raise RuntimeError(f'[ERROR]: {message}');
|
||||
|
||||
# creates a single job to compile for each platform
|
||||
def get_source_fbx_filename(request):
|
||||
fullPath = os.path.join(request.watchFolder, request.sourceFile)
|
||||
basePath, filePart = os.path.split(fullPath)
|
||||
filename = os.path.splitext(filePart)[0] + '.fbx'
|
||||
filename = os.path.join(basePath, filename)
|
||||
return filename
|
||||
|
||||
def create_jobs(request):
|
||||
fbxSidecarFilename = get_source_fbx_filename(request)
|
||||
if (os.path.exists(fbxSidecarFilename) is False):
|
||||
print('[WARN] Sidecar FBX file {} is missing for blast file {}'.format(fbxSidecarFilename, request.sourceFile))
|
||||
return azlmbr.asset.builder.CreateJobsResponse()
|
||||
|
||||
# see if the FBX file already has a .assetinfo source asset, if so then do not create a job
|
||||
establishedAssetInfo = f'{fbxSidecarFilename}.assetinfo';
|
||||
if (os.path.exists(establishedAssetInfo)):
|
||||
response = azlmbr.asset.builder.CreateJobsResponse()
|
||||
response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess
|
||||
return response
|
||||
|
||||
# create job descriptor for each platform
|
||||
jobDescriptorList = []
|
||||
for platformInfo in request.enabledPlatforms:
|
||||
sourceFileDependency = azlmbr.asset.builder.SourceFileDependency()
|
||||
sourceFileDependency.sourceFileDependencyPath = fbxSidecarFilename
|
||||
|
||||
jobDependency = azlmbr.asset.builder.JobDependency()
|
||||
jobDependency.sourceFile = sourceFileDependency
|
||||
jobDependency.jobKey = jobKeyName
|
||||
jobDependency.platformIdentifier = platformInfo.identifier
|
||||
|
||||
jobDesc = azlmbr.asset.builder.JobDescriptor()
|
||||
jobDesc.jobKey = jobKeyName
|
||||
jobDesc.set_platform_identifier(platformInfo.identifier)
|
||||
jobDesc.jobDependencyList = [jobDependency]
|
||||
jobDescriptorList.append(jobDesc)
|
||||
|
||||
response = azlmbr.asset.builder.CreateJobsResponse()
|
||||
response.result = azlmbr.asset.builder.CreateJobsResponse_ResultSuccess
|
||||
response.createJobOutputs = jobDescriptorList
|
||||
return response
|
||||
|
||||
# to create jobs for a source asset
|
||||
def on_create_jobs(args):
|
||||
try:
|
||||
request = args[0]
|
||||
return create_jobs(request)
|
||||
except:
|
||||
log_exception_traceback()
|
||||
return azlmbr.asset.builder.CreateJobsResponse()
|
||||
|
||||
def generate_assetinfo_product(request):
|
||||
# write out a product asset file with the extension of .fbx.assetinfo.generated
|
||||
basePath, sceneFile = os.path.split(request.sourceFile)
|
||||
assetinfoFilename = os.path.splitext(sceneFile)[0] + '.fbx.assetinfo.generated'
|
||||
assetinfoFilename = os.path.join(basePath, assetinfoFilename)
|
||||
assetinfoFilename = assetinfoFilename.replace('\\', '/').lower()
|
||||
outputFilename = os.path.join(request.tempDirPath, assetinfoFilename)
|
||||
|
||||
# the only rule in it is to run this file again as a scene processor
|
||||
currentScript = pathlib.Path(__file__).resolve()
|
||||
aDict = {"values": [{"$type": "ScriptProcessorRule", "scriptFilename": f"{currentScript}"}]}
|
||||
jsonString = json.dumps(aDict)
|
||||
jsonFile = open(outputFilename, "w")
|
||||
jsonFile.write(jsonString)
|
||||
jsonFile.close()
|
||||
|
||||
# return a job product for the generated assetinfo file
|
||||
sceneManifestType = azlmbr.math.Uuid_CreateString('{9274AD17-3212-4651-9F3B-7DCCB080E467}', 0)
|
||||
subId = 1
|
||||
product = azlmbr.asset.builder.JobProduct(outputFilename, sceneManifestType, subId)
|
||||
product.dependenciesHandled = True
|
||||
return product
|
||||
|
||||
def process_fbx_file(request):
|
||||
# fill out response object
|
||||
response = azlmbr.asset.builder.ProcessJobResponse()
|
||||
productOutputs = []
|
||||
|
||||
# prepare output folder
|
||||
basePath, _ = os.path.split(request.sourceFile)
|
||||
outputPath = os.path.join(request.tempDirPath, basePath)
|
||||
os.makedirs(outputPath)
|
||||
|
||||
# create assetinfo generated file
|
||||
productOutputs.append(generate_assetinfo_product(request))
|
||||
|
||||
response.outputProducts = productOutputs
|
||||
response.resultCode = azlmbr.asset.builder.ProcessJobResponse_Success
|
||||
response.dependenciesHandled = True
|
||||
return response
|
||||
|
||||
# using the incoming 'request' find the type of job via 'jobKey' to determine what to do
|
||||
def on_process_job(args):
|
||||
try:
|
||||
request = args[0]
|
||||
if (request.jobDescription.jobKey.startswith(jobKeyName)):
|
||||
return process_fbx_file(request)
|
||||
|
||||
return azlmbr.asset.builder.ProcessJobResponse()
|
||||
except:
|
||||
log_exception_traceback()
|
||||
return azlmbr.asset.builder.ProcessJobResponse()
|
||||
|
||||
# register asset builder
|
||||
def register_asset_builder():
|
||||
assetPattern = azlmbr.asset.builder.AssetBuilderPattern()
|
||||
assetPattern.pattern = '*.blast'
|
||||
assetPattern.type = azlmbr.asset.builder.AssetBuilderPattern_Wildcard
|
||||
|
||||
builderDescriptor = azlmbr.asset.builder.AssetBuilderDesc()
|
||||
builderDescriptor.name = "Blast Scene Builder"
|
||||
builderDescriptor.patterns = [assetPattern]
|
||||
builderDescriptor.busId = busId
|
||||
builderDescriptor.version = 1
|
||||
|
||||
outcome = azlmbr.asset.builder.PythonAssetBuilderRequestBus(azlmbr.bus.Broadcast, 'RegisterAssetBuilder', builderDescriptor)
|
||||
if outcome.IsSuccess():
|
||||
# created the asset builder to hook into the notification bus
|
||||
handler = azlmbr.asset.builder.PythonBuilderNotificationBusHandler()
|
||||
handler.connect(busId)
|
||||
handler.add_callback('OnCreateJobsRequest', on_create_jobs)
|
||||
handler.add_callback('OnProcessJobRequest', on_process_job)
|
||||
return handler
|
||||
|
||||
# create the asset builder handler
|
||||
pythonAssetBuilderHandler = None
|
||||
try:
|
||||
if (pythonAssetBuilderHandler == None):
|
||||
pythonAssetBuilderHandler = register_asset_builder()
|
||||
except:
|
||||
pythonAssetBuilderHandler = None
|
||||
|
||||
#
|
||||
# SceneAPI Processor
|
||||
#
|
||||
blastChunksAssetType = azlmbr.math.Uuid_CreateString('{993F0B0F-37D9-48C6-9CC2-E27D3F3E343E}', 0)
|
||||
|
||||
def export_chunk_asset(scene, outputDirectory, platformIdentifier, productList):
|
||||
import azlmbr.scene
|
||||
import azlmbr.object
|
||||
import azlmbr.paths
|
||||
import json, os
|
||||
|
||||
jsonFilename = os.path.basename(scene.sourceFilename)
|
||||
jsonFilename = os.path.join(outputDirectory, jsonFilename + '.blast_chunks')
|
||||
|
||||
# prepare output folder
|
||||
basePath, _ = os.path.split(jsonFilename)
|
||||
outputPath = os.path.join(outputDirectory, basePath)
|
||||
if not os.path.exists(outputPath):
|
||||
os.makedirs(outputPath, False)
|
||||
|
||||
# write out a JSON file with the chunk file info
|
||||
with open(jsonFilename, "w") as jsonFile:
|
||||
jsonFile.write(scene.manifest.ExportToJson())
|
||||
|
||||
exportProduct = azlmbr.scene.ExportProduct()
|
||||
exportProduct.filename = jsonFilename
|
||||
exportProduct.sourceId = scene.sourceGuid
|
||||
exportProduct.assetType = blastChunksAssetType
|
||||
exportProduct.subId = 101
|
||||
|
||||
exportProductList = azlmbr.scene.ExportProductList()
|
||||
exportProductList.AddProduct(exportProduct)
|
||||
return exportProductList
|
||||
|
||||
def on_prepare_for_export(args):
|
||||
try:
|
||||
scene = args[0] # azlmbr.scene.Scene
|
||||
outputDirectory = args[1] # string
|
||||
platformIdentifier = args[2] # string
|
||||
productList = args[3] # azlmbr.scene.ExportProductList
|
||||
return export_chunk_asset(scene, outputDirectory, platformIdentifier, productList)
|
||||
except:
|
||||
log_exception_traceback()
|
||||
|
||||
def get_mesh_node_names(sceneGraph):
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
meshDataList = []
|
||||
node = sceneGraph.get_root()
|
||||
children = []
|
||||
|
||||
while node.IsValid():
|
||||
# store children to process after siblings
|
||||
if sceneGraph.has_node_child(node):
|
||||
children.append(sceneGraph.get_node_child(node))
|
||||
|
||||
# store any node that has mesh data content
|
||||
nodeContent = sceneGraph.get_node_content(node)
|
||||
if nodeContent is not None and nodeContent.CastWithTypeName('MeshData'):
|
||||
if sceneGraph.is_node_end_point(node) is False:
|
||||
nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node))
|
||||
nodePath = nodeName.get_path()
|
||||
if (len(nodeName.get_path())):
|
||||
meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node)))
|
||||
|
||||
# advance to next node
|
||||
if sceneGraph.has_node_sibling(node):
|
||||
node = sceneGraph.get_node_sibling(node)
|
||||
elif children:
|
||||
node = children.pop()
|
||||
else:
|
||||
node = azlmbr.scene.graph.NodeIndex()
|
||||
|
||||
return meshDataList
|
||||
|
||||
def update_manifest(scene):
|
||||
import uuid, os
|
||||
import azlmbr.scene as sceneApi
|
||||
import azlmbr.scene.graph
|
||||
from scene_api import scene_data as sceneData
|
||||
|
||||
graph = sceneData.SceneGraph(scene.graph)
|
||||
meshNameList = get_mesh_node_names(graph)
|
||||
sceneManifest = sceneData.SceneManifest()
|
||||
sourceFilenameOnly = os.path.basename(scene.sourceFilename)
|
||||
sourceFilenameOnly = sourceFilenameOnly.replace('.','_')
|
||||
|
||||
for activeMeshIndex in range(len(meshNameList)):
|
||||
chunkName = meshNameList[activeMeshIndex]
|
||||
chunkPath = chunkName.get_path()
|
||||
meshGroupName = '{}_{}'.format(sourceFilenameOnly, chunkName.get_name())
|
||||
meshGroup = sceneManifest.add_mesh_group(meshGroupName)
|
||||
meshGroup['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, sourceFilenameOnly + chunkPath)) + '}'
|
||||
sceneManifest.mesh_group_select_node(meshGroup, chunkPath)
|
||||
|
||||
return sceneManifest.export()
|
||||
|
||||
sceneJobHandler = None
|
||||
|
||||
def on_update_manifest(args):
|
||||
try:
|
||||
scene = args[0]
|
||||
return update_manifest(scene)
|
||||
except:
|
||||
global sceneJobHandler
|
||||
sceneJobHandler = None
|
||||
log_exception_traceback()
|
||||
|
||||
# try to create SceneAPI handler for processing
|
||||
try:
|
||||
import azlmbr.scene as sceneApi
|
||||
if (sceneJobHandler == None):
|
||||
sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
|
||||
sceneJobHandler.connect()
|
||||
sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
|
||||
sceneJobHandler.add_callback('OnPrepareForExport', on_prepare_for_export)
|
||||
except:
|
||||
sceneJobHandler = None
|
||||
@@ -4,6 +4,13 @@ For complete copyright and license terms please see the LICENSE at the root of t
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
"""
|
||||
|
||||
# LYN-652 to re-enable once the Blast gem tests are stable
|
||||
# import asset_builder_blast
|
||||
try:
|
||||
import azlmbr.asset
|
||||
import azlmbr.asset.entity
|
||||
import azlmbr.asset.builder
|
||||
import blast_asset_builder
|
||||
except:
|
||||
# this script only runs in an asset processing environment
|
||||
# like the AssetProcessor or an AssetBuilder
|
||||
# plus the Blast gem needs to be enabled for the project
|
||||
pass
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "CommandManager.h"
|
||||
|
||||
#include <EMotionFX/CommandSystem/Source/AnimGraphTriggerActionCommands.h>
|
||||
#include <EMotionFX/CommandSystem/Source/AnimGraphNodeGroupCommands.h>
|
||||
#include <EMotionFX/Source/ActorInstance.h>
|
||||
#include <EMotionFX/Source/ActorManager.h>
|
||||
#include <EMotionFX/Source/AnimGraph.h>
|
||||
@@ -858,8 +859,16 @@ namespace CommandSystem
|
||||
// add it to the old node group if it was assigned to one before
|
||||
if (!mNodeGroupName.empty())
|
||||
{
|
||||
commandString = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %i -name \"%s\" -nodeNames \"%s\" -nodeAction \"add\"", animGraph->GetID(), mNodeGroupName.c_str(), mName.c_str());
|
||||
if (GetCommandManager()->ExecuteCommandInsideCommand(commandString.c_str(), outResult) == false)
|
||||
auto* command = aznew CommandSystem::CommandAnimGraphAdjustNodeGroup(
|
||||
GetCommandManager()->FindCommand(CommandSystem::CommandAnimGraphAdjustNodeGroup::s_commandName),
|
||||
/*animGraphId = */ animGraph->GetID(),
|
||||
/*name = */ mNodeGroupName,
|
||||
/*visible = */ AZStd::nullopt,
|
||||
/*newName = */ AZStd::nullopt,
|
||||
/*nodeNames = */ {{mName}},
|
||||
/*nodeAction = */ CommandSystem::CommandAnimGraphAdjustNodeGroup::NodeAction::Add
|
||||
);
|
||||
if (GetCommandManager()->ExecuteCommandInsideCommand(command, outResult) == false)
|
||||
{
|
||||
if (outResult.size() > 0)
|
||||
{
|
||||
@@ -1363,11 +1372,16 @@ namespace CommandSystem
|
||||
EMotionFX::AnimGraphNodeGroup* nodeGroup = node->GetAnimGraph()->FindNodeGroupForNode(node);
|
||||
if (nodeGroup && !cutMode)
|
||||
{
|
||||
commandString = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %d -name \"%s\" -nodeNames \"%s\" -nodeAction \"add\"",
|
||||
targetAnimGraph->GetID(),
|
||||
nodeGroup->GetName(),
|
||||
nodeName.c_str());
|
||||
commandGroup->AddCommandString(commandString);
|
||||
auto* command = aznew CommandSystem::CommandAnimGraphAdjustNodeGroup(
|
||||
GetCommandManager()->FindCommand(CommandSystem::CommandAnimGraphAdjustNodeGroup::s_commandName),
|
||||
/*animGraphId = */ targetAnimGraph->GetID(),
|
||||
/*name = */ nodeGroup->GetNameString(),
|
||||
/*visible = */ AZStd::nullopt,
|
||||
/*newName = */ AZStd::nullopt,
|
||||
/*nodeNames = */ {{nodeName}},
|
||||
/*nodeAction = */ CommandSystem::CommandAnimGraphAdjustNodeGroup::NodeAction::Add
|
||||
);
|
||||
commandGroup->AddCommand(command);
|
||||
}
|
||||
|
||||
// Recurse through the child nodes.
|
||||
|
||||
+121
-130
@@ -6,6 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <AzCore/std/optional.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include "AnimGraphNodeGroupCommands.h"
|
||||
#include "AnimGraphConnectionCommands.h"
|
||||
@@ -22,45 +23,46 @@
|
||||
|
||||
namespace CommandSystem
|
||||
{
|
||||
AZ_CLASS_ALLOCATOR_IMPL(CommandAnimGraphAdjustNodeGroup, EMotionFX::CommandAllocator, 0)
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// CommandAnimGraphAdjustNodeGroup
|
||||
//--------------------------------------------------------------------------------
|
||||
CommandAnimGraphAdjustNodeGroup::CommandAnimGraphAdjustNodeGroup(MCore::Command* orgCommand)
|
||||
: MCore::Command("AnimGraphAdjustNodeGroup", orgCommand)
|
||||
CommandAnimGraphAdjustNodeGroup::CommandAnimGraphAdjustNodeGroup(
|
||||
MCore::Command* orgCommand,
|
||||
AZ::u32 animGraphId,
|
||||
AZStd::string name,
|
||||
AZStd::optional<bool> visible,
|
||||
AZStd::optional<AZStd::string> newName,
|
||||
AZStd::optional<AZStd::vector<AZStd::string>> nodeNames,
|
||||
AZStd::optional<NodeAction> nodeAction,
|
||||
AZStd::optional<AZ::u32> color,
|
||||
AZStd::optional<bool> updateUI
|
||||
)
|
||||
: MCore::Command(s_commandName, orgCommand)
|
||||
, ParameterMixinAnimGraphId(animGraphId)
|
||||
, m_name(AZStd::move(name))
|
||||
, m_isVisible(visible)
|
||||
, m_newName(AZStd::move(newName))
|
||||
, m_nodeNames(AZStd::move(nodeNames))
|
||||
, m_nodeAction(nodeAction)
|
||||
, m_color(color)
|
||||
, m_updateUI(updateUI)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CommandAnimGraphAdjustNodeGroup::~CommandAnimGraphAdjustNodeGroup()
|
||||
AZStd::vector<AZStd::string> CommandAnimGraphAdjustNodeGroup::GenerateNodeNameVector(EMotionFX::AnimGraph* animGraph, const AZStd::vector<EMotionFX::AnimGraphNodeId>& nodeIDs)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AZStd::string CommandAnimGraphAdjustNodeGroup::GenerateNodeNameString(EMotionFX::AnimGraph* animGraph, const AZStd::vector<EMotionFX::AnimGraphNodeId>& nodeIDs)
|
||||
{
|
||||
if (nodeIDs.empty())
|
||||
AZStd::vector<AZStd::string> result;
|
||||
for (const auto& nodeID : nodeIDs)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
AZStd::string result;
|
||||
|
||||
const size_t numNodes = nodeIDs.size();
|
||||
for (size_t i = 0; i < numNodes; ++i)
|
||||
{
|
||||
EMotionFX::AnimGraphNode* animGraphNode = animGraph->RecursiveFindNodeById(nodeIDs[i]);
|
||||
const EMotionFX::AnimGraphNode* animGraphNode = animGraph->RecursiveFindNodeById(nodeID);
|
||||
if (!animGraphNode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result += animGraphNode->GetName();
|
||||
if (i < numNodes - 1)
|
||||
{
|
||||
result += ';';
|
||||
}
|
||||
result.emplace_back(animGraphNode->GetName());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -80,78 +82,51 @@ namespace CommandSystem
|
||||
}
|
||||
|
||||
|
||||
bool CommandAnimGraphAdjustNodeGroup::Execute(const MCore::CommandLine& parameters, AZStd::string& outResult)
|
||||
bool CommandAnimGraphAdjustNodeGroup::Execute(const MCore::CommandLine&, AZStd::string& outResult)
|
||||
{
|
||||
EMotionFX::AnimGraph* animGraph = CommandsGetAnimGraph(parameters, this, outResult);
|
||||
EMotionFX::AnimGraph* animGraph = EMotionFX::GetAnimGraphManager().FindAnimGraphByID(m_animGraphId);
|
||||
if (!animGraph)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the node group name
|
||||
AZStd::string groupName;
|
||||
parameters.GetValue("name", this, groupName);
|
||||
|
||||
// find the node group index
|
||||
const uint32 groupIndex = animGraph->FindNodeGroupIndexByName(groupName.c_str());
|
||||
const uint32 groupIndex = animGraph->FindNodeGroupIndexByName(m_name.c_str());
|
||||
if (groupIndex == MCORE_INVALIDINDEX32)
|
||||
{
|
||||
outResult = AZStd::string::format("Node group \"%s\" can not be found.", groupName.c_str());
|
||||
outResult = AZStd::string::format("Node group \"%s\" can not be found.", m_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// get a pointer to the node group and keep the old name
|
||||
EMotionFX::AnimGraphNodeGroup* nodeGroup = animGraph->GetNodeGroup(groupIndex);
|
||||
mOldName = nodeGroup->GetName();
|
||||
|
||||
// is visible?
|
||||
if (parameters.CheckIfHasParameter("isVisible"))
|
||||
if (m_isVisible.has_value())
|
||||
{
|
||||
const bool isVisible = parameters.GetValueAsBool("isVisible", this);
|
||||
mOldIsVisible = nodeGroup->GetIsVisible();
|
||||
nodeGroup->SetIsVisible(isVisible);
|
||||
m_oldIsVisible = nodeGroup->GetIsVisible();
|
||||
nodeGroup->SetIsVisible(*m_isVisible);
|
||||
}
|
||||
|
||||
// background color
|
||||
if (parameters.CheckIfHasParameter("color"))
|
||||
if (m_color.has_value())
|
||||
{
|
||||
const AZ::Vector4 colorVector4 = parameters.GetValueAsVector4("color", this);
|
||||
const AZ::u32 color = AZ::Color(static_cast<float>(colorVector4.GetX()), static_cast<float>(colorVector4.GetY()), static_cast<float>(colorVector4.GetZ()), static_cast<float>(colorVector4.GetW())).ToU32();
|
||||
mOldColor = nodeGroup->GetColor();
|
||||
nodeGroup->SetColor(color);
|
||||
m_oldColor = nodeGroup->GetColor();
|
||||
nodeGroup->SetColor(*m_color);
|
||||
}
|
||||
|
||||
// set the new name
|
||||
// if the new name is empty, the name is not changed
|
||||
AZStd::string newGroupName;
|
||||
parameters.GetValue("newName", this, newGroupName);
|
||||
if (!newGroupName.empty())
|
||||
if (m_newName.has_value())
|
||||
{
|
||||
nodeGroup->SetName(newGroupName.c_str());
|
||||
nodeGroup->SetName(m_newName->c_str());
|
||||
}
|
||||
|
||||
// check if parametes nodeNames is set
|
||||
if (parameters.CheckIfHasParameter("nodeNames"))
|
||||
if (m_nodeNames.has_value())
|
||||
{
|
||||
// keep the old nodes IDs
|
||||
mOldNodeIds = CollectNodeIdsFromGroup(nodeGroup);
|
||||
|
||||
// get the node action
|
||||
AZStd::string nodeAction;
|
||||
parameters.GetValue("nodeAction", this, nodeAction);
|
||||
|
||||
// get the node names and split the string
|
||||
AZStd::string nodeNamesString;
|
||||
parameters.GetValue("nodeNames", this, nodeNamesString);
|
||||
|
||||
|
||||
AZStd::vector<AZStd::string> nodeNames;
|
||||
AzFramework::StringFunc::Tokenize(nodeNamesString.c_str(), nodeNames, ";", false, true);
|
||||
m_oldNodeIds = CollectNodeIdsFromGroup(nodeGroup);
|
||||
|
||||
// remove the selected nodes from the given node group
|
||||
if (AzFramework::StringFunc::Equal(nodeAction.c_str(), "remove"))
|
||||
if (*m_nodeAction == NodeAction::Remove)
|
||||
{
|
||||
for (const AZStd::string& nodeName : nodeNames)
|
||||
for (const AZStd::string& nodeName : *m_nodeNames)
|
||||
{
|
||||
EMotionFX::AnimGraphNode* animGraphNode = animGraph->RecursiveFindNodeByName(nodeName.c_str());
|
||||
if (!animGraphNode)
|
||||
@@ -163,9 +138,9 @@ namespace CommandSystem
|
||||
nodeGroup->RemoveNodeById(animGraphNode->GetId());
|
||||
}
|
||||
}
|
||||
else if (AzFramework::StringFunc::Equal(nodeAction.c_str(), "add")) // add the selected nodes to the given node group
|
||||
else if (*m_nodeAction == NodeAction::Add)
|
||||
{
|
||||
for (const AZStd::string& nodeName : nodeNames)
|
||||
for (const AZStd::string& nodeName : *m_nodeNames)
|
||||
{
|
||||
EMotionFX::AnimGraphNode* animGraphNode = animGraph->RecursiveFindNodeByName(nodeName.c_str());
|
||||
if (!animGraphNode)
|
||||
@@ -184,12 +159,12 @@ namespace CommandSystem
|
||||
nodeGroup->AddNode(animGraphNode->GetId());
|
||||
}
|
||||
}
|
||||
else if (AzFramework::StringFunc::Equal(nodeAction.c_str(), "replace")) // clear the node group and then add the selected nodes to the given node group
|
||||
else if (*m_nodeAction == NodeAction::Replace)
|
||||
{
|
||||
// clear the node group upfront
|
||||
nodeGroup->RemoveAllNodes();
|
||||
|
||||
for (const AZStd::string& nodeName : nodeNames)
|
||||
for (const AZStd::string& nodeName : *m_nodeNames)
|
||||
{
|
||||
EMotionFX::AnimGraphNode* animGraphNode = animGraph->RecursiveFindNodeByName(nodeName.c_str());
|
||||
if (!animGraphNode)
|
||||
@@ -211,68 +186,40 @@ namespace CommandSystem
|
||||
}
|
||||
|
||||
// save the current dirty flag and tell the anim graph that something got changed
|
||||
mOldDirtyFlag = animGraph->GetDirtyFlag();
|
||||
m_oldDirtyFlag = animGraph->GetDirtyFlag();
|
||||
animGraph->SetDirtyFlag(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// undo the command
|
||||
bool CommandAnimGraphAdjustNodeGroup::Undo(const MCore::CommandLine& parameters, AZStd::string& outResult)
|
||||
bool CommandAnimGraphAdjustNodeGroup::Undo(const MCore::CommandLine&, AZStd::string& outResult)
|
||||
{
|
||||
EMotionFX::AnimGraph* animGraph = CommandsGetAnimGraph(parameters, this, outResult);
|
||||
EMotionFX::AnimGraph* animGraph = EMotionFX::GetAnimGraphManager().FindAnimGraphByID(m_animGraphId);
|
||||
if (!animGraph)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
AZStd::string commandString = AZStd::string::format("AnimGraphAdjustNodeGroup -animGraphID %i", animGraph->GetID());
|
||||
|
||||
// set the old name or simply set the name if the name is not changed
|
||||
if (parameters.CheckIfHasParameter("newName"))
|
||||
{
|
||||
AZStd::string newName;
|
||||
parameters.GetValue("newName", this, newName);
|
||||
|
||||
commandString += AZStd::string::format(" -name \"%s\"", newName.c_str());
|
||||
commandString += AZStd::string::format(" -newName \"%s\"", mOldName.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
commandString += AZStd::string::format(" -name \"%s\"", mOldName.c_str());
|
||||
}
|
||||
|
||||
// set the old visible flag
|
||||
if (parameters.CheckIfHasParameter("isVisible"))
|
||||
{
|
||||
commandString += AZStd::string::format(" -isVisible %i", mOldIsVisible);
|
||||
}
|
||||
|
||||
// set the old color
|
||||
if (parameters.CheckIfHasParameter("color"))
|
||||
{
|
||||
AZ::Color oldColor;
|
||||
oldColor.FromU32(mOldColor);
|
||||
const AZStd::string oldColorString = AZStd::string::format("%.8f,%.8f,%.8f,%.8f", static_cast<float>(oldColor.GetR()), static_cast<float>(oldColor.GetG()), static_cast<float>(oldColor.GetB()), static_cast<float>(oldColor.GetA()));
|
||||
|
||||
commandString += AZStd::string::format(" -color \"%s\"", oldColorString.c_str());
|
||||
}
|
||||
|
||||
// set the old nodes
|
||||
if (parameters.CheckIfHasParameter("nodeNames"))
|
||||
{
|
||||
const AZStd::string nodeNamesString = CommandAnimGraphAdjustNodeGroup::GenerateNodeNameString(animGraph, mOldNodeIds);
|
||||
commandString += AZStd::string::format(" -nodeNames \"%s\" -nodeAction \"replace\"", nodeNamesString.c_str());
|
||||
}
|
||||
CommandAnimGraphAdjustNodeGroup* command = aznew CommandAnimGraphAdjustNodeGroup(
|
||||
GetCommandManager()->FindCommand(CommandAnimGraphAdjustNodeGroup::s_commandName),
|
||||
/*animGraphId = */ m_animGraphId,
|
||||
/*name = */ m_newName.has_value() ? *m_newName : m_name,
|
||||
/*visible = */ m_isVisible.has_value() ? AZStd::optional<bool>(m_oldIsVisible) : AZStd::nullopt,
|
||||
/*newName = */ m_newName.has_value() ? AZStd::optional<AZStd::string>(m_name) : AZStd::nullopt,
|
||||
/*nodeNames = */ m_nodeNames.has_value() ? AZStd::optional<AZStd::vector<AZStd::string>>(GenerateNodeNameVector(animGraph, m_oldNodeIds)) : AZStd::nullopt,
|
||||
/*nodeAction = */ m_nodeNames.has_value() ? AZStd::optional<NodeAction>(NodeAction::Replace) : AZStd::nullopt,
|
||||
/*color = */ m_color.has_value() ? AZStd::optional<AZ::u32>(m_oldColor) : AZStd::nullopt
|
||||
);
|
||||
|
||||
// execute the command
|
||||
if (!GetCommandManager()->ExecuteCommandInsideCommand(commandString, outResult))
|
||||
if (!GetCommandManager()->ExecuteCommandInsideCommand(command, outResult))
|
||||
{
|
||||
AZ_Error("EMotionFX", false, outResult.c_str());
|
||||
}
|
||||
|
||||
// set the dirty flag back to the old value
|
||||
animGraph->SetDirtyFlag(mOldDirtyFlag);
|
||||
animGraph->SetDirtyFlag(m_oldDirtyFlag);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -282,7 +229,7 @@ namespace CommandSystem
|
||||
{
|
||||
GetSyntax().ReserveParameters(8);
|
||||
GetSyntax().AddRequiredParameter("name", "The name of the node group to adjust.", MCore::CommandSyntax::PARAMTYPE_STRING);
|
||||
GetSyntax().AddParameter("animGraphID", "The id of the blend set the node group belongs to.", MCore::CommandSyntax::PARAMTYPE_INT, "-1");
|
||||
EMotionFX::ParameterMixinAnimGraphId::InitSyntax(GetSyntax(), /*isParameterRequired=*/ false);
|
||||
GetSyntax().AddParameter("isVisible", "The visibility flag of the node group.", MCore::CommandSyntax::PARAMTYPE_BOOLEAN, "true");
|
||||
GetSyntax().AddParameter("newName", "The new name of the node group.", MCore::CommandSyntax::PARAMTYPE_STRING, "");
|
||||
GetSyntax().AddParameter("nodeNames", "A list of node names that should be added/removed to/from the node group.", MCore::CommandSyntax::PARAMTYPE_STRING, "");
|
||||
@@ -291,6 +238,51 @@ namespace CommandSystem
|
||||
GetSyntax().AddParameter("updateUI", "Setting this to true will trigger a refresh of the node groups UI.", MCore::CommandSyntax::PARAMTYPE_BOOLEAN, "true");
|
||||
}
|
||||
|
||||
bool CommandAnimGraphAdjustNodeGroup::SetCommandParameters(const MCore::CommandLine& parameters)
|
||||
{
|
||||
EMotionFX::ParameterMixinAnimGraphId::SetCommandParameters(parameters);
|
||||
m_name = parameters.GetValue("name", this);
|
||||
|
||||
if (parameters.CheckIfHasParameter("isVisible"))
|
||||
{
|
||||
m_isVisible = parameters.GetValueAsBool("isVisible", this);
|
||||
}
|
||||
if (parameters.CheckIfHasParameter("newName"))
|
||||
{
|
||||
m_newName = parameters.GetValue("newName", this);
|
||||
}
|
||||
if (parameters.CheckIfHasParameter("nodeNames"))
|
||||
{
|
||||
m_nodeNames.emplace();
|
||||
AzFramework::StringFunc::Tokenize(parameters.GetValue("nodeNames", this), m_nodeNames.value(), ";", false, true);
|
||||
}
|
||||
if (parameters.CheckIfHasValue("nodeAction"))
|
||||
{
|
||||
const AZStd::string& nodeActionStr = parameters.GetValue("nodeAction", this);
|
||||
if (nodeActionStr == "add")
|
||||
{
|
||||
m_nodeAction = NodeAction::Add;
|
||||
}
|
||||
else if (nodeActionStr == "remove")
|
||||
{
|
||||
m_nodeAction = NodeAction::Remove;
|
||||
}
|
||||
else if (nodeActionStr == "replace")
|
||||
{
|
||||
m_nodeAction = NodeAction::Replace;
|
||||
}
|
||||
}
|
||||
if (parameters.CheckIfHasParameter("color"))
|
||||
{
|
||||
m_color = AZ::Color(parameters.GetValueAsVector4("color", this)).ToU32();
|
||||
}
|
||||
if (parameters.CheckIfHasParameter("updateUI"))
|
||||
{
|
||||
m_updateUI = parameters.GetValueAsBool("updateUI", this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* CommandAnimGraphAdjustNodeGroup::GetDescription() const
|
||||
{
|
||||
@@ -447,21 +439,20 @@ namespace CommandSystem
|
||||
|
||||
MCore::CommandGroup commandGroup;
|
||||
|
||||
AZStd::string commandString = AZStd::string::format("AnimGraphAddNodeGroup -animGraphID %i -name \"%s\" -updateUI %s",animGraph->GetID(), mOldName.c_str(), updateWindow.c_str());
|
||||
commandGroup.AddCommandString(commandString);
|
||||
commandGroup.AddCommandString(AZStd::string::format("AnimGraphAddNodeGroup -animGraphID %i -name \"%s\" -updateUI %s",animGraph->GetID(), mOldName.c_str(), updateWindow.c_str()));
|
||||
|
||||
const AZStd::string nodeNamesString = CommandAnimGraphAdjustNodeGroup::GenerateNodeNameString(animGraph, mOldNodeIds);
|
||||
auto* command = aznew CommandAnimGraphAdjustNodeGroup(
|
||||
GetCommandManager()->FindCommand(CommandAnimGraphAdjustNodeGroup::s_commandName),
|
||||
/*animGraphId = */ animGraph->GetID(),
|
||||
/*name = */ mOldName,
|
||||
/*visible = */ mOldIsVisible,
|
||||
/*newName = */ AZStd::nullopt,
|
||||
/*nodeNames = */ CommandAnimGraphAdjustNodeGroup::GenerateNodeNameVector(animGraph, mOldNodeIds),
|
||||
/*nodeAction = */ CommandAnimGraphAdjustNodeGroup::NodeAction::Add,
|
||||
/*color = */ mOldColor
|
||||
);
|
||||
|
||||
AZ::Color oldColor;
|
||||
oldColor.FromU32(mOldColor);
|
||||
const AZStd::string oldColorString = AZStd::string::format("%.8f,%.8f,%.8f,%.8f",
|
||||
static_cast<float>(oldColor.GetR()), static_cast<float>(oldColor.GetG()), static_cast<float>(oldColor.GetB()), static_cast<float>(oldColor.GetA()));
|
||||
|
||||
commandString = AZStd::string::format(
|
||||
"AnimGraphAdjustNodeGroup -animGraphID %i -name \"%s\" -isVisible %s -color \"%s\" -nodeNames \"%s\" -nodeAction \"add\" -updateUI %s",
|
||||
animGraph->GetID(), mOldName.c_str(), AZStd::to_string(mOldIsVisible).c_str(), oldColorString.c_str(), nodeNamesString.c_str(), updateWindow.c_str());
|
||||
|
||||
commandGroup.AddCommandString(commandString);
|
||||
commandGroup.AddCommand(command);
|
||||
|
||||
AZStd::string result;
|
||||
if (!GetCommandManager()->ExecuteCommandGroupInsideCommand(commandGroup, result))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user