Merge branch 'development' of https://github.com/o3de/o3de into jckand/EditorPrefabTests
Signed-off-by: jckand-amzn <82226555+jckand-amzn@users.noreply.github.com>
This commit is contained in:
+5
-5
@@ -19,8 +19,8 @@
|
||||
|
||||
<RemoteProcedure Name="AutonomousToAuthorityNoParams" InvokeFrom="Autonomous" HandleOn="Authority" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" />
|
||||
|
||||
<RemoteProcedure Name="AuthorityToAutonomous" InvokeFrom="Authority" HandleOn="Autonomous" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" >
|
||||
<Param Type="float" Name="SomeFloat" />
|
||||
<RemoteProcedure Name="AuthorityToAutonomous_PlayerNumber" InvokeFrom="Authority" HandleOn="Autonomous" IsPublic="false" IsReliable="true" GenerateEventBindings="true" Description="" >
|
||||
<Param Type="int" Name="player_number" />
|
||||
</RemoteProcedure>
|
||||
|
||||
<RemoteProcedure Name="AuthorityToAutonomousNoParams" InvokeFrom="Authority" HandleOn="Autonomous" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" />
|
||||
@@ -29,10 +29,10 @@
|
||||
<Param Type="float" Name="SomeFloat" />
|
||||
</RemoteProcedure>
|
||||
|
||||
<RemoteProcedure Name="AuthorityToClientNoParams" InvokeFrom="Authority" HandleOn="Client" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" />
|
||||
<RemoteProcedure Name="AuthorityToClientNoParams_PlayFx" InvokeFrom="Authority" HandleOn="Client" IsPublic="false" IsReliable="true" GenerateEventBindings="true" Description="" />
|
||||
|
||||
<RemoteProcedure Name="ServerToAuthority" InvokeFrom="Server" HandleOn="Authority" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" >
|
||||
<Param Type="float" Name="SomeFloat" />
|
||||
<RemoteProcedure Name="ServerToAuthority_DealDamage" InvokeFrom="Server" HandleOn="Authority" IsPublic="false" IsReliable="true" GenerateEventBindings="true" Description="" >
|
||||
<Param Type="float" Name="damage" />
|
||||
</RemoteProcedure>
|
||||
|
||||
<RemoteProcedure Name="ServerToAuthorityNoParam" InvokeFrom="Server" HandleOn="Authority" IsPublic="false" IsReliable="false" GenerateEventBindings="true" Description="" />
|
||||
|
||||
+49
-23
@@ -100,6 +100,49 @@ class TestHelper:
|
||||
TestHelper.wait_for_condition(lambda : general.is_in_game_mode(), 1.0)
|
||||
Report.critical_result(msgtuple_success_fail, general.is_in_game_mode())
|
||||
|
||||
@staticmethod
|
||||
def find_line(window, line, print_infos):
|
||||
"""
|
||||
Looks for an expected line in a list of tracer log lines
|
||||
:param window: The log's window name. For example, logs printed via script-canvas use the "Script" window.
|
||||
:param line: The log message to search for.
|
||||
:param print_infos: A list of PrintInfos collected by Tracer to search. Example options: your_tracer.warnings, your_tracer.errors, your_tracer.asserts, or your_tracer.prints
|
||||
|
||||
:return: True if the line is found, otherwise false.
|
||||
"""
|
||||
for printInfo in print_infos:
|
||||
if printInfo.window == window.strip() and printInfo.message.strip() == line:
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def succeed_if_log_line_found(window, line, print_infos, time_out):
|
||||
"""
|
||||
Looks for a line in a list of tracer log lines and reports success if found.
|
||||
:param window: The log's window name. For example, logs printed via script-canvas use the "Script" window.
|
||||
:param line: The log message we're hoping to find.
|
||||
:param print_infos: A list of PrintInfos collected by Tracer to search. Example options: your_tracer.warnings, your_tracer.errors, your_tracer.asserts, or your_tracer.prints
|
||||
:param time_out: The total amount of time to wait before giving up looking for the expected line.
|
||||
|
||||
:return: No return value, but if the message is found, a successful critical result is reported; otherwise failure.
|
||||
"""
|
||||
TestHelper.wait_for_condition(lambda : TestHelper.find_line(window, line, print_infos), time_out)
|
||||
Report.critical_result(("Found expected line: " + line, "Failed to find expected line: " + line), TestHelper.find_line(window, line, print_infos))
|
||||
|
||||
@staticmethod
|
||||
def fail_if_log_line_found(window, line, print_infos, time_out):
|
||||
"""
|
||||
Reports a failure if a log line in a list of tracer log lines is found.
|
||||
:param window: The log's window name. For example, logs printed via script-canvas use the "Script" window.
|
||||
:param line: The log message we're hoping to not find.
|
||||
:param print_infos: A list of PrintInfos collected by Tracer to search. Example options: your_tracer.warnings, your_tracer.errors, your_tracer.asserts, or your_tracer.prints
|
||||
:param time_out: The total amount of time to wait before giving up looking for the unexpected line. If time runs out and we don't see the unexpected line then report a success.
|
||||
|
||||
:return: No return value, but if the line is found, a failed critical result is reported; otherwise success.
|
||||
"""
|
||||
TestHelper.wait_for_condition(lambda : TestHelper.find_line(window, line, print_infos), time_out)
|
||||
Report.critical_result(("Unexpected line not found: " + line, "Unexpected line found: " + line), not TestHelper.find_line(window, line, print_infos))
|
||||
|
||||
@staticmethod
|
||||
def multiplayer_enter_game_mode(msgtuple_success_fail: Tuple[str, str], sv_default_player_spawn_asset: str) -> None:
|
||||
"""
|
||||
@@ -108,23 +151,6 @@ class TestHelper:
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# looks for an expected line in a list of tracers lines
|
||||
# lines: the tracer list of lines to search. options are section_tracer.warnings, section_tracer.errors, section_tracer.asserts, section_tracer.prints
|
||||
# return: true if the line is found, otherwise false
|
||||
def find_expected_line(expected_line, lines):
|
||||
found_lines = [printInfo.message.strip() for printInfo in lines]
|
||||
return expected_line in found_lines
|
||||
|
||||
def wait_for_critical_expected_line(expected_line, lines, time_out):
|
||||
TestHelper.wait_for_condition(lambda : find_expected_line(expected_line, lines), time_out)
|
||||
Report.critical_result(("Found expected line: " + expected_line, "Failed to find expected line: " + expected_line), find_expected_line(expected_line, lines))
|
||||
|
||||
def wait_for_critical_unexpected_line(unexpected_line, lines, time_out):
|
||||
TestHelper.wait_for_condition(lambda : find_expected_line(unexpected_line, lines), time_out)
|
||||
Report.critical_result(("Unexpected line not found: " + unexpected_line, "Unexpected line found: " + unexpected_line), not find_expected_line(unexpected_line, lines))
|
||||
|
||||
|
||||
Report.info("Entering game mode")
|
||||
if sv_default_player_spawn_asset :
|
||||
general.set_cvar("sv_defaultPlayerSpawnAsset", sv_default_player_spawn_asset)
|
||||
@@ -135,20 +161,20 @@ class TestHelper:
|
||||
multiplayer.PythonEditorFuncs_enter_game_mode()
|
||||
|
||||
# make sure the server launcher binary exists
|
||||
wait_for_critical_unexpected_line("LaunchEditorServer failed! The ServerLauncher binary is missing!", section_tracer.errors, 0.5)
|
||||
TestHelper.fail_if_log_line_found("MultiplayerEditor", "LaunchEditorServer failed! The ServerLauncher binary is missing!", section_tracer.errors, 0.5)
|
||||
|
||||
# make sure the server launcher is running
|
||||
waiter.wait_for(lambda: process_utils.process_exists("AutomatedTesting.ServerLauncher", ignore_extensions=True), timeout=5.0, exc=AssertionError("AutomatedTesting.ServerLauncher has NOT launched!"), interval=1.0)
|
||||
|
||||
wait_for_critical_expected_line("MultiplayerEditorConnection: Editor-server activation has found and connected to the editor.", section_tracer.prints, 15.0)
|
||||
TestHelper.succeed_if_log_line_found("EditorServer", "MultiplayerEditorConnection: Editor-server activation has found and connected to the editor.", section_tracer.prints, 15.0)
|
||||
|
||||
wait_for_critical_expected_line("Editor is sending the editor-server the level data packet.", section_tracer.prints, 5.0)
|
||||
TestHelper.succeed_if_log_line_found("MultiplayerEditor", "Editor is sending the editor-server the level data packet.", section_tracer.prints, 5.0)
|
||||
|
||||
wait_for_critical_expected_line("Logger: Editor Server completed receiving the editor's level assets, responding to Editor...", section_tracer.prints, 5.0)
|
||||
TestHelper.succeed_if_log_line_found("EditorServer", "Logger: Editor Server completed receiving the editor's level assets, responding to Editor...", section_tracer.prints, 5.0)
|
||||
|
||||
wait_for_critical_expected_line("Editor-server ready. Editor has successfully connected to the editor-server's network simulation.", section_tracer.prints, 5.0)
|
||||
TestHelper.succeed_if_log_line_found("MultiplayerEditorConnection", "Editor-server ready. Editor has successfully connected to the editor-server's network simulation.", section_tracer.prints, 5.0)
|
||||
|
||||
wait_for_critical_unexpected_line(f"MultiplayerSystemComponent: SpawnDefaultPlayerPrefab failed. Missing sv_defaultPlayerSpawnAsset at path '{sv_default_player_spawn_asset.lower()}'.", section_tracer.prints, 0.5)
|
||||
TestHelper.fail_if_log_line_found("EditorServer", f"MultiplayerSystemComponent: SpawnDefaultPlayerPrefab failed. Missing sv_defaultPlayerSpawnAsset at path '{sv_default_player_spawn_asset.lower()}'.", section_tracer.prints, 0.5)
|
||||
|
||||
TestHelper.wait_for_condition(lambda : multiplayer.PythonEditorFuncs_is_in_game_mode(), 5.0)
|
||||
Report.critical_result(msgtuple_success_fail, multiplayer.PythonEditorFuncs_is_in_game_mode())
|
||||
|
||||
@@ -32,3 +32,6 @@ class TestAutomation(TestAutomationBase):
|
||||
from .tests import Multiplayer_AutoComponent_NetworkInput as test_module
|
||||
self._run_prefab_test(request, workspace, editor, test_module)
|
||||
|
||||
def test_Multiplayer_AutoComponent_RPC(self, request, workspace, editor, launcher_platform):
|
||||
from .tests import Multiplayer_AutoComponent_RPC as test_module
|
||||
self._run_prefab_test(request, workspace, editor, test_module)
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
"""
|
||||
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
|
||||
"""
|
||||
|
||||
|
||||
# Test Case Title : Check that the four network RPCs can be sent and received
|
||||
|
||||
|
||||
# fmt: off
|
||||
class TestSuccessFailTuples():
|
||||
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
||||
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
||||
find_network_player = ("Found network player", "Couldn't find network player")
|
||||
# fmt: on
|
||||
|
||||
|
||||
def Multiplayer_AutoComponent_RPC():
|
||||
r"""
|
||||
Summary:
|
||||
Runs a test to make sure that RPCs can be sent and received via script canvas
|
||||
|
||||
Level Description:
|
||||
- Dynamic
|
||||
1. Although the level is nearly empty, when the server and editor connect the server will spawn and replicate the player network prefab.
|
||||
a. The player network prefab has a NetworkTestPlayerComponent.AutoComponent and a script canvas attached which sends and receives various RPCs.
|
||||
Print logs occur upon sending and receiving the RPCs; we are testing to make sure the expected events and values are received.
|
||||
- Static
|
||||
1. NetLevelEntity. This is a networked entity which has a script attached. Used for cross-entity communication. The net-player prefab will send this level entity Server->Authority RPCs
|
||||
|
||||
|
||||
Expected Outcome:
|
||||
We should see editor logs stating that RPCs have been sent and received.
|
||||
However, if the script receives unexpected values for the Process event we will see print logs for bad data as well.
|
||||
|
||||
:return:
|
||||
"""
|
||||
import azlmbr.legacy.general as general
|
||||
from editor_python_test_tools.utils import Report
|
||||
from editor_python_test_tools.utils import Tracer
|
||||
|
||||
from editor_python_test_tools.utils import TestHelper as helper
|
||||
from ly_remote_console.remote_console_commands import RemoteConsole as RemoteConsole
|
||||
|
||||
level_name = "AutoComponent_RPC"
|
||||
player_prefab_name = "Player"
|
||||
player_prefab_path = f"levels/multiplayer/{level_name}/{player_prefab_name}.network.spawnable"
|
||||
|
||||
helper.init_idle()
|
||||
|
||||
# 1) Open Level
|
||||
helper.open_level("Multiplayer", level_name)
|
||||
|
||||
with Tracer() as section_tracer:
|
||||
# 2) Enter game mode
|
||||
helper.multiplayer_enter_game_mode(TestSuccessFailTuples.enter_game_mode, player_prefab_path.lower())
|
||||
|
||||
# 3) Make sure the network player was spawned
|
||||
player_id = general.find_game_entity(player_prefab_name)
|
||||
Report.critical_result(TestSuccessFailTuples.find_network_player, player_id.IsValid())
|
||||
|
||||
# 4) Check the editor logs for expected and unexpected log output
|
||||
PLAYERID_RPC_WAIT_TIME_SECONDS = 1.0 # The player id is sent from the server as soon as the player script is spawned. 1 second should be more than enough time to send/receive that RPC.
|
||||
helper.succeed_if_log_line_found('EditorServer', 'Script: AutoComponent_RPC: Sending client PlayerNumber 1', section_tracer.prints, PLAYERID_RPC_WAIT_TIME_SECONDS)
|
||||
helper.succeed_if_log_line_found('Script', "AutoComponent_RPC: I'm Player #1", section_tracer.prints, PLAYERID_RPC_WAIT_TIME_SECONDS)
|
||||
|
||||
# Uncomment once editor game-play mode supports level entities with net-binding
|
||||
#PLAYFX_RPC_WAIT_TIME_SECONDS = 1.1 # The server will send an RPC to play an fx on the client every second.
|
||||
#helper.succeed_if_log_line_found('EditorServer', "Script: AutoComponent_RPC_NetLevelEntity Activated on entity: NetLevelEntity", section_tracer.prints, PLAYFX_RPC_WAIT_TIME_SECONDS)
|
||||
#helper.succeed_if_log_line_found('EditorServer', "Script: AutoComponent_RPC_NetLevelEntity: Authority sending RPC to play some fx.", section_tracer.prints, PLAYFX_RPC_WAIT_TIME_SECONDS)
|
||||
#helper.succeed_if_log_line_found('Script', "AutoComponent_RPC_NetLevelEntity: I'm a client playing some superficial fx.", section_tracer.prints, PLAYFX_RPC_WAIT_TIME_SECONDS)
|
||||
|
||||
|
||||
# Exit game mode
|
||||
helper.exit_game_mode(TestSuccessFailTuples.exit_game_mode)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from editor_python_test_tools.utils import Report
|
||||
Report.start_test(Multiplayer_AutoComponent_RPC)
|
||||
@@ -0,0 +1,747 @@
|
||||
{
|
||||
"ContainerEntity": {
|
||||
"Id": "Entity_[1146574390643]",
|
||||
"Name": "Level",
|
||||
"Components": {
|
||||
"Component_[10641544592923449938]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 10641544592923449938
|
||||
},
|
||||
"Component_[12039882709170782873]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 12039882709170782873
|
||||
},
|
||||
"Component_[12265484671603697631]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 12265484671603697631
|
||||
},
|
||||
"Component_[14126657869720434043]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 14126657869720434043,
|
||||
"Child Entity Order": [
|
||||
"Entity_[1176639161715]",
|
||||
"Entity_[12685882829720]",
|
||||
"Entity_[31145534614197]"
|
||||
]
|
||||
},
|
||||
"Component_[15230859088967841193]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 15230859088967841193,
|
||||
"Parent Entity": ""
|
||||
},
|
||||
"Component_[16239496886950819870]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 16239496886950819870
|
||||
},
|
||||
"Component_[5688118765544765547]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 5688118765544765547
|
||||
},
|
||||
"Component_[6545738857812235305]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 6545738857812235305
|
||||
},
|
||||
"Component_[7247035804068349658]": {
|
||||
"$type": "EditorPrefabComponent",
|
||||
"Id": 7247035804068349658
|
||||
},
|
||||
"Component_[9307224322037797205]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 9307224322037797205
|
||||
},
|
||||
"Component_[9562516168917670048]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 9562516168917670048
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entities": {
|
||||
"Entity_[1155164325235]": {
|
||||
"Id": "Entity_[1155164325235]",
|
||||
"Name": "Sun",
|
||||
"Components": {
|
||||
"Component_[10440557478882592717]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 10440557478882592717
|
||||
},
|
||||
"Component_[13620450453324765907]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 13620450453324765907
|
||||
},
|
||||
"Component_[2134313378593666258]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 2134313378593666258
|
||||
},
|
||||
"Component_[234010807770404186]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 234010807770404186
|
||||
},
|
||||
"Component_[2970359110423865725]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 2970359110423865725
|
||||
},
|
||||
"Component_[3722854130373041803]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 3722854130373041803
|
||||
},
|
||||
"Component_[5992533738676323195]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 5992533738676323195
|
||||
},
|
||||
"Component_[7378860763541895402]": {
|
||||
"$type": "AZ::Render::EditorDirectionalLightComponent",
|
||||
"Id": 7378860763541895402,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"Intensity": 1.0,
|
||||
"CameraEntityId": "",
|
||||
"ShadowFilterMethod": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[7892834440890947578]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 7892834440890947578,
|
||||
"Parent Entity": "Entity_[1176639161715]",
|
||||
"Transform Data": {
|
||||
"Translate": [
|
||||
0.0,
|
||||
0.0,
|
||||
13.487043380737305
|
||||
],
|
||||
"Rotate": [
|
||||
-76.13099670410156,
|
||||
-0.847000002861023,
|
||||
-15.8100004196167
|
||||
]
|
||||
}
|
||||
},
|
||||
"Component_[8599729549570828259]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 8599729549570828259
|
||||
},
|
||||
"Component_[952797371922080273]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 952797371922080273
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entity_[1159459292531]": {
|
||||
"Id": "Entity_[1159459292531]",
|
||||
"Name": "Ground",
|
||||
"Components": {
|
||||
"Component_[11701138785793981042]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 11701138785793981042
|
||||
},
|
||||
"Component_[12260880513256986252]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 12260880513256986252
|
||||
},
|
||||
"Component_[13711420870643673468]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 13711420870643673468
|
||||
},
|
||||
"Component_[138002849734991713]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 138002849734991713
|
||||
},
|
||||
"Component_[16578565737331764849]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 16578565737331764849,
|
||||
"Parent Entity": "Entity_[1176639161715]"
|
||||
},
|
||||
"Component_[16919232076966545697]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 16919232076966545697
|
||||
},
|
||||
"Component_[5182430712893438093]": {
|
||||
"$type": "EditorMaterialComponent",
|
||||
"Id": 5182430712893438093
|
||||
},
|
||||
"Component_[5675108321710651991]": {
|
||||
"$type": "AZ::Render::EditorMeshComponent",
|
||||
"Id": 5675108321710651991,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"ModelAsset": {
|
||||
"assetId": {
|
||||
"guid": "{0CD745C0-6AA8-569A-A68A-73A3270986C4}",
|
||||
"subId": 277889906
|
||||
},
|
||||
"assetHint": "objects/groudplane/groundplane_512x512m.azmodel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[5681893399601237518]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 5681893399601237518
|
||||
},
|
||||
"Component_[592692962543397545]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 592692962543397545
|
||||
},
|
||||
"Component_[7090012899106946164]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 7090012899106946164
|
||||
},
|
||||
"Component_[9410832619875640998]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 9410832619875640998
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entity_[1163754259827]": {
|
||||
"Id": "Entity_[1163754259827]",
|
||||
"Name": "Camera",
|
||||
"Components": {
|
||||
"Component_[11895140916889160460]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 11895140916889160460
|
||||
},
|
||||
"Component_[16880285896855930892]": {
|
||||
"$type": "{CA11DA46-29FF-4083-B5F6-E02C3A8C3A3D} EditorCameraComponent",
|
||||
"Id": 16880285896855930892,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"Field of View": 55.0,
|
||||
"EditorEntityId": 11050384689878106598
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[17187464423780271193]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 17187464423780271193
|
||||
},
|
||||
"Component_[17495696818315413311]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 17495696818315413311
|
||||
},
|
||||
"Component_[18086214374043522055]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 18086214374043522055,
|
||||
"Parent Entity": "Entity_[1176639161715]",
|
||||
"Transform Data": {
|
||||
"Translate": [
|
||||
-2.3000001907348633,
|
||||
-3.9368600845336914,
|
||||
1.0
|
||||
],
|
||||
"Rotate": [
|
||||
-2.050307512283325,
|
||||
1.9552897214889526,
|
||||
-43.623355865478516
|
||||
]
|
||||
}
|
||||
},
|
||||
"Component_[18387556550380114975]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 18387556550380114975
|
||||
},
|
||||
"Component_[2654521436129313160]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 2654521436129313160
|
||||
},
|
||||
"Component_[5265045084611556958]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 5265045084611556958
|
||||
},
|
||||
"Component_[7169798125182238623]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 7169798125182238623
|
||||
},
|
||||
"Component_[7255796294953281766]": {
|
||||
"$type": "GenericComponentWrapper",
|
||||
"Id": 7255796294953281766,
|
||||
"m_template": {
|
||||
"$type": "FlyCameraInputComponent"
|
||||
}
|
||||
},
|
||||
"Component_[8866210352157164042]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 8866210352157164042
|
||||
},
|
||||
"Component_[9129253381063760879]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 9129253381063760879
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entity_[1168049227123]": {
|
||||
"Id": "Entity_[1168049227123]",
|
||||
"Name": "Grid",
|
||||
"Components": {
|
||||
"Component_[11443347433215807130]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 11443347433215807130
|
||||
},
|
||||
"Component_[11779275529534764488]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 11779275529534764488
|
||||
},
|
||||
"Component_[14249419413039427459]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 14249419413039427459
|
||||
},
|
||||
"Component_[15448581635946161318]": {
|
||||
"$type": "AZ::Render::EditorGridComponent",
|
||||
"Id": 15448581635946161318,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"primarySpacing": 4.0,
|
||||
"primaryColor": [
|
||||
0.501960813999176,
|
||||
0.501960813999176,
|
||||
0.501960813999176
|
||||
],
|
||||
"secondarySpacing": 0.5,
|
||||
"secondaryColor": [
|
||||
0.250980406999588,
|
||||
0.250980406999588,
|
||||
0.250980406999588
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[1843303322527297409]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 1843303322527297409
|
||||
},
|
||||
"Component_[380249072065273654]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 380249072065273654,
|
||||
"Parent Entity": "Entity_[1176639161715]"
|
||||
},
|
||||
"Component_[7476660583684339787]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 7476660583684339787
|
||||
},
|
||||
"Component_[7557626501215118375]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 7557626501215118375
|
||||
},
|
||||
"Component_[7984048488947365511]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 7984048488947365511
|
||||
},
|
||||
"Component_[8118181039276487398]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 8118181039276487398
|
||||
},
|
||||
"Component_[9189909764215270515]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 9189909764215270515
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entity_[1172344194419]": {
|
||||
"Id": "Entity_[1172344194419]",
|
||||
"Name": "Shader Ball",
|
||||
"Components": {
|
||||
"Component_[10789351944715265527]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 10789351944715265527
|
||||
},
|
||||
"Component_[12037033284781049225]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 12037033284781049225
|
||||
},
|
||||
"Component_[13759153306105970079]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 13759153306105970079
|
||||
},
|
||||
"Component_[14135560884830586279]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 14135560884830586279
|
||||
},
|
||||
"Component_[16247165675903986673]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 16247165675903986673
|
||||
},
|
||||
"Component_[18082433625958885247]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 18082433625958885247
|
||||
},
|
||||
"Component_[6472623349872972660]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 6472623349872972660,
|
||||
"Parent Entity": "Entity_[1176639161715]",
|
||||
"Transform Data": {
|
||||
"Rotate": [
|
||||
0.0,
|
||||
0.10000000149011612,
|
||||
180.0
|
||||
]
|
||||
}
|
||||
},
|
||||
"Component_[6495255223970673916]": {
|
||||
"$type": "AZ::Render::EditorMeshComponent",
|
||||
"Id": 6495255223970673916,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"ModelAsset": {
|
||||
"assetId": {
|
||||
"guid": "{FD340C30-755C-5911-92A3-19A3F7A77931}",
|
||||
"subId": 281415304
|
||||
},
|
||||
"assetHint": "objects/shaderball/shaderball_default_1m.azmodel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[8056625192494070973]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 8056625192494070973
|
||||
},
|
||||
"Component_[8550141614185782969]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 8550141614185782969
|
||||
},
|
||||
"Component_[9439770997198325425]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 9439770997198325425
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entity_[1176639161715]": {
|
||||
"Id": "Entity_[1176639161715]",
|
||||
"Name": "Atom Default Environment",
|
||||
"Components": {
|
||||
"Component_[10757302973393310045]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 10757302973393310045,
|
||||
"Parent Entity": "Entity_[1146574390643]"
|
||||
},
|
||||
"Component_[14505817420424255464]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 14505817420424255464,
|
||||
"ComponentOrderEntryArray": [
|
||||
{
|
||||
"ComponentId": 10757302973393310045
|
||||
}
|
||||
]
|
||||
},
|
||||
"Component_[14988041764659020032]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 14988041764659020032
|
||||
},
|
||||
"Component_[15808690248755038124]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 15808690248755038124
|
||||
},
|
||||
"Component_[15900837685796817138]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 15900837685796817138
|
||||
},
|
||||
"Component_[3298767348226484884]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 3298767348226484884
|
||||
},
|
||||
"Component_[4076975109609220594]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 4076975109609220594
|
||||
},
|
||||
"Component_[5679760548946028854]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 5679760548946028854
|
||||
},
|
||||
"Component_[5855590796136709437]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 5855590796136709437,
|
||||
"Child Entity Order": [
|
||||
"Entity_[1155164325235]",
|
||||
"Entity_[1180934129011]",
|
||||
"Entity_[1172344194419]",
|
||||
"Entity_[1168049227123]",
|
||||
"Entity_[1163754259827]",
|
||||
"Entity_[1159459292531]"
|
||||
]
|
||||
},
|
||||
"Component_[9277695270015777859]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 9277695270015777859
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entity_[1180934129011]": {
|
||||
"Id": "Entity_[1180934129011]",
|
||||
"Name": "Global Sky",
|
||||
"Components": {
|
||||
"Component_[11231930600558681245]": {
|
||||
"$type": "AZ::Render::EditorHDRiSkyboxComponent",
|
||||
"Id": 11231930600558681245,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"CubemapAsset": {
|
||||
"assetId": {
|
||||
"guid": "{215E47FD-D181-5832-B1AB-91673ABF6399}",
|
||||
"subId": 1000
|
||||
},
|
||||
"assetHint": "lightingpresets/highcontrast/goegap_4k_skyboxcm.exr.streamingimage"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[11980494120202836095]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 11980494120202836095
|
||||
},
|
||||
"Component_[1428633914413949476]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 1428633914413949476
|
||||
},
|
||||
"Component_[14936200426671614999]": {
|
||||
"$type": "AZ::Render::EditorImageBasedLightComponent",
|
||||
"Id": 14936200426671614999,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"diffuseImageAsset": {
|
||||
"assetId": {
|
||||
"guid": "{3FD09945-D0F2-55C8-B9AF-B2FD421FE3BE}",
|
||||
"subId": 3000
|
||||
},
|
||||
"assetHint": "lightingpresets/highcontrast/goegap_4k_iblglobalcm_ibldiffuse.exr.streamingimage"
|
||||
},
|
||||
"specularImageAsset": {
|
||||
"assetId": {
|
||||
"guid": "{3FD09945-D0F2-55C8-B9AF-B2FD421FE3BE}",
|
||||
"subId": 2000
|
||||
},
|
||||
"assetHint": "lightingpresets/highcontrast/goegap_4k_iblglobalcm_iblspecular.exr.streamingimage"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[14994774102579326069]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 14994774102579326069
|
||||
},
|
||||
"Component_[15417479889044493340]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 15417479889044493340
|
||||
},
|
||||
"Component_[15826613364991382688]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 15826613364991382688
|
||||
},
|
||||
"Component_[1665003113283562343]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 1665003113283562343
|
||||
},
|
||||
"Component_[3704934735944502280]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 3704934735944502280
|
||||
},
|
||||
"Component_[5698542331457326479]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 5698542331457326479
|
||||
},
|
||||
"Component_[6644513399057217122]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 6644513399057217122,
|
||||
"Parent Entity": "Entity_[1176639161715]"
|
||||
},
|
||||
"Component_[931091830724002070]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 931091830724002070
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entity_[12685882829720]": {
|
||||
"Id": "Entity_[12685882829720]",
|
||||
"Name": "GlobalGameData",
|
||||
"Components": {
|
||||
"Component_[11240656689650225106]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 11240656689650225106
|
||||
},
|
||||
"Component_[13863201640354873385]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 13863201640354873385
|
||||
},
|
||||
"Component_[14671754037021562789]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 14671754037021562789
|
||||
},
|
||||
"Component_[14750978061505735417]": {
|
||||
"$type": "EditorScriptCanvasComponent",
|
||||
"Id": 14750978061505735417,
|
||||
"m_name": "GlobalGameData",
|
||||
"m_assetHolder": {
|
||||
"m_asset": {
|
||||
"assetId": {
|
||||
"guid": "{B16589A0-EA01-56BC-8141-91A3967FB95F}"
|
||||
},
|
||||
"assetHint": "levels/multiplayer/autocomponent_rpc/globalgamedata.scriptcanvas"
|
||||
}
|
||||
},
|
||||
"runtimeDataIsValid": true,
|
||||
"runtimeDataOverrides": {
|
||||
"source": {
|
||||
"assetId": {
|
||||
"guid": "{B16589A0-EA01-56BC-8141-91A3967FB95F}"
|
||||
},
|
||||
"assetHint": "levels/multiplayer/autocomponent_rpc/globalgamedata.scriptcanvas"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[16436925042043744033]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 16436925042043744033,
|
||||
"Parent Entity": "Entity_[1146574390643]",
|
||||
"Transform Data": {
|
||||
"Translate": [
|
||||
0.0,
|
||||
0.10000038146972656,
|
||||
4.005393981933594
|
||||
]
|
||||
}
|
||||
},
|
||||
"Component_[16974524495698916088]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 16974524495698916088
|
||||
},
|
||||
"Component_[2753700837834389204]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 2753700837834389204
|
||||
},
|
||||
"Component_[3766473509503096065]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 3766473509503096065
|
||||
},
|
||||
"Component_[4025955184206569130]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 4025955184206569130
|
||||
},
|
||||
"Component_[7909743395732791573]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 7909743395732791573
|
||||
},
|
||||
"Component_[9550161640684119498]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 9550161640684119498
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entity_[31145534614197]": {
|
||||
"Id": "Entity_[31145534614197]",
|
||||
"Name": "NetLevelEntity",
|
||||
"Components": {
|
||||
"Component_[12132849363414901338]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 12132849363414901338
|
||||
},
|
||||
"Component_[12302672911455629152]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 12302672911455629152
|
||||
},
|
||||
"Component_[14169903623243423134]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 14169903623243423134
|
||||
},
|
||||
"Component_[14607413934411389854]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 14607413934411389854
|
||||
},
|
||||
"Component_[15396284312416541768]": {
|
||||
"$type": "GenericComponentWrapper",
|
||||
"Id": 15396284312416541768,
|
||||
"m_template": {
|
||||
"$type": "Multiplayer::LocalPredictionPlayerInputComponent"
|
||||
}
|
||||
},
|
||||
"Component_[15494977028055234270]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 15494977028055234270
|
||||
},
|
||||
"Component_[16325088972532345964]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 16325088972532345964
|
||||
},
|
||||
"Component_[1986030426392465743]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 1986030426392465743
|
||||
},
|
||||
"Component_[4591476848838823508]": {
|
||||
"$type": "AZ::Render::EditorMeshComponent",
|
||||
"Id": 4591476848838823508,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"ModelAsset": {
|
||||
"assetId": {
|
||||
"guid": "{80FA8BAF-4A5B-5937-9679-2E592E841A3A}",
|
||||
"subId": 275306041
|
||||
},
|
||||
"assetHint": "assets/physics/collider_pxmeshautoassigned/spherebot/r0-b_body.azmodel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[7256163899440301540]": {
|
||||
"$type": "EditorScriptCanvasComponent",
|
||||
"Id": 7256163899440301540,
|
||||
"m_name": "AutoComponent_RPC_NetLevelEntity",
|
||||
"m_assetHolder": {
|
||||
"m_asset": {
|
||||
"assetId": {
|
||||
"guid": "{1D517006-AC01-5ECA-AE66-0E007871F0CD}"
|
||||
},
|
||||
"assetHint": "levels/multiplayer/autocomponent_rpc/autocomponent_rpc_netlevelentity.scriptcanvas"
|
||||
}
|
||||
},
|
||||
"runtimeDataIsValid": true,
|
||||
"runtimeDataOverrides": {
|
||||
"source": {
|
||||
"assetId": {
|
||||
"guid": "{1D517006-AC01-5ECA-AE66-0E007871F0CD}"
|
||||
},
|
||||
"assetHint": "levels/multiplayer/autocomponent_rpc/autocomponent_rpc_netlevelentity.scriptcanvas"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[731336627222243355]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 731336627222243355,
|
||||
"Parent Entity": "Entity_[1146574390643]",
|
||||
"Transform Data": {
|
||||
"Translate": [
|
||||
2.561863899230957,
|
||||
-1.038161277770996,
|
||||
0.1487259864807129
|
||||
]
|
||||
}
|
||||
},
|
||||
"Component_[8012379125499217348]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 8012379125499217348
|
||||
},
|
||||
"Component_[8122568562140740597]": {
|
||||
"$type": "GenericComponentWrapper",
|
||||
"Id": 8122568562140740597,
|
||||
"m_template": {
|
||||
"$type": "Multiplayer::NetworkTransformComponent"
|
||||
}
|
||||
},
|
||||
"Component_[8805228647591404845]": {
|
||||
"$type": "GenericComponentWrapper",
|
||||
"Id": 8805228647591404845,
|
||||
"m_template": {
|
||||
"$type": "NetBindComponent"
|
||||
}
|
||||
},
|
||||
"Component_[9816897251206708579]": {
|
||||
"$type": "GenericComponentWrapper",
|
||||
"Id": 9816897251206708579,
|
||||
"m_template": {
|
||||
"$type": "AutomatedTesting::NetworkTestPlayerComponent"
|
||||
}
|
||||
},
|
||||
"Component_[9880860858035405475]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 9880860858035405475
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5019
File diff suppressed because it is too large
Load Diff
+1946
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,662 @@
|
||||
{
|
||||
"Type": "JsonSerialization",
|
||||
"Version": 1,
|
||||
"ClassName": "ScriptCanvasData",
|
||||
"ClassData": {
|
||||
"m_scriptCanvas": {
|
||||
"Id": {
|
||||
"id": 17732469402520
|
||||
},
|
||||
"Name": "Untitled-1",
|
||||
"Components": {
|
||||
"Component_[16492301523567686923]": {
|
||||
"$type": "{4D755CA9-AB92-462C-B24F-0B3376F19967} Graph",
|
||||
"Id": 16492301523567686923,
|
||||
"m_graphData": {
|
||||
"m_nodes": [
|
||||
{
|
||||
"Id": {
|
||||
"id": 17741059337112
|
||||
},
|
||||
"Name": "SC-Node(OperatorAdd)",
|
||||
"Components": {
|
||||
"Component_[11612963594766700030]": {
|
||||
"$type": "OperatorAdd",
|
||||
"Id": 11612963594766700030,
|
||||
"Slots": [
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{B7529112-C29F-45F0-811C-DB8EE18EB8B8}"
|
||||
},
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
}
|
||||
],
|
||||
"slotName": "In",
|
||||
"Descriptor": {
|
||||
"ConnectionType": 1,
|
||||
"SlotType": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{49618851-F6B2-4B90-BFDF-ADBAAA84BBA4}"
|
||||
},
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
}
|
||||
],
|
||||
"slotName": "Out",
|
||||
"Descriptor": {
|
||||
"ConnectionType": 2,
|
||||
"SlotType": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{4612C904-82DF-4B48-8485-4C878AF9A4D1}"
|
||||
},
|
||||
"DynamicTypeOverride": 3,
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
},
|
||||
{
|
||||
"$type": "MathOperatorContract",
|
||||
"NativeTypes": [
|
||||
{
|
||||
"m_type": 3
|
||||
},
|
||||
{
|
||||
"m_type": 6
|
||||
},
|
||||
{
|
||||
"m_type": 8
|
||||
},
|
||||
{
|
||||
"m_type": 9
|
||||
},
|
||||
{
|
||||
"m_type": 10
|
||||
},
|
||||
{
|
||||
"m_type": 11
|
||||
},
|
||||
{
|
||||
"m_type": 12
|
||||
},
|
||||
{
|
||||
"m_type": 14
|
||||
},
|
||||
{
|
||||
"m_type": 15
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"slotName": "Number",
|
||||
"toolTip": "An operand to use in performing the specified Operation",
|
||||
"DisplayDataType": {
|
||||
"m_type": 3
|
||||
},
|
||||
"DisplayGroup": {
|
||||
"Value": 1114760223
|
||||
},
|
||||
"Descriptor": {
|
||||
"ConnectionType": 1,
|
||||
"SlotType": 2
|
||||
},
|
||||
"DynamicGroup": {
|
||||
"Value": 1114760223
|
||||
},
|
||||
"DataType": 1,
|
||||
"IsReference": true,
|
||||
"VariableReference": {
|
||||
"m_id": "{8451E795-6A0E-44CE-81FD-AEF0EE5B0400}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{610B3BFB-9043-47A0-9694-5F14A1947E36}"
|
||||
},
|
||||
"DynamicTypeOverride": 3,
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
},
|
||||
{
|
||||
"$type": "MathOperatorContract",
|
||||
"NativeTypes": [
|
||||
{
|
||||
"m_type": 3
|
||||
},
|
||||
{
|
||||
"m_type": 6
|
||||
},
|
||||
{
|
||||
"m_type": 8
|
||||
},
|
||||
{
|
||||
"m_type": 9
|
||||
},
|
||||
{
|
||||
"m_type": 10
|
||||
},
|
||||
{
|
||||
"m_type": 11
|
||||
},
|
||||
{
|
||||
"m_type": 12
|
||||
},
|
||||
{
|
||||
"m_type": 14
|
||||
},
|
||||
{
|
||||
"m_type": 15
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"slotName": "Number",
|
||||
"toolTip": "An operand to use in performing the specified Operation",
|
||||
"DisplayDataType": {
|
||||
"m_type": 3
|
||||
},
|
||||
"DisplayGroup": {
|
||||
"Value": 1114760223
|
||||
},
|
||||
"Descriptor": {
|
||||
"ConnectionType": 1,
|
||||
"SlotType": 2
|
||||
},
|
||||
"DynamicGroup": {
|
||||
"Value": 1114760223
|
||||
},
|
||||
"DataType": 1
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{36FFF1AB-C208-47CB-8271-436C85E0AE42}"
|
||||
},
|
||||
"DynamicTypeOverride": 3,
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
},
|
||||
{
|
||||
"$type": "MathOperatorContract",
|
||||
"NativeTypes": [
|
||||
{
|
||||
"m_type": 3
|
||||
},
|
||||
{
|
||||
"m_type": 6
|
||||
},
|
||||
{
|
||||
"m_type": 8
|
||||
},
|
||||
{
|
||||
"m_type": 9
|
||||
},
|
||||
{
|
||||
"m_type": 10
|
||||
},
|
||||
{
|
||||
"m_type": 11
|
||||
},
|
||||
{
|
||||
"m_type": 12
|
||||
},
|
||||
{
|
||||
"m_type": 14
|
||||
},
|
||||
{
|
||||
"m_type": 15
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"slotName": "Result",
|
||||
"toolTip": "The result of the specified operation",
|
||||
"DisplayDataType": {
|
||||
"m_type": 3
|
||||
},
|
||||
"DisplayGroup": {
|
||||
"Value": 1114760223
|
||||
},
|
||||
"Descriptor": {
|
||||
"ConnectionType": 2,
|
||||
"SlotType": 2
|
||||
},
|
||||
"DynamicGroup": {
|
||||
"Value": 1114760223
|
||||
},
|
||||
"DataType": 1,
|
||||
"IsReference": true,
|
||||
"VariableReference": {
|
||||
"m_id": "{8451E795-6A0E-44CE-81FD-AEF0EE5B0400}"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Datums": [
|
||||
{
|
||||
"isOverloadedStorage": false,
|
||||
"scriptCanvasType": {
|
||||
"m_type": 3
|
||||
},
|
||||
"isNullPointer": false,
|
||||
"$type": "double",
|
||||
"value": 0.0,
|
||||
"label": "Number"
|
||||
},
|
||||
{
|
||||
"isOverloadedStorage": false,
|
||||
"scriptCanvasType": {
|
||||
"m_type": 3
|
||||
},
|
||||
"isNullPointer": false,
|
||||
"$type": "double",
|
||||
"value": 1.0,
|
||||
"label": "Number"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Id": {
|
||||
"id": 17736764369816
|
||||
},
|
||||
"Name": "ReceiveScriptEvent",
|
||||
"Components": {
|
||||
"Component_[16408183651077237195]": {
|
||||
"$type": "ReceiveScriptEvent",
|
||||
"Id": 16408183651077237195,
|
||||
"Slots": [
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{8DC10581-B8DF-473C-9C75-996111DBF560}"
|
||||
},
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
}
|
||||
],
|
||||
"slotName": "Connect",
|
||||
"toolTip": "Connect this event handler to the specified entity.",
|
||||
"Descriptor": {
|
||||
"ConnectionType": 1,
|
||||
"SlotType": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{E60D1951-E56D-41F8-84C5-AD0BA803DD51}"
|
||||
},
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
}
|
||||
],
|
||||
"slotName": "Disconnect",
|
||||
"toolTip": "Disconnect this event handler.",
|
||||
"Descriptor": {
|
||||
"ConnectionType": 1,
|
||||
"SlotType": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{1BCE6CAC-B1C0-43FA-B4F5-E9A34D5064E5}"
|
||||
},
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
}
|
||||
],
|
||||
"slotName": "OnConnected",
|
||||
"toolTip": "Signaled when a connection has taken place.",
|
||||
"Descriptor": {
|
||||
"ConnectionType": 2,
|
||||
"SlotType": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{FEB42E9A-D562-4BBD-90AB-32255124BFE8}"
|
||||
},
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
}
|
||||
],
|
||||
"slotName": "OnDisconnected",
|
||||
"toolTip": "Signaled when this event handler is disconnected.",
|
||||
"Descriptor": {
|
||||
"ConnectionType": 2,
|
||||
"SlotType": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{C9EF936B-8C74-42B4-8793-67FC7FD3BCBC}"
|
||||
},
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
}
|
||||
],
|
||||
"slotName": "OnFailure",
|
||||
"toolTip": "Signaled when it is not possible to connect this handler.",
|
||||
"Descriptor": {
|
||||
"ConnectionType": 2,
|
||||
"SlotType": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{76985C7A-761A-4CEF-9F55-6DD2B136317A}"
|
||||
},
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
}
|
||||
],
|
||||
"slotName": "ExecutionSlot:NewPlayerScriptActive",
|
||||
"Descriptor": {
|
||||
"ConnectionType": 2,
|
||||
"SlotType": 1
|
||||
},
|
||||
"IsLatent": true
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{5CD8E1E9-6192-4B7D-9C2C-6C18BE99CF44}"
|
||||
},
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
}
|
||||
],
|
||||
"slotName": "Number",
|
||||
"Descriptor": {
|
||||
"ConnectionType": 1,
|
||||
"SlotType": 2
|
||||
},
|
||||
"DataType": 1,
|
||||
"IsReference": true,
|
||||
"VariableReference": {
|
||||
"m_id": "{8451E795-6A0E-44CE-81FD-AEF0EE5B0400}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": {
|
||||
"m_id": "{9FDB71AA-0F19-406D-82CA-508A2CA10F95}"
|
||||
},
|
||||
"contracts": [
|
||||
{
|
||||
"$type": "SlotTypeContract"
|
||||
}
|
||||
],
|
||||
"slotName": "ExecutionSlot:GetNumberOfActivePlayers",
|
||||
"Descriptor": {
|
||||
"ConnectionType": 2,
|
||||
"SlotType": 1
|
||||
},
|
||||
"IsLatent": true
|
||||
}
|
||||
],
|
||||
"Datums": [
|
||||
{
|
||||
"isOverloadedStorage": false,
|
||||
"scriptCanvasType": {
|
||||
"m_type": 3
|
||||
},
|
||||
"isNullPointer": false,
|
||||
"$type": "double",
|
||||
"value": 0.0,
|
||||
"label": "Number"
|
||||
}
|
||||
],
|
||||
"m_version": 1,
|
||||
"m_eventMap": [
|
||||
{
|
||||
"Key": {
|
||||
"Value": 242067946
|
||||
},
|
||||
"Value": {
|
||||
"m_scriptEventAssetId": {
|
||||
"guid": "{FE1B1992-8220-5DD3-A60A-AEC85EB91C54}"
|
||||
},
|
||||
"m_eventName": "GetNumberOfActivePlayers",
|
||||
"m_eventSlotId": {
|
||||
"m_id": "{9FDB71AA-0F19-406D-82CA-508A2CA10F95}"
|
||||
},
|
||||
"m_resultSlotId": {
|
||||
"m_id": "{5CD8E1E9-6192-4B7D-9C2C-6C18BE99CF44}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Key": {
|
||||
"Value": 2930121176
|
||||
},
|
||||
"Value": {
|
||||
"m_scriptEventAssetId": {
|
||||
"guid": "{FE1B1992-8220-5DD3-A60A-AEC85EB91C54}"
|
||||
},
|
||||
"m_eventName": "NewPlayerScriptActive",
|
||||
"m_eventSlotId": {
|
||||
"m_id": "{76985C7A-761A-4CEF-9F55-6DD2B136317A}"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"m_eventSlotMapping": {
|
||||
"{155BF981-AD70-4D29-81A6-1517FAE59FB1}": {
|
||||
"m_id": "{5CD8E1E9-6192-4B7D-9C2C-6C18BE99CF44}"
|
||||
},
|
||||
"{65D394D3-F90D-4F10-94BF-F5E1581CF2CF}": {
|
||||
"m_id": "{76985C7A-761A-4CEF-9F55-6DD2B136317A}"
|
||||
},
|
||||
"{67784749-9B41-429C-9C97-3D296182EB67}": {
|
||||
"m_id": "{9FDB71AA-0F19-406D-82CA-508A2CA10F95}"
|
||||
}
|
||||
},
|
||||
"m_scriptEventAssetId": {
|
||||
"guid": "{FE1B1992-8220-5DD3-A60A-AEC85EB91C54}"
|
||||
},
|
||||
"m_asset": {
|
||||
"assetId": {
|
||||
"guid": "{FE1B1992-8220-5DD3-A60A-AEC85EB91C54}"
|
||||
},
|
||||
"assetHint": "levels/multiplayer/autocomponent_rpc/globalgamedata.scriptevents"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"m_connections": [
|
||||
{
|
||||
"Id": {
|
||||
"id": 17745354304408
|
||||
},
|
||||
"Name": "srcEndpoint=(Receive Script Event: ExecutionSlot:NewPlayerScriptActive), destEndpoint=(Add (+): In)",
|
||||
"Components": {
|
||||
"Component_[8782209668839578826]": {
|
||||
"$type": "{64CA5016-E803-4AC4-9A36-BDA2C890C6EB} Connection",
|
||||
"Id": 8782209668839578826,
|
||||
"sourceEndpoint": {
|
||||
"nodeId": {
|
||||
"id": 17736764369816
|
||||
},
|
||||
"slotId": {
|
||||
"m_id": "{76985C7A-761A-4CEF-9F55-6DD2B136317A}"
|
||||
}
|
||||
},
|
||||
"targetEndpoint": {
|
||||
"nodeId": {
|
||||
"id": 17741059337112
|
||||
},
|
||||
"slotId": {
|
||||
"m_id": "{B7529112-C29F-45F0-811C-DB8EE18EB8B8}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"m_scriptEventAssets": [
|
||||
[
|
||||
{
|
||||
"id": 17736764369816
|
||||
},
|
||||
{}
|
||||
]
|
||||
]
|
||||
},
|
||||
"m_assetType": "{3E2AC8CD-713F-453E-967F-29517F331784}",
|
||||
"versionData": {
|
||||
"_grammarVersion": 1,
|
||||
"_runtimeVersion": 1,
|
||||
"_fileVersion": 1
|
||||
},
|
||||
"m_variableCounter": 1,
|
||||
"GraphCanvasData": [
|
||||
{
|
||||
"Key": {
|
||||
"id": 17732469402520
|
||||
},
|
||||
"Value": {
|
||||
"ComponentData": {
|
||||
"{5F84B500-8C45-40D1-8EFC-A5306B241444}": {
|
||||
"$type": "SceneComponentSaveData"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Key": {
|
||||
"id": 17736764369816
|
||||
},
|
||||
"Value": {
|
||||
"ComponentData": {
|
||||
"{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
|
||||
"$type": "NodeSaveData"
|
||||
},
|
||||
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
|
||||
"$type": "GeometrySaveData",
|
||||
"Position": [
|
||||
-360.0,
|
||||
-60.0
|
||||
]
|
||||
},
|
||||
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
|
||||
"$type": "StylingComponentSaveData"
|
||||
},
|
||||
"{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
|
||||
"$type": "PersistentIdComponentSaveData",
|
||||
"PersistentId": "{C419A1CF-CBA8-416B-BF6C-4B574C3E59E3}"
|
||||
},
|
||||
"{D8BBE799-7E4D-495A-B69A-1E3940670891}": {
|
||||
"$type": "ScriptEventReceiverHandlerNodeDescriptorSaveData",
|
||||
"EventNames": [
|
||||
[
|
||||
{
|
||||
"Value": 242067946
|
||||
},
|
||||
"GetNumberOfActivePlayers"
|
||||
],
|
||||
[
|
||||
{
|
||||
"Value": 2930121176
|
||||
},
|
||||
"NewPlayerScriptActive"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Key": {
|
||||
"id": 17741059337112
|
||||
},
|
||||
"Value": {
|
||||
"ComponentData": {
|
||||
"{24CB38BB-1705-4EC5-8F63-B574571B4DCD}": {
|
||||
"$type": "NodeSaveData"
|
||||
},
|
||||
"{328FF15C-C302-458F-A43D-E1794DE0904E}": {
|
||||
"$type": "GeneralNodeTitleComponentSaveData",
|
||||
"PaletteOverride": "MathNodeTitlePalette"
|
||||
},
|
||||
"{7CC444B1-F9B3-41B5-841B-0C4F2179F111}": {
|
||||
"$type": "GeometrySaveData",
|
||||
"Position": [
|
||||
120.0,
|
||||
100.0
|
||||
]
|
||||
},
|
||||
"{B0B99C8A-03AF-4CF6-A926-F65C874C3D97}": {
|
||||
"$type": "StylingComponentSaveData"
|
||||
},
|
||||
"{B1F49A35-8408-40DA-B79E-F1E3B64322CE}": {
|
||||
"$type": "PersistentIdComponentSaveData",
|
||||
"PersistentId": "{0D0751AD-8164-4196-9C09-8CDB9AAA296F}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"StatisticsHelper": {
|
||||
"InstanceCounter": [
|
||||
{
|
||||
"Key": 1244476766431948410,
|
||||
"Value": 1
|
||||
},
|
||||
{
|
||||
"Key": 1678857390775488101,
|
||||
"Value": 1
|
||||
},
|
||||
{
|
||||
"Key": 1678857392390856307,
|
||||
"Value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"Component_[16498171485036643402]": {
|
||||
"$type": "EditorGraphVariableManagerComponent",
|
||||
"Id": 16498171485036643402,
|
||||
"m_variableData": {
|
||||
"m_nameVariableMap": [
|
||||
{
|
||||
"Key": {
|
||||
"m_id": "{8451E795-6A0E-44CE-81FD-AEF0EE5B0400}"
|
||||
},
|
||||
"Value": {
|
||||
"Datum": {
|
||||
"isOverloadedStorage": false,
|
||||
"scriptCanvasType": {
|
||||
"m_type": 3
|
||||
},
|
||||
"isNullPointer": false,
|
||||
"$type": "double",
|
||||
"value": 0.0
|
||||
},
|
||||
"VariableId": {
|
||||
"m_id": "{8451E795-6A0E-44CE-81FD-AEF0EE5B0400}"
|
||||
},
|
||||
"VariableName": "ActivePlayerCount"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<ObjectStream version="3">
|
||||
<Class name="ScriptEventsAsset" version="1" type="{CB4D603E-8CB0-4D80-8165-4244F28AF187}">
|
||||
<Class name="ScriptEvent" field="m_definition" version="1" type="{10A08CD3-32C9-4E18-8039-4B8A8157918E}">
|
||||
<Class name="unsigned int" field="m_version" value="1" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="VersionedProperty" field="m_name" version="4" type="{828CA9C0-32F1-40B3-8018-EE7C3C38192A}">
|
||||
<Class name="AZ::Uuid" field="m_id" value="{6C6C69BC-EACC-450D-86FB-4CFCEED68F59}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::string" field="m_label" value="Name" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="unsigned int" field="m_version" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="AZStd::vector" field="m_versions" type="{326CAAFE-9101-56E2-B869-D770629A6B19}"/>
|
||||
<Class name="any" field="m_data" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}">
|
||||
<Class name="AZStd::string" field="m_data" value="GlobalGameData" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="VersionedProperty" field="m_category" version="4" type="{828CA9C0-32F1-40B3-8018-EE7C3C38192A}">
|
||||
<Class name="AZ::Uuid" field="m_id" value="{2DF5A7AC-201B-4538-9903-8573C90CA595}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::string" field="m_label" value="Category" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="unsigned int" field="m_version" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="AZStd::vector" field="m_versions" type="{326CAAFE-9101-56E2-B869-D770629A6B19}"/>
|
||||
<Class name="any" field="m_data" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}">
|
||||
<Class name="AZStd::string" field="m_data" value="Script Events" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="VersionedProperty" field="m_tooltip" version="4" type="{828CA9C0-32F1-40B3-8018-EE7C3C38192A}">
|
||||
<Class name="AZ::Uuid" field="m_id" value="{E2175455-06AB-402A-B4B5-C33D7CB6EAF9}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::string" field="m_label" value="Tooltip" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="unsigned int" field="m_version" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="AZStd::vector" field="m_versions" type="{326CAAFE-9101-56E2-B869-D770629A6B19}"/>
|
||||
<Class name="any" field="m_data" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}">
|
||||
<Class name="AZStd::string" field="m_data" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="VersionedProperty" field="m_addressType" version="4" type="{828CA9C0-32F1-40B3-8018-EE7C3C38192A}">
|
||||
<Class name="AZ::Uuid" field="m_id" value="{1B2DA4A8-A367-4A58-A8CA-8BB6F1F56E66}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::string" field="m_label" value="Address Type" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="unsigned int" field="m_version" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="AZStd::vector" field="m_versions" type="{326CAAFE-9101-56E2-B869-D770629A6B19}"/>
|
||||
<Class name="any" field="m_data" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}">
|
||||
<Class name="AZ::Uuid" field="m_data" value="{C0F1AFAD-5CB3-450E-B0F5-ADB5D46B0E22}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="AZStd::vector" field="m_methods" type="{D9866B79-D11A-58E6-B974-0B45783F53A4}">
|
||||
<Class name="Method" field="element" type="{E034EA83-C798-413D-ACE8-4923C51CF4F7}">
|
||||
<Class name="VersionedProperty" field="m_name" version="4" type="{828CA9C0-32F1-40B3-8018-EE7C3C38192A}">
|
||||
<Class name="AZ::Uuid" field="m_id" value="{65D394D3-F90D-4F10-94BF-F5E1581CF2CF}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::string" field="m_label" value="Name" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="unsigned int" field="m_version" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="AZStd::vector" field="m_versions" type="{326CAAFE-9101-56E2-B869-D770629A6B19}"/>
|
||||
<Class name="any" field="m_data" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}">
|
||||
<Class name="AZStd::string" field="m_data" value="NewPlayerScriptActive" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="VersionedProperty" field="m_tooltip" version="4" type="{828CA9C0-32F1-40B3-8018-EE7C3C38192A}">
|
||||
<Class name="AZ::Uuid" field="m_id" value="{372785C7-51F9-4F51-989B-2C851F4D000E}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::string" field="m_label" value="Tooltip" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="unsigned int" field="m_version" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="AZStd::vector" field="m_versions" type="{326CAAFE-9101-56E2-B869-D770629A6B19}"/>
|
||||
<Class name="any" field="m_data" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}">
|
||||
<Class name="AZStd::string" field="m_data" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="VersionedProperty" field="m_returnType" version="4" type="{828CA9C0-32F1-40B3-8018-EE7C3C38192A}">
|
||||
<Class name="AZ::Uuid" field="m_id" value="{359740D1-3764-4267-8BEE-1D734C7D81FB}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::string" field="m_label" value="Return Type" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="unsigned int" field="m_version" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="AZStd::vector" field="m_versions" type="{326CAAFE-9101-56E2-B869-D770629A6B19}"/>
|
||||
<Class name="any" field="m_data" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}">
|
||||
<Class name="AZ::Uuid" field="m_data" value="{C0F1AFAD-5CB3-450E-B0F5-ADB5D46B0E22}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="AZStd::vector" field="m_parameters" type="{6ED13EA7-791B-57A8-A4F1-560B5F35B472}"/>
|
||||
</Class>
|
||||
<Class name="Method" field="element" type="{E034EA83-C798-413D-ACE8-4923C51CF4F7}">
|
||||
<Class name="VersionedProperty" field="m_name" version="4" type="{828CA9C0-32F1-40B3-8018-EE7C3C38192A}">
|
||||
<Class name="AZ::Uuid" field="m_id" value="{67784749-9B41-429C-9C97-3D296182EB67}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::string" field="m_label" value="Name" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="unsigned int" field="m_version" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="AZStd::vector" field="m_versions" type="{326CAAFE-9101-56E2-B869-D770629A6B19}"/>
|
||||
<Class name="any" field="m_data" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}">
|
||||
<Class name="AZStd::string" field="m_data" value="GetNumberOfActivePlayers" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="VersionedProperty" field="m_tooltip" version="4" type="{828CA9C0-32F1-40B3-8018-EE7C3C38192A}">
|
||||
<Class name="AZ::Uuid" field="m_id" value="{92E33EC2-4B10-42A7-A568-2E1392E85D9F}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::string" field="m_label" value="Tooltip" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="unsigned int" field="m_version" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="AZStd::vector" field="m_versions" type="{326CAAFE-9101-56E2-B869-D770629A6B19}"/>
|
||||
<Class name="any" field="m_data" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}">
|
||||
<Class name="AZStd::string" field="m_data" value="" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="VersionedProperty" field="m_returnType" version="4" type="{828CA9C0-32F1-40B3-8018-EE7C3C38192A}">
|
||||
<Class name="AZ::Uuid" field="m_id" value="{155BF981-AD70-4D29-81A6-1517FAE59FB1}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
<Class name="AZStd::string" field="m_label" value="Number" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
|
||||
<Class name="unsigned int" field="m_version" value="0" type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
|
||||
<Class name="AZStd::vector" field="m_versions" type="{326CAAFE-9101-56E2-B869-D770629A6B19}"/>
|
||||
<Class name="any" field="m_data" type="{03924488-C7F4-4D6D-948B-ABC2D1AE2FD3}">
|
||||
<Class name="AZ::Uuid" field="m_data" value="{110C4B14-11A8-4E9D-8638-5051013A56AC}" type="{E152C105-A133-4D03-BBF8-3D4B2FBA3E2A}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
<Class name="AZStd::vector" field="m_parameters" type="{6ED13EA7-791B-57A8-A4F1-560B5F35B472}"/>
|
||||
</Class>
|
||||
</Class>
|
||||
</Class>
|
||||
</Class>
|
||||
</ObjectStream>
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
{
|
||||
"ContainerEntity": {
|
||||
"Id": "ContainerEntity",
|
||||
"Name": "Player",
|
||||
"Components": {
|
||||
"Component_[10603663676997462041]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 10603663676997462041
|
||||
},
|
||||
"Component_[11066377844757909329]": {
|
||||
"$type": "EditorPrefabComponent",
|
||||
"Id": 11066377844757909329
|
||||
},
|
||||
"Component_[11664640320098005944]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 11664640320098005944
|
||||
},
|
||||
"Component_[12551690377468870725]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 12551690377468870725,
|
||||
"Parent Entity": ""
|
||||
},
|
||||
"Component_[16402163080075698011]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 16402163080075698011
|
||||
},
|
||||
"Component_[3491366785918494447]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 3491366785918494447
|
||||
},
|
||||
"Component_[4830373679514129871]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 4830373679514129871
|
||||
},
|
||||
"Component_[5144323498211834874]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 5144323498211834874
|
||||
},
|
||||
"Component_[5267607163086533733]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 5267607163086533733
|
||||
},
|
||||
"Component_[6678300504118618849]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 6678300504118618849
|
||||
},
|
||||
"Component_[8384628950786300469]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 8384628950786300469,
|
||||
"Child Entity Order": [
|
||||
"Entity_[10070247746456]"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Entities": {
|
||||
"Entity_[10070247746456]": {
|
||||
"Id": "Entity_[10070247746456]",
|
||||
"Name": "Player",
|
||||
"Components": {
|
||||
"Component_[1059478843478789313]": {
|
||||
"$type": "EditorInspectorComponent",
|
||||
"Id": 1059478843478789313,
|
||||
"ComponentOrderEntryArray": [
|
||||
{
|
||||
"ComponentId": 9878555871810913249
|
||||
},
|
||||
{
|
||||
"ComponentId": 11481641385923146202,
|
||||
"SortIndex": 1
|
||||
},
|
||||
{
|
||||
"ComponentId": 11440172471478606933,
|
||||
"SortIndex": 2
|
||||
},
|
||||
{
|
||||
"ComponentId": 17461691807054668218,
|
||||
"SortIndex": 3
|
||||
},
|
||||
{
|
||||
"ComponentId": 15530420875454157766,
|
||||
"SortIndex": 4
|
||||
},
|
||||
{
|
||||
"ComponentId": 10596595655489113153,
|
||||
"SortIndex": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
"Component_[10596595655489113153]": {
|
||||
"$type": "EditorScriptCanvasComponent",
|
||||
"Id": 10596595655489113153,
|
||||
"m_name": "AutoComponent_RPC",
|
||||
"m_assetHolder": {
|
||||
"m_asset": {
|
||||
"assetId": {
|
||||
"guid": "{5ED120C4-07DC-56F1-80A7-37BFC98FD74E}"
|
||||
},
|
||||
"assetHint": "levels/multiplayer/autocomponent_rpc/autocomponent_rpc.scriptcanvas"
|
||||
}
|
||||
},
|
||||
"runtimeDataIsValid": true,
|
||||
"runtimeDataOverrides": {
|
||||
"source": {
|
||||
"assetId": {
|
||||
"guid": "{5ED120C4-07DC-56F1-80A7-37BFC98FD74E}"
|
||||
},
|
||||
"assetHint": "levels/multiplayer/autocomponent_rpc/autocomponent_rpc.scriptcanvas"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[11440172471478606933]": {
|
||||
"$type": "GenericComponentWrapper",
|
||||
"Id": 11440172471478606933,
|
||||
"m_template": {
|
||||
"$type": "Multiplayer::NetworkTransformComponent"
|
||||
}
|
||||
},
|
||||
"Component_[11481641385923146202]": {
|
||||
"$type": "GenericComponentWrapper",
|
||||
"Id": 11481641385923146202,
|
||||
"m_template": {
|
||||
"$type": "NetBindComponent"
|
||||
}
|
||||
},
|
||||
"Component_[13110996849704981748]": {
|
||||
"$type": "EditorVisibilityComponent",
|
||||
"Id": 13110996849704981748
|
||||
},
|
||||
"Component_[1472895075383059499]": {
|
||||
"$type": "EditorLockComponent",
|
||||
"Id": 1472895075383059499
|
||||
},
|
||||
"Component_[1526920553231193509]": {
|
||||
"$type": "EditorPendingCompositionComponent",
|
||||
"Id": 1526920553231193509
|
||||
},
|
||||
"Component_[15530420875454157766]": {
|
||||
"$type": "GenericComponentWrapper",
|
||||
"Id": 15530420875454157766,
|
||||
"m_template": {
|
||||
"$type": "Multiplayer::LocalPredictionPlayerInputComponent"
|
||||
}
|
||||
},
|
||||
"Component_[1699895912837266792]": {
|
||||
"$type": "EditorDisabledCompositionComponent",
|
||||
"Id": 1699895912837266792
|
||||
},
|
||||
"Component_[17461691807054668218]": {
|
||||
"$type": "GenericComponentWrapper",
|
||||
"Id": 17461691807054668218,
|
||||
"m_template": {
|
||||
"$type": "AutomatedTesting::NetworkTestPlayerComponent"
|
||||
}
|
||||
},
|
||||
"Component_[3622545398462507871]": {
|
||||
"$type": "EditorOnlyEntityComponent",
|
||||
"Id": 3622545398462507871
|
||||
},
|
||||
"Component_[5778259918231688598]": {
|
||||
"$type": "AZ::Render::EditorMeshComponent",
|
||||
"Id": 5778259918231688598,
|
||||
"Controller": {
|
||||
"Configuration": {
|
||||
"ModelAsset": {
|
||||
"assetId": {
|
||||
"guid": "{F322592F-43BC-50E7-903C-CC231846093F}",
|
||||
"subId": 276443623
|
||||
},
|
||||
"assetHint": "objects/_primitives/_cylinder_1x1.azmodel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Component_[7004633483882343256]": {
|
||||
"$type": "SelectionComponent",
|
||||
"Id": 7004633483882343256
|
||||
},
|
||||
"Component_[8469628382507693850]": {
|
||||
"$type": "EditorEntitySortComponent",
|
||||
"Id": 8469628382507693850
|
||||
},
|
||||
"Component_[9407892837096707905]": {
|
||||
"$type": "EditorEntityIconComponent",
|
||||
"Id": 9407892837096707905
|
||||
},
|
||||
"Component_[9878555871810913249]": {
|
||||
"$type": "{27F1E1A1-8D9D-4C3B-BD3A-AFB9762449C0} TransformComponent",
|
||||
"Id": 9878555871810913249,
|
||||
"Parent Entity": "ContainerEntity"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
0,0,0,0,0,0
|
||||
@@ -7,7 +7,7 @@
|
||||
"android_settings": {
|
||||
"package_name": "com.lumberyard.yourgame",
|
||||
"version_number": 1,
|
||||
"version_name": "1.0.0.0",
|
||||
"version_name": "1.0.0",
|
||||
"orientation": "landscape"
|
||||
},
|
||||
"engine": "o3de",
|
||||
|
||||
@@ -30,8 +30,6 @@ CAboutDialog::CAboutDialog(QString versionText, QString richTextCopyrightNotice,
|
||||
m_ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
connect(m_ui->m_transparentAgreement, &QLabel::linkActivated, this, &CAboutDialog::OnCustomerAgreement);
|
||||
|
||||
m_ui->m_transparentTrademarks->setText(versionText);
|
||||
|
||||
m_ui->m_transparentAllRightReserved->setObjectName("copyrightNotice");
|
||||
@@ -84,9 +82,4 @@ void CAboutDialog::mouseReleaseEvent(QMouseEvent* event)
|
||||
QDialog::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void CAboutDialog::OnCustomerAgreement()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl(QStringLiteral("https://www.o3debinaries.org/license")));
|
||||
}
|
||||
|
||||
#include <moc_AboutDialog.cpp>
|
||||
|
||||
@@ -30,8 +30,6 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void OnCustomerAgreement();
|
||||
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
|
||||
|
||||
@@ -181,14 +181,17 @@
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ClickableLabel" name="m_transparentAgreement">
|
||||
<widget class="QLabel" name="m_transparentAgreement">
|
||||
<property name="text">
|
||||
<string>Terms of Use</string>
|
||||
<string><a href="https://www.o3debinaries.org/license">Terms of Use</a></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="showDecoration" stdset="0">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
@@ -274,11 +277,6 @@
|
||||
<extends>QWidget</extends>
|
||||
<header>qsvgwidget.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ClickableLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>QtUI/ClickableLabel.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -319,8 +319,8 @@ public:
|
||||
keys.push_back(QPair<QString, QString>("Edit Menu.Duplicate", "Ctrl+D"));
|
||||
keys.push_back(QPair<QString, QString>("Edit Menu.Undo", "Ctrl+Z"));
|
||||
keys.push_back(QPair<QString, QString>("Edit Menu.Redo", "Ctrl+Shift+Z"));
|
||||
keys.push_back(QPair<QString, QString>("Edit Menu.Group", "Ctrl+G"));
|
||||
keys.push_back(QPair<QString, QString>("Edit Menu.Ungroup", "Ctrl+Shift+G"));
|
||||
keys.push_back(QPair<QString, QString>("Edit Menu.Group", "Ctrl+Alt+O"));
|
||||
keys.push_back(QPair<QString, QString>("Edit Menu.Ungroup", "Ctrl+Alt+P"));
|
||||
keys.push_back(QPair<QString, QString>("Edit Menu.Rename", "Ctrl+R"));
|
||||
keys.push_back(QPair<QString, QString>("Edit Menu.Reset", ""));
|
||||
keys.push_back(QPair<QString, QString>("Edit Menu.Edit Hotkeys", ""));
|
||||
|
||||
@@ -1,58 +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 "EditorDefs.h"
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <QtUI/ClickableLabel.h>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
using namespace AZ;
|
||||
using namespace ::testing;
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
class TestingClickableLabel
|
||||
: public ScopedAllocatorSetupFixture
|
||||
{
|
||||
public:
|
||||
ClickableLabel m_clickableLabel;
|
||||
};
|
||||
|
||||
TEST_F(TestingClickableLabel, CursorDoesNotUpdateWhileDisabled)
|
||||
{
|
||||
m_clickableLabel.setEnabled(false);
|
||||
|
||||
QApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
|
||||
QEnterEvent enterEvent{ QPointF(), QPointF(), QPointF() };
|
||||
QApplication::sendEvent(&m_clickableLabel, &enterEvent);
|
||||
|
||||
const Qt::CursorShape cursorShape = QApplication::overrideCursor()->shape();
|
||||
EXPECT_THAT(cursorShape, Ne(Qt::PointingHandCursor));
|
||||
EXPECT_THAT(cursorShape, Eq(Qt::BlankCursor));
|
||||
}
|
||||
|
||||
TEST_F(TestingClickableLabel, DoesNotRespondToDblClickWhileDisabled)
|
||||
{
|
||||
m_clickableLabel.setEnabled(false);
|
||||
|
||||
bool linkActivated = false;
|
||||
QObject::connect(&m_clickableLabel, &QLabel::linkActivated, [&linkActivated]()
|
||||
{
|
||||
linkActivated = true;
|
||||
});
|
||||
|
||||
QMouseEvent mouseEvent {
|
||||
QEvent::MouseButtonDblClick, QPointF(),
|
||||
Qt::LeftButton, Qt::LeftButton, Qt::NoModifier };
|
||||
QApplication::sendEvent(&m_clickableLabel, &mouseEvent);
|
||||
|
||||
EXPECT_THAT(linkActivated, Eq(false));
|
||||
}
|
||||
} // namespace UnitTest
|
||||
@@ -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
|
||||
*
|
||||
*/
|
||||
#include "EditorDefs.h"
|
||||
|
||||
#include "ClickableLabel.h"
|
||||
|
||||
|
||||
ClickableLabel::ClickableLabel(const QString& text, QWidget* parent)
|
||||
: QLabel(parent)
|
||||
, m_text(text)
|
||||
, m_showDecoration(false)
|
||||
{
|
||||
setTextFormat(Qt::RichText);
|
||||
setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
}
|
||||
|
||||
ClickableLabel::ClickableLabel(QWidget* parent)
|
||||
: QLabel(parent)
|
||||
, m_showDecoration(false)
|
||||
{
|
||||
setTextFormat(Qt::RichText);
|
||||
setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
}
|
||||
|
||||
void ClickableLabel::showEvent([[maybe_unused]] QShowEvent* event)
|
||||
{
|
||||
updateFormatting(false);
|
||||
}
|
||||
|
||||
void ClickableLabel::enterEvent(QEvent* ev)
|
||||
{
|
||||
if (!isEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
updateFormatting(true);
|
||||
QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));
|
||||
QLabel::enterEvent(ev);
|
||||
}
|
||||
|
||||
void ClickableLabel::leaveEvent(QEvent* ev)
|
||||
{
|
||||
if (!isEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
updateFormatting(false);
|
||||
QApplication::restoreOverrideCursor();
|
||||
QLabel::leaveEvent(ev);
|
||||
}
|
||||
|
||||
void ClickableLabel::setText(const QString& text)
|
||||
{
|
||||
m_text = text;
|
||||
QLabel::setText(text);
|
||||
updateFormatting(false);
|
||||
}
|
||||
|
||||
void ClickableLabel::setShowDecoration(bool b)
|
||||
{
|
||||
m_showDecoration = b;
|
||||
updateFormatting(false);
|
||||
}
|
||||
|
||||
void ClickableLabel::updateFormatting(bool mouseOver)
|
||||
{
|
||||
//FIXME: this should be done differently. Using a style sheet would be easiest.
|
||||
|
||||
QColor c = palette().color(QPalette::WindowText);
|
||||
if (mouseOver || m_showDecoration)
|
||||
{
|
||||
QLabel::setText(QString(R"(<a href="dummy" style="color: %1";>%2</a>)").arg(c.name(), m_text));
|
||||
}
|
||||
else
|
||||
{
|
||||
QLabel::setText(m_text);
|
||||
}
|
||||
}
|
||||
|
||||
bool ClickableLabel::event(QEvent* e)
|
||||
{
|
||||
if (isEnabled())
|
||||
{
|
||||
if (e->type() == QEvent::MouseButtonDblClick)
|
||||
{
|
||||
emit linkActivated(QString());
|
||||
return true; //ignore
|
||||
}
|
||||
}
|
||||
|
||||
return QLabel::event(e);
|
||||
}
|
||||
|
||||
#include <QtUI/moc_ClickableLabel.cpp>
|
||||
@@ -1,39 +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
|
||||
#ifndef CRYINCLUDE_EDITORCOMMON_CLICKABLELABEL_H
|
||||
#define CRYINCLUDE_EDITORCOMMON_CLICKABLELABEL_H
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QLabel>
|
||||
#endif
|
||||
|
||||
class SANDBOX_API ClickableLabel
|
||||
: public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ClickableLabel(const QString& text, QWidget* parent = nullptr);
|
||||
explicit ClickableLabel(QWidget* parent = nullptr);
|
||||
bool event(QEvent* e) override;
|
||||
|
||||
void setText(const QString& text);
|
||||
void setShowDecoration(bool b);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent* event) override;
|
||||
void enterEvent(QEvent* ev) override;
|
||||
void leaveEvent(QEvent* ev) override;
|
||||
|
||||
private:
|
||||
void updateFormatting(bool mouseOver);
|
||||
QString m_text;
|
||||
bool m_showDecoration;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -526,8 +526,6 @@ set(FILES
|
||||
PythonEditorFuncs.h
|
||||
QtUI/QCollapsibleGroupBox.h
|
||||
QtUI/QCollapsibleGroupBox.cpp
|
||||
QtUI/ClickableLabel.h
|
||||
QtUI/ClickableLabel.cpp
|
||||
QtUI/PixmapLabelPreview.h
|
||||
QtUI/PixmapLabelPreview.cpp
|
||||
QtUI/WaitCursor.h
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
set(FILES
|
||||
Lib/Tests/IEditorMock.h
|
||||
Lib/Tests/test_ClickableLabel.cpp
|
||||
Lib/Tests/test_CryEditPythonBindings.cpp
|
||||
Lib/Tests/test_CryEditDocPythonBindings.cpp
|
||||
Lib/Tests/test_EditorPythonBindings.cpp
|
||||
|
||||
@@ -19,12 +19,14 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE Plane Plane::CreateFromNormalAndPoint(const Vector3& normal, const Vector3& point)
|
||||
{
|
||||
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
|
||||
return Plane(Simd::Vec4::ConstructPlane(normal.GetSimdValue(), point.GetSimdValue()));
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Plane Plane::CreateFromNormalAndDistance(const Vector3& normal, float dist)
|
||||
{
|
||||
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
|
||||
Plane result;
|
||||
result.Set(normal, dist);
|
||||
return result;
|
||||
@@ -33,6 +35,7 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE Plane Plane::CreateFromCoefficients(const float a, const float b, const float c, const float d)
|
||||
{
|
||||
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is notormalized");
|
||||
Plane result;
|
||||
result.Set(a, b, c, d);
|
||||
return result;
|
||||
@@ -65,18 +68,21 @@ namespace AZ
|
||||
|
||||
AZ_MATH_INLINE void Plane::Set(const Vector3& normal, float d)
|
||||
{
|
||||
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is notormalized");
|
||||
m_plane.Set(normal, d);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE void Plane::Set(float a, float b, float c, float d)
|
||||
{
|
||||
AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is notormalized");
|
||||
m_plane.Set(a, b, c, d);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE void Plane::SetNormal(const Vector3& normal)
|
||||
{
|
||||
AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is notormalized");
|
||||
m_plane.SetX(normal.GetX());
|
||||
m_plane.SetY(normal.GetY());
|
||||
m_plane.SetZ(normal.GetZ());
|
||||
|
||||
@@ -54,11 +54,11 @@ namespace AZ
|
||||
//! Sets components using a Vector3 for the imaginary part and a float for the real part.
|
||||
static Quaternion CreateFromVector3AndValue(const Vector3& v, float w);
|
||||
|
||||
//! Sets the quaternion to be a rotation around a specified axis.
|
||||
//! Sets the quaternion to be a rotation around a specified axis in radians.
|
||||
//! @{
|
||||
static Quaternion CreateRotationX(float angle);
|
||||
static Quaternion CreateRotationY(float angle);
|
||||
static Quaternion CreateRotationZ(float angle);
|
||||
static Quaternion CreateRotationX(float angleInRadians);
|
||||
static Quaternion CreateRotationY(float angleInRadians);
|
||||
static Quaternion CreateRotationZ(float angleInRadians);
|
||||
//! @}
|
||||
|
||||
//! Creates a quaternion from a Matrix3x3
|
||||
@@ -168,6 +168,14 @@ namespace AZ
|
||||
float NormalizeWithLengthEstimate();
|
||||
//! @}
|
||||
|
||||
//! Get the shortest equivalent of the rotation.
|
||||
//! In case the w component of the quaternion is negative the rotation is > 180° and taking the longer path.
|
||||
//! The quaternion will be inverted in that case to take the shortest path of rotation.
|
||||
//! @{
|
||||
Quaternion GetShortestEquivalent() const;
|
||||
void ShortestEquivalent();
|
||||
//! @}
|
||||
|
||||
//! Linearly interpolate towards a destination quaternion.
|
||||
//! @param[in] dest The quaternion to interpolate towards.
|
||||
//! @param[in] t Normalized interpolation value where 0.0 represents the current and 1.0 the destination value.
|
||||
|
||||
@@ -73,27 +73,27 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Quaternion Quaternion::CreateRotationX(float angle)
|
||||
AZ_MATH_INLINE Quaternion Quaternion::CreateRotationX(float angleInRadians)
|
||||
{
|
||||
const float halfAngle = 0.5f * angle;
|
||||
const float halfAngle = 0.5f * angleInRadians;
|
||||
float sin, cos;
|
||||
SinCos(halfAngle, sin, cos);
|
||||
return Quaternion(sin, 0.0f, 0.0f, cos);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Quaternion Quaternion::CreateRotationY(float angle)
|
||||
AZ_MATH_INLINE Quaternion Quaternion::CreateRotationY(float angleInRadians)
|
||||
{
|
||||
const float halfAngle = 0.5f * angle;
|
||||
const float halfAngle = 0.5f * angleInRadians;
|
||||
float sin, cos;
|
||||
SinCos(halfAngle, sin, cos);
|
||||
return Quaternion(0.0f, sin, 0.0f, cos);
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Quaternion Quaternion::CreateRotationZ(float angle)
|
||||
AZ_MATH_INLINE Quaternion Quaternion::CreateRotationZ(float angleInRadians)
|
||||
{
|
||||
const float halfAngle = 0.5f * angle;
|
||||
const float halfAngle = 0.5f * angleInRadians;
|
||||
float sin, cos;
|
||||
SinCos(halfAngle, sin, cos);
|
||||
return Quaternion(0.0f, 0.0f, sin, cos);
|
||||
@@ -345,6 +345,23 @@ namespace AZ
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Quaternion Quaternion::GetShortestEquivalent() const
|
||||
{
|
||||
if (GetW() < 0.0f)
|
||||
{
|
||||
return -(*this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE void Quaternion::ShortestEquivalent()
|
||||
{
|
||||
*this = GetShortestEquivalent();
|
||||
}
|
||||
|
||||
|
||||
AZ_MATH_INLINE Quaternion Quaternion::Lerp(const Quaternion& dest, float t) const
|
||||
{
|
||||
if (Dot(dest) >= 0.0f)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/Math/Matrix3x3.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AZTestShared/Math/MathTestHelpers.h>
|
||||
|
||||
using namespace AZ;
|
||||
|
||||
@@ -453,7 +454,7 @@ namespace UnitTest
|
||||
AZ::Quaternion backFromScaledAxisAngle = AZ::Quaternion::CreateFromScaledAxisAngle(scaledAxisAngle);
|
||||
|
||||
// Compare the original quaternion with the one after the conversion.
|
||||
EXPECT_TRUE(testQuat.IsClose(backFromScaledAxisAngle, 1e-6f));
|
||||
EXPECT_THAT(testQuat, IsCloseTolerance(backFromScaledAxisAngle, 1e-6f));
|
||||
}
|
||||
|
||||
TEST_P(QuaternionScaledAxisAngleConversionFixture, AxisAngleQuatRoundtripTests)
|
||||
@@ -467,7 +468,7 @@ namespace UnitTest
|
||||
|
||||
// Convert the axis-angle back into a quaternion and compare the original quaternion with the one after the conversion.
|
||||
const AZ::Quaternion backFromAxisAngle = AZ::Quaternion::CreateFromAxisAngle(axis, angle);
|
||||
EXPECT_TRUE(testQuat.IsClose(backFromAxisAngle, 1e-6f));
|
||||
EXPECT_THAT(testQuat, IsCloseTolerance(backFromAxisAngle, 1e-6f));
|
||||
}
|
||||
|
||||
TEST_P(QuaternionScaledAxisAngleConversionFixture, CompareAxisAngleConversionTests)
|
||||
@@ -506,8 +507,20 @@ namespace UnitTest
|
||||
}
|
||||
|
||||
const AZ::Quaternion backFromAxisAngle = AZ::Quaternion::CreateFromAxisAngle(axisFromScaledResult, angleFromScaledResult);
|
||||
EXPECT_TRUE(testQuat.IsClose(backFromAxisAngle, 1e-6f));
|
||||
EXPECT_THAT(testQuat, IsCloseTolerance(backFromAxisAngle, 1e-6f));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MATH_Quaternion, QuaternionScaledAxisAngleConversionFixture, ::testing::ValuesIn(RotationRepresentationConversionTestQuats));
|
||||
|
||||
TEST(MATH_Quaternion, ShortestEquivalent)
|
||||
{
|
||||
const AZ::Quaternion testQuat = AZ::Quaternion::CreateRotationX(AZ::Constants::HalfPi * 3.0f);
|
||||
|
||||
AZ::Quaternion absQuat = testQuat;
|
||||
absQuat.ShortestEquivalent();
|
||||
EXPECT_THAT(testQuat.GetShortestEquivalent(), IsCloseTolerance(absQuat, 1e-6f));
|
||||
|
||||
const float angle = absQuat.GetEulerRadians().GetX();
|
||||
EXPECT_THAT(angle, testing::FloatEq(-AZ::Constants::HalfPi));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ get_property(asset_builders GLOBAL PROPERTY LY_ASSET_BUILDERS)
|
||||
string (REPLACE ";" "," asset_builders "${asset_builders}")
|
||||
ly_add_source_properties(
|
||||
SOURCES native/utilities/ApplicationManager.cpp
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
VALUES LY_ASSET_BUILDERS="${asset_builders}"
|
||||
)
|
||||
|
||||
@@ -147,9 +147,9 @@ endif()
|
||||
# Tests
|
||||
################################################################################
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
|
||||
|
||||
ly_add_target(
|
||||
NAME AssetProcessor.Tests EXECUTABLE
|
||||
NAME AssetProcessor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||
NAMESPACE AZ
|
||||
AUTOMOC
|
||||
AUTORCC
|
||||
@@ -167,12 +167,12 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
)
|
||||
ly_add_source_properties(
|
||||
SOURCES native/tests/assetBuilderSDK/assetBuilderSDKTest.cpp
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
VALUES ${LY_PAL_TOOLS_DEFINES}
|
||||
)
|
||||
ly_add_source_properties(
|
||||
SOURCES native/unittests/AssetProcessorManagerUnitTests.cpp
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
PROPERTY COMPILE_DEFINITIONS
|
||||
VALUES LY_CMAKE_BINARY_DIR="${CMAKE_BINARY_DIR}"
|
||||
)
|
||||
|
||||
@@ -266,7 +266,10 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
|
||||
ly_add_googletest(
|
||||
NAME AZ::AssetProcessor.Tests
|
||||
TEST_COMMAND $<TARGET_FILE:AZ::AssetProcessor.Tests> --unittest --gtest_filter=-*.SUITE_sandbox*
|
||||
)
|
||||
ly_add_googlebenchmark(
|
||||
NAME AZ::AssetProcessor.Benchmarks
|
||||
TARGET AZ::AssetProcessor.Tests
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
@@ -63,13 +63,6 @@ set(FILES
|
||||
native/resourcecompiler/RCJobSortFilterProxyModel.h
|
||||
native/resourcecompiler/RCQueueSortModel.cpp
|
||||
native/resourcecompiler/RCQueueSortModel.h
|
||||
native/shadercompiler/shadercompilerjob.cpp
|
||||
native/shadercompiler/shadercompilerjob.h
|
||||
native/shadercompiler/shadercompilerManager.cpp
|
||||
native/shadercompiler/shadercompilerManager.h
|
||||
native/shadercompiler/shadercompilerMessages.h
|
||||
native/shadercompiler/shadercompilerModel.cpp
|
||||
native/shadercompiler/shadercompilerModel.h
|
||||
native/utilities/ApplicationManagerAPI.h
|
||||
native/utilities/ApplicationManager.cpp
|
||||
native/utilities/ApplicationManager.h
|
||||
|
||||
@@ -67,8 +67,6 @@ set(FILES
|
||||
native/unittests/PlatformConfigurationUnitTests.h
|
||||
native/unittests/RCcontrollerUnitTests.cpp
|
||||
native/unittests/RCcontrollerUnitTests.h
|
||||
native/unittests/ShaderCompilerUnitTests.cpp
|
||||
native/unittests/ShaderCompilerUnitTests.h
|
||||
native/unittests/UnitTestRunner.cpp
|
||||
native/unittests/UnitTestRunner.h
|
||||
native/unittests/UtilitiesUnitTests.cpp
|
||||
|
||||
@@ -1,162 +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 "shadercompilerManager.h"
|
||||
#include "shadercompilerjob.h"
|
||||
|
||||
#include <QThreadPool>
|
||||
|
||||
#include "native/utilities/assetUtils.h"
|
||||
|
||||
ShaderCompilerManager::ShaderCompilerManager(QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_isUnitTesting(false)
|
||||
, m_numberOfJobsStarted(0)
|
||||
, m_numberOfJobsEnded(0)
|
||||
, m_numberOfErrors(0)
|
||||
{
|
||||
}
|
||||
|
||||
ShaderCompilerManager::~ShaderCompilerManager()
|
||||
{
|
||||
}
|
||||
|
||||
void ShaderCompilerManager::process(unsigned int connID, unsigned int type, unsigned int serial, QByteArray payload)
|
||||
{
|
||||
(void)type;
|
||||
(void)serial;
|
||||
Q_ASSERT(AssetUtilities::ComputeCRC32Lowercase("ShaderCompilerProxyRequest") == type);
|
||||
decodeShaderCompilerRequest(connID, payload);
|
||||
}
|
||||
|
||||
void ShaderCompilerManager::decodeShaderCompilerRequest(unsigned int connID, QByteArray payload)
|
||||
{
|
||||
if (payload.length() < sizeof(unsigned int) + sizeof(unsigned int) + 2 + sizeof(unsigned short))
|
||||
{
|
||||
QString error = "Payload size is too small";
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, error.toUtf8().data());
|
||||
emit sendErrorMessage(error);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char* data_end = reinterpret_cast<unsigned char*>(payload.data() + payload.size());
|
||||
unsigned int* requestId = reinterpret_cast<unsigned int*>(data_end - sizeof(unsigned int));
|
||||
unsigned int* serverListSizePtr = reinterpret_cast<unsigned int*>(data_end - sizeof(unsigned int) - sizeof(unsigned int));
|
||||
unsigned short* serverPortPtr = reinterpret_cast<unsigned short*>(data_end - sizeof(unsigned int) - sizeof(unsigned int) - sizeof(unsigned short));
|
||||
|
||||
ShaderCompilerRequestMessage msg;
|
||||
QString error;
|
||||
|
||||
msg.requestId = *requestId;
|
||||
msg.serverListSize = *serverListSizePtr;
|
||||
msg.serverPort = *serverPortPtr;
|
||||
if ((msg.serverListSize <= 0) || (msg.serverListSize > 100000))
|
||||
{
|
||||
error = "Shader Compiler Server List is wrong";
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, error.toUtf8().data());
|
||||
emit sendErrorMessage(error);
|
||||
return;
|
||||
}
|
||||
if (msg.serverPort == 0)
|
||||
{
|
||||
error = "Shader Compiler port is wrong";
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, error.toUtf8().data());
|
||||
emit sendErrorMessage(error);
|
||||
return;
|
||||
}
|
||||
|
||||
char* position_of_first_null = reinterpret_cast<char*>(serverPortPtr) - 1;// -1 for null
|
||||
if ((*position_of_first_null) != '\0')
|
||||
{
|
||||
error = "Shader Compiler payload is corrupt,position is not null";
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, error.toUtf8().data());
|
||||
emit sendErrorMessage(error);
|
||||
return;
|
||||
}
|
||||
char* beginning_of_serverList = position_of_first_null - msg.serverListSize;
|
||||
char* position_of_second_null = beginning_of_serverList - 1;//-1 for null
|
||||
|
||||
if ((*position_of_second_null) != '\0')
|
||||
{
|
||||
error = "Shader Compiler payload is corrupt,position is not null";
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, error.toUtf8().data());
|
||||
emit sendErrorMessage(error);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int originalPayloadSize = static_cast<unsigned int>(payload.size()) - sizeof(unsigned int) - sizeof(unsigned int) - sizeof(unsigned short) - static_cast<unsigned int>(msg.serverListSize) - 2;
|
||||
msg.serverList = beginning_of_serverList;
|
||||
msg.originalPayload.insert(0, payload.data(), static_cast<unsigned int>(originalPayloadSize));
|
||||
ShaderCompilerJob* shaderCompilerJob = new ShaderCompilerJob();
|
||||
shaderCompilerJob->initialize(this, msg);
|
||||
shaderCompilerJob->setIsUnitTesting(m_isUnitTesting);
|
||||
m_shaderCompilerJobMap[msg.requestId] = connID;
|
||||
shaderCompilerJob->setAutoDelete(true);
|
||||
QThreadPool* threadPool = QThreadPool::globalInstance();
|
||||
threadPool->start(shaderCompilerJob);
|
||||
}
|
||||
|
||||
void ShaderCompilerManager::OnShaderCompilerJobComplete(QByteArray payload, unsigned int requestId)
|
||||
{
|
||||
auto iterator = m_shaderCompilerJobMap.find(requestId);
|
||||
if (iterator != m_shaderCompilerJobMap.end())
|
||||
{
|
||||
sendResponse(iterator.value(), AssetUtilities::ComputeCRC32Lowercase("ShaderCompilerProxyResponse"), 0, payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
QString error = "Shader Compiler cannot find the connection id";
|
||||
AZ_Warning(AssetProcessor::ConsoleChannel, false, error.toUtf8().data());
|
||||
emit sendErrorMessage(error);
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderCompilerManager::sendResponse(unsigned int connId, unsigned int /*type*/, unsigned int /*serial*/, QByteArray payload)
|
||||
{
|
||||
EBUS_EVENT_ID(connId, AssetProcessor::ConnectionBus, SendRaw, AssetUtilities::ComputeCRC32Lowercase("ShaderCompilerProxyResponse"), 0, payload);
|
||||
}
|
||||
|
||||
void ShaderCompilerManager::shaderCompilerError(QString errorMessage, QString server, QString timestamp, QString payload)
|
||||
{
|
||||
m_numberOfErrors++;
|
||||
emit numberOfErrorsChanged();
|
||||
emit sendErrorMessageFromShaderJob(errorMessage, server, timestamp, payload);
|
||||
}
|
||||
|
||||
void ShaderCompilerManager::jobStarted()
|
||||
{
|
||||
m_numberOfJobsStarted++;
|
||||
emit numberOfJobsStartedChanged();
|
||||
}
|
||||
|
||||
void ShaderCompilerManager::jobEnded()
|
||||
{
|
||||
m_numberOfJobsEnded++;
|
||||
numberOfJobsEndedChanged();
|
||||
}
|
||||
|
||||
|
||||
void ShaderCompilerManager::setIsUnitTesting(bool isUnitTesting)
|
||||
{
|
||||
m_isUnitTesting = isUnitTesting;
|
||||
}
|
||||
|
||||
int ShaderCompilerManager::numberOfJobsStarted()
|
||||
{
|
||||
return m_numberOfJobsStarted;
|
||||
}
|
||||
|
||||
int ShaderCompilerManager::numberOfJobsEnded()
|
||||
{
|
||||
return m_numberOfJobsEnded;
|
||||
}
|
||||
|
||||
int ShaderCompilerManager::numberOfErrors()
|
||||
{
|
||||
return m_numberOfErrors;
|
||||
}
|
||||
|
||||
@@ -1,67 +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
|
||||
*
|
||||
*/
|
||||
#ifndef SHADERCOMPILERMANAGER_H
|
||||
#define SHADERCOMPILERMANAGER_H
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QObject>
|
||||
#include <QHash>
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#endif
|
||||
|
||||
typedef QHash<unsigned int, unsigned int> ShaderCompilerJobMap;
|
||||
|
||||
/**
|
||||
* The Shader Compiler Manager class receive a shader compile request
|
||||
* and starts a shader compiler job for it
|
||||
*/
|
||||
class ShaderCompilerManager
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int numberOfJobsStarted READ numberOfJobsStarted NOTIFY numberOfJobsStartedChanged)
|
||||
Q_PROPERTY(int numberOfJobsEnded READ numberOfJobsEnded NOTIFY numberOfJobsEndedChanged)
|
||||
Q_PROPERTY(int numberOfErrors READ numberOfErrors NOTIFY numberOfErrorsChanged)
|
||||
public:
|
||||
|
||||
explicit ShaderCompilerManager(QObject* parent = 0);
|
||||
virtual ~ShaderCompilerManager();
|
||||
|
||||
void process(unsigned int connID, unsigned int type, unsigned int serial, QByteArray payload);
|
||||
void decodeShaderCompilerRequest(unsigned int connID, QByteArray payload);
|
||||
void setIsUnitTesting(bool isUnitTesting);
|
||||
int numberOfJobsStarted();
|
||||
int numberOfJobsEnded();
|
||||
int numberOfErrors();
|
||||
virtual void sendResponse(unsigned int connId, unsigned int type, unsigned int serial, QByteArray payload);
|
||||
|
||||
signals:
|
||||
void sendErrorMessage(QString errorMessage);
|
||||
void sendErrorMessageFromShaderJob(QString errorMessage, QString server, QString timestamp, QString payload);
|
||||
void numberOfJobsStartedChanged();
|
||||
void numberOfJobsEndedChanged();
|
||||
void numberOfErrorsChanged();
|
||||
|
||||
|
||||
public slots:
|
||||
void OnShaderCompilerJobComplete(QByteArray payload, unsigned int requestId);
|
||||
void shaderCompilerError(QString errorMessage, QString server, QString timestamp, QString payload);
|
||||
void jobStarted();
|
||||
void jobEnded();
|
||||
|
||||
|
||||
private:
|
||||
ShaderCompilerJobMap m_shaderCompilerJobMap;
|
||||
bool m_isUnitTesting;
|
||||
int m_numberOfJobsStarted;
|
||||
int m_numberOfJobsEnded;
|
||||
int m_numberOfErrors;
|
||||
};
|
||||
|
||||
#endif // SHADERCOMPILERMANAGER_H
|
||||
@@ -1,24 +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
|
||||
*
|
||||
*/
|
||||
#ifndef SHADERCOMPILERMESSAGES_H
|
||||
#define SHADERCOMPILERMESSAGES_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
|
||||
struct ShaderCompilerRequestMessage
|
||||
{
|
||||
QByteArray originalPayload;
|
||||
QString serverList;
|
||||
unsigned short serverPort;
|
||||
unsigned int serverListSize;
|
||||
unsigned int requestId;
|
||||
};
|
||||
|
||||
#endif //SHADERCOMPILERMESSAGES_H
|
||||
|
||||
@@ -1,150 +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 "shadercompilerModel.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
ShaderCompilerModel* s_singleton = nullptr;
|
||||
}
|
||||
|
||||
ShaderCompilerModel::ShaderCompilerModel(QObject* parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{
|
||||
Q_ASSERT(s_singleton == nullptr);
|
||||
s_singleton = this;
|
||||
}
|
||||
|
||||
ShaderCompilerModel::~ShaderCompilerModel()
|
||||
{
|
||||
s_singleton = nullptr;
|
||||
}
|
||||
|
||||
ShaderCompilerModel* ShaderCompilerModel::Get()
|
||||
{
|
||||
return s_singleton;
|
||||
}
|
||||
|
||||
QVariant ShaderCompilerModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int row = index.row();
|
||||
|
||||
if (row < 0)
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
if (row >= m_shaderErrorInfoList.count())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (role)
|
||||
{
|
||||
case TimeStampRole:
|
||||
return m_shaderErrorInfoList[row].m_shaderTimestamp;
|
||||
case ServerRole:
|
||||
return m_shaderErrorInfoList[row].m_shaderServerName;
|
||||
case ErrorRole:
|
||||
return m_shaderErrorInfoList[row].m_shaderError;
|
||||
case OriginalRequestRole:
|
||||
return m_shaderErrorInfoList[row].m_shaderOriginalPayload;
|
||||
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column())
|
||||
{
|
||||
case ColumnTimeStamp:
|
||||
return m_shaderErrorInfoList[row].m_shaderTimestamp;
|
||||
case ColumnServer:
|
||||
return m_shaderErrorInfoList[row].m_shaderServerName;
|
||||
case ColumnError:
|
||||
return m_shaderErrorInfoList[row].m_shaderServerName;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
Qt::ItemFlags ShaderCompilerModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
(void)index;
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
}
|
||||
|
||||
|
||||
int ShaderCompilerModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
(void)parent;
|
||||
return m_shaderErrorInfoList.count();
|
||||
}
|
||||
|
||||
|
||||
QModelIndex ShaderCompilerModel::parent(const QModelIndex&) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
|
||||
QModelIndex ShaderCompilerModel::index(int row, int column, const QModelIndex& parent) const
|
||||
{
|
||||
if (row >= rowCount(parent) || column >= columnCount(parent))
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
return createIndex(row, column);
|
||||
}
|
||||
|
||||
|
||||
int ShaderCompilerModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : Column::Max;
|
||||
}
|
||||
|
||||
|
||||
QVariant ShaderCompilerModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case ColumnTimeStamp:
|
||||
return tr("Time Stamp");
|
||||
case ColumnServer:
|
||||
return tr("Server");
|
||||
case ColumnError:
|
||||
return tr("Error");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QAbstractItemModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
|
||||
QHash<int, QByteArray> ShaderCompilerModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> result;
|
||||
result[TimeStampRole] = "timestamp";
|
||||
result[ServerRole] = "server";
|
||||
result[ErrorRole] = "error";
|
||||
result[OriginalRequestRole] = "originalRequest";
|
||||
return result;
|
||||
}
|
||||
void ShaderCompilerModel::addShaderErrorInfoEntry(QString errorMessage, QString timestamp, QString payload, QString server)
|
||||
{
|
||||
ShaderCompilerErrorInfo shaderCompileErrorInfo(errorMessage, timestamp, payload, server);
|
||||
beginInsertRows(QModelIndex(), m_shaderErrorInfoList.size(), m_shaderErrorInfoList.size());
|
||||
m_shaderErrorInfoList.append(shaderCompileErrorInfo);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
@@ -1,93 +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
|
||||
*
|
||||
*/
|
||||
#ifndef SHADERCOMPILERMODEL_H
|
||||
#define SHADERCOMPILERMODEL_H
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include <QAbstractItemModel>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QHash>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#endif
|
||||
|
||||
class QModelIndex;
|
||||
class QObject;
|
||||
|
||||
struct ShaderCompilerErrorInfo
|
||||
{
|
||||
QString m_shaderError;
|
||||
QString m_shaderTimestamp;
|
||||
QString m_shaderOriginalPayload;
|
||||
QString m_shaderServerName;
|
||||
|
||||
ShaderCompilerErrorInfo(QString shaderError, QString shaderTimestamp, QString shaderOriginalPayload, QString shaderServerName)
|
||||
: m_shaderError(shaderError)
|
||||
, m_shaderTimestamp(shaderTimestamp)
|
||||
, m_shaderOriginalPayload(shaderOriginalPayload)
|
||||
, m_shaderServerName(shaderServerName)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/** The Shader Compiler model is responsible for capturing error requests
|
||||
*/
|
||||
class ShaderCompilerModel
|
||||
: public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
enum DataRoles
|
||||
{
|
||||
TimeStampRole = Qt::UserRole + 1,
|
||||
ServerRole,
|
||||
ErrorRole,
|
||||
OriginalRequestRole,
|
||||
};
|
||||
|
||||
enum Column
|
||||
{
|
||||
ColumnTimeStamp,
|
||||
ColumnServer,
|
||||
ColumnError,
|
||||
Max
|
||||
};
|
||||
|
||||
/// standard Qt constructor
|
||||
explicit ShaderCompilerModel(QObject* parent = 0);
|
||||
virtual ~ShaderCompilerModel();
|
||||
|
||||
// singleton pattern
|
||||
static ShaderCompilerModel* Get();
|
||||
|
||||
|
||||
/// QAbstractListModel interface
|
||||
QModelIndex parent(const QModelIndex&) const override;
|
||||
QModelIndex index(int row, int column, const QModelIndex& parent) const override;
|
||||
int columnCount(const QModelIndex&) const override;
|
||||
virtual int rowCount(const QModelIndex& parent) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
virtual QVariant data(const QModelIndex& index, int role) const override;
|
||||
virtual QHash<int, QByteArray> roleNames() const override;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
|
||||
public slots:
|
||||
void addShaderErrorInfoEntry(QString errorMessage, QString timestamp, QString payload, QString server);
|
||||
|
||||
private:
|
||||
|
||||
QList<ShaderCompilerErrorInfo> m_shaderErrorInfoList;
|
||||
};
|
||||
|
||||
|
||||
#endif // SHADERCOMPILERMODEL_H
|
||||
|
||||
|
||||
|
||||
@@ -1,194 +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 "shadercompilerjob.h"
|
||||
#include "native/assetprocessor.h"
|
||||
|
||||
#include <QTcpSocket>
|
||||
|
||||
ShaderCompilerJob::ShaderCompilerJob()
|
||||
: m_isUnitTesting(false)
|
||||
, m_manager(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ShaderCompilerJob::~ShaderCompilerJob()
|
||||
{
|
||||
m_manager = nullptr;
|
||||
}
|
||||
|
||||
ShaderCompilerRequestMessage ShaderCompilerJob::ShaderCompilerMessage() const
|
||||
{
|
||||
return m_ShaderCompilerMessage;
|
||||
}
|
||||
|
||||
void ShaderCompilerJob::initialize(QObject* pManager, const ShaderCompilerRequestMessage& ShaderCompilerMessage)
|
||||
{
|
||||
m_manager = pManager;
|
||||
m_ShaderCompilerMessage = ShaderCompilerMessage;
|
||||
}
|
||||
|
||||
QString ShaderCompilerJob::getServerAddress()
|
||||
{
|
||||
if (isServerListEmpty())
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString serverAddress;
|
||||
if (!m_ShaderCompilerMessage.serverList.contains(","))
|
||||
{
|
||||
serverAddress = m_ShaderCompilerMessage.serverList;
|
||||
m_ShaderCompilerMessage.serverList.clear();
|
||||
return serverAddress;
|
||||
}
|
||||
|
||||
QStringList serverList = m_ShaderCompilerMessage.serverList.split(",");
|
||||
serverAddress = serverList.takeAt(0);
|
||||
m_ShaderCompilerMessage.serverList = serverList.join(",");
|
||||
return serverAddress;
|
||||
}
|
||||
|
||||
bool ShaderCompilerJob::isServerListEmpty()
|
||||
{
|
||||
return m_ShaderCompilerMessage.serverList.isEmpty();
|
||||
}
|
||||
|
||||
bool ShaderCompilerJob::attemptDelivery(QString serverAddress, QByteArray& payload)
|
||||
{
|
||||
QTcpSocket socket;
|
||||
QString error;
|
||||
int waitingTime = 8000; // 8 sec timeout for sending.
|
||||
int jobCompileMaxTime = 1000 * 60; // 60 sec timeout for compilation
|
||||
if (m_isUnitTesting)
|
||||
{
|
||||
waitingTime = 500;
|
||||
jobCompileMaxTime = 500;
|
||||
}
|
||||
|
||||
socket.connectToHost(serverAddress, m_ShaderCompilerMessage.serverPort, QIODevice::ReadWrite);
|
||||
|
||||
if (socket.waitForConnected(waitingTime))
|
||||
{
|
||||
qint64 bytesWritten = 0;
|
||||
qint64 payloadSize = static_cast<qint64>(m_ShaderCompilerMessage.originalPayload.size());
|
||||
// send payload size to server
|
||||
while (bytesWritten != sizeof(qint64))
|
||||
{
|
||||
qint64 currentWrite = socket.write(reinterpret_cast<char*>(&payloadSize) + bytesWritten,
|
||||
sizeof(qint64) - bytesWritten);
|
||||
if (currentWrite == -1)
|
||||
{
|
||||
//It is important to note that we are only outputting the error to debugchannel only here because
|
||||
//we are forwarding these error messages upstream to the manager,who will take the appropriate action
|
||||
error = "Connection Lost:Unable to send data";
|
||||
AZ_TracePrintf(AssetProcessor::DebugChannel, error.toUtf8().data());
|
||||
QMetaObject::invokeMethod(m_manager, "shaderCompilerError", Qt::QueuedConnection, Q_ARG(QString, error), Q_ARG(QString, QDateTime::currentDateTime().toString()), Q_ARG(QString, QString(m_ShaderCompilerMessage.originalPayload)), Q_ARG(QString, serverAddress));
|
||||
return false;
|
||||
}
|
||||
socket.flush();
|
||||
bytesWritten += currentWrite;
|
||||
}
|
||||
bytesWritten = 0;
|
||||
//send actual payload to server
|
||||
while (bytesWritten != m_ShaderCompilerMessage.originalPayload.size())
|
||||
{
|
||||
qint64 currentWrite = socket.write(m_ShaderCompilerMessage.originalPayload.data() + bytesWritten,
|
||||
m_ShaderCompilerMessage.originalPayload.size() - bytesWritten);
|
||||
if (currentWrite == -1)
|
||||
{
|
||||
error = "Connection Lost:Unable to send data";
|
||||
AZ_TracePrintf(AssetProcessor::DebugChannel, error.toUtf8().data());
|
||||
QMetaObject::invokeMethod(m_manager, "shaderCompilerError", Qt::QueuedConnection, Q_ARG(QString, error), Q_ARG(QString, QDateTime::currentDateTime().toString()), Q_ARG(QString, QString(m_ShaderCompilerMessage.originalPayload)), Q_ARG(QString, serverAddress));
|
||||
}
|
||||
socket.flush();
|
||||
bytesWritten += currentWrite;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "Unable to connect to IP Address " + serverAddress;
|
||||
AZ_TracePrintf(AssetProcessor::DebugChannel, error.toUtf8().data());
|
||||
QMetaObject::invokeMethod(m_manager, "shaderCompilerError", Qt::QueuedConnection, Q_ARG(QString, error), Q_ARG(QString, QDateTime::currentDateTime().toString()), Q_ARG(QString, QString(m_ShaderCompilerMessage.originalPayload)), Q_ARG(QString, serverAddress));
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int expectedBytes = sizeof(unsigned int) + sizeof(qint8);
|
||||
unsigned int bytesReadTotal = 0;
|
||||
unsigned int messageSize = 0;
|
||||
bool isMessageSizeKnown = false;
|
||||
//read the entire payload
|
||||
while ((bytesReadTotal < expectedBytes + messageSize))
|
||||
{
|
||||
if (socket.bytesAvailable() == 0)
|
||||
{
|
||||
if (!socket.waitForReadyRead(jobCompileMaxTime))
|
||||
{
|
||||
error = "Remote IP is taking too long to respond: " + serverAddress;
|
||||
AZ_TracePrintf(AssetProcessor::DebugChannel, error.toUtf8().data());
|
||||
QMetaObject::invokeMethod(m_manager, "shaderCompilerError", Qt::QueuedConnection, Q_ARG(QString, error), Q_ARG(QString, QDateTime::currentDateTime().toString()), Q_ARG(QString, QString(m_ShaderCompilerMessage.originalPayload)), Q_ARG(QString, serverAddress));
|
||||
payload.clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
qint64 bytesAvailable = socket.bytesAvailable();
|
||||
|
||||
if (bytesAvailable >= expectedBytes && !isMessageSizeKnown)
|
||||
{
|
||||
socket.peek(reinterpret_cast<char*>(&messageSize), sizeof(unsigned int));
|
||||
payload.resize(expectedBytes + messageSize);
|
||||
isMessageSizeKnown = true;
|
||||
}
|
||||
|
||||
if (bytesAvailable > 0)
|
||||
{
|
||||
qint64 bytesRead = socket.read(payload.data() + bytesReadTotal, bytesAvailable);
|
||||
|
||||
if (bytesRead <= 0)
|
||||
{
|
||||
error = "Connection closed by remote IP Address " + serverAddress;
|
||||
AZ_TracePrintf(AssetProcessor::DebugChannel, error.toUtf8().data());
|
||||
QMetaObject::invokeMethod(m_manager, "shaderCompilerError", Qt::QueuedConnection, Q_ARG(QString, error), Q_ARG(QString, QDateTime::currentDateTime().toString()), Q_ARG(QString, QString(m_ShaderCompilerMessage.originalPayload)), Q_ARG(QString, serverAddress));
|
||||
payload.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bytesReadTotal = aznumeric_cast<uint32_t>(bytesReadTotal + bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
return true; // payload successfully send
|
||||
}
|
||||
|
||||
void ShaderCompilerJob::run()
|
||||
{
|
||||
QMetaObject::invokeMethod(m_manager, "jobStarted", Qt::QueuedConnection);
|
||||
QByteArray payload;
|
||||
//until server list is empty, keep trying
|
||||
while (!isServerListEmpty())
|
||||
{
|
||||
QString serverAddress = getServerAddress();
|
||||
//attempt to send payload
|
||||
if (attemptDelivery(serverAddress, payload))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
//we are appending request id at the end of every payload,
|
||||
//therefore in the case of any errors also
|
||||
//we will be sending atleast four bytes to the game
|
||||
payload.append(reinterpret_cast<char*>(&m_ShaderCompilerMessage.requestId), sizeof(unsigned int));
|
||||
QMetaObject::invokeMethod(m_manager, "OnShaderCompilerJobComplete", Qt::QueuedConnection, Q_ARG(QByteArray, payload), Q_ARG(unsigned int, m_ShaderCompilerMessage.requestId));
|
||||
QMetaObject::invokeMethod(m_manager, "jobEnded", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
|
||||
void ShaderCompilerJob::setIsUnitTesting(bool isUnitTesting)
|
||||
{
|
||||
m_isUnitTesting = isUnitTesting;
|
||||
}
|
||||
@@ -1,44 +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
|
||||
*
|
||||
*/
|
||||
#ifndef SHADERCOMPILERJOB_H
|
||||
#define SHADERCOMPILERJOB_H
|
||||
|
||||
#include <QRunnable>
|
||||
#include "shadercompilerMessages.h"
|
||||
|
||||
class QByteArray;
|
||||
class QObject;
|
||||
|
||||
/**
|
||||
* This class is responsible for connecting to the shader compiler server
|
||||
* and getting back the response to the shader compiler manager
|
||||
*/
|
||||
class ShaderCompilerJob
|
||||
: public QRunnable
|
||||
{
|
||||
public:
|
||||
|
||||
explicit ShaderCompilerJob();
|
||||
virtual ~ShaderCompilerJob();
|
||||
ShaderCompilerRequestMessage ShaderCompilerMessage() const;
|
||||
void initialize(QObject* pManager, const ShaderCompilerRequestMessage& ShaderCompilerMessage);
|
||||
QString getServerAddress();
|
||||
bool isServerListEmpty();
|
||||
virtual void run() override;
|
||||
|
||||
void setIsUnitTesting(bool isUnitTesting);
|
||||
|
||||
bool attemptDelivery(QString serverAddress, QByteArray& payload);
|
||||
|
||||
private:
|
||||
ShaderCompilerRequestMessage m_ShaderCompilerMessage;
|
||||
QObject* m_manager;
|
||||
bool m_isUnitTesting;
|
||||
};
|
||||
|
||||
#endif // SHADERCOMPILERJOB_H
|
||||
@@ -18,8 +18,6 @@
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
AZ_UNIT_TEST_HOOK(new BaseAssetProcessorTestEnvironment)
|
||||
|
||||
namespace AssetProcessor
|
||||
{
|
||||
class UnitTestAppManager : public BatchApplicationManager
|
||||
@@ -35,7 +33,7 @@ namespace AssetProcessor
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// tests which use the builder bus plug in their own mock version, so disconnect ours.
|
||||
AssetProcessor::AssetBuilderInfoBus::Handler::BusDisconnect();
|
||||
|
||||
@@ -59,7 +57,7 @@ namespace AssetProcessor
|
||||
void SetUp() override
|
||||
{
|
||||
AssetProcessorTest::SetUp();
|
||||
|
||||
|
||||
static int numParams = 1;
|
||||
static char processName[] = {"AssetProcessorBatch"};
|
||||
static char* namePtr = &processName[0];
|
||||
@@ -147,7 +145,7 @@ namespace AssetProcessor
|
||||
time.start();
|
||||
|
||||
actualTest->StartTest();
|
||||
|
||||
|
||||
while (!testIsComplete)
|
||||
{
|
||||
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
|
||||
|
||||
@@ -5,76 +5,8 @@
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
#include "utilities/BatchApplicationManager.h"
|
||||
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzTest/Utils.h>
|
||||
#include <native/tests/BaseAssetProcessorTest.h>
|
||||
|
||||
DECLARE_AZ_UNIT_TEST_MAIN()
|
||||
|
||||
int RunUnitTests(int argc, char* argv[], bool& ranUnitTests)
|
||||
{
|
||||
ranUnitTests = true;
|
||||
|
||||
INVOKE_AZ_UNIT_TEST_MAIN(nullptr); // nullptr turns off default test environment used to catch stray asserts
|
||||
|
||||
// This looks a bit weird, but the macro returns conditionally, so *if* we get here, it means the unit tests didn't run
|
||||
ranUnitTests = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
qputenv("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM", "1");
|
||||
|
||||
AZ::Debug::Trace::HandleExceptions(true);
|
||||
AZ::Test::ApplyGlobalParameters(&argc, argv);
|
||||
|
||||
// If "--unittest" is present on the command line, run unit testing
|
||||
// and return immediately. Otherwise, continue as normal.
|
||||
AZ::Test::addTestEnvironment(new BaseAssetProcessorTestEnvironment());
|
||||
|
||||
bool pauseOnComplete = false;
|
||||
|
||||
if (AZ::Test::ContainsParameter(argc, argv, "--pause-on-completion"))
|
||||
{
|
||||
pauseOnComplete = true;
|
||||
}
|
||||
|
||||
bool ranUnitTests;
|
||||
int result = RunUnitTests(argc, argv, ranUnitTests);
|
||||
|
||||
if (ranUnitTests)
|
||||
{
|
||||
if (pauseOnComplete)
|
||||
{
|
||||
system("pause");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
BatchApplicationManager applicationManager(&argc, &argv);
|
||||
setvbuf(stdout, NULL, _IONBF, 0); // Disabling output buffering to fix test failures due to incomplete logs
|
||||
|
||||
ApplicationManager::BeforeRunStatus status = applicationManager.BeforeRun();
|
||||
|
||||
if (status != ApplicationManager::BeforeRunStatus::Status_Success)
|
||||
{
|
||||
if (status == ApplicationManager::BeforeRunStatus::Status_Restarting)
|
||||
{
|
||||
//AssetProcessor will restart
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Initialization failed
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return applicationManager.Run() ? 0 : 1;
|
||||
}
|
||||
|
||||
AZ_UNIT_TEST_HOOK(new BaseAssetProcessorTestEnvironment)
|
||||
|
||||
@@ -29,14 +29,16 @@ namespace AssetProcessor
|
||||
AssetTreeItem::AssetTreeItem(
|
||||
AZStd::shared_ptr<AssetTreeItemData> data,
|
||||
QIcon errorIcon,
|
||||
QIcon folderIcon,
|
||||
QIcon fileIcon,
|
||||
AssetTreeItem* parentItem) :
|
||||
m_data(data),
|
||||
m_parent(parentItem),
|
||||
m_errorIcon(errorIcon), // QIcon is implicitily shared.
|
||||
m_folderIcon(QIcon(QStringLiteral(":/Gallery/Asset_Folder.svg"))),
|
||||
m_fileIcon(QIcon(QStringLiteral(":/Gallery/Asset_File.svg")))
|
||||
m_errorIcon(errorIcon), // QIcon is implicitly shared.
|
||||
m_folderIcon(folderIcon),
|
||||
m_fileIcon(fileIcon)
|
||||
{
|
||||
m_folderIcon.addFile(QStringLiteral(":/Gallery/Asset_Folder.svg"), QSize(), QIcon::Selected);
|
||||
|
||||
}
|
||||
|
||||
AssetTreeItem::~AssetTreeItem()
|
||||
@@ -45,7 +47,7 @@ namespace AssetProcessor
|
||||
|
||||
AssetTreeItem* AssetTreeItem::CreateChild(AZStd::shared_ptr<AssetTreeItemData> data)
|
||||
{
|
||||
m_childItems.emplace_back(new AssetTreeItem(data, m_errorIcon, this));
|
||||
m_childItems.emplace_back(new AssetTreeItem(data, m_errorIcon, m_folderIcon, m_fileIcon, this));
|
||||
return m_childItems.back().get();
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ namespace AssetProcessor
|
||||
explicit AssetTreeItem(
|
||||
AZStd::shared_ptr<AssetTreeItemData> data,
|
||||
QIcon errorIcon,
|
||||
QIcon folderIcon,
|
||||
QIcon fileIcon,
|
||||
AssetTreeItem* parentItem = nullptr);
|
||||
virtual ~AssetTreeItem();
|
||||
|
||||
|
||||
@@ -16,9 +16,12 @@ namespace AssetProcessor
|
||||
|
||||
AssetTreeModel::AssetTreeModel(AZStd::shared_ptr<AzToolsFramework::AssetDatabase::AssetDatabaseConnection> sharedDbConnection, QObject *parent) :
|
||||
QAbstractItemModel(parent),
|
||||
m_sharedDbConnection(sharedDbConnection),
|
||||
m_errorIcon(QStringLiteral(":/stylesheet/img/logging/error.svg"))
|
||||
m_sharedDbConnection(sharedDbConnection)
|
||||
, m_errorIcon(QStringLiteral(":/stylesheet/img/logging/error.svg"))
|
||||
, m_folderIcon(QIcon(QStringLiteral(":/Gallery/Asset_Folder.svg")))
|
||||
, m_fileIcon(QIcon(QStringLiteral(":/Gallery/Asset_File.svg")))
|
||||
{
|
||||
m_folderIcon.addFile(QStringLiteral(":/Gallery/Asset_Folder.svg"), QSize(), QIcon::Selected);
|
||||
ApplicationManagerNotifications::Bus::Handler::BusConnect();
|
||||
AzToolsFramework::AssetDatabase::AssetDatabaseNotificationBus::Handler::BusConnect();
|
||||
}
|
||||
@@ -40,7 +43,7 @@ namespace AssetProcessor
|
||||
void AssetTreeModel::Reset()
|
||||
{
|
||||
beginResetModel();
|
||||
m_root.reset(new AssetTreeItem(AZStd::make_shared<AssetTreeItemData>("", "", true, AZ::Uuid::CreateNull()), m_errorIcon));
|
||||
m_root.reset(new AssetTreeItem(AZStd::make_shared<AssetTreeItemData>("", "", true, AZ::Uuid::CreateNull()), m_errorIcon, m_folderIcon, m_fileIcon));
|
||||
|
||||
ResetModel();
|
||||
|
||||
|
||||
@@ -54,5 +54,7 @@ namespace AssetProcessor
|
||||
AZStd::shared_ptr<AzToolsFramework::AssetDatabase::AssetDatabaseConnection> m_sharedDbConnection;
|
||||
|
||||
QIcon m_errorIcon;
|
||||
QIcon m_folderIcon;
|
||||
QIcon m_fileIcon;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include "../connection/connection.h"
|
||||
#include "../resourcecompiler/rccontroller.h"
|
||||
#include "../resourcecompiler/RCJobSortFilterProxyModel.h"
|
||||
#include "../shadercompiler/shadercompilerModel.h"
|
||||
|
||||
|
||||
#include <QClipboard>
|
||||
@@ -148,7 +147,6 @@ void MainWindow::Activate()
|
||||
ui->buttonList->addTab(QStringLiteral("Jobs"));
|
||||
ui->buttonList->addTab(QStringLiteral("Assets"));
|
||||
ui->buttonList->addTab(QStringLiteral("Logs"));
|
||||
ui->buttonList->addTab(QStringLiteral("Shaders"));
|
||||
ui->buttonList->addTab(QStringLiteral("Connections"));
|
||||
ui->buttonList->addTab(QStringLiteral("Tools"));
|
||||
|
||||
@@ -317,14 +315,6 @@ void MainWindow::Activate()
|
||||
connect(ui->jobFilteredSearchWidget, &AzQtComponents::FilteredSearchWidget::TextFilterChanged,
|
||||
this, writeJobFilterSettings);
|
||||
|
||||
//Shader view
|
||||
ui->shaderTreeView->setModel(m_guiApplicationManager->GetShaderCompilerModel());
|
||||
ui->shaderTreeView->header()->resizeSection(ShaderCompilerModel::ColumnTimeStamp, 80);
|
||||
ui->shaderTreeView->header()->resizeSection(ShaderCompilerModel::ColumnServer, 40);
|
||||
ui->shaderTreeView->header()->resizeSection(ShaderCompilerModel::ColumnError, 220);
|
||||
ui->shaderTreeView->header()->setSectionResizeMode(ShaderCompilerModel::ColumnError, QHeaderView::Stretch);
|
||||
ui->shaderTreeView->header()->setStretchLastSection(false);
|
||||
|
||||
// Asset view
|
||||
m_sourceAssetTreeFilterModel = new AssetProcessor::AssetTreeFilterModel(this);
|
||||
m_sourceModel = new AssetProcessor::SourceAssetTreeModel(m_sharedDbConnection, this);
|
||||
|
||||
@@ -65,7 +65,6 @@ public:
|
||||
Jobs,
|
||||
Assets,
|
||||
Logs,
|
||||
Shaders,
|
||||
Connections,
|
||||
Tools
|
||||
};
|
||||
|
||||
@@ -763,59 +763,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="shaderDialog">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="shaderLabel">
|
||||
<property name="text">
|
||||
<string>Shaders</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="shaderInfoPane" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="AzQtComponents::TableView" name="shaderTreeView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="connectionsDialog">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="spacing">
|
||||
|
||||
@@ -1,188 +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 "ShaderCompilerUnitTests.h"
|
||||
#include "native/connection/connectionManager.h"
|
||||
#include "native/connection/connection.h"
|
||||
#include "native/utilities/assetUtils.h"
|
||||
|
||||
#define UNIT_TEST_CONNECT_PORT 12125
|
||||
|
||||
ShaderCompilerUnitTest::ShaderCompilerUnitTest()
|
||||
{
|
||||
m_connectionManager = ConnectionManager::Get();
|
||||
connect(this, SIGNAL(StartUnitTestForGoodShaderCompiler()), this, SLOT(UnitTestForGoodShaderCompiler()));
|
||||
connect(this, SIGNAL(StartUnitTestForFirstBadShaderCompiler()), this, SLOT(UnitTestForFirstBadShaderCompiler()));
|
||||
connect(this, SIGNAL(StartUnitTestForSecondBadShaderCompiler()), this, SLOT(UnitTestForSecondBadShaderCompiler()));
|
||||
connect(this, SIGNAL(StartUnitTestForThirdBadShaderCompiler()), this, SLOT(UnitTestForThirdBadShaderCompiler()));
|
||||
connect(&m_shaderCompilerManager, SIGNAL(sendErrorMessageFromShaderJob(QString, QString, QString, QString)), this, SLOT(ReceiveShaderCompilerErrorMessage(QString, QString, QString, QString)));
|
||||
|
||||
m_shaderCompilerManager.setIsUnitTesting(true);
|
||||
m_connectionManager->RegisterService(AssetUtilities::ComputeCRC32Lowercase("ShaderCompilerProxyRequest"), AZStd::bind(&ShaderCompilerManager::process, &m_shaderCompilerManager, AZStd::placeholders::_1, AZStd::placeholders::_2, AZStd::placeholders::_3, AZStd::placeholders::_4));
|
||||
ContructPayloadForShaderCompilerServer(m_testPayload);
|
||||
}
|
||||
|
||||
ShaderCompilerUnitTest::~ShaderCompilerUnitTest()
|
||||
{
|
||||
m_connectionManager->removeConnection(m_connectionId);
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::ContructPayloadForShaderCompilerServer(QByteArray& payload)
|
||||
{
|
||||
QString testString = "This is a test string";
|
||||
QString testServerList = "127.0.0.3,198.51.100.0,127.0.0.1"; // note - 198.51.100.0 is in the 'test' range that will never be assigned to anyone.
|
||||
unsigned int testServerListLength = static_cast<unsigned int>(testServerList.size());
|
||||
unsigned short testServerPort = 12348;
|
||||
unsigned int testRequestId = 1;
|
||||
qint64 testStringLength = static_cast<qint64>(testString.size());
|
||||
payload.resize(static_cast<unsigned int>(testStringLength));
|
||||
memcpy(payload.data(), (testString.toStdString().c_str()), testStringLength);
|
||||
unsigned int payloadSize = payload.size();
|
||||
payload.resize(payloadSize + 1 + static_cast<unsigned int>(testServerListLength) + 1 + sizeof(unsigned short) + sizeof(unsigned int) + sizeof(unsigned int));
|
||||
char* dataStart = payload.data() + payloadSize;
|
||||
*dataStart = 0;// null
|
||||
memcpy(payload.data() + payloadSize + 1, (testServerList.toStdString().c_str()), testServerListLength);
|
||||
dataStart += 1 + testServerListLength;
|
||||
*dataStart = 0; //null
|
||||
memcpy(payload.data() + payloadSize + 1 + testServerListLength + 1, reinterpret_cast<char*>(&testServerPort), sizeof(unsigned short));
|
||||
memcpy(payload.data() + payloadSize + 1 + testServerListLength + 1 + sizeof(unsigned short), reinterpret_cast<char*>(&testServerListLength), sizeof(unsigned int));
|
||||
memcpy(payload.data() + payloadSize + 1 + testServerListLength + 1 + sizeof(unsigned short) + sizeof(unsigned int), reinterpret_cast<char*>(&testRequestId), sizeof(unsigned int));
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::StartTest()
|
||||
{
|
||||
m_connectionId = m_connectionManager->addConnection();
|
||||
Connection* connection = m_connectionManager->getConnection(m_connectionId);
|
||||
connection->SetPort(UNIT_TEST_CONNECT_PORT);
|
||||
connection->SetIpAddress("127.0.0.1");
|
||||
connection->SetAutoConnect(true);
|
||||
UnitTestForGoodShaderCompiler();
|
||||
}
|
||||
|
||||
int ShaderCompilerUnitTest::UnitTestPriority() const
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::UnitTestForGoodShaderCompiler()
|
||||
{
|
||||
AZ_TracePrintf("ShaderCompilerUnitTest", " ... Starting test of 'good' shader compiler...\n");
|
||||
m_shaderCompilerManager.m_sendResponseCallbackFn = AZStd::bind(&ShaderCompilerUnitTest::VerifyPayloadForGoodShaderCompiler, this , AZStd::placeholders::_1, AZStd::placeholders::_2, AZStd::placeholders::_3, AZStd::placeholders::_4);
|
||||
m_server.Init("127.0.0.1", 12348);
|
||||
m_server.setServerStatus(UnitTestShaderCompilerServer::GoodServer);
|
||||
m_connectionManager->SendMessageToService(m_connectionId, AssetUtilities::ComputeCRC32Lowercase("ShaderCompilerProxyRequest"), 0, m_testPayload);
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::UnitTestForFirstBadShaderCompiler()
|
||||
{
|
||||
AZ_TracePrintf("ShaderCompilerUnitTest", " ... Starting test of 'bad' shader compiler... (Incomplete Payload)\n");
|
||||
m_shaderCompilerManager.m_sendResponseCallbackFn = AZStd::bind(&ShaderCompilerUnitTest::VerifyPayloadForFirstBadShaderCompiler, this, AZStd::placeholders::_1, AZStd::placeholders::_2, AZStd::placeholders::_3, AZStd::placeholders::_4);
|
||||
m_server.setServerStatus(UnitTestShaderCompilerServer::BadServer_SendsIncompletePayload);
|
||||
m_connectionManager->SendMessageToService(m_connectionId, AssetUtilities::ComputeCRC32Lowercase("ShaderCompilerProxyRequest"), 0, m_testPayload);
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::UnitTestForSecondBadShaderCompiler()
|
||||
{
|
||||
AZ_TracePrintf("ShaderCompilerUnitTest", " ... Starting test of 'bad' shader compiler... (Payload followed by disconnection)\n");
|
||||
m_shaderCompilerManager.m_sendResponseCallbackFn = AZStd::bind(&ShaderCompilerUnitTest::VerifyPayloadForSecondBadShaderCompiler, this, AZStd::placeholders::_1, AZStd::placeholders::_2, AZStd::placeholders::_3, AZStd::placeholders::_4);
|
||||
m_server.setServerStatus(UnitTestShaderCompilerServer::BadServer_ReadsPayloadAndDisconnect);
|
||||
m_connectionManager->SendMessageToService(m_connectionId, AssetUtilities::ComputeCRC32Lowercase("ShaderCompilerProxyRequest"), 0, m_testPayload);
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::UnitTestForThirdBadShaderCompiler()
|
||||
{
|
||||
AZ_TracePrintf("ShaderCompilerUnitTest", " ... Starting test of 'bad' shader compiler... (Connect but disconnect without data)\n");
|
||||
m_shaderCompilerManager.m_sendResponseCallbackFn = AZStd::bind(&ShaderCompilerUnitTest::VerifyPayloadForThirdBadShaderCompiler, this, AZStd::placeholders::_1, AZStd::placeholders::_2, AZStd::placeholders::_3, AZStd::placeholders::_4);
|
||||
m_server.setServerStatus(UnitTestShaderCompilerServer::BadServer_DisconnectAfterConnect);
|
||||
m_server.startServer();
|
||||
m_connectionManager->SendMessageToService(m_connectionId, AssetUtilities::ComputeCRC32Lowercase("ShaderCompilerProxyRequest"), 0, m_testPayload);
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::VerifyPayloadForGoodShaderCompiler(unsigned int connId, unsigned int type, unsigned int serial, QByteArray payload)
|
||||
{
|
||||
(void) connId;
|
||||
(void) type;
|
||||
(void) serial;
|
||||
m_shaderCompilerManager.m_sendResponseCallbackFn = nullptr;
|
||||
|
||||
unsigned int messageSize;
|
||||
quint8 status;
|
||||
QByteArray payloadToCheck;
|
||||
unsigned int requestId;
|
||||
memcpy((&messageSize), payload.data(), sizeof(unsigned int));
|
||||
memcpy((&status), payload.data() + sizeof(unsigned int), sizeof(unsigned char));
|
||||
payloadToCheck.resize(messageSize);
|
||||
memcpy((payloadToCheck.data()), payload.data() + sizeof(unsigned int) + sizeof(unsigned char), messageSize);
|
||||
memcpy((&requestId), payload.data() + sizeof(unsigned int) + sizeof(unsigned char) + messageSize, sizeof(unsigned int));
|
||||
QString outgoingTestString = "Test string validated";
|
||||
if (QString::compare(QString(payloadToCheck), outgoingTestString, Qt::CaseSensitive) != 0)
|
||||
{
|
||||
Q_EMIT UnitTestFailed("Unit Test for Good Shader Compiler Failed");
|
||||
return;
|
||||
}
|
||||
Q_EMIT StartUnitTestForFirstBadShaderCompiler();
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::VerifyPayloadForFirstBadShaderCompiler(unsigned int connId, unsigned int type, unsigned int serial, QByteArray payload)
|
||||
{
|
||||
(void) connId;
|
||||
(void) type;
|
||||
(void) serial;
|
||||
m_shaderCompilerManager.m_sendResponseCallbackFn = nullptr;
|
||||
QString error = "Remote IP is taking too long to respond: 127.0.0.1";
|
||||
if ((payload.size() != 4) || (QString::compare(m_lastShaderCompilerErrorMessage, error, Qt::CaseSensitive) != 0))
|
||||
{
|
||||
Q_EMIT UnitTestFailed("Unit Test for First Bad Shader Compiler Failed");
|
||||
return;
|
||||
}
|
||||
m_lastShaderCompilerErrorMessage.clear();
|
||||
Q_EMIT StartUnitTestForSecondBadShaderCompiler();
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::VerifyPayloadForSecondBadShaderCompiler(unsigned int connId, unsigned int type, unsigned int serial, QByteArray payload)
|
||||
{
|
||||
(void) connId;
|
||||
(void) type;
|
||||
(void) serial;
|
||||
m_shaderCompilerManager.m_sendResponseCallbackFn = nullptr;
|
||||
QString error = "Remote IP is taking too long to respond: 127.0.0.1";
|
||||
if ((payload.size() != 4) || (QString::compare(m_lastShaderCompilerErrorMessage, error, Qt::CaseSensitive) != 0))
|
||||
{
|
||||
Q_EMIT UnitTestFailed("Unit Test for Second Bad Shader Compiler Failed");
|
||||
return;
|
||||
}
|
||||
m_lastShaderCompilerErrorMessage.clear();
|
||||
Q_EMIT StartUnitTestForThirdBadShaderCompiler();
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::VerifyPayloadForThirdBadShaderCompiler(unsigned int connId, unsigned int type, unsigned int serial, QByteArray payload)
|
||||
{
|
||||
(void) connId;
|
||||
(void) type;
|
||||
(void) serial;
|
||||
m_shaderCompilerManager.m_sendResponseCallbackFn = nullptr;
|
||||
QString error = "Remote IP is taking too long to respond: 127.0.0.1";
|
||||
if ((payload.size() != 4) || (QString::compare(m_lastShaderCompilerErrorMessage, error, Qt::CaseSensitive) != 0))
|
||||
{
|
||||
Q_EMIT UnitTestFailed("Unit Test for Third Bad Shader Compiler Failed");
|
||||
return;
|
||||
}
|
||||
m_lastShaderCompilerErrorMessage.clear();
|
||||
Q_EMIT UnitTestPassed();
|
||||
}
|
||||
|
||||
void ShaderCompilerUnitTest::ReceiveShaderCompilerErrorMessage(QString error, QString server, QString timestamp, QString payload)
|
||||
{
|
||||
(void) server;
|
||||
(void) timestamp;
|
||||
(void) payload;
|
||||
m_lastShaderCompilerErrorMessage = error;
|
||||
}
|
||||
|
||||
|
||||
REGISTER_UNIT_TEST(ShaderCompilerUnitTest)
|
||||
|
||||
@@ -1,81 +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
|
||||
*
|
||||
*/
|
||||
#ifndef SHADERCOMPILERUNITTEST_H
|
||||
#define SHADERCOMPILERUNITTEST_H
|
||||
|
||||
#if !defined(Q_MOC_RUN)
|
||||
#include "UnitTestRunner.h"
|
||||
|
||||
#include <AzCore/std/functional.h>
|
||||
|
||||
#include "native/shadercompiler/shadercompilerManager.h"
|
||||
//#include "native/shadercompiler/shadercompilerMessages.h"
|
||||
#include "native/utilities/UnitTestShaderCompilerServer.h"
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#endif
|
||||
|
||||
class ConnectionManager;
|
||||
|
||||
class ShaderCompilerManagerForUnitTest : public ShaderCompilerManager
|
||||
{
|
||||
public:
|
||||
explicit ShaderCompilerManagerForUnitTest(QObject* parent = 0) : ShaderCompilerManager(parent) {};
|
||||
|
||||
// for this test, we override sendResponse and make it so that it just calls a callback instead of actually sending it to the connection manager.
|
||||
void sendResponse(unsigned int connId, unsigned int type, unsigned int serial, QByteArray payload) override
|
||||
{
|
||||
if (m_sendResponseCallbackFn)
|
||||
{
|
||||
m_sendResponseCallbackFn(connId, type, serial, payload);
|
||||
}
|
||||
}
|
||||
AZStd::function<void(unsigned int, unsigned int, unsigned int, QByteArray)> m_sendResponseCallbackFn;
|
||||
};
|
||||
|
||||
class ShaderCompilerUnitTest
|
||||
: public UnitTestRun
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ShaderCompilerUnitTest();
|
||||
~ShaderCompilerUnitTest();
|
||||
virtual void StartTest() override;
|
||||
virtual int UnitTestPriority() const override;
|
||||
void ContructPayloadForShaderCompilerServer(QByteArray& payload);
|
||||
|
||||
Q_SIGNALS:
|
||||
void StartUnitTestForGoodShaderCompiler();
|
||||
void StartUnitTestForFirstBadShaderCompiler();
|
||||
void StartUnitTestForSecondBadShaderCompiler();
|
||||
void StartUnitTestForThirdBadShaderCompiler();
|
||||
|
||||
public Q_SLOTS:
|
||||
void UnitTestForGoodShaderCompiler();
|
||||
void UnitTestForFirstBadShaderCompiler();
|
||||
void UnitTestForSecondBadShaderCompiler();
|
||||
void UnitTestForThirdBadShaderCompiler();
|
||||
void VerifyPayloadForGoodShaderCompiler(unsigned int connId, unsigned int type, unsigned int serial, QByteArray payload);
|
||||
void VerifyPayloadForFirstBadShaderCompiler(unsigned int connId, unsigned int type, unsigned int serial, QByteArray payload);
|
||||
void VerifyPayloadForSecondBadShaderCompiler(unsigned int connId, unsigned int type, unsigned int serial, QByteArray payload);
|
||||
void VerifyPayloadForThirdBadShaderCompiler(unsigned int connId, unsigned int type, unsigned int serial, QByteArray payload);
|
||||
void ReceiveShaderCompilerErrorMessage(QString error, QString server, QString timestamp, QString payload);
|
||||
|
||||
|
||||
private:
|
||||
UnitTestShaderCompilerServer m_server;
|
||||
ShaderCompilerManagerForUnitTest m_shaderCompilerManager;
|
||||
ConnectionManager* m_connectionManager;
|
||||
QByteArray m_testPayload;
|
||||
QString m_lastShaderCompilerErrorMessage;
|
||||
unsigned int m_connectionId = 0;
|
||||
};
|
||||
|
||||
#endif // SHADERCOMPILERUNITTEST_H
|
||||
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#include "native/resourcecompiler/rccontroller.h"
|
||||
#include "native/FileServer/fileServer.h"
|
||||
#include "native/AssetManager/assetScanner.h"
|
||||
#include "native/shadercompiler/shadercompilerManager.h"
|
||||
#include "native/shadercompiler/shadercompilerModel.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDialogButtonBox>
|
||||
@@ -55,7 +53,7 @@ namespace
|
||||
{
|
||||
moduleFileInfo.setFile(executableDirectory);
|
||||
}
|
||||
|
||||
|
||||
QDir binaryDir = moduleFileInfo.absoluteDir();
|
||||
// strip extension
|
||||
QString applicationBase = moduleFileInfo.completeBaseName();
|
||||
@@ -70,7 +68,7 @@ namespace
|
||||
binaryDir.remove(tempFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -145,8 +143,6 @@ void GUIApplicationManager::Destroy()
|
||||
|
||||
DestroyIniConfiguration();
|
||||
DestroyFileServer();
|
||||
DestroyShaderCompilerManager();
|
||||
DestroyShaderCompilerModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +188,7 @@ bool GUIApplicationManager::Run()
|
||||
wrapper->enableSaveRestoreGeometry(GetOrganizationName(), GetApplicationName(), "MainWindow", restoreOnFirstShow);
|
||||
|
||||
AzQtComponents::StyleManager::setStyleSheet(m_mainWindow, QStringLiteral("style:AssetProcessor.qss"));
|
||||
|
||||
|
||||
auto refreshStyleSheets = [styleManager]()
|
||||
{
|
||||
styleManager->Refresh();
|
||||
@@ -334,7 +330,7 @@ bool GUIApplicationManager::Run()
|
||||
m_duringStartup = false;
|
||||
|
||||
int resultCode = qApp->exec(); // this blocks until the last window is closed.
|
||||
|
||||
|
||||
if(!InitiatedShutdown())
|
||||
{
|
||||
// if we are here it implies that AP did not stop the Qt event loop and is shutting down prematurely
|
||||
@@ -427,7 +423,7 @@ bool GUIApplicationManager::OnError(const char* /*window*/, const char* message)
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we're the main thread, then consider showing the message box directly.
|
||||
// If we're the main thread, then consider showing the message box directly.
|
||||
// note that all other threads will PAUSE if they emit a message while the main thread is showing this box
|
||||
// due to the way the trace system EBUS is mutex-protected.
|
||||
Qt::ConnectionType connection = Qt::DirectConnection;
|
||||
@@ -470,7 +466,7 @@ bool GUIApplicationManager::Activate()
|
||||
AssetUtilities::ComputeProjectCacheRoot(projectCacheRoot);
|
||||
m_localUserSettings.Load(projectCacheRoot.filePath("AssetProcessorUserSettings.xml").toUtf8().data(), context);
|
||||
m_localUserSettings.Activate(AZ::UserSettings::CT_LOCAL);
|
||||
|
||||
|
||||
InitIniConfiguration();
|
||||
InitFileServer();
|
||||
|
||||
@@ -479,9 +475,6 @@ bool GUIApplicationManager::Activate()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
InitShaderCompilerModel();
|
||||
InitShaderCompilerManager();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -606,7 +599,7 @@ void GUIApplicationManager::InitConnectionManager()
|
||||
QObject::connect(m_fileServer, SIGNAL(AddRenameRequest(unsigned int, bool)), m_connectionManager, SLOT(AddRenameRequest(unsigned int, bool)));
|
||||
QObject::connect(m_fileServer, SIGNAL(AddFindFileNamesRequest(unsigned int, bool)), m_connectionManager, SLOT(AddFindFileNamesRequest(unsigned int, bool)));
|
||||
QObject::connect(m_fileServer, SIGNAL(UpdateConnectionMetrics()), m_connectionManager, SLOT(UpdateConnectionMetrics()));
|
||||
|
||||
|
||||
m_connectionManager->RegisterService(ShowAssetProcessorRequest::MessageType,
|
||||
std::bind([this](unsigned int /*connId*/, unsigned int /*type*/, unsigned int /*serial*/, QByteArray /*payload*/)
|
||||
{
|
||||
@@ -661,40 +654,6 @@ void GUIApplicationManager::DestroyFileServer()
|
||||
}
|
||||
}
|
||||
|
||||
void GUIApplicationManager::InitShaderCompilerManager()
|
||||
{
|
||||
m_shaderCompilerManager = new ShaderCompilerManager();
|
||||
|
||||
//Shader compiler stuff
|
||||
m_connectionManager->RegisterService(AssetUtilities::ComputeCRC32Lowercase("ShaderCompilerProxyRequest"), std::bind(&ShaderCompilerManager::process, m_shaderCompilerManager, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4));
|
||||
QObject::connect(m_shaderCompilerManager, SIGNAL(sendErrorMessageFromShaderJob(QString, QString, QString, QString)), m_shaderCompilerModel, SLOT(addShaderErrorInfoEntry(QString, QString, QString, QString)));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void GUIApplicationManager::DestroyShaderCompilerManager()
|
||||
{
|
||||
if (m_shaderCompilerManager)
|
||||
{
|
||||
delete m_shaderCompilerManager;
|
||||
m_shaderCompilerManager = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GUIApplicationManager::InitShaderCompilerModel()
|
||||
{
|
||||
m_shaderCompilerModel = new ShaderCompilerModel();
|
||||
}
|
||||
|
||||
void GUIApplicationManager::DestroyShaderCompilerModel()
|
||||
{
|
||||
if (m_shaderCompilerModel)
|
||||
{
|
||||
delete m_shaderCompilerModel;
|
||||
m_shaderCompilerModel = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
IniConfiguration* GUIApplicationManager::GetIniConfiguration() const
|
||||
{
|
||||
return m_iniConfiguration;
|
||||
@@ -704,14 +663,6 @@ FileServer* GUIApplicationManager::GetFileServer() const
|
||||
{
|
||||
return m_fileServer;
|
||||
}
|
||||
ShaderCompilerManager* GUIApplicationManager::GetShaderCompilerManager() const
|
||||
{
|
||||
return m_shaderCompilerManager;
|
||||
}
|
||||
ShaderCompilerModel* GUIApplicationManager::GetShaderCompilerModel() const
|
||||
{
|
||||
return m_shaderCompilerModel;
|
||||
}
|
||||
|
||||
void GUIApplicationManager::ShowTrayIconErrorMessage(QString msg)
|
||||
{
|
||||
|
||||
@@ -24,8 +24,6 @@ class ConnectionManager;
|
||||
class IniConfiguration;
|
||||
class ApplicationServer;
|
||||
class FileServer;
|
||||
class ShaderCompilerManager;
|
||||
class ShaderCompilerModel;
|
||||
|
||||
namespace AssetProcessor
|
||||
{
|
||||
@@ -47,8 +45,6 @@ public:
|
||||
ApplicationManager::BeforeRunStatus BeforeRun() override;
|
||||
IniConfiguration* GetIniConfiguration() const;
|
||||
FileServer* GetFileServer() const;
|
||||
ShaderCompilerManager* GetShaderCompilerManager() const;
|
||||
ShaderCompilerModel* GetShaderCompilerModel() const;
|
||||
|
||||
bool Run() override;
|
||||
////////////////////////////////////////////////////
|
||||
@@ -72,10 +68,6 @@ private:
|
||||
void DestroyIniConfiguration();
|
||||
void InitFileServer();
|
||||
void DestroyFileServer();
|
||||
void InitShaderCompilerManager();
|
||||
void DestroyShaderCompilerManager();
|
||||
void InitShaderCompilerModel();
|
||||
void DestroyShaderCompilerModel();
|
||||
void Destroy() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
@@ -99,8 +91,7 @@ private:
|
||||
|
||||
IniConfiguration* m_iniConfiguration = nullptr;
|
||||
FileServer* m_fileServer = nullptr;
|
||||
ShaderCompilerManager* m_shaderCompilerManager = nullptr;
|
||||
ShaderCompilerModel* m_shaderCompilerModel = nullptr;
|
||||
|
||||
QFileSystemWatcher m_qtFileWatcher;
|
||||
AZ::UserSettingsProvider m_localUserSettings;
|
||||
bool m_messageBoxIsVisible = false;
|
||||
|
||||
@@ -13,4 +13,5 @@
|
||||
#ifdef AZ_COLLECTING_PARTIAL_SRGS
|
||||
#include <Atom/RPI/ShaderResourceGroups/DefaultSceneSrg.azsli>
|
||||
#include <Atom/Feature/Common/Assets/ShaderResourceGroups/SceneSrg.azsli>
|
||||
#include <Terrain/Assets/Shaders/Terrain/SceneSrg.azsli> // Temporary until gem partial view srgs can be included automatically.
|
||||
#endif
|
||||
|
||||
@@ -12,5 +12,4 @@
|
||||
|
||||
#ifdef AZ_COLLECTING_PARTIAL_SRGS
|
||||
#include <Atom/Feature/Common/Assets/ShaderResourceGroups/ViewSrg.azsli>
|
||||
#include <Terrain/Assets/Shaders/Terrain/ViewSrg.azsli> // Temporary until gem partial view srgs can be included automatically.
|
||||
#endif
|
||||
|
||||
@@ -101,6 +101,13 @@ namespace AZ
|
||||
void EsmShadowmapsPass::UpdateChildren()
|
||||
{
|
||||
const RPI::PassAttachmentBinding& inputBinding = GetInputBinding(0);
|
||||
|
||||
if (!inputBinding.m_attachment)
|
||||
{
|
||||
AZ_Assert(false, "[EsmShadowmapsPass %s] requires an input attachment", GetPathName().GetCStr());
|
||||
return;
|
||||
}
|
||||
|
||||
AZ_Assert(inputBinding.m_attachment->m_descriptor.m_type == RHI::AttachmentType::Image, "[EsmShadowmapsPass %s] input attachment requires an image attachment", GetPathName().GetCStr());
|
||||
m_shadowmapImageSize = inputBinding.m_attachment->m_descriptor.m_image.m_size;
|
||||
m_shadowmapArraySize = inputBinding.m_attachment->m_descriptor.m_image.m_arraySize;
|
||||
|
||||
@@ -24,14 +24,14 @@ namespace AZ
|
||||
{
|
||||
m_elementSize = descriptor.m_elementSize;
|
||||
m_elementCount = 0;
|
||||
|
||||
|
||||
m_bufferIndex = descriptor.m_srgLayout->FindShaderInputBufferIndex(Name(descriptor.m_bufferSrgName));
|
||||
AZ_Error(ClassName, m_bufferIndex.IsValid(), "Unable to find %s in view shader resource group.", descriptor.m_bufferSrgName.c_str());
|
||||
AZ_Error(ClassName, m_bufferIndex.IsValid(), "Unable to find %s in %s shader resource group.", descriptor.m_bufferSrgName.c_str(), descriptor.m_srgLayout->GetName().GetCStr());
|
||||
|
||||
if (!descriptor.m_elementCountSrgName.empty())
|
||||
{
|
||||
m_elementCountIndex = descriptor.m_srgLayout->FindShaderInputConstantIndex(Name(descriptor.m_elementCountSrgName));
|
||||
AZ_Error(ClassName, m_elementCountIndex.IsValid(), "Unable to find %s in view shader resource group.", descriptor.m_elementCountSrgName.c_str());
|
||||
AZ_Error(ClassName, m_elementCountIndex.IsValid(), "Unable to find %s in %s shader resource group.", descriptor.m_elementCountSrgName.c_str(), descriptor.m_srgLayout->GetName().GetCStr());
|
||||
}
|
||||
|
||||
if (m_bufferIndex.IsValid())
|
||||
|
||||
@@ -28,101 +28,105 @@
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QDockWidget" name="m_pATLControlsDockWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="features">
|
||||
<set>QDockWidget::NoDockWidgetFeatures</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>ATL Controls</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="m_pATLControlsWidget">
|
||||
<layout class="QVBoxLayout" name="m_pATLControlsDockLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDockWidget" name="m_pInspectorDockWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>2</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="features">
|
||||
<set>QDockWidget::NoDockWidgetFeatures</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Inspector</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="m_pInspectorWidget">
|
||||
<layout class="QVBoxLayout" name="m_pInspectorDockLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDockWidget" name="m_pMiddlewareDockWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="floating">
|
||||
<property name="childrenCollapsible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="features">
|
||||
<set>QDockWidget::NoDockWidgetFeatures</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Audio Middleware Controls</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="m_pMiddlewareWidget">
|
||||
<layout class="QVBoxLayout" name="m_pMiddlewareDockLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</layout>
|
||||
<widget class="QDockWidget" name="m_pATLControlsDockWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="features">
|
||||
<set>QDockWidget::NoDockWidgetFeatures</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>ATL Controls</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="m_pATLControlsWidget">
|
||||
<layout class="QVBoxLayout" name="m_pATLControlsDockLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="m_pInspectorDockWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>2</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="features">
|
||||
<set>QDockWidget::NoDockWidgetFeatures</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Inspector</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="m_pInspectorWidget">
|
||||
<layout class="QVBoxLayout" name="m_pInspectorDockLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="m_pMiddlewareDockWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="floating">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="features">
|
||||
<set>QDockWidget::NoDockWidgetFeatures</set>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Audio Middleware Controls</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="m_pMiddlewareWidget">
|
||||
<layout class="QVBoxLayout" name="m_pMiddlewareDockLayout">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -134,7 +138,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>972</width>
|
||||
<height>21</height>
|
||||
<height>26</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
@@ -143,6 +147,7 @@
|
||||
</property>
|
||||
<addaction name="actionSaveAll"/>
|
||||
<addaction name="actionReload"/>
|
||||
<addaction name="actionRefreshAudioSystem"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
@@ -166,6 +171,17 @@
|
||||
<property name="text">
|
||||
<string>Reload</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+R</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRefreshAudioSystem">
|
||||
<property name="text">
|
||||
<string>Refresh Audio System</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+R</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
@@ -204,6 +220,22 @@
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>actionRefreshAudioSystem</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>RefreshAudioSystem()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>485</x>
|
||||
<y>336</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<slots>
|
||||
<signal>CurrentControlNameChanged(QString)</signal>
|
||||
|
||||
@@ -198,6 +198,20 @@ namespace AudioControls
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
void CAudioControlsEditorWindow::RefreshAudioSystem()
|
||||
{
|
||||
QString sLevelName = GetIEditor()->GetLevelName();
|
||||
|
||||
if (QString::compare(sLevelName, "Untitled", Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
// Rather pass empty QString to indicate that no level is loaded!
|
||||
sLevelName = QString();
|
||||
}
|
||||
|
||||
Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::RefreshAudioSystem, sLevelName.toUtf8().data());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
void CAudioControlsEditorWindow::Save()
|
||||
{
|
||||
@@ -215,15 +229,7 @@ namespace AudioControls
|
||||
messageBox.setWindowTitle("Audio Controls Editor");
|
||||
if (messageBox.exec() == QMessageBox::Yes)
|
||||
{
|
||||
QString sLevelName = GetIEditor()->GetLevelName();
|
||||
|
||||
if (QString::compare(sLevelName, "Untitled", Qt::CaseInsensitive) == 0)
|
||||
{
|
||||
// Rather pass empty QString to indicate that no level is loaded!
|
||||
sLevelName = QString();
|
||||
}
|
||||
|
||||
Audio::AudioSystemRequestBus::Broadcast(&Audio::AudioSystemRequestBus::Events::RefreshAudioSystem, sLevelName.toUtf8().data());
|
||||
RefreshAudioSystem();
|
||||
}
|
||||
}
|
||||
m_pATLModel->ClearDirtyFlags();
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace AudioControls
|
||||
void UpdateInspector();
|
||||
void FilterControlType(EACEControlType type, bool bShow);
|
||||
void Update();
|
||||
void RefreshAudioSystem();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* pEvent) override;
|
||||
|
||||
@@ -439,6 +439,12 @@ namespace CommandSystem
|
||||
return false;
|
||||
}
|
||||
|
||||
if (actorInstance->GetEntity())
|
||||
{
|
||||
outResult = AZStd::string::format("Cannot remove actor instance. Actor instance %i belongs to an entity.", actorInstanceID);
|
||||
return false;
|
||||
}
|
||||
|
||||
// store the old values before removing the instance
|
||||
m_oldPosition = actorInstance->GetLocalSpaceTransform().m_position;
|
||||
m_oldRotation = actorInstance->GetLocalSpaceTransform().m_rotation;
|
||||
@@ -618,7 +624,7 @@ namespace CommandSystem
|
||||
MCore::CommandGroup commandGroup("Remove actor instances", numActorInstances);
|
||||
AZStd::string tempString;
|
||||
|
||||
// iterate over the selected instances and clone them
|
||||
// iterate over the selected instances and remove them
|
||||
for (size_t i = 0; i < numActorInstances; ++i)
|
||||
{
|
||||
// get the current actor instance
|
||||
@@ -628,6 +634,18 @@ namespace CommandSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not remove any runtime instance from the manager using the commands.
|
||||
if (actorInstance->GetIsOwnedByRuntime())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do not remove the any instances owned by an entity from the manager using the commands.
|
||||
if (actorInstance->GetEntity())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tempString = AZStd::string::format("RemoveActorInstance -actorInstanceID %i", actorInstance->GetID());
|
||||
commandGroup.AddCommandString(tempString.c_str());
|
||||
}
|
||||
|
||||
@@ -455,8 +455,17 @@ namespace CommandSystem
|
||||
EMotionFX::ActorInstance* actorInstance = nullptr;
|
||||
if (parameters.CheckIfHasParameter("actorInstanceID"))
|
||||
{
|
||||
const uint32 actorInstanceID = parameters.GetValueAsInt("actorInstanceID", this);
|
||||
actorInstance = EMotionFX::GetActorManager().FindActorInstanceByID(actorInstanceID);
|
||||
const int actorInstanceID = parameters.GetValueAsInt("actorInstanceID", this);
|
||||
if (actorInstanceID == -1)
|
||||
{
|
||||
// If there isn't an actorInstanceId, grab the first actor instance.
|
||||
actorInstance = EMotionFX::GetActorManager().GetFirstEditorActorInstance();
|
||||
}
|
||||
else
|
||||
{
|
||||
actorInstance = EMotionFX::GetActorManager().FindActorInstanceByID(actorInstanceID);
|
||||
}
|
||||
|
||||
if (!actorInstance)
|
||||
{
|
||||
outResult = AZStd::string::format("Cannot activate anim graph. Actor instance id '%i' is not valid.", actorInstanceID);
|
||||
|
||||
@@ -434,6 +434,20 @@ namespace EMotionFX
|
||||
}
|
||||
|
||||
|
||||
ActorInstance* ActorManager::GetFirstEditorActorInstance() const
|
||||
{
|
||||
const size_t numActorInstances = m_actorInstances.size();
|
||||
for (size_t i = 0; i < numActorInstances; ++i)
|
||||
{
|
||||
if (!m_actorInstances[i]->GetIsOwnedByRuntime())
|
||||
{
|
||||
return m_actorInstances[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
const AZStd::vector<ActorInstance*>& ActorManager::GetActorInstanceArray() const
|
||||
{
|
||||
return m_actorInstances;
|
||||
|
||||
@@ -136,6 +136,12 @@ namespace EMotionFX
|
||||
*/
|
||||
MCORE_INLINE ActorInstance* GetActorInstance(size_t nr) const { return m_actorInstances[nr]; }
|
||||
|
||||
/**
|
||||
* Get a given registered actor instance owned by editor (not owned by runtime).
|
||||
* @result A pointer to the actor instance.
|
||||
*/
|
||||
ActorInstance* GetFirstEditorActorInstance() const;
|
||||
|
||||
/**
|
||||
* Get the array of actor instances.
|
||||
* @result The const reference to the actor instance array.
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 <EMotionFX/Source/Velocity.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
|
||||
namespace EMotionFX
|
||||
{
|
||||
AZ::Vector3 CalculateLinearVelocity(const AZ::Vector3& lastPosition,
|
||||
const AZ::Vector3& currentPosition,
|
||||
float timeDelta)
|
||||
{
|
||||
if (timeDelta <= AZ::Constants::FloatEpsilon)
|
||||
{
|
||||
return AZ::Vector3::CreateZero();
|
||||
}
|
||||
|
||||
const AZ::Vector3 deltaPosition = currentPosition - lastPosition;
|
||||
const AZ::Vector3 velocity = deltaPosition / timeDelta;
|
||||
|
||||
if (velocity.GetLength() > AZ::Constants::FloatEpsilon)
|
||||
{
|
||||
return velocity;
|
||||
}
|
||||
|
||||
return AZ::Vector3::CreateZero();
|
||||
}
|
||||
|
||||
AZ::Vector3 CalculateAngularVelocity(const AZ::Quaternion& lastRotation,
|
||||
const AZ::Quaternion& currentRotation,
|
||||
float timeDelta)
|
||||
{
|
||||
if (timeDelta <= AZ::Constants::FloatEpsilon)
|
||||
{
|
||||
return AZ::Vector3::CreateZero();
|
||||
}
|
||||
|
||||
const AZ::Quaternion deltaRotation = currentRotation * lastRotation.GetInverseFull();
|
||||
const AZ::Quaternion shortestEquivalent = deltaRotation.GetShortestEquivalent().GetNormalized();
|
||||
const AZ::Vector3 scaledAxisAngle = shortestEquivalent.ConvertToScaledAxisAngle();
|
||||
const AZ::Vector3 angularVelocity = scaledAxisAngle / timeDelta;
|
||||
|
||||
if (angularVelocity.GetLength() > AZ::Constants::FloatEpsilon)
|
||||
{
|
||||
return angularVelocity;
|
||||
}
|
||||
|
||||
return AZ::Vector3::CreateZero();
|
||||
}
|
||||
|
||||
void DebugDrawVelocity(AzFramework::DebugDisplayRequests& debugDisplay,
|
||||
const AZ::Vector3& position, const AZ::Vector3& velocity, const AZ::Color& color)
|
||||
{
|
||||
// Don't visualize joints that remain motionless (zero velocity).
|
||||
if (velocity.GetLength() < AZ::Constants::FloatEpsilon)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const float scale = 0.15f;
|
||||
const AZ::Vector3 arrowPosition = position + velocity;
|
||||
|
||||
debugDisplay.DepthTestOff();
|
||||
debugDisplay.SetColor(color);
|
||||
|
||||
debugDisplay.DrawSolidCylinder(/*center=*/(arrowPosition + position) * 0.5f,
|
||||
/*direction=*/(arrowPosition - position).GetNormalizedSafe(),
|
||||
/*radius=*/0.003f,
|
||||
/*height=*/(arrowPosition - position).GetLength(),
|
||||
/*drawShaded=*/false);
|
||||
|
||||
debugDisplay.DrawSolidCone(position + velocity,
|
||||
velocity,
|
||||
0.1f * scale,
|
||||
scale * 0.5f,
|
||||
/*drawShaded=*/false);
|
||||
}
|
||||
} // namespace EMotionFX
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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/Math/Vector3.h>
|
||||
#include <AzCore/Math/Quaternion.h>
|
||||
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
|
||||
#include <EMotionFX/Source/EMotionFXConfig.h>
|
||||
|
||||
namespace EMotionFX
|
||||
{
|
||||
AZ::Vector3 EMFX_API CalculateLinearVelocity(const AZ::Vector3& lastPosition, const AZ::Vector3& currentPosition, float timeDelta);
|
||||
AZ::Vector3 EMFX_API CalculateAngularVelocity(const AZ::Quaternion& lastRotation, const AZ::Quaternion& currentRotation, float timeDelta);
|
||||
|
||||
void EMFX_API DebugDrawVelocity(AzFramework::DebugDisplayRequests& debugDisplay,
|
||||
const AZ::Vector3& position, const AZ::Vector3& velocity, const AZ::Color& color);
|
||||
} // namespace EMotionFX
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
|
||||
#include <EMotionFX/CommandSystem/Source/MiscCommands.h>
|
||||
#include <EMotionFX/CommandSystem/Source/SelectionCommands.h>
|
||||
#include <EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/OpenGLRenderPlugin.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <AzQtComponents/Components/FancyDocking.h>
|
||||
@@ -1340,8 +1341,15 @@ namespace EMStudio
|
||||
|
||||
// add the load and the create instance commands
|
||||
commandGroup.AddCommandString(loadActorCommand.c_str());
|
||||
commandGroup.AddCommandString("CreateActorInstance -actorID %LASTRESULT%");
|
||||
|
||||
// Temp solution after we refactor / remove the actor manager.
|
||||
// We only need to create the actor instance by ourselves when openGLRenderPlugin is present.
|
||||
// Atom render viewport will create actor instance along with the actor component.
|
||||
PluginManager* pluginManager = GetPluginManager();
|
||||
if (pluginManager->FindActivePlugin(static_cast<uint32>(OpenGLRenderPlugin::CLASS_ID)))
|
||||
{
|
||||
commandGroup.AddCommandString("CreateActorInstance -actorID %LASTRESULT%");
|
||||
}
|
||||
|
||||
// execute the group command
|
||||
if (GetCommandManager()->ExecuteCommandGroup(commandGroup, outResult) == false)
|
||||
|
||||
+9
-1
@@ -429,6 +429,7 @@ namespace EMStudio
|
||||
|
||||
// 3. Relink the actor instances with the emstudio actors
|
||||
const size_t numActorInstances = EMotionFX::GetActorManager().GetNumActorInstances();
|
||||
size_t numActorInstancesInRenderPlugin = 0;
|
||||
for (size_t i = 0; i < numActorInstances; ++i)
|
||||
{
|
||||
EMotionFX::ActorInstance* actorInstance = EMotionFX::GetActorManager().GetActorInstance(i);
|
||||
@@ -440,6 +441,12 @@ namespace EMStudio
|
||||
continue;
|
||||
}
|
||||
|
||||
if (actorInstance->GetEntity())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
numActorInstancesInRenderPlugin++;
|
||||
if (!emstudioActor)
|
||||
{
|
||||
for (EMStudioRenderActor* currentEMStudioActor : m_actors)
|
||||
@@ -485,6 +492,7 @@ namespace EMStudio
|
||||
if (found == false)
|
||||
{
|
||||
emstudioActor->m_actorInstances.erase(AZStd::next(begin(emstudioActor->m_actorInstances), j));
|
||||
numActorInstancesInRenderPlugin--;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -497,7 +505,7 @@ namespace EMStudio
|
||||
m_reinitRequested = false;
|
||||
|
||||
// zoom the camera to the available character only in case we're dealing with a single instance
|
||||
if (resetViewCloseup && numActorInstances == 1)
|
||||
if (resetViewCloseup && numActorInstancesInRenderPlugin == 1)
|
||||
{
|
||||
ViewCloseup(false);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <EMotionFX/CommandSystem/Source/CommandManager.h>
|
||||
#include <EMotionFX/CommandSystem/Source/MotionSetCommands.h>
|
||||
#include <EMotionFX/Source/ActorManager.h>
|
||||
#include <EMotionFX/Tools/EMotionStudio/Plugins/RenderPlugins/Source/OpenGLRender/OpenGLRenderPlugin.h>
|
||||
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
|
||||
@@ -430,6 +431,18 @@ namespace EMStudio
|
||||
continue;
|
||||
}
|
||||
|
||||
// Temp solution after we refactor / remove the actor manager.
|
||||
// We only need to create the actor instance by ourselves when openGLRenderPlugin is present.
|
||||
// Atom render viewport will create actor instance along with the actor component.
|
||||
PluginManager* pluginManager = GetPluginManager();
|
||||
if (!pluginManager->FindActivePlugin(static_cast<uint32>(OpenGLRenderPlugin::CLASS_ID)))
|
||||
{
|
||||
if (commands[i].find("CreateActorInstance") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
AzFramework::StringFunc::Replace(commands[i], "@products@", assetCacheFolder.c_str());
|
||||
AzFramework::StringFunc::Replace(commands[i], "@assets@", assetCacheFolder.c_str());
|
||||
AzFramework::StringFunc::Replace(commands[i], "@root@", assetCacheFolder.c_str());
|
||||
|
||||
@@ -144,6 +144,8 @@ set(FILES
|
||||
Source/TransformData.h
|
||||
Source/TriggerActionSetup.cpp
|
||||
Source/TriggerActionSetup.h
|
||||
Source/Velocity.cpp
|
||||
Source/Velocity.h
|
||||
Source/VertexAttributeLayer.cpp
|
||||
Source/VertexAttributeLayer.h
|
||||
Source/VertexAttributeLayerAbstractData.cpp
|
||||
|
||||
@@ -547,7 +547,12 @@ namespace MCore
|
||||
}
|
||||
|
||||
tmpStr = commandString.substr(lastResultIndex, rightPercentagePos - lastResultIndex + 1);
|
||||
AzFramework::StringFunc::Replace(commandString, tmpStr.c_str(), intermediateCommandResults[i - relativeIndex].c_str());
|
||||
AZStd::string replaceStr = intermediateCommandResults[i - relativeIndex];
|
||||
if (replaceStr.empty())
|
||||
{
|
||||
replaceStr = "-1";
|
||||
}
|
||||
AzFramework::StringFunc::Replace(commandString, tmpStr.c_str(), replaceStr.c_str());
|
||||
replaceHappen = true;
|
||||
|
||||
// Search again in case the command group is referring to other results
|
||||
|
||||
@@ -234,6 +234,10 @@ namespace EMotionFX
|
||||
const float updateRateInSeconds = animGraphSampleRate > 0.0f ? 1.0f / animGraphSampleRate : 0.0f;
|
||||
actorInstance->SetMotionSamplingRate(updateRateInSeconds);
|
||||
}
|
||||
else if (actorInstance->GetMotionSamplingRate() != 0)
|
||||
{
|
||||
actorInstance->SetMotionSamplingRate(0);
|
||||
}
|
||||
|
||||
// Disable the automatic mesh LOD level adjustment based on screen space in case a simple LOD component is present.
|
||||
// The simple LOD component overrides the mesh LOD level and syncs the skeleton with the mesh LOD level.
|
||||
|
||||
@@ -249,6 +249,9 @@ namespace FastNoiseGem
|
||||
|
||||
void FastNoiseGradientComponent::Activate()
|
||||
{
|
||||
// This will immediately call OnGradientTransformChanged and initialize m_gradientTransform.
|
||||
GradientSignal::GradientTransformNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
|
||||
// Some platforms require random seeds to be > 0. Clamp to a positive range to ensure we're always safe.
|
||||
m_generator.SetSeed(AZ::GetMax(m_configuration.m_seed, 1));
|
||||
m_generator.SetFrequency(m_configuration.m_frequency);
|
||||
@@ -272,6 +275,7 @@ namespace FastNoiseGem
|
||||
{
|
||||
GradientSignal::GradientRequestBus::Handler::BusDisconnect();
|
||||
FastNoiseGradientRequestBus::Handler::BusDisconnect();
|
||||
GradientSignal::GradientTransformNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
bool FastNoiseGradientComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
|
||||
@@ -294,14 +298,21 @@ namespace FastNoiseGem
|
||||
return false;
|
||||
}
|
||||
|
||||
void FastNoiseGradientComponent::OnGradientTransformChanged(const GradientSignal::GradientTransform& newTransform)
|
||||
{
|
||||
AZStd::unique_lock<decltype(m_transformMutex)> lock(m_transformMutex);
|
||||
m_gradientTransform = newTransform;
|
||||
}
|
||||
|
||||
float FastNoiseGradientComponent::GetValue(const GradientSignal::GradientSampleParams& sampleParams) const
|
||||
{
|
||||
AZ::Vector3 uvw = sampleParams.m_position;
|
||||
|
||||
bool wasPointRejected = false;
|
||||
const bool shouldNormalizeOutput = false;
|
||||
GradientSignal::GradientTransformRequestBus::Event(
|
||||
GetEntityId(), &GradientSignal::GradientTransformRequestBus::Events::TransformPositionToUVW, sampleParams.m_position, uvw, shouldNormalizeOutput, wasPointRejected);
|
||||
|
||||
{
|
||||
AZStd::shared_lock<decltype(m_transformMutex)> lock(m_transformMutex);
|
||||
m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected);
|
||||
}
|
||||
|
||||
if (!wasPointRejected)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/RTTI/TypeInfo.h>
|
||||
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
|
||||
#include <FastNoise/Ebuses/FastNoiseGradientRequestBus.h>
|
||||
|
||||
#include <External/FastNoise/FastNoise.h>
|
||||
@@ -67,6 +68,7 @@ namespace FastNoiseGem
|
||||
: public AZ::Component
|
||||
, private GradientSignal::GradientRequestBus::Handler
|
||||
, private FastNoiseGradientRequestBus::Handler
|
||||
, private GradientSignal::GradientTransformNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
friend class EditorFastNoiseGradientComponent;
|
||||
@@ -80,23 +82,25 @@ namespace FastNoiseGem
|
||||
FastNoiseGradientComponent(const FastNoiseGradientConfig& configuration);
|
||||
FastNoiseGradientComponent() = default;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component interface implementation
|
||||
// AZ::Component overrides...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GradientRequestBus
|
||||
// GradientRequestBus overrides...
|
||||
float GetValue(const GradientSignal::GradientSampleParams& sampleParams) const override;
|
||||
|
||||
protected:
|
||||
FastNoiseGradientConfig m_configuration;
|
||||
FastNoise m_generator;
|
||||
GradientSignal::GradientTransform m_gradientTransform;
|
||||
mutable AZStd::shared_mutex m_transformMutex;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// FastNoiseGradientRequest overrides
|
||||
// GradientTransformNotificationBus overrides...
|
||||
void OnGradientTransformChanged(const GradientSignal::GradientTransform& newTransform) override;
|
||||
|
||||
// FastNoiseGradientRequest overrides...
|
||||
int GetRandomSeed() const override;
|
||||
void SetRandomSeed(int seed) override;
|
||||
|
||||
|
||||
@@ -46,9 +46,10 @@ public:
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//// GradientTransformRequestBus
|
||||
void TransformPositionToUVW([[maybe_unused]] const AZ::Vector3& inPosition, [[maybe_unused]] AZ::Vector3& outUVW, [[maybe_unused]] const bool shouldNormalizeOutput, [[maybe_unused]] bool& wasPointRejected) const override {}
|
||||
void GetGradientLocalBounds([[maybe_unused]] AZ::Aabb& bounds) const override {}
|
||||
void GetGradientEncompassingBounds([[maybe_unused]] AZ::Aabb& bounds) const override {}
|
||||
const GradientSignal::GradientTransform& GetGradientTransform() const override
|
||||
{
|
||||
return m_gradientTransform;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GradientTransformModifierRequestBus
|
||||
@@ -96,6 +97,8 @@ public:
|
||||
|
||||
bool GetAdvancedMode() const override { return false; }
|
||||
void SetAdvancedMode([[maybe_unused]] bool value) override {}
|
||||
|
||||
GradientSignal::GradientTransform m_gradientTransform;
|
||||
};
|
||||
|
||||
TEST(FastNoiseTest, ComponentsWithComponentApplication)
|
||||
|
||||
@@ -136,6 +136,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
AZ::AzTestShared
|
||||
Gem::GradientSignal.Static
|
||||
Gem::LmbrCentral
|
||||
Gem::GradientSignal.Mocks
|
||||
@@ -144,6 +145,12 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
NAME Gem::GradientSignal.Tests
|
||||
)
|
||||
|
||||
ly_add_googlebenchmark(
|
||||
NAME Gem::GradientSignal.Benchmarks
|
||||
TARGET Gem::GradientSignal.Tests
|
||||
)
|
||||
|
||||
|
||||
if(PAL_TRAIT_BUILD_HOST_TOOLS)
|
||||
ly_add_target(
|
||||
NAME GradientSignal.Editor.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
|
||||
@@ -157,6 +164,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
BUILD_DEPENDENCIES
|
||||
PRIVATE
|
||||
AZ::AzTest
|
||||
AZ::AzTestShared
|
||||
Gem::GradientSignal.Static
|
||||
Gem::GradientSignal.Editor.Static
|
||||
Gem::LmbrCentral.Editor
|
||||
|
||||
+20
-4
@@ -13,14 +13,30 @@
|
||||
|
||||
namespace GradientSignal
|
||||
{
|
||||
//! TransformType describes where the gradient's origin is mapped to.
|
||||
enum class TransformType : AZ::u8
|
||||
{
|
||||
//! The gradient's origin is the world position of this entity.
|
||||
World_ThisEntity = 0,
|
||||
//! The gradient's origin is the local position of this entity, but in world space.
|
||||
//! i.e. If the parent is at (2, 2), and the gradient is at (3,3) in local space, the gradient entity itself will be at (5,5) in
|
||||
//! world space but its origin will frozen at (3,3) in world space, no matter how much the parent moves around.
|
||||
Local_ThisEntity,
|
||||
//! The gradient's origin is the world position of the reference entity.
|
||||
World_ReferenceEntity,
|
||||
//! The gradient's origin is the local position of the reference entity, but in world space.
|
||||
Local_ReferenceEntity,
|
||||
//! The gradient's origin is at (0,0,0) in world space.
|
||||
World_Origin,
|
||||
//! The gradient's origin is in translated world space relative to the reference entity.
|
||||
Relative,
|
||||
};
|
||||
|
||||
class GradientTransformModifierRequests
|
||||
: public AZ::ComponentBus
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Overrides the default AZ::EBusTraits handler policy to allow one
|
||||
* listener only.
|
||||
*/
|
||||
//! Overrides the default AZ::EBusTraits handler policy to allow only one listener.
|
||||
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
|
||||
|
||||
virtual bool GetAllowReference() const = 0;
|
||||
|
||||
+46
-4
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/EBus/EBus.h>
|
||||
#include <AzCore/Math/Aabb.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <GradientSignal/GradientTransform.h>
|
||||
|
||||
namespace GradientSignal
|
||||
{
|
||||
@@ -22,15 +23,56 @@ namespace GradientSignal
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
using BusIdType = AZ::EntityId;
|
||||
|
||||
//! allows multiple threads to call shape requests
|
||||
//! allows multiple threads to call gradient transform requests
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
|
||||
virtual ~GradientTransformRequests() = default;
|
||||
|
||||
virtual void TransformPositionToUVW(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, const bool shouldNormalizeOutput, bool& wasPointRejected) const = 0;
|
||||
virtual void GetGradientLocalBounds(AZ::Aabb& bounds) const = 0;
|
||||
virtual void GetGradientEncompassingBounds(AZ::Aabb& bounds) const = 0;
|
||||
//! Get the GradientTransform that's been configured by the bus listener.
|
||||
//! \return the GradientTransform instance that can be used to transform world points into gradient lookup space.
|
||||
virtual const GradientTransform& GetGradientTransform() const = 0;
|
||||
};
|
||||
|
||||
using GradientTransformRequestBus = AZ::EBus<GradientTransformRequests>;
|
||||
|
||||
/**
|
||||
* Notifies about changes to the GradientTransform configuration
|
||||
*/
|
||||
class GradientTransformNotifications
|
||||
: public AZ::EBusTraits
|
||||
{
|
||||
public:
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// EBusTraits
|
||||
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
|
||||
using BusIdType = AZ::EntityId;
|
||||
using MutexType = AZStd::recursive_mutex;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! Notify listeners that the GradientTransform configuration has changed.
|
||||
//! \return the GradientTransform instance that can be used to transform world points into gradient lookup space.
|
||||
virtual void OnGradientTransformChanged(const GradientTransform& newTransform) = 0;
|
||||
|
||||
//! Connection policy that auto-calls OnGradientTransformChanged on connection with the current GradientTransform data.
|
||||
template<class Bus>
|
||||
struct ConnectionPolicy : public AZ::EBusConnectionPolicy<Bus>
|
||||
{
|
||||
static void Connect(
|
||||
typename Bus::BusPtr& busPtr,
|
||||
typename Bus::Context& context,
|
||||
typename Bus::HandlerNode& handler,
|
||||
typename Bus::Context::ConnectLockGuard& connectLock,
|
||||
const typename Bus::BusIdType& id = 0)
|
||||
{
|
||||
AZ::EBusConnectionPolicy<Bus>::Connect(busPtr, context, handler, connectLock, id);
|
||||
|
||||
GradientTransform transform;
|
||||
GradientTransformRequestBus::EventResult(transform, id, &GradientTransformRequests::GetGradientTransform);
|
||||
handler->OnGradientTransformChanged(transform);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
using GradientTransformNotificationBus = AZ::EBus<GradientTransformNotifications>;
|
||||
|
||||
} //namespace GradientSignal
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* 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/Math/Aabb.h>
|
||||
#include <AzCore/Math/Vector3.h>
|
||||
#include <AzCore/Math/Matrix3x4.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <AzCore/std/functional.h>
|
||||
|
||||
namespace GradientSignal
|
||||
{
|
||||
//! Controls how the gradient repeats itself when queried outside the bounds of the shape.
|
||||
enum class WrappingType : AZ::u8
|
||||
{
|
||||
None = 0, //! Unbounded - the gradient ignores the shape bounds.
|
||||
ClampToEdge, //! The values on the edge of the shape will be extended outward in each direction.
|
||||
Mirror, //! The gradient signal will be repeated but mirrored on every repeat.
|
||||
Repeat, //! The gradient signal will be repeated in every direction.
|
||||
ClampToZero, //! The value will always be 0 outside of the shape.
|
||||
};
|
||||
|
||||
class GradientTransform
|
||||
{
|
||||
public:
|
||||
GradientTransform() = default;
|
||||
|
||||
/**
|
||||
* Create a GradientTransform with the given parameters.
|
||||
* GradientTransform is a utility class that converts world space positions to gradient space UVW values which can be used
|
||||
* to look up deterministic gradient values for the input spatial locations.
|
||||
* \param shapeBounds The bounds of the shape associated with the gradient, in local space.
|
||||
* \param transform The transform to use to convert from world space to gradient space.
|
||||
* \param use3d True for 3D gradient lookup outputs, false for 2D gradient lookup outputs. (i.e. output W will be nonzero or zero)
|
||||
* \param frequencyZoom Amount to scale the UVW results after wrapping is applied.
|
||||
* \param wrappingType The way in which the gradient repeats itself outside the shape bounds.
|
||||
*/
|
||||
GradientTransform(
|
||||
const AZ::Aabb& shapeBounds,
|
||||
const AZ::Matrix3x4& transform,
|
||||
bool use3d,
|
||||
float frequencyZoom,
|
||||
GradientSignal::WrappingType wrappingType);
|
||||
|
||||
/**
|
||||
* Checks to see if two GradientTransform instances are equivalent.
|
||||
* Useful for being able to send out notifications when a GradientTransform has changed.
|
||||
* \param rhs The second GradientTranform to compare against.
|
||||
* \return True if they're equal, False if they aren't.
|
||||
*/
|
||||
bool operator==(const GradientTransform& rhs) const
|
||||
{
|
||||
return (
|
||||
(m_shapeBounds == rhs.m_shapeBounds) &&
|
||||
(m_inverseTransform == rhs.m_inverseTransform) &&
|
||||
(m_alwaysAcceptPoint == rhs.m_alwaysAcceptPoint) &&
|
||||
(m_frequencyZoom == rhs.m_frequencyZoom) &&
|
||||
(m_wrappingType == rhs.m_wrappingType) &&
|
||||
(m_normalizeExtentsReciprocal == rhs.m_normalizeExtentsReciprocal));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if two GradientTransform instances aren't equivalent.
|
||||
* Useful for being able to send out notifications when a GradientTransform has changed.
|
||||
* \param rhs The second GradientTranform to compare against.
|
||||
* \return True if they're not equal, False if they are.
|
||||
*/
|
||||
bool operator!=(const GradientTransform& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transform the given world space position to a gradient space UVW lookup value.
|
||||
* \param inPosition The input world space position to transform.
|
||||
* \param outUVW [out] The UVW value that can be used to look up a deterministic gradient value.
|
||||
* \param wasPointRejected [out] True if the input position doesn't have a gradient value, false if it does.
|
||||
* Most gradients have values mapped to infinite world space, so wasPointRejected will almost always be false.
|
||||
* It will only be true when using ClampToZero and the world space position falls outside the shape bounds.
|
||||
*/
|
||||
void TransformPositionToUVW(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, bool& wasPointRejected) const;
|
||||
|
||||
/**
|
||||
* Transform the given world space position to a gradient space UVW lookup value and normalize to the shape bounds.
|
||||
* "Normalizing" in this context means that regardless of the world space coordinates, (0,0,0) represents the minimum
|
||||
* shape bounds corner, and (1,1,1) represents the maximum shape bounds corner. Depending on the wrapping type, it's possible
|
||||
* (and even likely) to get values outside the 0-1 range.
|
||||
* \param inPosition The input world space position to transform.
|
||||
* \param outUVW [out] The UVW value that can be used to look up a deterministic gradient value.
|
||||
* \param wasPointRejected [out] True if the input position doesn't have a gradient value, false if it does.
|
||||
* Most gradients have values mapped to infinite world space, so wasPointRejected will almost always be false.
|
||||
* It will only be true when using ClampToZero and the world space position falls outside the shape bounds.
|
||||
*/
|
||||
void TransformPositionToUVWNormalized(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, bool& wasPointRejected) const;
|
||||
|
||||
/**
|
||||
* Epsilon value to allow our UVW range to go to [min, max) by using the range [min, max - epsilon].
|
||||
* To keep things behaving consistently between clamped and unbounded uv ranges, we want our clamped uvs to use a
|
||||
* range of [min, max), so we'll actually clamp to [min, max - epsilon]. Since our floating-point numbers are likely in the
|
||||
* -16384 to 16384 range, an epsilon of 0.001 will work without rounding to 0.
|
||||
* (This constant is public so that it can be used from unit tests for validating transformation results)
|
||||
*/
|
||||
static constexpr float UvEpsilon = 0.001f;
|
||||
|
||||
private:
|
||||
|
||||
//! These are the various transformations that will be performed, based on wrapping type.
|
||||
static AZ::Vector3 NoTransform(const AZ::Vector3& point, const AZ::Aabb& bounds);
|
||||
static AZ::Vector3 GetUnboundedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
|
||||
static AZ::Vector3 GetClampedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
|
||||
static AZ::Vector3 GetMirroredPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
|
||||
static AZ::Vector3 GetRelativePointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
|
||||
static AZ::Vector3 GetWrappedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
|
||||
|
||||
//! The shape bounds are used for determining the wrapping bounds, and to normalize the UVW results into if requested.
|
||||
AZ::Aabb m_shapeBounds = AZ::Aabb::CreateNull();
|
||||
|
||||
/**
|
||||
* The relative transform to use for converting from world space to gradient space, stored as an inverse transform.
|
||||
* We only ever need to use the inverse transform, so we compute it once and store it instead of keeping the original
|
||||
* transform around. Note that the GradientTransformComponent has many options for choosing which relative space to use
|
||||
* for the transform, so the transform passed in to this class might already have many modifications applied to it.
|
||||
* The inverse transform will also get its 3rd row cleared out if "use3d" is false and we're only performing 2D gradient
|
||||
* transformations, so that the W component of the UVW output will always be 0.
|
||||
*/
|
||||
AZ::Matrix3x4 m_inverseTransform = AZ::Matrix3x4::CreateIdentity();
|
||||
|
||||
/**
|
||||
* Whether or not to always accept the input point as a valid output point.
|
||||
* Most of the time, the gradient exists everywhere in world space, so we always accept the input point.
|
||||
* The one exception is ClampToZero, which will return that the point is rejected if it falls outside the shape bounds.
|
||||
*/
|
||||
bool m_alwaysAcceptPoint = true;
|
||||
|
||||
//! Apply a scale to the point *after* the wrapping is applied.
|
||||
float m_frequencyZoom = 1.0f;
|
||||
|
||||
//! How the gradient should repeat itself outside of the shape bounds.
|
||||
WrappingType m_wrappingType = WrappingType::None;
|
||||
|
||||
/**
|
||||
* Cached reciprocal for performing an inverse lerp back to shape bounds.
|
||||
* When normalizing the output UVW back into the shape bounds, we perform an inverse lerp. The inverse lerp
|
||||
* equation is (point - min) * (1 / (max-min)), so we save off the (1 / (max-min)) term to avoid recalculating it on every point.
|
||||
*/
|
||||
AZ::Vector3 m_normalizeExtentsReciprocal = AZ::Vector3(1.0f);
|
||||
};
|
||||
|
||||
} // namespace GradientSignal
|
||||
@@ -35,6 +35,13 @@ namespace GradientSignal
|
||||
static bool VersionConverter(AZ::SerializeContext& context,
|
||||
AZ::SerializeContext::DataElementNode& classElement);
|
||||
|
||||
ImageAsset() = default;
|
||||
|
||||
ImageAsset(const AZ::Data::AssetId& assetId, AZ::Data::AssetData::AssetStatus status)
|
||||
: AssetData(assetId, status)
|
||||
{
|
||||
}
|
||||
|
||||
AZ::u32 m_imageWidth = 0;
|
||||
AZ::u32 m_imageHeight = 0;
|
||||
AZ::u8 m_bytesPerPixel = 0;
|
||||
|
||||
@@ -13,49 +13,10 @@
|
||||
#include <AzCore/Math/Matrix3x4.h>
|
||||
#include <AzCore/Math/Transform.h>
|
||||
#include <LmbrCentral/Shape/ShapeComponentBus.h>
|
||||
#include <GradientSignal/GradientTransform.h>
|
||||
|
||||
namespace GradientSignal
|
||||
{
|
||||
enum class WrappingType : AZ::u8
|
||||
{
|
||||
None = 0,
|
||||
ClampToEdge,
|
||||
Mirror,
|
||||
Repeat,
|
||||
ClampToZero,
|
||||
};
|
||||
|
||||
enum class TransformType : AZ::u8
|
||||
{
|
||||
World_ThisEntity = 0,
|
||||
Local_ThisEntity,
|
||||
World_ReferenceEntity,
|
||||
Local_ReferenceEntity,
|
||||
World_Origin,
|
||||
Relative,
|
||||
};
|
||||
|
||||
AZ::Vector3 GetUnboundedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
|
||||
AZ::Vector3 GetClampedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
|
||||
AZ::Vector3 GetMirroredPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
|
||||
AZ::Vector3 GetRelativePointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds);
|
||||
|
||||
inline AZ::Vector3 GetWrappedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds)
|
||||
{
|
||||
return AZ::Vector3(
|
||||
AZ::Wrap(point.GetX(), bounds.GetMin().GetX(), bounds.GetMax().GetX()),
|
||||
AZ::Wrap(point.GetY(), bounds.GetMin().GetY(), bounds.GetMax().GetY()),
|
||||
AZ::Wrap(point.GetZ(), bounds.GetMin().GetZ(), bounds.GetMax().GetZ()));
|
||||
}
|
||||
|
||||
inline AZ::Vector3 GetNormalizedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds)
|
||||
{
|
||||
return AZ::Vector3(
|
||||
AZ::LerpInverse(bounds.GetMin().GetX(), bounds.GetMax().GetX(), point.GetX()),
|
||||
AZ::LerpInverse(bounds.GetMin().GetY(), bounds.GetMax().GetY(), point.GetY()),
|
||||
AZ::LerpInverse(bounds.GetMin().GetZ(), bounds.GetMax().GetZ(), point.GetZ()));
|
||||
}
|
||||
|
||||
inline void GetObbParamsFromShape(const AZ::EntityId& entity, AZ::Aabb& bounds, AZ::Matrix3x4& worldToBoundsTransform)
|
||||
{
|
||||
//get bound and transform data for associated shape
|
||||
@@ -115,4 +76,5 @@ namespace GradientSignal
|
||||
|
||||
return AZ::Lerp(outputMin, outputMax, inputCorrected);
|
||||
}
|
||||
|
||||
} // namespace GradientSignal
|
||||
|
||||
@@ -276,24 +276,29 @@ namespace GradientSignal
|
||||
|
||||
void GradientTransformComponent::Activate()
|
||||
{
|
||||
m_dirty = false;
|
||||
m_gradientTransform = GradientTransform();
|
||||
|
||||
// Update our GradientTransform to be configured correctly. We don't need to notify dependents of the change though.
|
||||
// If anyone is listening, they're already getting notified below.
|
||||
const bool notifyDependentsOfChange = false;
|
||||
UpdateFromShape(notifyDependentsOfChange);
|
||||
|
||||
GradientTransformRequestBus::Handler::BusConnect(GetEntityId());
|
||||
LmbrCentral::DependencyNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
AZ::TickBus::Handler::BusConnect();
|
||||
GradientTransformModifierRequestBus::Handler::BusConnect(GetEntityId());
|
||||
|
||||
m_dirty = false;
|
||||
|
||||
m_dependencyMonitor.Reset();
|
||||
m_dependencyMonitor.ConnectOwner(GetEntityId());
|
||||
m_dependencyMonitor.ConnectDependency(GetEntityId());
|
||||
m_dependencyMonitor.ConnectDependency(GetShapeEntityId());
|
||||
|
||||
UpdateFromShape();
|
||||
}
|
||||
|
||||
void GradientTransformComponent::Deactivate()
|
||||
{
|
||||
m_dirty = false;
|
||||
m_gradientTransform = GradientTransform();
|
||||
|
||||
m_dependencyMonitor.Reset();
|
||||
GradientTransformRequestBus::Handler::BusDisconnect();
|
||||
@@ -322,66 +327,10 @@ namespace GradientSignal
|
||||
return false;
|
||||
}
|
||||
|
||||
void GradientTransformComponent::TransformPositionToUVW(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, const bool shouldNormalizeOutput, bool& wasPointRejected) const
|
||||
const GradientTransform& GradientTransformComponent::GetGradientTransform() const
|
||||
{
|
||||
AZStd::lock_guard<decltype(m_cacheMutex)> lock(m_cacheMutex);
|
||||
|
||||
//transforming coordinate into "local" relative space of shape bounds
|
||||
outUVW = m_shapeTransformInverse * inPosition;
|
||||
|
||||
if (!m_configuration.m_advancedMode || !m_configuration.m_is3d)
|
||||
{
|
||||
outUVW.SetZ(0.0f);
|
||||
}
|
||||
|
||||
wasPointRejected = false;
|
||||
if (m_shapeBounds.IsValid())
|
||||
{
|
||||
//all wrap types and transformations are applied after the coordinate is transformed into shape relative space
|
||||
//this allows all calculations to be simplified and done using the shapes untransformed aabb
|
||||
//outputting a value that can be used to sample a gradient in its local space
|
||||
switch (m_configuration.m_wrappingType)
|
||||
{
|
||||
default:
|
||||
case WrappingType::None:
|
||||
outUVW = GetUnboundedPointInAabb(outUVW, m_shapeBounds);
|
||||
break;
|
||||
case WrappingType::ClampToEdge:
|
||||
outUVW = GetClampedPointInAabb(outUVW, m_shapeBounds);
|
||||
break;
|
||||
case WrappingType::ClampToZero:
|
||||
// We don't want to use m_shapeBounds.Contains() here because Contains() is inclusive on all edges.
|
||||
// For uv consistency between clamped and unclamped states, we only want to accept uv ranges of [min, max),
|
||||
// so we specifically need to exclude the max edges here.
|
||||
wasPointRejected = !(outUVW.IsGreaterEqualThan(m_shapeBounds.GetMin()) && outUVW.IsLessThan(m_shapeBounds.GetMax()));
|
||||
outUVW = GetClampedPointInAabb(outUVW, m_shapeBounds);
|
||||
break;
|
||||
case WrappingType::Mirror:
|
||||
outUVW = GetMirroredPointInAabb(outUVW, m_shapeBounds);
|
||||
break;
|
||||
case WrappingType::Repeat:
|
||||
outUVW = GetWrappedPointInAabb(outUVW, m_shapeBounds);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
outUVW *= m_configuration.m_frequencyZoom;
|
||||
|
||||
if (shouldNormalizeOutput)
|
||||
{
|
||||
outUVW = GetNormalizedPointInAabb(outUVW, m_shapeBounds);
|
||||
}
|
||||
}
|
||||
|
||||
void GradientTransformComponent::GetGradientLocalBounds(AZ::Aabb& bounds) const
|
||||
{
|
||||
bounds = m_shapeBounds;
|
||||
}
|
||||
|
||||
void GradientTransformComponent::GetGradientEncompassingBounds(AZ::Aabb& bounds) const
|
||||
{
|
||||
bounds = m_shapeBounds;
|
||||
bounds.ApplyMatrix3x4(m_shapeTransformInverse.GetInverseFull());
|
||||
return m_gradientTransform;
|
||||
}
|
||||
|
||||
void GradientTransformComponent::OnCompositionChanged()
|
||||
@@ -393,25 +342,16 @@ namespace GradientSignal
|
||||
{
|
||||
if (m_dirty)
|
||||
{
|
||||
const auto configurationOld = m_configuration;
|
||||
const auto shapeBoundsOld = m_shapeBounds;
|
||||
const auto shapeTransformInverseOld = m_shapeTransformInverse;
|
||||
// Updating on tick to query transform bus on main thread.
|
||||
// Also, if the GradientTransform configuration changes, notify listeners so they can refresh themselves.
|
||||
const bool notifyDependentsOfChange = true;
|
||||
UpdateFromShape(notifyDependentsOfChange);
|
||||
|
||||
//updating on tick to query transform bus on main thread
|
||||
UpdateFromShape();
|
||||
|
||||
//notify observers if content has changed
|
||||
if (configurationOld != m_configuration ||
|
||||
shapeBoundsOld != m_shapeBounds ||
|
||||
shapeTransformInverseOld != m_shapeTransformInverse)
|
||||
{
|
||||
LmbrCentral::DependencyNotificationBus::Event(GetEntityId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
|
||||
}
|
||||
m_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void GradientTransformComponent::UpdateFromShape()
|
||||
void GradientTransformComponent::UpdateFromShape(bool notifyDependentsOfChange)
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
@@ -423,6 +363,10 @@ namespace GradientSignal
|
||||
return;
|
||||
}
|
||||
|
||||
const GradientTransform oldGradientTransform = m_gradientTransform;
|
||||
AZ::Aabb shapeBounds = AZ::Aabb::CreateNull();
|
||||
AZ::Matrix3x4 shapeTransformInverse = AZ::Matrix3x4::CreateIdentity();
|
||||
|
||||
AZ::Transform shapeTransform = AZ::Transform::CreateIdentity();
|
||||
switch (m_configuration.m_transformType)
|
||||
{
|
||||
@@ -466,10 +410,10 @@ namespace GradientSignal
|
||||
if (!m_configuration.m_advancedMode || !m_configuration.m_overrideBounds)
|
||||
{
|
||||
// If we have a shape reference, grab its local space bounds and (inverse) transform into that local space
|
||||
GetObbParamsFromShape(shapeReference, m_shapeBounds, m_shapeTransformInverse);
|
||||
if (m_shapeBounds.IsValid())
|
||||
GetObbParamsFromShape(shapeReference, shapeBounds, shapeTransformInverse);
|
||||
if (shapeBounds.IsValid())
|
||||
{
|
||||
m_configuration.m_bounds = m_shapeBounds.GetExtents();
|
||||
m_configuration.m_bounds = shapeBounds.GetExtents();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -491,14 +435,34 @@ namespace GradientSignal
|
||||
|
||||
//rebuild bounds from parameters
|
||||
m_configuration.m_bounds = m_configuration.m_bounds.GetAbs();
|
||||
m_shapeBounds = AZ::Aabb::CreateFromMinMax(-m_configuration.m_bounds * 0.5f, m_configuration.m_bounds * 0.5f);
|
||||
shapeBounds = AZ::Aabb::CreateFromMinMax(-m_configuration.m_bounds * 0.5f, m_configuration.m_bounds * 0.5f);
|
||||
|
||||
//rebuild transform from parameters
|
||||
AZ::Matrix3x4 shapeTransformFinal;
|
||||
shapeTransformFinal.SetFromEulerDegrees(m_configuration.m_rotate);
|
||||
shapeTransformFinal.SetTranslation(m_configuration.m_translate);
|
||||
shapeTransformFinal.MultiplyByScale(m_configuration.m_scale);
|
||||
m_shapeTransformInverse = shapeTransformFinal.GetInverseFull();
|
||||
shapeTransformInverse = shapeTransformFinal.GetInverseFull();
|
||||
|
||||
// Set everything up on the Gradient Transform
|
||||
const bool use3dGradients = m_configuration.m_advancedMode && m_configuration.m_is3d;
|
||||
m_gradientTransform = GradientTransform(
|
||||
shapeBounds, shapeTransformFinal, use3dGradients, m_configuration.m_frequencyZoom, m_configuration.m_wrappingType);
|
||||
|
||||
// If the transform has changed, send out notifications.
|
||||
if (oldGradientTransform != m_gradientTransform)
|
||||
{
|
||||
// Always notify on the GradientTransformNotificationBus.
|
||||
GradientTransformNotificationBus::Event(
|
||||
GetEntityId(), &GradientTransformNotificationBus::Events::OnGradientTransformChanged, m_gradientTransform);
|
||||
|
||||
// Only notify the DependencyNotificationBus when requested by the caller.
|
||||
if (notifyDependentsOfChange)
|
||||
{
|
||||
LmbrCentral::DependencyNotificationBus::Event(
|
||||
GetEntityId(), &LmbrCentral::DependencyNotificationBus::Events::OnCompositionChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AZ::EntityId GradientTransformComponent::GetShapeEntityId() const
|
||||
|
||||
@@ -101,9 +101,7 @@ namespace GradientSignal
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GradientTransformRequestBus
|
||||
void TransformPositionToUVW(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, const bool shouldNormalizeOutput, bool& wasPointRejected) const override;
|
||||
void GetGradientLocalBounds(AZ::Aabb& bounds) const override;
|
||||
void GetGradientEncompassingBounds(AZ::Aabb& bounds) const override;
|
||||
const GradientTransform& GetGradientTransform() const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// DependencyNotificationBus
|
||||
@@ -113,7 +111,7 @@ namespace GradientSignal
|
||||
// AZ::TickBus::Handler
|
||||
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
|
||||
|
||||
void UpdateFromShape();
|
||||
void UpdateFromShape(bool notifyDependentsOfChange);
|
||||
|
||||
AZ::EntityId GetShapeEntityId() const;
|
||||
|
||||
@@ -168,9 +166,8 @@ namespace GradientSignal
|
||||
private:
|
||||
mutable AZStd::recursive_mutex m_cacheMutex;
|
||||
GradientTransformConfig m_configuration;
|
||||
AZ::Aabb m_shapeBounds = AZ::Aabb::CreateNull();
|
||||
AZ::Matrix3x4 m_shapeTransformInverse = AZ::Matrix3x4::CreateIdentity();
|
||||
LmbrCentral::DependencyMonitor m_dependencyMonitor;
|
||||
AZStd::atomic_bool m_dirty{ false };
|
||||
GradientTransform m_gradientTransform;
|
||||
};
|
||||
} //namespace GradientSignal
|
||||
|
||||
@@ -129,6 +129,9 @@ namespace GradientSignal
|
||||
|
||||
void ImageGradientComponent::Activate()
|
||||
{
|
||||
// This will immediately call OnGradientTransformChanged and initialize m_gradientTransform.
|
||||
GradientTransformNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
|
||||
SetupDependencies();
|
||||
|
||||
ImageGradientRequestBus::Handler::BusConnect(GetEntityId());
|
||||
@@ -144,6 +147,7 @@ namespace GradientSignal
|
||||
AZ::Data::AssetBus::Handler::BusDisconnect();
|
||||
GradientRequestBus::Handler::BusDisconnect();
|
||||
ImageGradientRequestBus::Handler::BusDisconnect();
|
||||
GradientTransformNotificationBus::Handler::BusDisconnect();
|
||||
|
||||
m_dependencyMonitor.Reset();
|
||||
|
||||
@@ -189,19 +193,27 @@ namespace GradientSignal
|
||||
m_configuration.m_imageAsset = asset;
|
||||
}
|
||||
|
||||
void ImageGradientComponent::OnGradientTransformChanged(const GradientTransform& newTransform)
|
||||
{
|
||||
AZStd::unique_lock<decltype(m_imageMutex)> lock(m_imageMutex);
|
||||
m_gradientTransform = newTransform;
|
||||
}
|
||||
|
||||
float ImageGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
|
||||
{
|
||||
AZ::Vector3 uvw = sampleParams.m_position;
|
||||
|
||||
bool wasPointRejected = false;
|
||||
const bool shouldNormalizeOutput = true;
|
||||
GradientTransformRequestBus::Event(
|
||||
GetEntityId(), &GradientTransformRequestBus::Events::TransformPositionToUVW, sampleParams.m_position, uvw, shouldNormalizeOutput, wasPointRejected);
|
||||
|
||||
if (!wasPointRejected)
|
||||
{
|
||||
AZStd::shared_lock<decltype(m_imageMutex)> imageLock(m_imageMutex);
|
||||
return GetValueFromImageAsset(m_configuration.m_imageAsset, uvw, m_configuration.m_tilingX, m_configuration.m_tilingY, 0.0f);
|
||||
|
||||
m_gradientTransform.TransformPositionToUVWNormalized(sampleParams.m_position, uvw, wasPointRejected);
|
||||
|
||||
if (!wasPointRejected)
|
||||
{
|
||||
return GetValueFromImageAsset(
|
||||
m_configuration.m_imageAsset, uvw, m_configuration.m_tilingX, m_configuration.m_tilingY, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
return 0.0f;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <AzCore/Asset/AssetCommon.h>
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/ImageGradientRequestBus.h>
|
||||
#include <GradientSignal/ImageAsset.h>
|
||||
#include <GradientSignal/Util.h>
|
||||
@@ -46,6 +47,7 @@ namespace GradientSignal
|
||||
, private AZ::Data::AssetBus::Handler
|
||||
, private GradientRequestBus::Handler
|
||||
, private ImageGradientRequestBus::Handler
|
||||
, private GradientTransformNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
template<typename, typename> friend class LmbrCentral::EditorWrappedComponentBase;
|
||||
@@ -59,29 +61,27 @@ namespace GradientSignal
|
||||
ImageGradientComponent() = default;
|
||||
~ImageGradientComponent() = default;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component interface implementation
|
||||
// AZ::Component overrides...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GradientRequestBus
|
||||
// GradientRequestBus overrides...
|
||||
float GetValue(const GradientSampleParams& sampleParams) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Data::AssetBus::Handler
|
||||
// AZ::Data::AssetBus overrides...
|
||||
void OnAssetReady(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
void OnAssetMoved(AZ::Data::Asset<AZ::Data::AssetData> asset, void* oldDataPointer) override;
|
||||
void OnAssetReloaded(AZ::Data::Asset<AZ::Data::AssetData> asset) override;
|
||||
|
||||
protected:
|
||||
// GradientTransformNotificationBus overrides...
|
||||
void OnGradientTransformChanged(const GradientTransform& newTransform) override;
|
||||
|
||||
void SetupDependencies();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// ImageGradientRequestBus
|
||||
// ImageGradientRequestBus overrides...
|
||||
AZStd::string GetImageAssetPath() const override;
|
||||
void SetImageAssetPath(const AZStd::string& assetPath) override;
|
||||
|
||||
@@ -95,5 +95,6 @@ namespace GradientSignal
|
||||
ImageGradientConfig m_configuration;
|
||||
LmbrCentral::DependencyMonitor m_dependencyMonitor;
|
||||
mutable AZStd::shared_mutex m_imageMutex;
|
||||
GradientTransform m_gradientTransform;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,6 +138,9 @@ namespace GradientSignal
|
||||
|
||||
void PerlinGradientComponent::Activate()
|
||||
{
|
||||
// This will immediately call OnGradientTransformChanged and initialize m_gradientTransform.
|
||||
GradientTransformNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
|
||||
m_perlinImprovedNoise.reset(aznew PerlinImprovedNoise(AZ::GetMax(m_configuration.m_randomSeed, 1)));
|
||||
GradientRequestBus::Handler::BusConnect(GetEntityId());
|
||||
PerlinGradientRequestBus::Handler::BusConnect(GetEntityId());
|
||||
@@ -148,6 +151,7 @@ namespace GradientSignal
|
||||
m_perlinImprovedNoise.reset();
|
||||
GradientRequestBus::Handler::BusDisconnect();
|
||||
PerlinGradientRequestBus::Handler::BusDisconnect();
|
||||
GradientTransformNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
bool PerlinGradientComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
|
||||
@@ -170,22 +174,29 @@ namespace GradientSignal
|
||||
return false;
|
||||
}
|
||||
|
||||
void PerlinGradientComponent::OnGradientTransformChanged(const GradientTransform& newTransform)
|
||||
{
|
||||
AZStd::unique_lock<decltype(m_transformMutex)> lock(m_transformMutex);
|
||||
m_gradientTransform = newTransform;
|
||||
}
|
||||
|
||||
float PerlinGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
if (m_perlinImprovedNoise)
|
||||
{
|
||||
AZ::Vector3 uvw = sampleParams.m_position;
|
||||
|
||||
bool wasPointRejected = false;
|
||||
const bool shouldNormalizeOutput = false;
|
||||
GradientTransformRequestBus::Event(
|
||||
GetEntityId(), &GradientTransformRequestBus::Events::TransformPositionToUVW, sampleParams.m_position, uvw, shouldNormalizeOutput, wasPointRejected);
|
||||
|
||||
{
|
||||
AZStd::shared_lock<decltype(m_transformMutex)> lock(m_transformMutex);
|
||||
m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected);
|
||||
}
|
||||
|
||||
if (!wasPointRejected)
|
||||
{
|
||||
return m_perlinImprovedNoise->GenerateOctaveNoise(uvw.GetX(), uvw.GetY(), uvw.GetZ(), m_configuration.m_octave, m_configuration.m_amplitude, m_configuration.m_frequency);
|
||||
return m_perlinImprovedNoise->GenerateOctaveNoise(
|
||||
uvw.GetX(), uvw.GetY(), uvw.GetZ(), m_configuration.m_octave, m_configuration.m_amplitude,
|
||||
m_configuration.m_frequency);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <AzCore/Component/ComponentBus.h>
|
||||
#include <AzCore/std/smart_ptr/unique_ptr.h>
|
||||
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/PerlinGradientRequestBus.h>
|
||||
#include <GradientSignal/PerlinImprovedNoise.h>
|
||||
|
||||
@@ -47,6 +48,7 @@ namespace GradientSignal
|
||||
: public AZ::Component
|
||||
, private GradientRequestBus::Handler
|
||||
, private PerlinGradientRequestBus::Handler
|
||||
, private GradientTransformNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
template<typename, typename> friend class LmbrCentral::EditorWrappedComponentBase;
|
||||
@@ -60,23 +62,25 @@ namespace GradientSignal
|
||||
PerlinGradientComponent() = default;
|
||||
~PerlinGradientComponent() = default;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component interface implementation
|
||||
// AZ::Component overrides...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GradientRequestBus
|
||||
// GradientRequestBus overrides...
|
||||
float GetValue(const GradientSampleParams& sampleParams) const override;
|
||||
|
||||
private:
|
||||
PerlinGradientConfig m_configuration;
|
||||
AZStd::unique_ptr<PerlinImprovedNoise> m_perlinImprovedNoise;
|
||||
GradientTransform m_gradientTransform;
|
||||
mutable AZStd::shared_mutex m_transformMutex;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//PerlinGradientRequest overrides
|
||||
// GradientTransformNotificationBus overrides...
|
||||
void OnGradientTransformChanged(const GradientTransform& newTransform) override;
|
||||
|
||||
// PerlinGradientRequestBus overrides...
|
||||
int GetRandomSeed() const override;
|
||||
void SetRandomSeed(int seed) override;
|
||||
|
||||
|
||||
@@ -105,6 +105,9 @@ namespace GradientSignal
|
||||
|
||||
void RandomGradientComponent::Activate()
|
||||
{
|
||||
// This will immediately call OnGradientTransformChanged and initialize m_gradientTransform.
|
||||
GradientTransformNotificationBus::Handler::BusConnect(GetEntityId());
|
||||
|
||||
GradientRequestBus::Handler::BusConnect(GetEntityId());
|
||||
RandomGradientRequestBus::Handler::BusConnect(GetEntityId());
|
||||
}
|
||||
@@ -113,6 +116,7 @@ namespace GradientSignal
|
||||
{
|
||||
GradientRequestBus::Handler::BusDisconnect();
|
||||
RandomGradientRequestBus::Handler::BusDisconnect();
|
||||
GradientTransformNotificationBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
bool RandomGradientComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
|
||||
@@ -135,16 +139,22 @@ namespace GradientSignal
|
||||
return false;
|
||||
}
|
||||
|
||||
void RandomGradientComponent::OnGradientTransformChanged(const GradientTransform& newTransform)
|
||||
{
|
||||
AZStd::unique_lock<decltype(m_transformMutex)> lock(m_transformMutex);
|
||||
m_gradientTransform = newTransform;
|
||||
}
|
||||
|
||||
float RandomGradientComponent::GetValue(const GradientSampleParams& sampleParams) const
|
||||
{
|
||||
AZ_PROFILE_FUNCTION(Entity);
|
||||
|
||||
AZ::Vector3 uvw = sampleParams.m_position;
|
||||
|
||||
bool wasPointRejected = false;
|
||||
const bool shouldNormalizeOutput = false;
|
||||
GradientTransformRequestBus::Event(
|
||||
GetEntityId(), &GradientTransformRequestBus::Events::TransformPositionToUVW, sampleParams.m_position, uvw, shouldNormalizeOutput, wasPointRejected);
|
||||
|
||||
{
|
||||
AZStd::shared_lock<decltype(m_transformMutex)> lock(m_transformMutex);
|
||||
m_gradientTransform.TransformPositionToUVW(sampleParams.m_position, uvw, wasPointRejected);
|
||||
}
|
||||
|
||||
if (!wasPointRejected)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <AzCore/Component/Component.h>
|
||||
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/GradientTransformRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/RandomGradientRequestBus.h>
|
||||
|
||||
namespace LmbrCentral
|
||||
@@ -38,6 +39,7 @@ namespace GradientSignal
|
||||
: public AZ::Component
|
||||
, private GradientRequestBus::Handler
|
||||
, private RandomGradientRequestBus::Handler
|
||||
, private GradientTransformNotificationBus::Handler
|
||||
{
|
||||
public:
|
||||
template<typename, typename> friend class LmbrCentral::EditorWrappedComponentBase;
|
||||
@@ -51,22 +53,24 @@ namespace GradientSignal
|
||||
RandomGradientComponent() = default;
|
||||
~RandomGradientComponent() = default;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// AZ::Component interface implementation
|
||||
// AZ::Component overrides...
|
||||
void Activate() override;
|
||||
void Deactivate() override;
|
||||
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
|
||||
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// GradientRequestBus
|
||||
// GradientRequestBus overrides...
|
||||
float GetValue(const GradientSampleParams& sampleParams) const override;
|
||||
|
||||
private:
|
||||
RandomGradientConfig m_configuration;
|
||||
GradientTransform m_gradientTransform;
|
||||
mutable AZStd::shared_mutex m_transformMutex;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// RandomGradientRequest overrides
|
||||
// GradientTransformNotificationBus overrides...
|
||||
void OnGradientTransformChanged(const GradientTransform& newTransform) override;
|
||||
|
||||
// RandomGradientRequestBus overrides...
|
||||
int GetRandomSeed() const override;
|
||||
void SetRandomSeed(int seed) override;
|
||||
};
|
||||
|
||||
@@ -55,9 +55,13 @@ namespace GradientSignal
|
||||
|
||||
void EditorGradientTransformComponent::UpdateFromShape()
|
||||
{
|
||||
// Update config from shape on game component, copy that back to our config
|
||||
m_component.UpdateFromShape();
|
||||
m_component.WriteOutConfig(&m_configuration);
|
||||
SetDirty();
|
||||
if (m_runtimeComponentActive)
|
||||
{
|
||||
// Update config from shape on game component, copy that back to our config.
|
||||
bool notifyDependentsOfChange = true;
|
||||
m_component.UpdateFromShape(notifyDependentsOfChange);
|
||||
m_component.WriteOutConfig(&m_configuration);
|
||||
SetDirty();
|
||||
}
|
||||
}
|
||||
} //namespace GradientSignal
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) Contributors to the Open 3D Engine Project.
|
||||
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include <GradientSignal/GradientTransform.h>
|
||||
|
||||
|
||||
namespace GradientSignal
|
||||
{
|
||||
GradientTransform::GradientTransform(
|
||||
const AZ::Aabb& shapeBounds, const AZ::Matrix3x4& transform, bool use3d,
|
||||
float frequencyZoom, GradientSignal::WrappingType wrappingType)
|
||||
: m_shapeBounds(shapeBounds)
|
||||
, m_inverseTransform(transform.GetInverseFull())
|
||||
, m_frequencyZoom(frequencyZoom)
|
||||
, m_wrappingType(wrappingType)
|
||||
, m_alwaysAcceptPoint(true)
|
||||
{
|
||||
// If we want this to be a 2D gradient lookup, we always want to set the W result in the output to 0.
|
||||
// The easiest / cheapest way to make this happen is just to clear out the third row in the inverseTransform.
|
||||
if (!use3d)
|
||||
{
|
||||
m_inverseTransform.SetRow(2, AZ::Vector4::CreateZero());
|
||||
}
|
||||
|
||||
// If we have invalid shape bounds, reset the wrapping type back to None. Wrapping won't work without valid bounds.
|
||||
if (!m_shapeBounds.IsValid())
|
||||
{
|
||||
m_wrappingType = WrappingType::None;
|
||||
}
|
||||
|
||||
// ClampToZero is the only wrapping type that allows us to return a "pointIsRejected" result for points that fall
|
||||
// outside the shape bounds.
|
||||
if (m_wrappingType == WrappingType::ClampToZero)
|
||||
{
|
||||
m_alwaysAcceptPoint = false;
|
||||
}
|
||||
|
||||
m_normalizeExtentsReciprocal = AZ::Vector3(
|
||||
AZ::IsClose(0.0f, m_shapeBounds.GetXExtent()) ? 0.0f : (1.0f / m_shapeBounds.GetXExtent()),
|
||||
AZ::IsClose(0.0f, m_shapeBounds.GetYExtent()) ? 0.0f : (1.0f / m_shapeBounds.GetYExtent()),
|
||||
AZ::IsClose(0.0f, m_shapeBounds.GetZExtent()) ? 0.0f : (1.0f / m_shapeBounds.GetZExtent()));
|
||||
}
|
||||
|
||||
void GradientTransform::TransformPositionToUVW(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, bool& wasPointRejected) const
|
||||
{
|
||||
// Transform coordinate into "local" relative space of shape bounds, and set W to 0 if this is a 2D gradient.
|
||||
outUVW = m_inverseTransform * inPosition;
|
||||
|
||||
// For most wrapping types, we always accept the point, but for ClampToZero we only accept it if it's within
|
||||
// the shape bounds. We don't use m_shapeBounds.Contains() here because Contains() is inclusive on all edges.
|
||||
// For uv consistency between clamped and unclamped states, we only want to accept uv ranges of [min, max),
|
||||
// so we specifically need to exclude the max edges here.
|
||||
bool wasPointAccepted = m_alwaysAcceptPoint ||
|
||||
(outUVW.IsGreaterEqualThan(m_shapeBounds.GetMin()) && outUVW.IsLessThan(m_shapeBounds.GetMax()));
|
||||
wasPointRejected = !wasPointAccepted;
|
||||
|
||||
switch (m_wrappingType)
|
||||
{
|
||||
default:
|
||||
case WrappingType::None:
|
||||
outUVW = GetUnboundedPointInAabb(outUVW, m_shapeBounds);
|
||||
break;
|
||||
case WrappingType::ClampToEdge:
|
||||
outUVW = GetClampedPointInAabb(outUVW, m_shapeBounds);
|
||||
break;
|
||||
case WrappingType::ClampToZero:
|
||||
outUVW = GetClampedPointInAabb(outUVW, m_shapeBounds);
|
||||
break;
|
||||
case WrappingType::Mirror:
|
||||
outUVW = GetMirroredPointInAabb(outUVW, m_shapeBounds);
|
||||
break;
|
||||
case WrappingType::Repeat:
|
||||
outUVW = GetWrappedPointInAabb(outUVW, m_shapeBounds);
|
||||
break;
|
||||
}
|
||||
|
||||
outUVW *= m_frequencyZoom;
|
||||
}
|
||||
|
||||
void GradientTransform::TransformPositionToUVWNormalized(const AZ::Vector3& inPosition, AZ::Vector3& outUVW, bool& wasPointRejected) const
|
||||
{
|
||||
TransformPositionToUVW(inPosition, outUVW, wasPointRejected);
|
||||
|
||||
// This effectively does AZ::LerpInverse(bounds.GetMin(), bounds.GetMax(), point) if shouldNormalize is true,
|
||||
// and just returns outUVW if shouldNormalize is false.
|
||||
outUVW = m_normalizeExtentsReciprocal * (outUVW - m_shapeBounds.GetMin());
|
||||
}
|
||||
|
||||
AZ::Vector3 GradientTransform::NoTransform(const AZ::Vector3& point, const AZ::Aabb& /*bounds*/)
|
||||
{
|
||||
return point;
|
||||
}
|
||||
|
||||
AZ::Vector3 GradientTransform::GetUnboundedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& /*bounds*/)
|
||||
{
|
||||
return point;
|
||||
}
|
||||
|
||||
AZ::Vector3 GradientTransform::GetClampedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds)
|
||||
{
|
||||
// We want the clamped sampling states to clamp uvs to the [min, max) range.
|
||||
return point.GetClamp(bounds.GetMin(), bounds.GetMax() - AZ::Vector3(UvEpsilon));
|
||||
}
|
||||
|
||||
AZ::Vector3 GradientTransform::GetWrappedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds)
|
||||
{
|
||||
return AZ::Vector3(
|
||||
AZ::Wrap(point.GetX(), bounds.GetMin().GetX(), bounds.GetMax().GetX()),
|
||||
AZ::Wrap(point.GetY(), bounds.GetMin().GetY(), bounds.GetMax().GetY()),
|
||||
AZ::Wrap(point.GetZ(), bounds.GetMin().GetZ(), bounds.GetMax().GetZ()));
|
||||
}
|
||||
|
||||
AZ::Vector3 GradientTransform::GetMirroredPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds)
|
||||
{
|
||||
/* For mirroring, we want to produce the following pattern:
|
||||
* [min, max) : value
|
||||
* [max, min) : max - value - epsilon
|
||||
* [min, max) : value
|
||||
* [max, min) : max - value - epsilon
|
||||
* ...
|
||||
* The epsilon is because we always want to keep our output values in the [min, max) range. We apply the epsilon to all
|
||||
* the mirrored values so that we get consistent spacing between the values.
|
||||
*/
|
||||
|
||||
auto GetMirror = [](float value, float min, float max) -> float
|
||||
{
|
||||
// To calculate the mirror value, we move our value into relative space of [0, rangeX2), then use
|
||||
// the first half of the range for our "[min, max)" range, and the second half for our "[max, min)" mirrored range.
|
||||
|
||||
float relativeValue = value - min;
|
||||
float range = max - min;
|
||||
float rangeX2 = range * 2.0f;
|
||||
|
||||
// A positive relativeValue will produce a value of [0, rangeX2) from a single mod, but a negative relativeValue
|
||||
// will produce a value of (-rangeX2, 0]. Adding rangeX2 to the result and taking the mod again puts us back in
|
||||
// the range of [0, rangeX2) for both negative and positive values. This keeps our mirroring pattern consistent and
|
||||
// unbroken across both negative and positive coordinate space.
|
||||
relativeValue = AZ::Mod(AZ::Mod(relativeValue, rangeX2) + rangeX2, rangeX2);
|
||||
|
||||
// [range, rangeX2) is our mirrored range, so flip the value when we're in this range and apply the epsilon so that
|
||||
// we never return the max value, and so that our mirrored values have consistent spacing in the results.
|
||||
if (relativeValue >= range)
|
||||
{
|
||||
relativeValue = rangeX2 - (relativeValue + UvEpsilon);
|
||||
}
|
||||
|
||||
return relativeValue + min;
|
||||
};
|
||||
|
||||
return AZ::Vector3(
|
||||
GetMirror(point.GetX(), bounds.GetMin().GetX(), bounds.GetMax().GetX()),
|
||||
GetMirror(point.GetY(), bounds.GetMin().GetY(), bounds.GetMax().GetY()),
|
||||
GetMirror(point.GetZ(), bounds.GetMin().GetZ(), bounds.GetMax().GetZ()));
|
||||
}
|
||||
|
||||
AZ::Vector3 GradientTransform::GetRelativePointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds)
|
||||
{
|
||||
return point - bounds.GetMin();
|
||||
}
|
||||
}
|
||||
@@ -1,77 +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 <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Debug/Profiler.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include <LmbrCentral/Shape/ShapeComponentBus.h>
|
||||
#include <GradientSignal/Util.h>
|
||||
|
||||
|
||||
namespace GradientSignal
|
||||
{
|
||||
// To keep things behaving consistently between clamped and unbounded uv ranges, we
|
||||
// we want our clamped uvs to use a range of [min, max), so we'll actually clamp to
|
||||
// [min, max - epsilon]. Since our floating-point numbers are likely in the
|
||||
// -16384 to 16384 range, an epsilon of 0.001 will work without rounding to 0.
|
||||
static const float uvEpsilon = 0.001f;
|
||||
|
||||
AZ::Vector3 GetUnboundedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& /*bounds*/)
|
||||
{
|
||||
return point;
|
||||
}
|
||||
|
||||
AZ::Vector3 GetClampedPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds)
|
||||
{
|
||||
// We want the clamped sampling states to clamp uvs to the [min, max) range.
|
||||
return AZ::Vector3(
|
||||
AZ::GetClamp(point.GetX(), bounds.GetMin().GetX(), bounds.GetMax().GetX() - uvEpsilon),
|
||||
AZ::GetClamp(point.GetY(), bounds.GetMin().GetY(), bounds.GetMax().GetY() - uvEpsilon),
|
||||
AZ::GetClamp(point.GetZ(), bounds.GetMin().GetZ(), bounds.GetMax().GetZ() - uvEpsilon));
|
||||
}
|
||||
|
||||
float GetMirror(float value, float min, float max)
|
||||
{
|
||||
float relativeValue = value - min;
|
||||
float range = max - min;
|
||||
float rangeX2 = range * 2.0f;
|
||||
if (relativeValue < 0.0)
|
||||
{
|
||||
relativeValue = rangeX2 - fmod(-relativeValue, rangeX2);
|
||||
}
|
||||
else
|
||||
{
|
||||
relativeValue = fmod(relativeValue, rangeX2);
|
||||
}
|
||||
if (relativeValue >= range)
|
||||
{
|
||||
// Since we want our uv range to stay in the [min, max) range,
|
||||
// it means that for mirroring, we want both the "forward" values
|
||||
// and the "mirrored" values to be in [0, range). We don't want
|
||||
// relativeValue == range, so we shift relativeValue by a small epsilon
|
||||
// in the mirrored case.
|
||||
relativeValue = rangeX2 - (relativeValue + uvEpsilon);
|
||||
}
|
||||
|
||||
return relativeValue + min;
|
||||
}
|
||||
|
||||
AZ::Vector3 GetMirroredPointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds)
|
||||
{
|
||||
return AZ::Vector3(
|
||||
GetMirror(point.GetX(), bounds.GetMin().GetX(), bounds.GetMax().GetX()),
|
||||
GetMirror(point.GetY(), bounds.GetMin().GetY(), bounds.GetMax().GetY()),
|
||||
GetMirror(point.GetZ(), bounds.GetMin().GetZ(), bounds.GetMax().GetZ()));
|
||||
}
|
||||
|
||||
AZ::Vector3 GetRelativePointInAabb(const AZ::Vector3& point, const AZ::Aabb& bounds)
|
||||
{
|
||||
return point - bounds.GetMin();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
#include <GradientSignal/Editor/EditorGradientPreviewRenderer.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
@@ -28,7 +28,6 @@ namespace UnitTest
|
||||
void SetUp() override
|
||||
{
|
||||
GradientSignalTest::SetUp();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
|
||||
// Set up job manager with two threads so that we can run and test the preview job logic.
|
||||
AZ::JobManagerDesc desc;
|
||||
@@ -46,7 +45,6 @@ namespace UnitTest
|
||||
delete m_jobContext;
|
||||
delete m_jobManager;
|
||||
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
|
||||
GradientSignalTest::TearDown();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef HAVE_BENCHMARK
|
||||
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/Memory/PoolAllocator.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
#include <AzFramework/Asset/AssetCatalogBus.h>
|
||||
|
||||
#include <Source/Components/ImageGradientComponent.h>
|
||||
#include <Source/Components/PerlinGradientComponent.h>
|
||||
#include <Source/Components/RandomGradientComponent.h>
|
||||
#include <Source/Components/GradientTransformComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_ImageGradientGetValue)(benchmark::State& state)
|
||||
{
|
||||
// Create the Image Gradient Component with some default sizes and parameters.
|
||||
GradientSignal::ImageGradientConfig config;
|
||||
const uint32_t imageSize = 4096;
|
||||
const int32_t imageSeed = 12345;
|
||||
config.m_imageAsset = ImageAssetMockAssetHandler::CreateImageAsset(imageSize, imageSize, imageSeed);
|
||||
config.m_tilingX = 1.0f;
|
||||
config.m_tilingY = 1.0f;
|
||||
CreateComponent<GradientSignal::ImageGradientComponent>(m_testEntity.get(), config);
|
||||
|
||||
// Create the Gradient Transform Component with some default parameters.
|
||||
GradientSignal::GradientTransformConfig gradientTransformConfig;
|
||||
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
|
||||
CreateComponent<GradientSignal::GradientTransformComponent>(m_testEntity.get(), gradientTransformConfig);
|
||||
|
||||
// Run the benchmark
|
||||
RunGetValueBenchmark(state);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_ImageGradientGetValue)
|
||||
->Args({ 1024, 1024 })
|
||||
->Args({ 2048, 2048 })
|
||||
->Args({ 4096, 4096 })
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_PerlinGradientGetValue)(benchmark::State& state)
|
||||
{
|
||||
// Create the Perlin Gradient Component with some default sizes and parameters.
|
||||
GradientSignal::PerlinGradientConfig config;
|
||||
config.m_amplitude = 1.0f;
|
||||
config.m_frequency = 1.1f;
|
||||
config.m_octave = 4;
|
||||
config.m_randomSeed = 12345;
|
||||
CreateComponent<GradientSignal::PerlinGradientComponent>(m_testEntity.get(), config);
|
||||
|
||||
// Create the Gradient Transform Component with some default parameters.
|
||||
GradientSignal::GradientTransformConfig gradientTransformConfig;
|
||||
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
|
||||
CreateComponent<GradientSignal::GradientTransformComponent>(m_testEntity.get(), gradientTransformConfig);
|
||||
|
||||
// Run the benchmark
|
||||
RunGetValueBenchmark(state);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_PerlinGradientGetValue)
|
||||
->Args({ 1024, 1024 })
|
||||
->Args({ 2048, 2048 })
|
||||
->Args({ 4096, 4096 })
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
|
||||
BENCHMARK_DEFINE_F(GradientSignalBenchmarkFixture, BM_RandomGradientGetValue)(benchmark::State& state)
|
||||
{
|
||||
// Create the Random Gradient Component with some default parameters.
|
||||
GradientSignal::RandomGradientConfig config;
|
||||
config.m_randomSeed = 12345;
|
||||
CreateComponent<GradientSignal::RandomGradientComponent>(m_testEntity.get(), config);
|
||||
|
||||
// Create the Gradient Transform Component with some default parameters.
|
||||
GradientSignal::GradientTransformConfig gradientTransformConfig;
|
||||
gradientTransformConfig.m_wrappingType = GradientSignal::WrappingType::None;
|
||||
CreateComponent<GradientSignal::GradientTransformComponent>(m_testEntity.get(), gradientTransformConfig);
|
||||
|
||||
// Run the benchmark
|
||||
RunGetValueBenchmark(state);
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(GradientSignalBenchmarkFixture, BM_RandomGradientGetValue)
|
||||
->Args({ 1024, 1024 })
|
||||
->Args({ 2048, 2048 })
|
||||
->Args({ 4096, 4096 })
|
||||
->Unit(::benchmark::kMillisecond);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
@@ -23,69 +23,6 @@ namespace UnitTest
|
||||
struct GradientSignalImageTestsFixture
|
||||
: public GradientSignalTest
|
||||
{
|
||||
struct MockAssetHandler
|
||||
: public AZ::Data::AssetHandler
|
||||
{
|
||||
AZ::Data::AssetPtr CreateAsset([[maybe_unused]] const AZ::Data::AssetId& id, [[maybe_unused]] const AZ::Data::AssetType& type) override
|
||||
{
|
||||
return AZ::Data::AssetPtr();
|
||||
}
|
||||
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GetHandledAssetTypes([[maybe_unused]] AZStd::vector<AZ::Data::AssetType>& assetTypes) override
|
||||
{
|
||||
}
|
||||
|
||||
AZ::Data::AssetHandler::LoadResult LoadAssetData(
|
||||
[[maybe_unused]] const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
[[maybe_unused]] AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
[[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB) override
|
||||
{
|
||||
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
MockAssetHandler* m_mockHandler = nullptr;
|
||||
GradientSignal::ImageAsset* m_imageData = nullptr;
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
GradientSignalTest::SetUp();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
AZ::Data::AssetManager::Descriptor desc;
|
||||
AZ::Data::AssetManager::Create(desc);
|
||||
m_mockHandler = new MockAssetHandler();
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(m_mockHandler, azrtti_typeid<GradientSignal::ImageAsset>());
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
AZ::Data::AssetManager::Instance().UnregisterHandler(m_mockHandler);
|
||||
delete m_mockHandler; // delete after removing from the asset manager
|
||||
AzFramework::LegacyAssetEventBus::ClearQueuedEvents();
|
||||
AZ::Data::AssetManager::Destroy();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
|
||||
GradientSignalTest::TearDown();
|
||||
}
|
||||
|
||||
struct AssignIdToAsset
|
||||
: public AZ::Data::AssetData
|
||||
{
|
||||
void MakeReady()
|
||||
{
|
||||
m_assetId = AZ::Data::AssetId(AZ::Uuid::CreateRandom());
|
||||
m_status.store(AZ::Data::AssetData::AssetStatus::Ready);
|
||||
}
|
||||
};
|
||||
|
||||
struct PixelTestSetup
|
||||
{
|
||||
// How to create the source image
|
||||
@@ -105,61 +42,6 @@ namespace UnitTest
|
||||
static const AZ::Vector2 EndOfList;
|
||||
};
|
||||
|
||||
AZ::Data::Asset<GradientSignal::ImageAsset> CreateImageAsset(AZ::u32 width, AZ::u32 height, AZ::s32 seed)
|
||||
{
|
||||
m_imageData = aznew GradientSignal::ImageAsset();
|
||||
m_imageData->m_imageWidth = width;
|
||||
m_imageData->m_imageHeight = height;
|
||||
m_imageData->m_bytesPerPixel = 1;
|
||||
m_imageData->m_imageFormat = ImageProcessingAtom::EPixelFormat::ePixelFormat_R8;
|
||||
|
||||
size_t value = 0;
|
||||
AZStd::hash_combine(value, seed);
|
||||
|
||||
for (AZ::u32 x = 0; x < width; ++x)
|
||||
{
|
||||
for (AZ::u32 y = 0; y < height; ++y)
|
||||
{
|
||||
AZStd::hash_combine(value, x);
|
||||
AZStd::hash_combine(value, y);
|
||||
m_imageData->m_imageData.push_back(static_cast<AZ::u8>(value));
|
||||
}
|
||||
}
|
||||
|
||||
reinterpret_cast<AssignIdToAsset*>(m_imageData)->MakeReady();
|
||||
return AZ::Data::Asset<GradientSignal::ImageAsset>(m_imageData, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
|
||||
AZ::Data::Asset<GradientSignal::ImageAsset> CreateSpecificPixelImageAsset(AZ::u32 width, AZ::u32 height, AZ::u32 pixelX, AZ::u32 pixelY)
|
||||
{
|
||||
m_imageData = aznew GradientSignal::ImageAsset();
|
||||
m_imageData->m_imageWidth = width;
|
||||
m_imageData->m_imageHeight = height;
|
||||
m_imageData->m_bytesPerPixel = 1;
|
||||
m_imageData->m_imageFormat = ImageProcessingAtom::EPixelFormat::ePixelFormat_R8;
|
||||
|
||||
const AZ::u8 pixelValue = 255;
|
||||
|
||||
// Image data should be stored inverted on the y axis relative to our engine, so loop backwards through y.
|
||||
for (int y = static_cast<int>(height) - 1; y >= 0; --y)
|
||||
{
|
||||
for (AZ::u32 x = 0; x < width; ++x)
|
||||
{
|
||||
if ((x == static_cast<int>(pixelX)) && (y == static_cast<int>(pixelY)))
|
||||
{
|
||||
m_imageData->m_imageData.push_back(pixelValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_imageData->m_imageData.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reinterpret_cast<AssignIdToAsset*>(m_imageData)->MakeReady();
|
||||
return AZ::Data::Asset<GradientSignal::ImageAsset>(m_imageData, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
|
||||
void TestPixels(GradientSignal::GradientSampler& sampler, AZ::u32 width, AZ::u32 height, float stepSize, const AZStd::vector<AZ::Vector3>& expectedPoints)
|
||||
{
|
||||
AZStd::vector<AZ::Vector3> foundPoints;
|
||||
@@ -203,7 +85,8 @@ namespace UnitTest
|
||||
|
||||
// Create the Image Gradient Component.
|
||||
GradientSignal::ImageGradientConfig config;
|
||||
config.m_imageAsset = CreateSpecificPixelImageAsset(test.m_imageSize, test.m_imageSize, static_cast<AZ::u32>(test.m_pixel.GetX()), static_cast<AZ::u32>(test.m_pixel.GetY()));
|
||||
config.m_imageAsset = ImageAssetMockAssetHandler::CreateSpecificPixelImageAsset(
|
||||
test.m_imageSize, test.m_imageSize, static_cast<AZ::u32>(test.m_pixel.GetX()), static_cast<AZ::u32>(test.m_pixel.GetY()));
|
||||
config.m_tilingX = test.m_tiling;
|
||||
config.m_tilingY = test.m_tiling;
|
||||
CreateComponent<GradientSignal::ImageGradientComponent>(entity.get(), config);
|
||||
@@ -495,7 +378,7 @@ namespace UnitTest
|
||||
|
||||
// Create an ImageGradient with a 3x3 asset with the center pixel set.
|
||||
GradientSignal::ImageGradientConfig gradientConfig;
|
||||
gradientConfig.m_imageAsset = CreateSpecificPixelImageAsset(3, 3, 1, 1);
|
||||
gradientConfig.m_imageAsset = ImageAssetMockAssetHandler::CreateSpecificPixelImageAsset(3, 3, 1, 1);
|
||||
CreateComponent<GradientSignal::ImageGradientComponent>(entity.get(), gradientConfig);
|
||||
|
||||
// Create the test GradientTransform
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <Source/Components/MixedGradientComponent.h>
|
||||
#include <Source/Components/ReferenceGradientComponent.h>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/std/smart_ptr/make_shared.h>
|
||||
#include <AzCore/Math/MathUtils.h>
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <Source/Components/ConstantGradientComponent.h>
|
||||
#include <Source/Components/GradientSurfaceDataComponent.h>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "Tests/GradientSignalTestMocks.h"
|
||||
#include <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <GradientSignal/PerlinImprovedNoise.h>
|
||||
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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 <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
void GradientSignalBaseFixture::SetupCoreSystems()
|
||||
{
|
||||
m_app = AZStd::make_unique<AZ::ComponentApplication>();
|
||||
ASSERT_TRUE(m_app != nullptr);
|
||||
|
||||
AZ::ComponentApplication::Descriptor componentAppDesc;
|
||||
|
||||
m_systemEntity = m_app->Create(componentAppDesc);
|
||||
ASSERT_TRUE(m_systemEntity != nullptr);
|
||||
m_app->AddEntity(m_systemEntity);
|
||||
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Create();
|
||||
AZ::Data::AssetManager::Descriptor desc;
|
||||
AZ::Data::AssetManager::Create(desc);
|
||||
m_mockHandler = new ImageAssetMockAssetHandler();
|
||||
AZ::Data::AssetManager::Instance().RegisterHandler(m_mockHandler, azrtti_typeid<GradientSignal::ImageAsset>());
|
||||
}
|
||||
|
||||
void GradientSignalBaseFixture::TearDownCoreSystems()
|
||||
{
|
||||
AZ::Data::AssetManager::Instance().UnregisterHandler(m_mockHandler);
|
||||
delete m_mockHandler; // delete after removing from the asset manager
|
||||
AzFramework::LegacyAssetEventBus::ClearQueuedEvents();
|
||||
AZ::Data::AssetManager::Destroy();
|
||||
AZ::AllocatorInstance<AZ::ThreadPoolAllocator>::Destroy();
|
||||
|
||||
m_app->Destroy();
|
||||
m_app.reset();
|
||||
m_systemEntity = nullptr;
|
||||
}
|
||||
|
||||
void GradientSignalTest::TestFixedDataSampler(const AZStd::vector<float>& expectedOutput, int size, AZ::EntityId gradientEntityId)
|
||||
{
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = gradientEntityId;
|
||||
|
||||
for (int y = 0; y < size; ++y)
|
||||
{
|
||||
for (int x = 0; x < size; ++x)
|
||||
{
|
||||
GradientSignal::GradientSampleParams params;
|
||||
params.m_position = AZ::Vector3(static_cast<float>(x), static_cast<float>(y), 0.0f);
|
||||
|
||||
const int index = y * size + x;
|
||||
float actualValue = gradientSampler.GetValue(params);
|
||||
float expectedValue = expectedOutput[index];
|
||||
|
||||
EXPECT_NEAR(actualValue, expectedValue, 0.01f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_BENCHMARK
|
||||
void GradientSignalBenchmarkFixture::CreateTestEntity(float shapeHalfBounds)
|
||||
{
|
||||
// Create the base entity
|
||||
m_testEntity = CreateEntity();
|
||||
|
||||
// Create a mock Shape component that describes the bounds that we're using to map our gradient into world space.
|
||||
CreateComponent<MockShapeComponent>(m_testEntity.get());
|
||||
MockShapeComponentHandler mockShapeHandler(m_testEntity->GetId());
|
||||
mockShapeHandler.m_GetLocalBounds = AZ::Aabb::CreateCenterRadius(AZ::Vector3(shapeHalfBounds), shapeHalfBounds);
|
||||
|
||||
// Create a mock Transform component that locates our gradient in the center of our desired mock Shape.
|
||||
MockTransformHandler mockTransformHandler;
|
||||
mockTransformHandler.m_GetLocalTMOutput = AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds));
|
||||
mockTransformHandler.m_GetWorldTMOutput = AZ::Transform::CreateTranslation(AZ::Vector3(shapeHalfBounds));
|
||||
mockTransformHandler.BusConnect(m_testEntity->GetId());
|
||||
}
|
||||
|
||||
void GradientSignalBenchmarkFixture::DestroyTestEntity()
|
||||
{
|
||||
m_testEntity.reset();
|
||||
}
|
||||
|
||||
void GradientSignalBenchmarkFixture::RunGetValueBenchmark(benchmark::State& state)
|
||||
{
|
||||
// All components are created, so activate the entity
|
||||
ActivateEntity(m_testEntity.get());
|
||||
|
||||
// Create a gradient sampler and run through a series of points to see if they match expectations.
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = m_testEntity->GetId();
|
||||
|
||||
// Get the height and width ranges for querying from our benchmark parameters
|
||||
float height = aznumeric_cast<float>(state.range(0));
|
||||
float width = aznumeric_cast<float>(state.range(1));
|
||||
|
||||
// Call GetValue() for every height and width in our ranges.
|
||||
for (auto _ : state)
|
||||
{
|
||||
for (float y = 0.0f; y < height; y += 1.0f)
|
||||
{
|
||||
for (float x = 0.0f; x < width; x += 1.0f)
|
||||
{
|
||||
GradientSignal::GradientSampleParams params;
|
||||
params.m_position = AZ::Vector3(x, y, 0.0f);
|
||||
float value = gradientSampler.GetValue(params);
|
||||
benchmark::DoNotOptimize(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 <Tests/GradientSignalTestMocks.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
// Base test fixture used for GradientSignal unit tests and benchmark tests
|
||||
class GradientSignalBaseFixture
|
||||
{
|
||||
public:
|
||||
void SetupCoreSystems();
|
||||
void TearDownCoreSystems();
|
||||
|
||||
AZStd::unique_ptr<AZ::Entity> CreateEntity()
|
||||
{
|
||||
return AZStd::make_unique<AZ::Entity>();
|
||||
}
|
||||
|
||||
void ActivateEntity(AZ::Entity* entity)
|
||||
{
|
||||
entity->Init();
|
||||
entity->Activate();
|
||||
}
|
||||
|
||||
template<typename Component, typename Configuration>
|
||||
AZ::Component* CreateComponent(AZ::Entity* entity, const Configuration& config)
|
||||
{
|
||||
m_app->RegisterComponentDescriptor(Component::CreateDescriptor());
|
||||
return entity->CreateComponent<Component>(config);
|
||||
}
|
||||
|
||||
template<typename Component>
|
||||
AZ::Component* CreateComponent(AZ::Entity* entity)
|
||||
{
|
||||
m_app->RegisterComponentDescriptor(Component::CreateDescriptor());
|
||||
return entity->CreateComponent<Component>();
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::ComponentApplication> m_app;
|
||||
AZ::Entity* m_systemEntity = nullptr;
|
||||
ImageAssetMockAssetHandler* m_mockHandler = nullptr;
|
||||
};
|
||||
|
||||
struct GradientSignalTest
|
||||
: public GradientSignalBaseFixture
|
||||
, public UnitTest::AllocatorsTestFixture
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
UnitTest::AllocatorsTestFixture::SetUp();
|
||||
SetupCoreSystems();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
TearDownCoreSystems();
|
||||
UnitTest::AllocatorsTestFixture::TearDown();
|
||||
}
|
||||
|
||||
void TestFixedDataSampler(const AZStd::vector<float>& expectedOutput, int size, AZ::EntityId gradientEntityId);
|
||||
};
|
||||
|
||||
#ifdef HAVE_BENCHMARK
|
||||
class GradientSignalBenchmarkFixture
|
||||
: public GradientSignalBaseFixture
|
||||
, public UnitTest::AllocatorsBenchmarkFixture
|
||||
, public UnitTest::TraceBusRedirector
|
||||
{
|
||||
public:
|
||||
void internalSetUp(const benchmark::State& state)
|
||||
{
|
||||
AZ::Debug::TraceMessageBus::Handler::BusConnect();
|
||||
UnitTest::AllocatorsBenchmarkFixture::SetUp(state);
|
||||
SetupCoreSystems();
|
||||
|
||||
// Create a default test entity with bounds of 256 m x 256 m x 256 m.
|
||||
const float shapeHalfBounds = 128.0f;
|
||||
CreateTestEntity(shapeHalfBounds);
|
||||
}
|
||||
|
||||
void internalTearDown(const benchmark::State& state)
|
||||
{
|
||||
DestroyTestEntity();
|
||||
TearDownCoreSystems();
|
||||
UnitTest::AllocatorsBenchmarkFixture::TearDown(state);
|
||||
AZ::Debug::TraceMessageBus::Handler::BusDisconnect();
|
||||
}
|
||||
|
||||
void CreateTestEntity(float shapeHalfBounds);
|
||||
void DestroyTestEntity();
|
||||
|
||||
void RunGetValueBenchmark(benchmark::State& state);
|
||||
|
||||
protected:
|
||||
void SetUp(const benchmark::State& state) override
|
||||
{
|
||||
internalSetUp(state);
|
||||
}
|
||||
void SetUp(benchmark::State& state) override
|
||||
{
|
||||
internalSetUp(state);
|
||||
}
|
||||
|
||||
void TearDown(const benchmark::State& state) override
|
||||
{
|
||||
internalTearDown(state);
|
||||
}
|
||||
void TearDown(benchmark::State& state) override
|
||||
{
|
||||
internalTearDown(state);
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::Entity> m_testEntity;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 <Tests/GradientSignalTestMocks.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
AZ::Data::Asset<GradientSignal::ImageAsset> ImageAssetMockAssetHandler::CreateImageAsset(AZ::u32 width, AZ::u32 height, AZ::s32 seed)
|
||||
{
|
||||
GradientSignal::ImageAsset* imageData =
|
||||
aznew GradientSignal::ImageAsset(AZ::Data::AssetId(AZ::Uuid::CreateRandom()), AZ::Data::AssetData::AssetStatus::Ready);
|
||||
imageData->m_imageWidth = width;
|
||||
imageData->m_imageHeight = height;
|
||||
imageData->m_bytesPerPixel = 1;
|
||||
imageData->m_imageFormat = ImageProcessingAtom::EPixelFormat::ePixelFormat_R8;
|
||||
imageData->m_imageData.reserve(width * height);
|
||||
|
||||
size_t value = 0;
|
||||
AZStd::hash_combine(value, seed);
|
||||
|
||||
for (AZ::u32 x = 0; x < width; ++x)
|
||||
{
|
||||
for (AZ::u32 y = 0; y < height; ++y)
|
||||
{
|
||||
AZStd::hash_combine(value, x);
|
||||
AZStd::hash_combine(value, y);
|
||||
imageData->m_imageData.push_back(static_cast<AZ::u8>(value));
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Data::Asset<GradientSignal::ImageAsset>(imageData, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
|
||||
AZ::Data::Asset<GradientSignal::ImageAsset> ImageAssetMockAssetHandler::CreateSpecificPixelImageAsset(
|
||||
AZ::u32 width, AZ::u32 height, AZ::u32 pixelX, AZ::u32 pixelY)
|
||||
{
|
||||
GradientSignal::ImageAsset* imageData =
|
||||
aznew GradientSignal::ImageAsset(AZ::Data::AssetId(AZ::Uuid::CreateRandom()), AZ::Data::AssetData::AssetStatus::Ready);
|
||||
imageData->m_imageWidth = width;
|
||||
imageData->m_imageHeight = height;
|
||||
imageData->m_bytesPerPixel = 1;
|
||||
imageData->m_imageFormat = ImageProcessingAtom::EPixelFormat::ePixelFormat_R8;
|
||||
imageData->m_imageData.reserve(width * height);
|
||||
|
||||
const AZ::u8 pixelValue = 255;
|
||||
|
||||
// Image data should be stored inverted on the y axis relative to our engine, so loop backwards through y.
|
||||
for (int y = static_cast<int>(height) - 1; y >= 0; --y)
|
||||
{
|
||||
for (AZ::u32 x = 0; x < width; ++x)
|
||||
{
|
||||
if ((x == static_cast<int>(pixelX)) && (y == static_cast<int>(pixelY)))
|
||||
{
|
||||
imageData->m_imageData.push_back(pixelValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
imageData->m_imageData.push_back(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return AZ::Data::Asset<GradientSignal::ImageAsset>(imageData, AZ::Data::AssetLoadBehavior::Default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,90 +8,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/std/hash.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
#include <AzCore/Component/Entity.h>
|
||||
#include <AzCore/Component/ComponentApplication.h>
|
||||
#include <AzCore/Component/TransformBus.h>
|
||||
#include <AzCore/Memory/PoolAllocator.h>
|
||||
#include <AzCore/std/hash.h>
|
||||
#include <AzCore/UnitTest/TestTypes.h>
|
||||
|
||||
#include <GradientSignal/Ebuses/GradientRequestBus.h>
|
||||
#include <GradientSignal/Ebuses/GradientPreviewContextRequestBus.h>
|
||||
#include <GradientSignal/GradientSampler.h>
|
||||
#include <GradientSignal/ImageAsset.h>
|
||||
#include <LmbrCentral/Shape/ShapeComponentBus.h>
|
||||
#include <SurfaceData/SurfaceDataSystemRequestBus.h>
|
||||
#include <AzCore/Casting/lossy_cast.h>
|
||||
|
||||
#include <SurfaceData/Tests/SurfaceDataTestMocks.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
struct GradientSignalTest
|
||||
: public ::testing::Test
|
||||
// Mock asset handler for GradientSignal::ImageAsset that we can use in unit tests to pretend to load an image asset with.
|
||||
// Also includes utility functions for creating image assets with specific testable patterns.
|
||||
struct ImageAssetMockAssetHandler : public AZ::Data::AssetHandler
|
||||
{
|
||||
protected:
|
||||
AZ::ComponentApplication m_app;
|
||||
AZ::Entity* m_systemEntity = nullptr;
|
||||
//! Creates a deterministically random set of pixel data as an ImageAsset.
|
||||
//! \param width The width of the ImageAsset
|
||||
//! \param height The height of the ImageAsset
|
||||
//! \param seed The random seed to use for generating the random data
|
||||
//! \return The ImageAsset in a loaded ready state
|
||||
static AZ::Data::Asset<GradientSignal::ImageAsset> CreateImageAsset(AZ::u32 width, AZ::u32 height, AZ::s32 seed);
|
||||
|
||||
void SetUp() override
|
||||
//! Creates an ImageAsset where all the pixels are 0 except for the one pixel at the given coordinates, which is set to 1.
|
||||
//! \param width The width of the ImageAsset
|
||||
//! \param height The height of the ImageAsset
|
||||
//! \param pixelX The X coordinate of the pixel to set to 1
|
||||
//! \param pixelY The Y coordinate of the pixel to set to 1
|
||||
//! \return The ImageAsset in a loaded ready state
|
||||
static AZ::Data::Asset<GradientSignal::ImageAsset> CreateSpecificPixelImageAsset(
|
||||
AZ::u32 width, AZ::u32 height, AZ::u32 pixelX, AZ::u32 pixelY);
|
||||
|
||||
AZ::Data::AssetPtr CreateAsset(
|
||||
[[maybe_unused]] const AZ::Data::AssetId& id, [[maybe_unused]] const AZ::Data::AssetType& type) override
|
||||
{
|
||||
AZ::ComponentApplication::Descriptor appDesc;
|
||||
appDesc.m_memoryBlocksByteSize = 128 * 1024 * 1024;
|
||||
m_systemEntity = m_app.Create(appDesc);
|
||||
m_app.AddEntity(m_systemEntity);
|
||||
return AZ::Data::AssetPtr();
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
void DestroyAsset(AZ::Data::AssetPtr ptr) override
|
||||
{
|
||||
m_app.Destroy();
|
||||
m_systemEntity = nullptr;
|
||||
}
|
||||
|
||||
void TestFixedDataSampler(const AZStd::vector<float>& expectedOutput, int size, AZ::EntityId gradientEntityId)
|
||||
{
|
||||
GradientSignal::GradientSampler gradientSampler;
|
||||
gradientSampler.m_gradientId = gradientEntityId;
|
||||
|
||||
for(int y = 0; y < size; ++y)
|
||||
if (ptr)
|
||||
{
|
||||
for (int x = 0; x < size; ++x)
|
||||
{
|
||||
GradientSignal::GradientSampleParams params;
|
||||
params.m_position = AZ::Vector3(static_cast<float>(x), static_cast<float>(y), 0.0f);
|
||||
|
||||
const int index = y * size + x;
|
||||
float actualValue = gradientSampler.GetValue(params);
|
||||
float expectedValue = expectedOutput[index];
|
||||
|
||||
EXPECT_NEAR(actualValue, expectedValue, 0.01f);
|
||||
}
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
|
||||
AZStd::unique_ptr<AZ::Entity> CreateEntity()
|
||||
void GetHandledAssetTypes([[maybe_unused]] AZStd::vector<AZ::Data::AssetType>& assetTypes) override
|
||||
{
|
||||
return AZStd::make_unique<AZ::Entity>();
|
||||
}
|
||||
|
||||
void ActivateEntity(AZ::Entity* entity)
|
||||
AZ::Data::AssetHandler::LoadResult LoadAssetData(
|
||||
[[maybe_unused]] const AZ::Data::Asset<AZ::Data::AssetData>& asset,
|
||||
[[maybe_unused]] AZStd::shared_ptr<AZ::Data::AssetDataStream> stream,
|
||||
[[maybe_unused]] const AZ::Data::AssetFilterCB& assetLoadFilterCB) override
|
||||
{
|
||||
entity->Init();
|
||||
EXPECT_EQ(AZ::Entity::State::Init, entity->GetState());
|
||||
|
||||
entity->Activate();
|
||||
EXPECT_EQ(AZ::Entity::State::Active, entity->GetState());
|
||||
}
|
||||
|
||||
template <typename Component, typename Configuration>
|
||||
AZ::Component* CreateComponent(AZ::Entity* entity, const Configuration& config)
|
||||
{
|
||||
m_app.RegisterComponentDescriptor(Component::CreateDescriptor());
|
||||
return entity->CreateComponent<Component>(config);
|
||||
}
|
||||
|
||||
template <typename Component>
|
||||
AZ::Component* CreateComponent(AZ::Entity* entity)
|
||||
{
|
||||
m_app.RegisterComponentDescriptor(Component::CreateDescriptor());
|
||||
return entity->CreateComponent<Component>();
|
||||
return AZ::Data::AssetHandler::LoadResult::LoadComplete;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* 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 <Tests/GradientSignalTestFixtures.h>
|
||||
|
||||
#include <AzTest/AzTest.h>
|
||||
#include <AzCore/Asset/AssetManager.h>
|
||||
#include <AzCore/Memory/PoolAllocator.h>
|
||||
#include <AzCore/Math/Vector2.h>
|
||||
#include <AZTestShared/Math/MathTestHelpers.h>
|
||||
|
||||
#include <Source/Components/GradientTransformComponent.h>
|
||||
|
||||
namespace UnitTest
|
||||
{
|
||||
struct GradientSignalTransformTestsFixture : public GradientSignalTest
|
||||
{
|
||||
// By default, we'll use a shape half extents of (5, 10, 20) for every test, and a world translation of (100, 200, 300).
|
||||
struct GradientTransformSetupData
|
||||
{
|
||||
GradientSignal::WrappingType m_wrappingType{ GradientSignal::WrappingType::None };
|
||||
AZ::Vector3 m_shapeHalfExtents{ 5.0f, 10.0f, 20.0f };
|
||||
AZ::Vector3 m_worldTranslation{ 100.0f, 200.0f, 300.0f };
|
||||
float m_frequencyZoom{ 1.0f };
|
||||
};
|
||||
|
||||
struct GradientTransformTestData
|
||||
{
|
||||
AZ::Vector3 m_positionToTest;
|
||||
AZ::Vector3 m_expectedOutputUVW;
|
||||
bool m_expectedOutputRejectionResult;
|
||||
};
|
||||
|
||||
static constexpr float UvEpsilon = GradientSignal::GradientTransform::UvEpsilon;
|
||||
|
||||
void TestGradientTransform(const GradientTransformSetupData& setup, const GradientTransformTestData& test)
|
||||
{
|
||||
AZ::Aabb shapeBounds = AZ::Aabb::CreateCenterHalfExtents(AZ::Vector3::CreateZero(), setup.m_shapeHalfExtents);
|
||||
AZ::Matrix3x4 transform = AZ::Matrix3x4::CreateTranslation(setup.m_worldTranslation);
|
||||
float frequencyZoom = setup.m_frequencyZoom;
|
||||
GradientSignal::WrappingType wrappingType = setup.m_wrappingType;
|
||||
|
||||
AZ::Vector3 outUVW;
|
||||
bool wasPointRejected;
|
||||
|
||||
// Perform the query with a 3D gradient and verify that the results match expectations.
|
||||
GradientSignal::GradientTransform gradientTransform3d(shapeBounds, transform, true, frequencyZoom, wrappingType);
|
||||
gradientTransform3d.TransformPositionToUVW(test.m_positionToTest, outUVW, wasPointRejected);
|
||||
EXPECT_THAT(outUVW, IsClose(test.m_expectedOutputUVW));
|
||||
EXPECT_EQ(wasPointRejected, test.m_expectedOutputRejectionResult);
|
||||
|
||||
// Perform the query with a 2D gradient and verify that the results match, but always returns a W value of 0.
|
||||
GradientSignal::GradientTransform gradientTransform2d(shapeBounds, transform, false, frequencyZoom, wrappingType);
|
||||
gradientTransform2d.TransformPositionToUVW(test.m_positionToTest, outUVW, wasPointRejected);
|
||||
EXPECT_THAT(outUVW, IsClose(AZ::Vector3(test.m_expectedOutputUVW.GetX(), test.m_expectedOutputUVW.GetY(), 0.0f)));
|
||||
EXPECT_EQ(wasPointRejected, test.m_expectedOutputRejectionResult);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(GradientSignalTransformTestsFixture, UnboundedWrappingReturnsTranslatedInput)
|
||||
{
|
||||
GradientTransformSetupData setup = { GradientSignal::WrappingType::None };
|
||||
GradientTransformTestData test = {
|
||||
// Input position to query
|
||||
{ 0.0f, 0.0f, 0.0f },
|
||||
|
||||
// Output: For no wrapping, the output is just the input position offset by the world translation.
|
||||
{ -100.0f, -200.0f, -300.0f }, false
|
||||
};
|
||||
|
||||
TestGradientTransform(setup, test);
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalTransformTestsFixture, ClampToEdgeReturnsValuesClampedToShapeBounds)
|
||||
{
|
||||
GradientTransformSetupData setup = { GradientSignal::WrappingType::ClampToEdge };
|
||||
GradientTransformTestData tests[] = {
|
||||
// Test: Input point far below minimum shape bounds
|
||||
// Our input point is below the minimum of shape bounds, so the result should be the minimum corner of the shape.
|
||||
{ { 0.0f, 0.0f, 0.0f }, { -5.0f, -10.0f, -20.0f }, false },
|
||||
|
||||
// Test: Input point directly on minimum shape bounds
|
||||
// Our input point is directly on the minimum of shape bounds, so the result should be the minimum corner of the shape.
|
||||
{ { 95.0f, 190.0f, 280.0f }, { -5.0f, -10.0f, -20.0f }, false },
|
||||
|
||||
// Test: Input point inside shape bounds
|
||||
// Our input point is inside the shape bounds, so the result is just input - translation.
|
||||
{ { 101.0f, 202.0f, 303.0f }, { 1.0f, 2.0f, 3.0f }, false },
|
||||
|
||||
// Test: Input point directly on maximum shape bounds
|
||||
// On the maximum side, GradientTransform clamps to "max - epsilon" for consistency with other wrapping types, so our
|
||||
// expected results are the max shape corner - epsilon.
|
||||
{ { 105.0f, 210.0f, 320.0f }, { 5.0f - UvEpsilon, 10.0f - UvEpsilon, 20.0f - UvEpsilon }, false },
|
||||
|
||||
// Test: Input point far above maximum shape bounds
|
||||
// On the maximum side, GradientTransform clamps to "max - epsilon" for consistency with other wrapping types, so our
|
||||
// expected results are the max shape corner - epsilon.
|
||||
{ { 1000.0f, 1000.0f, 1000.0f }, { 5.0f - UvEpsilon, 10.0f - UvEpsilon, 20.0f - UvEpsilon }, false },
|
||||
};
|
||||
|
||||
for (auto& test : tests)
|
||||
{
|
||||
TestGradientTransform(setup, test);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalTransformTestsFixture, MirrorReturnsValuesMirroredBasedOnShapeBounds)
|
||||
{
|
||||
/* Here's how the results are expected to work for various inputs when using Mirror wrapping.
|
||||
* This assumes shape half extents of (5, 10, 20), and a center translation of (100, 200, 300):
|
||||
* Inputs: Outputs:
|
||||
* ... ...
|
||||
* (75, 150, 200) - (85, 170, 240) (-5, -10, -20) to (5, 10, 20) // forward mirror
|
||||
* (85, 170, 240) - (95, 190, 280) (5, 10, 20) to (-5, -10, -20) // back mirror
|
||||
* (95, 190, 280) - (105, 210, 320) (-5, -10, -20) to (5, 10, 20) // starting point
|
||||
* (105, 210, 320) - (115, 230, 360) (5, 10, 20) to (-5, -10, -20) // back mirror
|
||||
* (115, 230, 360) - (125, 250, 400) (-5, -10, -20) to (5, 10, 20) // forward mirror
|
||||
* ... ...
|
||||
* When below the starting point, both forward and back mirrors will be adjusted by UvEpsilon except for points that fall on the
|
||||
* shape minimums.
|
||||
* When above the starting point, only back mirrors will be adjusted by UvEpsilon.
|
||||
*/
|
||||
|
||||
GradientTransformSetupData setup = { GradientSignal::WrappingType::Mirror };
|
||||
GradientTransformTestData tests[] = {
|
||||
// Test: Input exactly 2x below minimum bounds
|
||||
// When landing exactly on the 2x boundary, we return the minumum shape bounds. There is no adjustment by epsilon
|
||||
// on the minimum side of the bounds, even when we're in a mirror below the shape bounds.
|
||||
{ { 75.0f, 150.0f, 200.0f }, { -5.0f, -10.0f, -20.0f }, false },
|
||||
|
||||
// Test: Input within 2nd mirror repeat below minimum bounds
|
||||
// The second mirror repeat should go forward in values, but will be adjusted by UvEpsilon since we're below the
|
||||
// minimum bounds.
|
||||
{ { 84.0f, 168.0f, 237.0f }, { 4.0f - UvEpsilon, 8.0f - UvEpsilon, 17.0f - UvEpsilon }, false },
|
||||
|
||||
// Test: Input exactly 1x below minimum bounds.
|
||||
// When landing exactly on the 1x boundary, we return the maximum shape bounds minus epsilon.
|
||||
{ { 85.0f, 170.0f, 240.0f }, { 5.0f - UvEpsilon, 10.0f - UvEpsilon, 20.0f - UvEpsilon }, false },
|
||||
|
||||
// Test: Input within 1st mirror repeat below minimum bounds
|
||||
// The first mirror repeat should go backwards in values, but will be adjusted by UvEpsilon since we're below the
|
||||
// minimum bounds.
|
||||
{ { 94.0f, 188.0f, 277.0f }, { -4.0f - UvEpsilon, -8.0f - UvEpsilon, -17.0f - UvEpsilon }, false },
|
||||
|
||||
// Test: Input inside shape bounds
|
||||
// The translated input position is (1, 2, 3) is inside the shape bounds, so we should just get the translated
|
||||
// position back as output.
|
||||
{ { 101.0f, 202.0f, 303.0f }, { 1.0f, 2.0f, 3.0f }, false },
|
||||
|
||||
// Test: Input within 1st mirror repeat above maximum bounds
|
||||
// The first mirror repeat should go backwards in values. We're above the maximum bounds, so the expected result
|
||||
// is (4, 8, 17) minus an epsilon.
|
||||
{ { 106.0f, 212.0f, 323.0f }, { 4.0f - UvEpsilon, 8.0f - UvEpsilon, 17.0f - UvEpsilon }, false },
|
||||
|
||||
// Test: Input exactly 2x above minimum bounds.
|
||||
// When landing exactly on the 2x boundary, we return the exact minimum value again.
|
||||
{ { 115.0f, 230.0f, 360.0f }, { -5.0f, -10.0f, -20.0f }, false },
|
||||
|
||||
// Test: Input within 2nd mirror repeat above maximum bounds
|
||||
// The second mirror repeat should go forwards in values. We're above the maximum bounds, so the expected result
|
||||
// is (-4, -8, -17) with no epsilon.
|
||||
{ { 116.0f, 232.0f, 363.0f }, { -4.0f, -8.0f, -17.0f }, false },
|
||||
|
||||
// Test: Input exactly 2x above maximum bounds
|
||||
// When landing exactly on the 2x boundary, we return the maximum adjusted by the epsilon again.
|
||||
{ { 125.0f, 250.0f, 400.0f }, { 5.0f - UvEpsilon, 10.0f - UvEpsilon, 20.0f - UvEpsilon }, false }
|
||||
};
|
||||
|
||||
for (auto& test : tests)
|
||||
{
|
||||
TestGradientTransform(setup, test);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalTransformTestsFixture, RepeatReturnsRepeatingValuesBasedOnShapeBounds)
|
||||
{
|
||||
/* Here's how the results are expected to work for various inputs when using Repeat wrapping.
|
||||
* This assumes shape half extents of (5, 10, 20), and a center translation of (100, 200, 300):
|
||||
* Inputs: Outputs:
|
||||
* ... ...
|
||||
* (75, 150, 200) - (85, 170, 240) (-5, -10, -20) to (5, 10, 20)
|
||||
* (85, 170, 240) - (95, 190, 280) (-5, -10, -20) to (5, 10, 20)
|
||||
* (95, 190, 280) - (105, 210, 320) (-5, -10, -20) to (5, 10, 20) // starting point
|
||||
* (105, 210, 320) - (115, 230, 360) (-5, -10, -20) to (5, 10, 20)
|
||||
* (115, 230, 360) - (125, 250, 400) (-5, -10, -20) to (5, 10, 20)
|
||||
* ... ...
|
||||
* Every shape min/max boundary point below the starting point will have the max shape value.
|
||||
* Every shape min/max boundary point above the starting point with have the min shape value.
|
||||
*/
|
||||
|
||||
|
||||
GradientTransformSetupData setup = { GradientSignal::WrappingType::Repeat };
|
||||
GradientTransformTestData tests[] = {
|
||||
// Test: 2x below minimum shape bounds
|
||||
// We're on a shape boundary below the minimum bounds, so it should return the maximum.
|
||||
{ { 75.0f, 150.0f, 200.0f }, { 5.0f, 10.0f, 20.0f }, false },
|
||||
|
||||
// Test: Input within 2nd repeat below minimum shape bounds
|
||||
// Every repeat should go forwards in values.
|
||||
{ { 76.0f, 152.0f, 203.0f }, { -4.0f, -8.0f, -17.0f }, false },
|
||||
|
||||
// Test: 1x below minimum shape bounds
|
||||
// We're on a shape boundary below the minimum bounds, so it should return the maximum.
|
||||
{ { 85.0f, 170.0f, 240.0f }, { 5.0f, 10.0f, 20.0f }, false },
|
||||
|
||||
// Test: Input within 1st repeat below minimum shape bounds
|
||||
// Every repeat should go forwards in values.
|
||||
{ { 86.0f, 172.0f, 243.0f }, { -4.0f, -8.0f, -17.0f }, false },
|
||||
|
||||
// Test: Input exactly on minimum shape bounds
|
||||
// This should return the actual minimum bounds.
|
||||
{ { 95.0f, 190.0f, 280.0f }, { -5.0f, -10.0f, -20.0f }, false },
|
||||
|
||||
// Test: Input inside shape bounds
|
||||
// This should return the mapped value.
|
||||
{ { 101.0f, 202.0f, 303.0f }, { 1.0f, 2.0f, 3.0f }, false },
|
||||
|
||||
// Test: Input exactly on maximum shape bounds
|
||||
// We're on a shape boundary above the minimum bounds, so it should return the minimum.
|
||||
{ { 105.0f, 210.0f, 320.0f }, { -5.0f, -10.0f, -20.0f }, false },
|
||||
|
||||
// Test: Input within 1st repeat above maximum shape bounds
|
||||
// Every repeat should go forwards in values.
|
||||
{ { 106.0f, 212.0f, 323.0f }, { -4.0f, -8.0f, -17.0f }, false },
|
||||
|
||||
// Test: 1x above maximum shape bounds
|
||||
// We're on a shape boundary above the minimum bounds, so it should return the minimum.
|
||||
{ { 105.0f, 210.0f, 320.0f }, { -5.0f, -10.0f, -20.0f }, false },
|
||||
|
||||
// Test: Input within 2nd repeat above maximum shape bounds
|
||||
// Every repeat should go forwards in values.
|
||||
{ { 106.0f, 212.0f, 323.0f }, { -4.0f, -8.0f, -17.0f }, false },
|
||||
};
|
||||
|
||||
for (auto& test : tests)
|
||||
{
|
||||
TestGradientTransform(setup, test);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(GradientSignalTransformTestsFixture, ClampToZeroReturnsClampedValuesBasedOnShapeBounds)
|
||||
{
|
||||
GradientTransformSetupData setup = { GradientSignal::WrappingType::ClampToZero };
|
||||
GradientTransformTestData tests[] = {
|
||||
// Test: Input point far below minimum shape bounds
|
||||
// Our input point is below the minimum of shape bounds, so the result should be the minimum corner of the shape.
|
||||
// Points outside the shape bounds should return "true" for rejected.
|
||||
{ { 0.0f, 0.0f, 0.0f }, { -5.0f, -10.0f, -20.0f }, true },
|
||||
|
||||
// Test: Input point directly on minimum shape bounds
|
||||
// Our input point is directly on the minimum of shape bounds, so the result should be the minimum corner of the shape.
|
||||
{ { 95.0f, 190.0f, 280.0f }, { -5.0f, -10.0f, -20.0f }, false },
|
||||
|
||||
// Test: Input point inside shape bounds
|
||||
// Our input point is inside the shape bounds, so the result is just input - translation.
|
||||
{ { 101.0f, 202.0f, 303.0f }, { 1.0f, 2.0f, 3.0f }, false },
|
||||
|
||||
// Test: Input point directly on maximum shape bounds
|
||||
// On the maximum side, GradientTransform clamps to "max - epsilon" for consistency with other wrapping types, so our
|
||||
// expected results are the max shape corner - epsilon.
|
||||
// Points outside the shape bounds (which includes the maximum edge of the shape bounds) should return "true" for rejected.
|
||||
{ { 105.0f, 210.0f, 320.0f }, { 5.0f - UvEpsilon, 10.0f - UvEpsilon, 20.0f - UvEpsilon }, true },
|
||||
|
||||
// Test: Input point far above maximum shape bounds
|
||||
// On the maximum side, GradientTransform clamps to "max - epsilon" for consistency with other wrapping types, so our
|
||||
// expected results are the max shape corner - epsilon.
|
||||
// Points outside the shape bounds should return "true" for rejected.
|
||||
{ { 1000.0f, 1000.0f, 1000.0f }, { 5.0f - UvEpsilon, 10.0f - UvEpsilon, 20.0f - UvEpsilon }, true },
|
||||
};
|
||||
|
||||
for (auto& test : tests)
|
||||
{
|
||||
TestGradientTransform(setup, test);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
#
|
||||
|
||||
set(FILES
|
||||
Tests/GradientSignalTestFixtures.cpp
|
||||
Tests/EditorGradientSignalPreviewTests.cpp
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user