merging latest dev with small conflict resolution taking theirs

Signed-off-by: Gene Walters <genewalt@amazon.com>
This commit is contained in:
Gene Walters
2021-10-08 14:08:36 -07:00
251 changed files with 3401 additions and 2441 deletions
@@ -6,12 +6,7 @@
#
#
################################################################################
# Atom Renderer: Automated Tests
# Runs EditorPythonBindings (hydra) scripts inside the Editor to verify test results for the Atom renderer.
################################################################################
if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedTesting IN_LIST LY_PROJECTS)
if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_pytest(
NAME AutomatedTesting::Atom_TestSuite_Main
TEST_SUITE main
@@ -25,6 +25,7 @@ TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "tests")
class TestAtomEditorComponentsMain(object):
"""Holds tests for Atom components."""
@pytest.mark.xfail(reason="This test is being marked xfail as it failed during an unrelated development run. See LYN-7530 for more details.")
def test_AtomEditorComponents_AddedToEntity(self, request, editor, level, workspace, project, launcher_platform):
"""
Please review the hydra script run by this test for more specific test info.
@@ -14,33 +14,50 @@ from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAutomation(EditorTestSuite):
@pytest.mark.test_case_id("C32078118")
class AtomEditorComponents_DecalAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_DecalAdded as test_module
@pytest.mark.test_case_id("C32078119")
class AtomEditorComponents_DepthOfFieldAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_DepthOfFieldAdded as test_module
@pytest.mark.test_case_id("C32078120")
class AtomEditorComponents_DirectionalLightAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_DirectionalLightAdded as test_module
@pytest.mark.test_case_id("C32078121")
class AtomEditorComponents_ExposureControlAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_ExposureControlAdded as test_module
@pytest.mark.test_case_id("C32078115")
class AtomEditorComponents_GlobalSkylightIBLAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_GlobalSkylightIBLAdded as test_module
@pytest.mark.test_case_id("C32078125")
class AtomEditorComponents_PhysicalSkyAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_PhysicalSkyAdded as test_module
@pytest.mark.test_case_id("C32078131")
class AtomEditorComponents_PostFXRadiusWeightModifierAdded(EditorSharedTest):
from Atom.tests import (
hydra_AtomEditorComponents_PostFXRadiusWeightModifierAdded as test_module)
@pytest.mark.test_case_id("C32078117")
class AtomEditorComponents_LightAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_LightAdded as test_module
@pytest.mark.test_case_id("C36525660")
class AtomEditorComponents_DisplayMapperAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_DisplayMapperAdded as test_module
@pytest.mark.test_case_id("C32078128")
class AtomEditorComponents_ReflectionProbeAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_ReflectionProbeAdded as test_module
@pytest.mark.test_case_id("C32078124")
class AtomEditorComponents_MeshAdded(EditorSharedTest):
from Atom.tests import hydra_AtomEditorComponents_MeshAdded as test_module
class ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges(EditorSharedTest):
from Atom.tests import hydra_ShaderAssetBuilder_RecompilesShaderAsChainOfDependenciesChanges as test_module
@@ -0,0 +1,171 @@
"""
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
"""
class Tests:
creation_undo = (
"UNDO Entity creation success",
"UNDO Entity creation failed")
creation_redo = (
"REDO Entity creation success",
"REDO Entity creation failed")
mesh_entity_creation = (
"Mesh Entity successfully created",
"Mesh Entity failed to be created")
mesh_component_added = (
"Entity has a Mesh component",
"Entity failed to find Mesh component")
mesh_asset_specified = (
"Mesh asset set",
"Mesh asset not set")
enter_game_mode = (
"Entered game mode",
"Failed to enter game mode")
exit_game_mode = (
"Exited game mode",
"Couldn't exit game mode")
is_visible = (
"Entity is visible",
"Entity was not visible")
is_hidden = (
"Entity is hidden",
"Entity was not hidden")
entity_deleted = (
"Entity deleted",
"Entity was not deleted")
deletion_undo = (
"UNDO deletion success",
"UNDO deletion failed")
deletion_redo = (
"REDO deletion success",
"REDO deletion failed")
def AtomEditorComponents_Mesh_AddedToEntity():
"""
Summary:
Tests the Mesh component can be added to an entity and has the expected functionality.
Test setup:
- Wait for Editor idle loop.
- Open the "Base" level.
Expected Behavior:
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
Creation and deletion undo/redo should also work.
Test Steps:
1) Create a Mesh entity with no components.
2) Add a Mesh component to Mesh entity.
3) UNDO the entity creation and component addition.
4) REDO the entity creation and component addition.
5) Specify the Mesh component asset
6) Enter/Exit game mode.
7) Test IsHidden.
8) Test IsVisible.
9) Delete Mesh entity.
10) UNDO deletion.
11) REDO deletion.
12) Look for errors.
:return: None
"""
import os
import azlmbr.legacy.general as general
from editor_python_test_tools.asset_utils import Asset
from editor_python_test_tools.editor_entity_utils import EditorEntity
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
with Tracer() as error_tracer:
# Test setup begins.
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
helper.init_idle()
helper.open_level("", "Base")
# Test steps begin.
# 1. Create a Mesh entity with no components.
mesh_name = "Mesh"
mesh_entity = EditorEntity.create_editor_entity(mesh_name)
Report.critical_result(Tests.mesh_entity_creation, mesh_entity.exists())
# 2. Add a Mesh component to Mesh entity.
mesh_component = mesh_entity.add_component(mesh_name)
Report.critical_result(
Tests.mesh_component_added,
mesh_entity.has_component(mesh_name))
# 3. UNDO the entity creation and component addition.
# -> UNDO component addition.
general.undo()
# -> UNDO naming entity.
general.undo()
# -> UNDO selecting entity.
general.undo()
# -> UNDO entity creation.
general.undo()
general.idle_wait_frames(1)
Report.result(Tests.creation_undo, not mesh_entity.exists())
# 4. REDO the entity creation and component addition.
# -> REDO entity creation.
general.redo()
# -> REDO selecting entity.
general.redo()
# -> REDO naming entity.
general.redo()
# -> REDO component addition.
general.redo()
general.idle_wait_frames(1)
Report.result(Tests.creation_redo, mesh_entity.exists())
# 5. Set Mesh component asset property
mesh_property_asset = 'Controller|Configuration|Mesh Asset'
model_path = os.path.join('Objects', 'shaderball', 'shaderball_default_1m.azmodel')
model = Asset.find_asset_by_path(model_path)
mesh_component.set_component_property_value(mesh_property_asset, model.id)
Report.result(Tests.mesh_asset_specified,
mesh_component.get_component_property_value(mesh_property_asset) == model.id)
# 6. Enter/Exit game mode.
helper.enter_game_mode(Tests.enter_game_mode)
general.idle_wait_frames(1)
helper.exit_game_mode(Tests.exit_game_mode)
# 7. Test IsHidden.
mesh_entity.set_visibility_state(False)
Report.result(Tests.is_hidden, mesh_entity.is_hidden() is True)
# 8. Test IsVisible.
mesh_entity.set_visibility_state(True)
general.idle_wait_frames(1)
Report.result(Tests.is_visible, mesh_entity.is_visible() is True)
# 9. Delete Mesh entity.
mesh_entity.delete()
Report.result(Tests.entity_deleted, not mesh_entity.exists())
# 10. UNDO deletion.
general.undo()
Report.result(Tests.deletion_undo, mesh_entity.exists())
# 11. REDO deletion.
general.redo()
Report.result(Tests.deletion_redo, not mesh_entity.exists())
# 12. Look for errors or asserts.
helper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
for error_info in error_tracer.errors:
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
for assert_info in error_tracer.asserts:
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(AtomEditorComponents_Mesh_AddedToEntity)
@@ -0,0 +1,194 @@
"""
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
"""
class Tests:
creation_undo = (
"UNDO Entity creation success",
"UNDO Entity creation failed")
creation_redo = (
"REDO Entity creation success",
"REDO Entity creation failed")
reflection_probe_creation = (
"Reflection Probe Entity successfully created",
"Reflection Probe Entity failed to be created")
reflection_probe_component = (
"Entity has a Reflection Probe component",
"Entity failed to find Reflection Probe component")
reflection_probe_disabled = (
"Reflection Probe component disabled",
"Reflection Probe component was not disabled.")
reflection_map_generated = (
"Reflection Probe cubemap generated",
"Reflection Probe cubemap not generated")
box_shape_component = (
"Entity has a Box Shape component",
"Entity did not have a Box Shape component")
reflection_probe_enabled = (
"Reflection Probe component enabled",
"Reflection Probe component was not enabled.")
enter_game_mode = (
"Entered game mode",
"Failed to enter game mode")
exit_game_mode = (
"Exited game mode",
"Couldn't exit game mode")
is_visible = (
"Entity is visible",
"Entity was not visible")
is_hidden = (
"Entity is hidden",
"Entity was not hidden")
entity_deleted = (
"Entity deleted",
"Entity was not deleted")
deletion_undo = (
"UNDO deletion success",
"UNDO deletion failed")
deletion_redo = (
"REDO deletion success",
"REDO deletion failed")
def AtomEditorComponents_ReflectionProbe_AddedToEntity():
"""
Summary:
Tests the Reflection Probe component can be added to an entity and has the expected functionality.
Test setup:
- Wait for Editor idle loop.
- Open the "Base" level.
Expected Behavior:
The component can be added, used in game mode, hidden/shown, deleted, and has accurate required components.
Creation and deletion undo/redo should also work.
Test Steps:
1) Create a Reflection Probe entity with no components.
2) Add a Reflection Probe component to Reflection Probe entity.
3) UNDO the entity creation and component addition.
4) REDO the entity creation and component addition.
5) Verify Reflection Probe component not enabled.
6) Add Shape component since it is required by the Reflection Probe component.
7) Verify Reflection Probe component is enabled.
8) Enter/Exit game mode.
9) Test IsHidden.
10) Test IsVisible.
11) Verify cubemap generation
12) Delete Reflection Probe entity.
13) UNDO deletion.
14) REDO deletion.
15) Look for errors.
:return: None
"""
import azlmbr.legacy.general as general
import azlmbr.math as math
import azlmbr.render as render
from editor_python_test_tools.editor_entity_utils import EditorEntity
from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
with Tracer() as error_tracer:
# Test setup begins.
# Setup: Wait for Editor idle loop before executing Python hydra scripts then open "Base" level.
helper.init_idle()
helper.open_level("", "Base")
# Test steps begin.
# 1. Create a Reflection Probe entity with no components.
reflection_probe_name = "Reflection Probe"
reflection_probe_entity = EditorEntity.create_editor_entity_at(
math.Vector3(512.0, 512.0, 34.0), reflection_probe_name)
Report.critical_result(Tests.reflection_probe_creation, reflection_probe_entity.exists())
# 2. Add a Reflection Probe component to Reflection Probe entity.
reflection_probe_component = reflection_probe_entity.add_component(reflection_probe_name)
Report.critical_result(
Tests.reflection_probe_component,
reflection_probe_entity.has_component(reflection_probe_name))
# 3. UNDO the entity creation and component addition.
# -> UNDO component addition.
general.undo()
# -> UNDO naming entity.
general.undo()
# -> UNDO selecting entity.
general.undo()
# -> UNDO entity creation.
general.undo()
general.idle_wait_frames(1)
Report.result(Tests.creation_undo, not reflection_probe_entity.exists())
# 4. REDO the entity creation and component addition.
# -> REDO entity creation.
general.redo()
# -> REDO selecting entity.
general.redo()
# -> REDO naming entity.
general.redo()
# -> REDO component addition.
general.redo()
general.idle_wait_frames(1)
Report.result(Tests.creation_redo, reflection_probe_entity.exists())
# 5. Verify Reflection Probe component not enabled.
Report.result(Tests.reflection_probe_disabled, not reflection_probe_component.is_enabled())
# 6. Add Box Shape component since it is required by the Reflection Probe component.
box_shape = "Box Shape"
reflection_probe_entity.add_component(box_shape)
Report.result(Tests.box_shape_component, reflection_probe_entity.has_component(box_shape))
# 7. Verify Reflection Probe component is enabled.
Report.result(Tests.reflection_probe_enabled, reflection_probe_component.is_enabled())
# 8. Enter/Exit game mode.
helper.enter_game_mode(Tests.enter_game_mode)
general.idle_wait_frames(1)
helper.exit_game_mode(Tests.exit_game_mode)
# 9. Test IsHidden.
reflection_probe_entity.set_visibility_state(False)
Report.result(Tests.is_hidden, reflection_probe_entity.is_hidden() is True)
# 10. Test IsVisible.
reflection_probe_entity.set_visibility_state(True)
general.idle_wait_frames(1)
Report.result(Tests.is_visible, reflection_probe_entity.is_visible() is True)
# 11. Verify cubemap generation
render.EditorReflectionProbeBus(azlmbr.bus.Event, "BakeReflectionProbe", reflection_probe_entity.id)
Report.result(
Tests.reflection_map_generated,
helper.wait_for_condition(
lambda: reflection_probe_component.get_component_property_value("Cubemap|Baked Cubemap Path") != "",
20.0))
# 12. Delete Reflection Probe entity.
reflection_probe_entity.delete()
Report.result(Tests.entity_deleted, not reflection_probe_entity.exists())
# 13. UNDO deletion.
general.undo()
Report.result(Tests.deletion_undo, reflection_probe_entity.exists())
# 14. REDO deletion.
general.redo()
Report.result(Tests.deletion_redo, not reflection_probe_entity.exists())
# 15. Look for errors or asserts.
helper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
for error_info in error_tracer.errors:
Report.info(f"Error: {error_info.filename} {error_info.function} | {error_info.message}")
for assert_info in error_tracer.asserts:
Report.info(f"Assert: {assert_info.filename} {assert_info.function} | {assert_info.message}")
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(AtomEditorComponents_ReflectionProbe_AddedToEntity)
@@ -487,8 +487,6 @@ void LevelEditorMenuHandler::PopulateEditMenu(ActionManager::MenuWrapper& editMe
editMenu.AddAction(AzToolsFramework::EditPivot);
editMenu.AddAction(AzToolsFramework::EditReset);
editMenu.AddAction(AzToolsFramework::EditResetManipulator);
editMenu.AddAction(AzToolsFramework::EditResetLocal);
editMenu.AddAction(AzToolsFramework::EditResetWorld);
// Hide Selection
editMenu.AddAction(AzToolsFramework::HideSelection);
+2
View File
@@ -2124,6 +2124,8 @@ bool CCryEditApp::FixDanglingSharedMemory(const QString& sharedMemName) const
int CCryEditApp::ExitInstance(int exitCode)
{
AZ_TracePrintf("Exit", "Called ExitInstance() with exit code: 0x%x", exitCode);
if (m_pEditor)
{
m_pEditor->OnBeginShutdownSequence();
@@ -96,7 +96,7 @@ namespace SandboxEditor
cameras.AddCamera(m_firstPersonTranslateCamera);
cameras.AddCamera(m_firstPersonScrollCamera);
cameras.AddCamera(m_firstPersonFocusCamera);
cameras.AddCamera(m_pivotCamera);
cameras.AddCamera(m_orbitCamera);
});
return controller;
@@ -135,7 +135,7 @@ namespace SandboxEditor
m_firstPersonRotateCamera->SetActivationEndedFn(showCursor);
m_firstPersonPanCamera = AZStd::make_shared<AzFramework::PanCameraInput>(
SandboxEditor::CameraFreePanChannelId(), AzFramework::LookPan, AzFramework::TranslatePivot);
SandboxEditor::CameraFreePanChannelId(), AzFramework::LookPan, AzFramework::TranslatePivotLook);
m_firstPersonPanCamera->m_panSpeedFn = []
{
@@ -155,7 +155,7 @@ namespace SandboxEditor
const auto translateCameraInputChannelIds = BuildTranslateCameraInputChannelIds();
m_firstPersonTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivot);
translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook);
m_firstPersonTranslateCamera->m_translateSpeedFn = []
{
@@ -167,7 +167,7 @@ namespace SandboxEditor
return SandboxEditor::CameraBoostMultiplier();
};
m_firstPersonScrollCamera = AZStd::make_shared<AzFramework::ScrollTranslationCameraInput>();
m_firstPersonScrollCamera = AZStd::make_shared<AzFramework::LookScrollTranslationCameraInput>();
m_firstPersonScrollCamera->m_scrollSpeedFn = []
{
@@ -196,82 +196,82 @@ namespace SandboxEditor
m_firstPersonFocusCamera->SetPivotFn(pivotFn);
m_pivotCamera = AZStd::make_shared<AzFramework::PivotCameraInput>(SandboxEditor::CameraPivotChannelId());
m_orbitCamera = AZStd::make_shared<AzFramework::OrbitCameraInput>(SandboxEditor::CameraOrbitChannelId());
m_pivotCamera->SetPivotFn(
m_orbitCamera->SetPivotFn(
[pivotFn]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction)
{
return pivotFn();
});
m_pivotRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(SandboxEditor::CameraPivotLookChannelId());
m_orbitRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(SandboxEditor::CameraOrbitLookChannelId());
m_pivotRotateCamera->m_rotateSpeedFn = []
m_orbitRotateCamera->m_rotateSpeedFn = []
{
return SandboxEditor::CameraRotateSpeed();
};
m_pivotRotateCamera->m_invertYawFn = []
m_orbitRotateCamera->m_invertYawFn = []
{
return SandboxEditor::CameraPivotYawRotationInverted();
return SandboxEditor::CameraOrbitYawRotationInverted();
};
m_pivotTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslateOffset);
m_orbitTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslateOffsetOrbit);
m_pivotTranslateCamera->m_translateSpeedFn = []
m_orbitTranslateCamera->m_translateSpeedFn = []
{
return SandboxEditor::CameraTranslateSpeed();
};
m_pivotTranslateCamera->m_boostMultiplierFn = []
m_orbitTranslateCamera->m_boostMultiplierFn = []
{
return SandboxEditor::CameraBoostMultiplier();
};
m_pivotDollyScrollCamera = AZStd::make_shared<AzFramework::PivotDollyScrollCameraInput>();
m_orbitDollyScrollCamera = AZStd::make_shared<AzFramework::OrbitDollyScrollCameraInput>();
m_pivotDollyScrollCamera->m_scrollSpeedFn = []
m_orbitDollyScrollCamera->m_scrollSpeedFn = []
{
return SandboxEditor::CameraScrollSpeed();
};
m_pivotDollyMoveCamera = AZStd::make_shared<AzFramework::PivotDollyMotionCameraInput>(SandboxEditor::CameraPivotDollyChannelId());
m_orbitDollyMoveCamera = AZStd::make_shared<AzFramework::OrbitDollyMotionCameraInput>(SandboxEditor::CameraOrbitDollyChannelId());
m_pivotDollyMoveCamera->m_motionSpeedFn = []
m_orbitDollyMoveCamera->m_motionSpeedFn = []
{
return SandboxEditor::CameraDollyMotionSpeed();
};
m_pivotPanCamera = AZStd::make_shared<AzFramework::PanCameraInput>(
SandboxEditor::CameraPivotPanChannelId(), AzFramework::LookPan, AzFramework::TranslateOffset);
m_orbitPanCamera = AZStd::make_shared<AzFramework::PanCameraInput>(
SandboxEditor::CameraOrbitPanChannelId(), AzFramework::LookPan, AzFramework::TranslateOffsetOrbit);
m_pivotPanCamera->m_panSpeedFn = []
m_orbitPanCamera->m_panSpeedFn = []
{
return SandboxEditor::CameraPanSpeed();
};
m_pivotPanCamera->m_invertPanXFn = []
m_orbitPanCamera->m_invertPanXFn = []
{
return SandboxEditor::CameraPanInvertedX();
};
m_pivotPanCamera->m_invertPanYFn = []
m_orbitPanCamera->m_invertPanYFn = []
{
return SandboxEditor::CameraPanInvertedY();
};
m_pivotFocusCamera =
AZStd::make_shared<AzFramework::FocusCameraInput>(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusPivot);
m_orbitFocusCamera =
AZStd::make_shared<AzFramework::FocusCameraInput>(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusOrbit);
m_pivotFocusCamera->SetPivotFn(pivotFn);
m_orbitFocusCamera->SetPivotFn(pivotFn);
m_pivotCamera->m_pivotCameras.AddCamera(m_pivotRotateCamera);
m_pivotCamera->m_pivotCameras.AddCamera(m_pivotTranslateCamera);
m_pivotCamera->m_pivotCameras.AddCamera(m_pivotDollyScrollCamera);
m_pivotCamera->m_pivotCameras.AddCamera(m_pivotDollyMoveCamera);
m_pivotCamera->m_pivotCameras.AddCamera(m_pivotPanCamera);
m_pivotCamera->m_pivotCameras.AddCamera(m_pivotFocusCamera);
m_orbitCamera->m_orbitCameras.AddCamera(m_orbitRotateCamera);
m_orbitCamera->m_orbitCameras.AddCamera(m_orbitTranslateCamera);
m_orbitCamera->m_orbitCameras.AddCamera(m_orbitDollyScrollCamera);
m_orbitCamera->m_orbitCameras.AddCamera(m_orbitDollyMoveCamera);
m_orbitCamera->m_orbitCameras.AddCamera(m_orbitPanCamera);
m_orbitCamera->m_orbitCameras.AddCamera(m_orbitFocusCamera);
}
void EditorModularViewportCameraComposer::OnEditorModularViewportCameraComposerSettingsChanged()
@@ -282,12 +282,12 @@ namespace SandboxEditor
m_firstPersonRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraFreeLookChannelId());
m_firstPersonFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId());
m_pivotCamera->SetPivotInputChannelId(SandboxEditor::CameraPivotChannelId());
m_pivotTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds);
m_pivotPanCamera->SetPanInputChannelId(SandboxEditor::CameraPivotPanChannelId());
m_pivotRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraPivotLookChannelId());
m_pivotDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraPivotDollyChannelId());
m_pivotFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId());
m_orbitCamera->SetOrbitInputChannelId(SandboxEditor::CameraOrbitChannelId());
m_orbitTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds);
m_orbitPanCamera->SetPanInputChannelId(SandboxEditor::CameraOrbitPanChannelId());
m_orbitRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraOrbitLookChannelId());
m_orbitDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraOrbitDollyChannelId());
m_orbitFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId());
}
void EditorModularViewportCameraComposer::OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId)
@@ -41,15 +41,15 @@ namespace SandboxEditor
AZStd::shared_ptr<AzFramework::RotateCameraInput> m_firstPersonRotateCamera;
AZStd::shared_ptr<AzFramework::PanCameraInput> m_firstPersonPanCamera;
AZStd::shared_ptr<AzFramework::TranslateCameraInput> m_firstPersonTranslateCamera;
AZStd::shared_ptr<AzFramework::ScrollTranslationCameraInput> m_firstPersonScrollCamera;
AZStd::shared_ptr<AzFramework::LookScrollTranslationCameraInput> m_firstPersonScrollCamera;
AZStd::shared_ptr<AzFramework::FocusCameraInput> m_firstPersonFocusCamera;
AZStd::shared_ptr<AzFramework::PivotCameraInput> m_pivotCamera;
AZStd::shared_ptr<AzFramework::RotateCameraInput> m_pivotRotateCamera;
AZStd::shared_ptr<AzFramework::TranslateCameraInput> m_pivotTranslateCamera;
AZStd::shared_ptr<AzFramework::PivotDollyScrollCameraInput> m_pivotDollyScrollCamera;
AZStd::shared_ptr<AzFramework::PivotDollyMotionCameraInput> m_pivotDollyMoveCamera;
AZStd::shared_ptr<AzFramework::PanCameraInput> m_pivotPanCamera;
AZStd::shared_ptr<AzFramework::FocusCameraInput> m_pivotFocusCamera;
AZStd::shared_ptr<AzFramework::OrbitCameraInput> m_orbitCamera;
AZStd::shared_ptr<AzFramework::RotateCameraInput> m_orbitRotateCamera;
AZStd::shared_ptr<AzFramework::TranslateCameraInput> m_orbitTranslateCamera;
AZStd::shared_ptr<AzFramework::OrbitDollyScrollCameraInput> m_orbitDollyScrollCamera;
AZStd::shared_ptr<AzFramework::OrbitDollyMotionCameraInput> m_orbitDollyMoveCamera;
AZStd::shared_ptr<AzFramework::PanCameraInput> m_orbitPanCamera;
AZStd::shared_ptr<AzFramework::FocusCameraInput> m_orbitFocusCamera;
AzFramework::ViewportId m_viewportId;
};
@@ -73,7 +73,7 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial
->Field("TranslateSmoothing", &CameraMovementSettings::m_translateSmoothing)
->Field("TranslateSmoothness", &CameraMovementSettings::m_translateSmoothness)
->Field("CaptureCursorLook", &CameraMovementSettings::m_captureCursorLook)
->Field("PivotYawRotationInverted", &CameraMovementSettings::m_pivotYawRotationInverted)
->Field("OrbitYawRotationInverted", &CameraMovementSettings::m_orbitYawRotationInverted)
->Field("PanInvertedX", &CameraMovementSettings::m_panInvertedX)
->Field("PanInvertedY", &CameraMovementSettings::m_panInvertedY);
@@ -86,12 +86,12 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial
->Field("TranslateUp", &CameraInputSettings::m_translateUpChannelId)
->Field("TranslateDown", &CameraInputSettings::m_translateDownChannelId)
->Field("Boost", &CameraInputSettings::m_boostChannelId)
->Field("Pivot", &CameraInputSettings::m_pivotChannelId)
->Field("Orbit", &CameraInputSettings::m_orbitChannelId)
->Field("FreeLook", &CameraInputSettings::m_freeLookChannelId)
->Field("FreePan", &CameraInputSettings::m_freePanChannelId)
->Field("PivotLook", &CameraInputSettings::m_pivotLookChannelId)
->Field("PivotDolly", &CameraInputSettings::m_pivotDollyChannelId)
->Field("PivotPan", &CameraInputSettings::m_pivotPanChannelId)
->Field("OrbitLook", &CameraInputSettings::m_orbitLookChannelId)
->Field("OrbitDolly", &CameraInputSettings::m_orbitDollyChannelId)
->Field("OrbitPan", &CameraInputSettings::m_orbitPanChannelId)
->Field("Focus", &CameraInputSettings::m_focusChannelId);
serialize.Class<CEditorPreferencesPage_ViewportCamera>()
@@ -144,8 +144,8 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial
->Attribute(AZ::Edit::Attributes::Min, minValue)
->Attribute(AZ::Edit::Attributes::Visibility, &CameraMovementSettings::TranslateSmoothingVisibility)
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_pivotYawRotationInverted, "Camera Pivot Yaw Inverted",
"Inverted yaw rotation while pivoting")
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_orbitYawRotationInverted, "Camera Orbit Yaw Inverted",
"Inverted yaw rotation while orbiting")
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_panInvertedX, "Invert Pan X",
"Invert direction of pan in local X axis")
@@ -186,8 +186,8 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial
"Key/button to move the camera more quickly")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames)
->DataElement(
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotChannelId, "Pivot",
"Key/button to begin the camera pivot behavior")
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitChannelId, "Orbit",
"Key/button to begin the camera orbit behavior")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames)
->DataElement(
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_freeLookChannelId, "Free Look",
@@ -197,19 +197,19 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_freePanChannelId, "Free Pan", "Key/button to begin camera free pan")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames)
->DataElement(
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotLookChannelId, "Pivot Look",
"Key/button to begin camera pivot look")
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitLookChannelId, "Orbit Look",
"Key/button to begin camera orbit look")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames)
->DataElement(
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotDollyChannelId, "Pivot Dolly",
"Key/button to begin camera pivot dolly")
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitDollyChannelId, "Orbit Dolly",
"Key/button to begin camera orbit dolly")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames)
->DataElement(
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotPanChannelId, "Pivot Pan",
"Key/button to begin camera pivot pan")
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitPanChannelId, "Orbit Pan",
"Key/button to begin camera orbit pan")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames)
->DataElement(
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_focusChannelId, "Focus", "Key/button to focus camera pivot")
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_focusChannelId, "Focus", "Key/button to focus camera orbit")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames);
editContext->Class<CEditorPreferencesPage_ViewportCamera>("Viewport Preferences", "Viewport Preferences")
@@ -268,7 +268,7 @@ void CEditorPreferencesPage_ViewportCamera::OnApply()
SandboxEditor::SetCameraTranslateSmoothness(m_cameraMovementSettings.m_translateSmoothness);
SandboxEditor::SetCameraTranslateSmoothingEnabled(m_cameraMovementSettings.m_translateSmoothing);
SandboxEditor::SetCameraCaptureCursorForLook(m_cameraMovementSettings.m_captureCursorLook);
SandboxEditor::SetCameraPivotYawRotationInverted(m_cameraMovementSettings.m_pivotYawRotationInverted);
SandboxEditor::SetCameraOrbitYawRotationInverted(m_cameraMovementSettings.m_orbitYawRotationInverted);
SandboxEditor::SetCameraPanInvertedX(m_cameraMovementSettings.m_panInvertedX);
SandboxEditor::SetCameraPanInvertedY(m_cameraMovementSettings.m_panInvertedY);
@@ -279,12 +279,12 @@ void CEditorPreferencesPage_ViewportCamera::OnApply()
SandboxEditor::SetCameraTranslateUpChannelId(m_cameraInputSettings.m_translateUpChannelId);
SandboxEditor::SetCameraTranslateDownChannelId(m_cameraInputSettings.m_translateDownChannelId);
SandboxEditor::SetCameraTranslateBoostChannelId(m_cameraInputSettings.m_boostChannelId);
SandboxEditor::SetCameraPivotChannelId(m_cameraInputSettings.m_pivotChannelId);
SandboxEditor::SetCameraOrbitChannelId(m_cameraInputSettings.m_orbitChannelId);
SandboxEditor::SetCameraFreeLookChannelId(m_cameraInputSettings.m_freeLookChannelId);
SandboxEditor::SetCameraFreePanChannelId(m_cameraInputSettings.m_freePanChannelId);
SandboxEditor::SetCameraPivotLookChannelId(m_cameraInputSettings.m_pivotLookChannelId);
SandboxEditor::SetCameraPivotDollyChannelId(m_cameraInputSettings.m_pivotDollyChannelId);
SandboxEditor::SetCameraPivotPanChannelId(m_cameraInputSettings.m_pivotPanChannelId);
SandboxEditor::SetCameraOrbitLookChannelId(m_cameraInputSettings.m_orbitLookChannelId);
SandboxEditor::SetCameraOrbitDollyChannelId(m_cameraInputSettings.m_orbitDollyChannelId);
SandboxEditor::SetCameraOrbitPanChannelId(m_cameraInputSettings.m_orbitPanChannelId);
SandboxEditor::SetCameraFocusChannelId(m_cameraInputSettings.m_focusChannelId);
SandboxEditor::EditorModularViewportCameraComposerNotificationBus::Broadcast(
@@ -304,7 +304,7 @@ void CEditorPreferencesPage_ViewportCamera::InitializeSettings()
m_cameraMovementSettings.m_translateSmoothness = SandboxEditor::CameraTranslateSmoothness();
m_cameraMovementSettings.m_translateSmoothing = SandboxEditor::CameraTranslateSmoothingEnabled();
m_cameraMovementSettings.m_captureCursorLook = SandboxEditor::CameraCaptureCursorForLook();
m_cameraMovementSettings.m_pivotYawRotationInverted = SandboxEditor::CameraPivotYawRotationInverted();
m_cameraMovementSettings.m_orbitYawRotationInverted = SandboxEditor::CameraOrbitYawRotationInverted();
m_cameraMovementSettings.m_panInvertedX = SandboxEditor::CameraPanInvertedX();
m_cameraMovementSettings.m_panInvertedY = SandboxEditor::CameraPanInvertedY();
@@ -315,11 +315,11 @@ void CEditorPreferencesPage_ViewportCamera::InitializeSettings()
m_cameraInputSettings.m_translateUpChannelId = SandboxEditor::CameraTranslateUpChannelId().GetName();
m_cameraInputSettings.m_translateDownChannelId = SandboxEditor::CameraTranslateDownChannelId().GetName();
m_cameraInputSettings.m_boostChannelId = SandboxEditor::CameraTranslateBoostChannelId().GetName();
m_cameraInputSettings.m_pivotChannelId = SandboxEditor::CameraPivotChannelId().GetName();
m_cameraInputSettings.m_orbitChannelId = SandboxEditor::CameraOrbitChannelId().GetName();
m_cameraInputSettings.m_freeLookChannelId = SandboxEditor::CameraFreeLookChannelId().GetName();
m_cameraInputSettings.m_freePanChannelId = SandboxEditor::CameraFreePanChannelId().GetName();
m_cameraInputSettings.m_pivotLookChannelId = SandboxEditor::CameraPivotLookChannelId().GetName();
m_cameraInputSettings.m_pivotDollyChannelId = SandboxEditor::CameraPivotDollyChannelId().GetName();
m_cameraInputSettings.m_pivotPanChannelId = SandboxEditor::CameraPivotPanChannelId().GetName();
m_cameraInputSettings.m_orbitLookChannelId = SandboxEditor::CameraOrbitLookChannelId().GetName();
m_cameraInputSettings.m_orbitDollyChannelId = SandboxEditor::CameraOrbitDollyChannelId().GetName();
m_cameraInputSettings.m_orbitPanChannelId = SandboxEditor::CameraOrbitPanChannelId().GetName();
m_cameraInputSettings.m_focusChannelId = SandboxEditor::CameraFocusChannelId().GetName();
}
@@ -54,7 +54,7 @@ private:
float m_translateSmoothness;
bool m_translateSmoothing;
bool m_captureCursorLook;
bool m_pivotYawRotationInverted;
bool m_orbitYawRotationInverted;
bool m_panInvertedX;
bool m_panInvertedY;
@@ -80,12 +80,12 @@ private:
AZStd::string m_translateUpChannelId;
AZStd::string m_translateDownChannelId;
AZStd::string m_boostChannelId;
AZStd::string m_pivotChannelId;
AZStd::string m_orbitChannelId;
AZStd::string m_freeLookChannelId;
AZStd::string m_freePanChannelId;
AZStd::string m_pivotLookChannelId;
AZStd::string m_pivotDollyChannelId;
AZStd::string m_pivotPanChannelId;
AZStd::string m_orbitLookChannelId;
AZStd::string m_orbitDollyChannelId;
AZStd::string m_orbitPanChannelId;
AZStd::string m_focusChannelId;
};
+25 -25
View File
@@ -28,7 +28,7 @@ namespace SandboxEditor
constexpr AZStd::string_view CameraRotateSpeedSetting = "/Amazon/Preferences/Editor/Camera/RotateSpeed";
constexpr AZStd::string_view CameraScrollSpeedSetting = "/Amazon/Preferences/Editor/Camera/DollyScrollSpeed";
constexpr AZStd::string_view CameraDollyMotionSpeedSetting = "/Amazon/Preferences/Editor/Camera/DollyMotionSpeed";
constexpr AZStd::string_view CameraPivotYawRotationInvertedSetting = "/Amazon/Preferences/Editor/Camera/YawRotationInverted";
constexpr AZStd::string_view CameraOrbitYawRotationInvertedSetting = "/Amazon/Preferences/Editor/Camera/YawRotationInverted";
constexpr AZStd::string_view CameraPanInvertedXSetting = "/Amazon/Preferences/Editor/Camera/PanInvertedX";
constexpr AZStd::string_view CameraPanInvertedYSetting = "/Amazon/Preferences/Editor/Camera/PanInvertedY";
constexpr AZStd::string_view CameraPanSpeedSetting = "/Amazon/Preferences/Editor/Camera/PanSpeed";
@@ -44,12 +44,12 @@ namespace SandboxEditor
constexpr AZStd::string_view CameraTranslateUpIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpId";
constexpr AZStd::string_view CameraTranslateDownIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateUpDownId";
constexpr AZStd::string_view CameraTranslateBoostIdSetting = "/Amazon/Preferences/Editor/Camera/TranslateBoostId";
constexpr AZStd::string_view CameraPivotIdSetting = "/Amazon/Preferences/Editor/Camera/PivotId";
constexpr AZStd::string_view CameraOrbitIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitId";
constexpr AZStd::string_view CameraFreeLookIdSetting = "/Amazon/Preferences/Editor/Camera/FreeLookId";
constexpr AZStd::string_view CameraFreePanIdSetting = "/Amazon/Preferences/Editor/Camera/FreePanId";
constexpr AZStd::string_view CameraPivotLookIdSetting = "/Amazon/Preferences/Editor/Camera/PivotLookId";
constexpr AZStd::string_view CameraPivotDollyIdSetting = "/Amazon/Preferences/Editor/Camera/PivotDollyId";
constexpr AZStd::string_view CameraPivotPanIdSetting = "/Amazon/Preferences/Editor/Camera/PivotPanId";
constexpr AZStd::string_view CameraOrbitLookIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitLookId";
constexpr AZStd::string_view CameraOrbitDollyIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitDollyId";
constexpr AZStd::string_view CameraOrbitPanIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitPanId";
constexpr AZStd::string_view CameraFocusIdSetting = "/Amazon/Preferences/Editor/Camera/FocusId";
template<typename T>
@@ -240,14 +240,14 @@ namespace SandboxEditor
SetRegistry(CameraDollyMotionSpeedSetting, speed);
}
bool CameraPivotYawRotationInverted()
bool CameraOrbitYawRotationInverted()
{
return GetRegistry(CameraPivotYawRotationInvertedSetting, false);
return GetRegistry(CameraOrbitYawRotationInvertedSetting, false);
}
void SetCameraPivotYawRotationInverted(const bool inverted)
void SetCameraOrbitYawRotationInverted(const bool inverted)
{
SetRegistry(CameraPivotYawRotationInvertedSetting, inverted);
SetRegistry(CameraOrbitYawRotationInvertedSetting, inverted);
}
bool CameraPanInvertedX()
@@ -404,14 +404,14 @@ namespace SandboxEditor
SetRegistry(CameraTranslateBoostIdSetting, cameraTranslateBoostId);
}
AzFramework::InputChannelId CameraPivotChannelId()
AzFramework::InputChannelId CameraOrbitChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraPivotIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str());
return AzFramework::InputChannelId(GetRegistry(CameraOrbitIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str());
}
void SetCameraPivotChannelId(AZStd::string_view cameraPivotId)
void SetCameraOrbitChannelId(AZStd::string_view cameraOrbitId)
{
SetRegistry(CameraPivotIdSetting, cameraPivotId);
SetRegistry(CameraOrbitIdSetting, cameraOrbitId);
}
AzFramework::InputChannelId CameraFreeLookChannelId()
@@ -434,34 +434,34 @@ namespace SandboxEditor
SetRegistry(CameraFreePanIdSetting, cameraFreePanId);
}
AzFramework::InputChannelId CameraPivotLookChannelId()
AzFramework::InputChannelId CameraOrbitLookChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraPivotLookIdSetting, AZStd::string("mouse_button_left")).c_str());
return AzFramework::InputChannelId(GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str());
}
void SetCameraPivotLookChannelId(AZStd::string_view cameraPivotLookId)
void SetCameraOrbitLookChannelId(AZStd::string_view cameraOrbitLookId)
{
SetRegistry(CameraPivotLookIdSetting, cameraPivotLookId);
SetRegistry(CameraOrbitLookIdSetting, cameraOrbitLookId);
}
AzFramework::InputChannelId CameraPivotDollyChannelId()
AzFramework::InputChannelId CameraOrbitDollyChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraPivotDollyIdSetting, AZStd::string("mouse_button_right")).c_str());
return AzFramework::InputChannelId(GetRegistry(CameraOrbitDollyIdSetting, AZStd::string("mouse_button_right")).c_str());
}
void SetCameraPivotDollyChannelId(AZStd::string_view cameraPivotDollyId)
void SetCameraOrbitDollyChannelId(AZStd::string_view cameraOrbitDollyId)
{
SetRegistry(CameraPivotDollyIdSetting, cameraPivotDollyId);
SetRegistry(CameraOrbitDollyIdSetting, cameraOrbitDollyId);
}
AzFramework::InputChannelId CameraPivotPanChannelId()
AzFramework::InputChannelId CameraOrbitPanChannelId()
{
return AzFramework::InputChannelId(GetRegistry(CameraPivotPanIdSetting, AZStd::string("mouse_button_middle")).c_str());
return AzFramework::InputChannelId(GetRegistry(CameraOrbitPanIdSetting, AZStd::string("mouse_button_middle")).c_str());
}
void SetCameraPivotPanChannelId(AZStd::string_view cameraPivotPanId)
void SetCameraOrbitPanChannelId(AZStd::string_view cameraOrbitPanId)
{
SetRegistry(CameraPivotPanIdSetting, cameraPivotPanId);
SetRegistry(CameraOrbitPanIdSetting, cameraOrbitPanId);
}
AzFramework::InputChannelId CameraFocusChannelId()
+10 -10
View File
@@ -71,8 +71,8 @@ namespace SandboxEditor
SANDBOX_API float CameraDollyMotionSpeed();
SANDBOX_API void SetCameraDollyMotionSpeed(float speed);
SANDBOX_API bool CameraPivotYawRotationInverted();
SANDBOX_API void SetCameraPivotYawRotationInverted(bool inverted);
SANDBOX_API bool CameraOrbitYawRotationInverted();
SANDBOX_API void SetCameraOrbitYawRotationInverted(bool inverted);
SANDBOX_API bool CameraPanInvertedX();
SANDBOX_API void SetCameraPanInvertedX(bool inverted);
@@ -119,8 +119,8 @@ namespace SandboxEditor
SANDBOX_API AzFramework::InputChannelId CameraTranslateBoostChannelId();
SANDBOX_API void SetCameraTranslateBoostChannelId(AZStd::string_view cameraTranslateBoostId);
SANDBOX_API AzFramework::InputChannelId CameraPivotChannelId();
SANDBOX_API void SetCameraPivotChannelId(AZStd::string_view cameraPivotId);
SANDBOX_API AzFramework::InputChannelId CameraOrbitChannelId();
SANDBOX_API void SetCameraOrbitChannelId(AZStd::string_view cameraOrbitId);
SANDBOX_API AzFramework::InputChannelId CameraFreeLookChannelId();
SANDBOX_API void SetCameraFreeLookChannelId(AZStd::string_view cameraFreeLookId);
@@ -128,14 +128,14 @@ namespace SandboxEditor
SANDBOX_API AzFramework::InputChannelId CameraFreePanChannelId();
SANDBOX_API void SetCameraFreePanChannelId(AZStd::string_view cameraFreePanId);
SANDBOX_API AzFramework::InputChannelId CameraPivotLookChannelId();
SANDBOX_API void SetCameraPivotLookChannelId(AZStd::string_view cameraPivotLookId);
SANDBOX_API AzFramework::InputChannelId CameraOrbitLookChannelId();
SANDBOX_API void SetCameraOrbitLookChannelId(AZStd::string_view cameraOrbitLookId);
SANDBOX_API AzFramework::InputChannelId CameraPivotDollyChannelId();
SANDBOX_API void SetCameraPivotDollyChannelId(AZStd::string_view cameraPivotDollyId);
SANDBOX_API AzFramework::InputChannelId CameraOrbitDollyChannelId();
SANDBOX_API void SetCameraOrbitDollyChannelId(AZStd::string_view cameraOrbitDollyId);
SANDBOX_API AzFramework::InputChannelId CameraPivotPanChannelId();
SANDBOX_API void SetCameraPivotPanChannelId(AZStd::string_view cameraPivotPanId);
SANDBOX_API AzFramework::InputChannelId CameraOrbitPanChannelId();
SANDBOX_API void SetCameraOrbitPanChannelId(AZStd::string_view cameraOrbitPanId);
SANDBOX_API AzFramework::InputChannelId CameraFocusChannelId();
SANDBOX_API void SetCameraFocusChannelId(AZStd::string_view cameraFocusId);
@@ -173,6 +173,7 @@ namespace AZ
if (assetTracker)
{
assetTracker->FixUpAsset(*instance);
assetTracker->AddAsset(*instance);
}
@@ -185,7 +186,20 @@ namespace AZ
return context.Report(result, message);
}
void SerializedAssetTracker::AddAsset(Asset<AssetData>& asset)
void SerializedAssetTracker::SetAssetFixUp(AssetFixUp assetFixUpCallback)
{
m_assetFixUpCallback = AZStd::move(assetFixUpCallback);
}
void SerializedAssetTracker::FixUpAsset(Asset<AssetData>& asset)
{
if (m_assetFixUpCallback)
{
m_assetFixUpCallback(asset);
}
}
void SerializedAssetTracker::AddAsset(Asset<AssetData> asset)
{
m_serializedAssets.emplace_back(asset);
}
@@ -199,5 +213,6 @@ namespace AZ
{
return m_serializedAssets;
}
} // namespace Data
} // namespace AZ
@@ -39,13 +39,18 @@ namespace AZ
{
public:
AZ_RTTI(SerializedAssetTracker, "{1E067091-8C0A-44B1-A455-6E97663F6963}");
using AssetFixUp = AZStd::function<void(Asset<AssetData>& asset)>;
void AddAsset(Asset<AssetData>& asset);
void SetAssetFixUp(AssetFixUp assetFixUpCallback);
void FixUpAsset(Asset<AssetData>& asset);
void AddAsset(Asset<AssetData> asset);
AZStd::vector<Asset<AssetData>>& GetTrackedAssets();
const AZStd::vector<Asset<AssetData>>& GetTrackedAssets() const;
private:
AZStd::vector<Asset<AssetData>> m_serializedAssets;
AssetFixUp m_assetFixUpCallback;
};
} // namespace Data
} // namespace AZ
@@ -224,6 +224,8 @@ namespace AZ
void Debug::Trace::Terminate(int exitCode)
{
AZ_TracePrintf("Exit", "Called Terminate() with exit code: 0x%x", exitCode);
AZ::Debug::Trace::PrintCallstack("Exit");
Platform::Terminate(exitCode);
}
+17 -9
View File
@@ -160,8 +160,8 @@ namespace AZ
/**
* Locking primitive that is used when executing events in the event queue.
*/
using EventQueueMutexType = typename AZStd::Utils::if_c<AZStd::is_same<typename Traits::EventQueueMutexType, NullMutex>::value, // if EventQueueMutexType==NullMutex use MutexType otherwise EventQueueMutexType
MutexType, typename Traits::EventQueueMutexType>::type;
using EventQueueMutexType = AZStd::conditional_t<AZStd::is_same<typename Traits::EventQueueMutexType, NullMutex>::value, // if EventQueueMutexType==NullMutex use MutexType otherwise EventQueueMutexType
MutexType, typename Traits::EventQueueMutexType>;
/**
* Pointer to an address on the bus.
@@ -180,14 +180,22 @@ namespace AZ
* `<BusName>::ExecuteQueuedEvents()`.
* By default, the event queue is disabled.
*/
static const bool EnableEventQueue = Traits::EnableEventQueue;
static const bool EventQueueingActiveByDefault = Traits::EventQueueingActiveByDefault;
static const bool EnableQueuedReferences = Traits::EnableQueuedReferences;
static constexpr bool EnableEventQueue = Traits::EnableEventQueue;
static constexpr bool EventQueueingActiveByDefault = Traits::EventQueueingActiveByDefault;
static constexpr bool EnableQueuedReferences = Traits::EnableQueuedReferences;
/**
* True if the EBus supports more than one address. Otherwise, false.
*/
static const bool HasId = Traits::AddressPolicy != EBusAddressPolicy::Single;
static constexpr bool HasId = Traits::AddressPolicy != EBusAddressPolicy::Single;
/**
* Template Lock Guard class that wraps around the Mutex
* The EBus uses for Dispatching Events.
* This is not the EBus Context Mutex if LocklessDispatch is true
*/
template <typename DispatchMutex>
using DispatchLockGuard = typename Traits::template DispatchLockGuard<DispatchMutex, Traits::LocklessDispatch>;
};
/**
@@ -460,7 +468,7 @@ namespace AZ
using BusPtr = typename Traits::BusPtr;
/**
* Helper to queue an event by BusIdType only when function queueing is enabled
* Helper to queue an event by BusIdType only when function queueing is enabled
* @param id Address ID. Handlers that are connected to this ID will receive the event.
* @param func Function pointer of the event to dispatch.
* @param args Function arguments that are passed to each handler.
@@ -581,7 +589,7 @@ namespace AZ
, public EBusBroadcaster<Bus, Traits>
, public EBusEventer<Bus, Traits>
, public EBusEventEnumerator<Bus, Traits>
, public AZStd::Utils::if_c<Traits::EnableEventQueue, EBusEventQueue<Bus, Traits>, EBusNullQueue>::type
, public AZStd::conditional_t<Traits::EnableEventQueue, EBusEventQueue<Bus, Traits>, EBusNullQueue>
{
};
@@ -599,7 +607,7 @@ namespace AZ
: public EventDispatcher<Bus, Traits>
, public EBusBroadcaster<Bus, Traits>
, public EBusBroadcastEnumerator<Bus, Traits>
, public AZStd::Utils::if_c<Traits::EnableEventQueue, EBusBroadcastQueue<Bus, Traits>, EBusNullQueue>::type
, public AZStd::conditional_t<Traits::EnableEventQueue, EBusBroadcastQueue<Bus, Traits>, EBusNullQueue>
{
};
+33 -2
View File
@@ -236,6 +236,17 @@ namespace AZ
* code before or after an event.
*/
using EventProcessingPolicy = EBusEventProcessingPolicy;
/**
* Template Lock Guard class that wraps around the Mutex
* The EBus Context uses the LockGuard when dispatching
* (either AZStd::scoped_lock<MutexType> or NullLockGuard<MutexType>)
* The IsLocklessDispatch bool is there to defer evaluation of the LocklessDispatch constant
* Otherwise the value above in EBusTraits.h is always used and not the value
* that the derived trait class sets.
*/
template <typename DispatchMutex, bool IsLocklessDispatch>
using DispatchLockGuard = AZStd::conditional_t<IsLocklessDispatch, AZ::Internal::NullLockGuard<DispatchMutex>, AZStd::scoped_lock<DispatchMutex>>;
};
namespace Internal
@@ -496,6 +507,14 @@ namespace AZ
*/
static const bool HasId = Traits::AddressPolicy != EBusAddressPolicy::Single;
/**
* Template Lock Guard class that wraps around the Mutex
* The EBus uses for Dispatching Events.
* This is not EBus Context Mutex when LocklessDispatch is set
*/
template <typename DispatchMutex>
using DispatchLockGuard = typename ImplTraits::template DispatchLockGuard<DispatchMutex>;
//////////////////////////////////////////////////////////////////////////
// Check to help identify common mistakes
/// @cond EXCLUDE_DOCS
@@ -620,11 +639,11 @@ namespace AZ
using ContextMutexType = AZStd::conditional_t<BusTraits::LocklessDispatch && AZStd::is_same_v<MutexType, AZ::NullMutex>, AZStd::shared_mutex, MutexType>;
/**
* The scoped lock guard to use (either AZStd::scoped_lock<MutexType> or NullLockGuard<MutexType>
* The scoped lock guard to use
* during broadcast/event dispatch.
* @see EBusTraits::LocklessDispatch
*/
using DispatchLockGuard = AZStd::conditional_t<BusTraits::LocklessDispatch, AZ::Internal::NullLockGuard<ContextMutexType>, AZStd::scoped_lock<ContextMutexType>>;
using DispatchLockGuard = DispatchLockGuard<ContextMutexType>;
/**
* The scoped lock guard to use during connection. Some specialized policies execute handler methods which
@@ -704,6 +723,11 @@ namespace AZ
static Context& GetOrCreateContext(bool trackCallstack=true);
static bool IsInDispatch(Context* context = GetContext(false));
/**
* Returns whether the EBus context is in the middle of a dispatch on the current thread
*/
static bool IsInDispatchThisThread(Context* context = GetContext(false));
/// @cond EXCLUDE_DOCS
struct RouterCallstackEntry
: public CallstackEntry
@@ -1208,6 +1232,13 @@ AZ_POP_DISABLE_WARNING
return context != nullptr && context->m_dispatches > 0;
}
template<class Interface, class Traits>
bool EBus<Interface, Traits>::IsInDispatchThisThread(Context* context)
{
return context != nullptr && context->s_callstack != nullptr
&& context->s_callstack->m_prev != nullptr;
}
//=========================================================================
template<class Interface, class Traits>
EBus<Interface, Traits>::RouterCallstackEntry::RouterCallstackEntry(Iterator it, const BusIdType* busId, bool isQueued, bool isReverse)
@@ -18,6 +18,14 @@
#include <AzCore/std/parallel/thread.h>
#include <AzCore/Math/MathUtils.h>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Threading/ThreadUtils.h>
AZ_CVAR(float, cl_jobThreadsConcurrencyRatio, 0.6f, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system multiplier on the number of hw threads the machine creates at initialization");
AZ_CVAR(uint32_t, cl_jobThreadsNumReserved, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system number of hardware threads that are reserved for O3DE system threads");
AZ_CVAR(uint32_t, cl_jobThreadsMinNumber, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "Legacy Job system minimum number of worker threads to create after scaling the number of hw threads");
namespace AZ
{
//=========================================================================
@@ -46,9 +54,10 @@ namespace AZ
JobManagerThreadDesc threadDesc;
int numberOfWorkerThreads = m_numberOfWorkerThreads;
if (numberOfWorkerThreads <= 0)
if (numberOfWorkerThreads <= 0) // spawn default number of threads
{
numberOfWorkerThreads = AZ::GetMin(static_cast<unsigned int>(desc.m_workerThreads.capacity()), AZStd::thread::hardware_concurrency());
uint32_t scaledHardwareThreads = Threading::CalcNumWorkerThreads(cl_jobThreadsConcurrencyRatio, cl_jobThreadsMinNumber, cl_jobThreadsNumReserved);
numberOfWorkerThreads = AZ::GetMin(static_cast<unsigned int>(desc.m_workerThreads.capacity()), scaledHardwareThreads);
#if (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS)
numberOfWorkerThreads = AZ::GetMin(numberOfWorkerThreads, AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS);
#endif // (AZ_TRAIT_MAX_JOB_MANAGER_WORKER_THREADS)
@@ -36,7 +36,7 @@ namespace AZ
*/
int m_stackSize;
JobManagerThreadDesc(int cpuId = -1, int priority = -100000, int stackSize = -1)
JobManagerThreadDesc(int cpuId = -1, int priority = 0, int stackSize = -1)
: m_cpuId(cpuId)
, m_priority(priority)
, m_stackSize(stackSize)
@@ -308,11 +308,11 @@ namespace AZ
void TaskExecutor::SetInstance(TaskExecutor* executor)
{
if (!executor)
if (!executor) // allow unsetting the executor
{
s_executor.Reset();
}
else if (!s_executor) // ignore any calls to set after the first (this happens in unit tests that create new system entities)
else if (!s_executor) // ignore any extra executors after the first (this happens during unit tests)
{
s_executor = AZ::Environment::CreateVariable<TaskExecutor*>(s_executorName, executor);
}
@@ -11,9 +11,15 @@
#include <AzCore/Task/TaskGraphSystemComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Math/MathUtils.h>
#include <AzCore/Threading/ThreadUtils.h>
// Create a cvar as a central location for experimentation with switching from the Job system to TaskGraph system.
AZ_CVAR(bool, cl_activateTaskGraph, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Flag clients of TaskGraph to switch between jobs/taskgraph (Note does not disable task graph system)");
AZ_CVAR(float, cl_taskGraphThreadsConcurrencyRatio, 1.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph calculate the number of worker threads to spawn by scaling the number of hw threads, value is clamped between 0.0f and 1.0f");
AZ_CVAR(uint32_t, cl_taskGraphThreadsNumReserved, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph number of hardware threads that are reserved for O3DE system threads. Value is clamped between 0 and the number of logical cores in the system");
AZ_CVAR(uint32_t, cl_taskGraphThreadsMinNumber, 2, nullptr, AZ::ConsoleFunctorFlags::Null, "TaskGraph minimum number of worker threads to create after scaling the number of hw threads");
static constexpr uint32_t TaskExecutorServiceCrc = AZ_CRC_CE("TaskExecutorService");
namespace AZ
@@ -24,8 +30,8 @@ namespace AZ
if (Interface<TaskGraphActiveInterface>::Get() == nullptr)
{
Interface<TaskGraphActiveInterface>::Register(this);
m_taskExecutor = aznew TaskExecutor();
Interface<TaskGraphActiveInterface>::Register(this); // small window that another thread can try to use taskgraph between this line and the set instance.
m_taskExecutor = aznew TaskExecutor(Threading::CalcNumWorkerThreads(cl_taskGraphThreadsConcurrencyRatio, cl_taskGraphThreadsMinNumber, cl_taskGraphThreadsNumReserved));
TaskExecutor::SetInstance(m_taskExecutor);
}
}
@@ -0,0 +1,25 @@
/*
* 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/Threading/ThreadUtils.h>
#include <AzCore/std/parallel/thread.h>
#include <AzCore/Math/MathUtils.h>
namespace AZ::Threading
{
uint32_t CalcNumWorkerThreads(float workerThreadsRatio, uint32_t minNumWorkerThreads, uint32_t reservedNumThreads)
{
const uint32_t maxHardwareThreads = AZStd::thread::hardware_concurrency();
const uint32_t numReservedThreads = AZ::GetMin<uint32_t>(reservedNumThreads, maxHardwareThreads); // protect against num reserved being bigger than the number of hw threads
const uint32_t maxWorkerThreads = maxHardwareThreads - numReservedThreads;
const float requestedWorkerThreads = AZ::GetClamp<float>(workerThreadsRatio, 0.0f, 1.0f) * static_cast<float>(maxWorkerThreads);
const uint32_t requestedWorkerThreadsRounded = AZStd::lround(requestedWorkerThreads);
const uint32_t numWorkerThreads = AZ::GetMax<uint32_t>(minNumWorkerThreads, requestedWorkerThreadsRounded);
return numWorkerThreads;
}
};
@@ -0,0 +1,22 @@
/*
* 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/base.h>
namespace AZ::Threading
{
//! Calculates the number of worker threads a system should use based on the number of hardware threads a device has.
//! result = max (minNumWorkerThreads, workerThreadsRatio * (num_hardware_threads - reservedNumThreads))
//! @param workerThreadsRatio scale applied to the calculated maximum number of threads available after reserved threads have been accounted for. Clamped between 0 and 1.
//! @param minNumWorkerThreads minimum value that will be returned. Value is unclamped and can be more than num_hardware_threads.
//! @param reservedNumThreads number of hardware threads to reserve for O3DE system threads. Value clamped to num_hardware_threads.
//! @return number of worker threads for the calling system to allocate
uint32_t CalcNumWorkerThreads(float workerThreadsRatio, uint32_t minNumWorkerThreads, uint32_t reservedNumThreads);
};
@@ -639,6 +639,8 @@ set(FILES
Threading/ThreadSafeDeque.inl
Threading/ThreadSafeObject.h
Threading/ThreadSafeObject.inl
Threading/ThreadUtils.h
Threading/ThreadUtils.cpp
Time/ITime.h
Time/TimeSystemComponent.cpp
Time/TimeSystemComponent.h
@@ -59,6 +59,10 @@ namespace AZStd
{
priority = desc->m_priority;
}
else
{
priority = SCHED_OTHER;
}
if (desc->m_name)
{
name = desc->m_name;
+193 -8
View File
@@ -2088,7 +2088,7 @@ namespace UnitTest
DisconnectNextHandlerByIdImpl multiHandler2;
multiHandler2.BusConnect(DisconnectNextHandlerByIdImpl::firstBusAddress);
multiHandler2.BusConnect(DisconnectNextHandlerByIdImpl::secondBusAddress);
// Set the first handler m_nextHandler field to point to the second handler
multiHandler1.m_nextHandler = &multiHandler2;
@@ -2807,7 +2807,7 @@ namespace UnitTest
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds(m_val % m_maxSleep));
}
}
void DoConnect() override
{
MyEventGroupBus::Handler::BusConnect(m_id);
@@ -2854,7 +2854,7 @@ namespace UnitTest
}
MyEventGroupBus::Event(id, &MyEventGroupBus::Events::Calculate, i, i * 2, i << 4);
LocklessConnectorBus::Event(id, &LocklessConnectorBus::Events::DoDisconnect);
bool failed = (AZStd::find_if(&sentinel[0], end, [](char s) { return s != 0; }) != end);
@@ -2891,7 +2891,7 @@ namespace UnitTest
{
MyEventGroupImpl()
{
}
~MyEventGroupImpl() override
@@ -3614,7 +3614,7 @@ namespace UnitTest
{
AZStd::this_thread::yield();
}
EXPECT_GE(AZStd::chrono::system_clock::now(), endTime);
};
AZStd::thread connectThread([&connectHandler, &waitHandler]()
@@ -3813,7 +3813,7 @@ namespace UnitTest
struct LastHandlerDisconnectHandler
: public LastHandlerDisconnectBus::Handler
{
void OnEvent() override
void OnEvent() override
{
++m_numOnEvents;
BusDisconnect();
@@ -3854,7 +3854,7 @@ namespace UnitTest
struct DisconnectAssertHandler
: public DisconnectAssertBus::Handler
{
};
TEST_F(EBus, HandlerDestroyedWithoutDisconnect_Asserts)
@@ -3995,6 +3995,191 @@ namespace UnitTest
idTestRequest.Disconnect();
}
// IsInDispatchThisThread
struct IsInThreadDispatchRequests
: AZ::EBusTraits
{
using MutexType = AZStd::recursive_mutex;
};
using IsInThreadDispatchBus = AZ::EBus<IsInThreadDispatchRequests>;
class IsInThreadDispatchHandler
: public IsInThreadDispatchBus::Handler
{};
TEST_F(EBus, InvokingIsInThisThread_ReturnsSuccess_OnlyIfThreadIsInDispatch)
{
IsInThreadDispatchHandler handler;
handler.BusConnect();
auto ThreadDispatcher = [](IsInThreadDispatchRequests*)
{
EXPECT_TRUE(IsInThreadDispatchBus::IsInDispatchThisThread());
auto PerThreadBusDispatch = []()
{
EXPECT_FALSE(IsInThreadDispatchBus::IsInDispatchThisThread());
};
AZStd::array threads{ AZStd::thread(PerThreadBusDispatch), AZStd::thread(PerThreadBusDispatch) };
for (AZStd::thread& thread : threads)
{
thread.join();
}
};
static constexpr size_t ThreadDispatcherIterations = 4;
for (size_t iteration = 0; iteration < ThreadDispatcherIterations; ++iteration)
{
EXPECT_FALSE(IsInThreadDispatchBus::IsInDispatchThisThread());
IsInThreadDispatchBus::Broadcast(ThreadDispatcher);
EXPECT_FALSE(IsInThreadDispatchBus::IsInDispatchThisThread());
}
}
// Thread Dispatch Policy
struct ThreadDispatchTestBusTraits
: AZ::EBusTraits
{
using MutexType = AZStd::recursive_mutex;
struct PostThreadDispatchTestInvoker
{
~PostThreadDispatchTestInvoker();
};
template <typename DispatchMutex>
struct ThreadDispatchTestLockGuard
{
ThreadDispatchTestLockGuard(DispatchMutex& contextMutex)
: m_lock{ contextMutex }
{}
ThreadDispatchTestLockGuard(DispatchMutex& contextMutex, AZStd::adopt_lock_t adopt_lock)
: m_lock{ contextMutex, adopt_lock }
{}
ThreadDispatchTestLockGuard(const ThreadDispatchTestLockGuard&) = delete;
ThreadDispatchTestLockGuard& operator=(const ThreadDispatchTestLockGuard&) = delete;
private:
PostThreadDispatchTestInvoker m_threadPolicyInvoker;
using LockType = AZStd::conditional_t<LocklessDispatch, AZ::Internal::NullLockGuard<DispatchMutex>, AZStd::scoped_lock<DispatchMutex>>;
LockType m_lock;
};
template <typename DispatchMutex, bool IsLocklessDispatch>
using DispatchLockGuard = ThreadDispatchTestLockGuard<DispatchMutex>;
static inline AZStd::atomic<int32_t> s_threadPostDispatchCalls;
};
class ThreadDispatchTestRequests
{
public:
virtual void FirstCall() = 0;
virtual void SecondCall() = 0;
virtual void ThirdCall() = 0;
};
using ThreadDispatchTestBus = AZ::EBus<ThreadDispatchTestRequests, ThreadDispatchTestBusTraits>;
ThreadDispatchTestBusTraits::PostThreadDispatchTestInvoker::~PostThreadDispatchTestInvoker()
{
if (!ThreadDispatchTestBus::IsInDispatchThisThread())
{
++s_threadPostDispatchCalls;
}
}
class ThreadDispatchTestHandler
: public ThreadDispatchTestBus::Handler
{
public:
void Connect()
{
ThreadDispatchTestBus::Handler::BusConnect();
}
void Disconnect()
{
ThreadDispatchTestBus::Handler::BusDisconnect();
}
void FirstCall() override
{
ThreadDispatchTestBus::Broadcast(&ThreadDispatchTestBus::Events::SecondCall);
}
void SecondCall() override
{
ThreadDispatchTestBus::Broadcast(&ThreadDispatchTestBus::Events::ThirdCall);
}
void ThirdCall() override
{
}
};
template <typename ParamType>
class EBusParamFixture
: public ScopedAllocatorSetupFixture
, public ::testing::WithParamInterface<ParamType>
{};
struct ThreadDispatchParams
{
size_t m_threadCount{};
size_t m_handlerCount{};
};
using ThreadDispatchParamFixture = EBusParamFixture<ThreadDispatchParams>;
INSTANTIATE_TEST_CASE_P(
ThreadDispatch,
ThreadDispatchParamFixture,
::testing::Values(
ThreadDispatchParams{ 1, 1 },
ThreadDispatchParams{ 2, 1 },
ThreadDispatchParams{ 1, 2 },
ThreadDispatchParams{ 2, 2 },
ThreadDispatchParams{ 16, 8 }
)
);
TEST_P(ThreadDispatchParamFixture, CustomDispatchLockGuard_InvokesPostDispatchFunction_AfterThreadHasFinishedDispatch)
{
ThreadDispatchTestBusTraits::s_threadPostDispatchCalls = 0;
ThreadDispatchParams threadDispatchParams = GetParam();
AZStd::vector<AZStd::thread> testThreads;
AZStd::vector<ThreadDispatchTestHandler> testHandlers(threadDispatchParams.m_handlerCount);
for (ThreadDispatchTestHandler& testHandler : testHandlers)
{
testHandler.Connect();
}
static constexpr size_t DispatchThreadCalls = 3;
const size_t totalThreadDispatchCalls = threadDispatchParams.m_threadCount * DispatchThreadCalls;
auto DispatchThreadWorker = []()
{
ThreadDispatchTestBus::Broadcast(&ThreadDispatchTestBus::Events::FirstCall);
ThreadDispatchTestBus::Broadcast(&ThreadDispatchTestBus::Events::SecondCall);
ThreadDispatchTestBus::Broadcast(&ThreadDispatchTestBus::Events::ThirdCall);
};
for (size_t threadIndex = 0; threadIndex < threadDispatchParams.m_threadCount; ++threadIndex)
{
testThreads.emplace_back(DispatchThreadWorker);
}
for (AZStd::thread& thread : testThreads)
{
thread.join();
}
for (ThreadDispatchTestHandler& testHandler : testHandlers)
{
testHandler.Disconnect();
}
EXPECT_EQ(totalThreadDispatchCalls, ThreadDispatchTestBusTraits::s_threadPostDispatchCalls);
ThreadDispatchTestBusTraits::s_threadPostDispatchCalls = 0;
}
} // namespace UnitTest
#if defined(HAVE_BENCHMARK)
@@ -4370,7 +4555,7 @@ namespace Benchmark
Bus::ExecuteQueuedEvents();
}
s_benchmarkEBusEnv<Bus>.Disconnect(state);
}
BUS_BENCHMARK_REGISTER_ALL(BM_EBus_ExecuteBroadcast);
@@ -533,8 +533,8 @@ namespace AzFramework
m_translateCameraInputChannelIds = translateCameraInputChannelIds;
}
PivotCameraInput::PivotCameraInput(const InputChannelId& pivotChannelId)
: m_pivotChannelId(pivotChannelId)
OrbitCameraInput::OrbitCameraInput(const InputChannelId& orbitChannelId)
: m_orbitChannelId(orbitChannelId)
{
m_pivotFn = []([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction)
{
@@ -542,11 +542,11 @@ namespace AzFramework
};
}
bool PivotCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, const float scrollDelta)
bool OrbitCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, const float scrollDelta)
{
if (const auto* input = AZStd::get_if<DiscreteInputEvent>(&event))
{
if (input->m_channelId == m_pivotChannelId)
if (input->m_channelId == m_orbitChannelId)
{
if (input->m_state == InputChannel::State::Began)
{
@@ -561,13 +561,13 @@ namespace AzFramework
if (Active())
{
return m_pivotCameras.HandleEvents(event, cursorDelta, scrollDelta);
return m_orbitCameras.HandleEvents(event, cursorDelta, scrollDelta);
}
return !Idle();
}
Camera PivotCameraInput::StepCamera(
Camera OrbitCameraInput::StepCamera(
const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime)
{
Camera nextCamera = targetCamera;
@@ -581,12 +581,12 @@ namespace AzFramework
if (Active())
{
MovePivotDetached(nextCamera, m_pivotFn(targetCamera.Translation(), targetCamera.Rotation().GetBasisY()));
nextCamera = m_pivotCameras.StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
nextCamera = m_orbitCameras.StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
}
if (Ending())
{
m_pivotCameras.Reset();
m_orbitCameras.Reset();
nextCamera.m_pivot = nextCamera.Translation();
nextCamera.m_offset = AZ::Vector3::CreateZero();
@@ -595,12 +595,12 @@ namespace AzFramework
return nextCamera;
}
void PivotCameraInput::SetPivotInputChannelId(const InputChannelId& pivotChanneId)
void OrbitCameraInput::SetOrbitInputChannelId(const InputChannelId& orbitChanneId)
{
m_pivotChannelId = pivotChanneId;
m_orbitChannelId = orbitChanneId;
}
PivotDollyScrollCameraInput::PivotDollyScrollCameraInput()
OrbitDollyScrollCameraInput::OrbitDollyScrollCameraInput()
{
m_scrollSpeedFn = []() constexpr
{
@@ -608,7 +608,7 @@ namespace AzFramework
};
}
bool PivotDollyScrollCameraInput::HandleEvents(
bool OrbitDollyScrollCameraInput::HandleEvents(
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta)
{
if (const auto* scroll = AZStd::get_if<ScrollEvent>(&event))
@@ -619,7 +619,7 @@ namespace AzFramework
return !Idle();
}
static Camera PivotDolly(const Camera& targetCamera, const float delta)
static Camera OrbitDolly(const Camera& targetCamera, const float delta)
{
Camera nextCamera = targetCamera;
@@ -646,18 +646,18 @@ namespace AzFramework
return nextCamera;
}
Camera PivotDollyScrollCameraInput::StepCamera(
Camera OrbitDollyScrollCameraInput::StepCamera(
const Camera& targetCamera,
[[maybe_unused]] const ScreenVector& cursorDelta,
const float scrollDelta,
[[maybe_unused]] const float deltaTime)
{
const auto nextCamera = PivotDolly(targetCamera, aznumeric_cast<float>(scrollDelta) * m_scrollSpeedFn());
const auto nextCamera = OrbitDolly(targetCamera, aznumeric_cast<float>(scrollDelta) * m_scrollSpeedFn());
EndActivation();
return nextCamera;
}
PivotDollyMotionCameraInput::PivotDollyMotionCameraInput(const InputChannelId& dollyChannelId)
OrbitDollyMotionCameraInput::OrbitDollyMotionCameraInput(const InputChannelId& dollyChannelId)
: m_dollyChannelId(dollyChannelId)
{
m_motionSpeedFn = []() constexpr
@@ -666,28 +666,28 @@ namespace AzFramework
};
}
bool PivotDollyMotionCameraInput::HandleEvents(
bool OrbitDollyMotionCameraInput::HandleEvents(
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta)
{
HandleActivationEvents(event, m_dollyChannelId, cursorDelta, m_clickDetector, *this);
return CameraInputUpdatingAfterMotion(*this);
}
Camera PivotDollyMotionCameraInput::StepCamera(
Camera OrbitDollyMotionCameraInput::StepCamera(
const Camera& targetCamera,
const ScreenVector& cursorDelta,
[[maybe_unused]] const float scrollDelta,
[[maybe_unused]] const float deltaTime)
{
return PivotDolly(targetCamera, aznumeric_cast<float>(cursorDelta.m_y) * m_motionSpeedFn());
return OrbitDolly(targetCamera, aznumeric_cast<float>(cursorDelta.m_y) * m_motionSpeedFn());
}
void PivotDollyMotionCameraInput::SetDollyInputChannelId(const InputChannelId& dollyChannelId)
void OrbitDollyMotionCameraInput::SetDollyInputChannelId(const InputChannelId& dollyChannelId)
{
m_dollyChannelId = dollyChannelId;
}
ScrollTranslationCameraInput::ScrollTranslationCameraInput()
LookScrollTranslationCameraInput::LookScrollTranslationCameraInput()
{
m_scrollSpeedFn = []() constexpr
{
@@ -695,7 +695,7 @@ namespace AzFramework
};
}
bool ScrollTranslationCameraInput::HandleEvents(
bool LookScrollTranslationCameraInput::HandleEvents(
const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta)
{
if (const auto* scroll = AZStd::get_if<ScrollEvent>(&event))
@@ -706,7 +706,7 @@ namespace AzFramework
return !Idle();
}
Camera ScrollTranslationCameraInput::StepCamera(
Camera LookScrollTranslationCameraInput::StepCamera(
const Camera& targetCamera,
[[maybe_unused]] const ScreenVector& cursorDelta,
const float scrollDelta,
@@ -30,8 +30,11 @@ namespace AzFramework
AZ::Vector3 EulerAngles(const AZ::Matrix3x3& orientation);
//! A simple camera representation using spherical coordinates as input (pitch, yaw, pivot and offset).
//! The cameras transform and view can be obtained through accessor functions that use the internal
//! The camera's transform and view can be obtained through accessor functions that use the internal
//! spherical coordinates to calculate the position and orientation.
//! @note Modifying m_pivot directly and leaving m_offset as zero will produce a free look camera effect, giving
//! m_offset a value (e.g. in negative Y only) will produce an orbit camera effect, modifying X and Z of m_offset
//! will further alter the camera translation in relation to m_pivot so it appears off center.
struct Camera
{
AZ::Vector3 m_pivot = AZ::Vector3::CreateZero(); //!< Pivot point to rotate about (modified in world space).
@@ -291,7 +294,7 @@ namespace AzFramework
Cameras m_cameras; //!< Represents a collection of camera inputs that together provide a camera controller.
private:
ScreenVector m_motionDelta; //!< The delta used for look/pivot/pan (rotation + translation) - two dimensional.
ScreenVector m_motionDelta; //!< The delta used for look/orbit/pan (rotation + translation) - two dimensional.
CursorState m_cursorState; //!< The current and previous position of the cursor (used to calculate movement delta).
float m_scrollDelta = 0.0f; //!< The delta used for dolly/movement (translation) - one dimensional.
bool m_handlingEvents = false; //!< Is the camera system currently handling events (events are consumed and not propagated).
@@ -316,7 +319,7 @@ namespace AzFramework
return AZStd::fmod(yaw + AZ::Constants::TwoPi, AZ::Constants::TwoPi);
}
//! A camera input to handle motion deltas that can rotate or pivot the camera.
//! A camera input to handle motion deltas that can change the orientation of the camera (update pitch and yaw).
class RotateCameraInput : public CameraInput
{
public:
@@ -348,15 +351,16 @@ namespace AzFramework
//! PanAxes build function that will return a pair of pan axes depending on the camera orientation.
using PanAxesFn = AZStd::function<PanAxes(const Camera& camera)>;
//! PanAxes to use while in 'look' camera behavior (free look).
//! PanAxes to use while in 'look' or 'orbit' camera behavior.
inline PanAxes LookPan(const Camera& camera)
{
const AZ::Matrix3x3 orientation = camera.Rotation();
return { orientation.GetBasisX(), orientation.GetBasisZ() };
}
//! PanAxes to use while in 'pivot' camera behavior.
inline PanAxes PivotPan(const Camera& camera)
//! Optional PanAxes to use while in 'orbit' camera behavior.
//! @note This will move the camera in the local X/Y plane instead of usual X/Z plane.
inline PanAxes OrbitPan(const Camera& camera)
{
const AZ::Matrix3x3 orientation = camera.Rotation();
@@ -370,14 +374,23 @@ namespace AzFramework
return { basisX, basisY };
}
//! TranslationDeltaFn is used by PanCameraInput and TranslateCameraInput
//! @note Choose the appropriate function if the behavior should be operating as a free look camera (TranslatePivotLook)
//! or an orbit camera (TranslateOffsetOrbit).
using TranslationDeltaFn = AZStd::function<void(Camera& camera, const AZ::Vector3& delta)>;
inline void TranslatePivot(Camera& camera, const AZ::Vector3& delta)
//! Update the pivot camera position.
//! @note delta will need to have been transformed to world space, e.g. To move the camera right, (1, 0, 0) must
//! first be transformed by the orientation of the camera before being applied to m_pivot.
inline void TranslatePivotLook(Camera& camera, const AZ::Vector3& delta)
{
camera.m_pivot += delta;
}
inline void TranslateOffset(Camera& camera, const AZ::Vector3& delta)
//! Update the offset camera position.
//! @note delta still needs to be transformed to world space (as with TranslatePivotLook) but internally this is undone
//! to be performed in local space when being applied to m_offset.
inline void TranslateOffsetOrbit(Camera& camera, const AZ::Vector3& delta)
{
camera.m_offset += camera.View().TransformVector(delta);
}
@@ -409,7 +422,7 @@ namespace AzFramework
//! Axes to use while translating the camera.
using TranslationAxesFn = AZStd::function<AZ::Matrix3x3(const Camera& camera)>;
//! TranslationAxes to use while in 'look' camera behavior (free look).
//! TranslationAxes to use while in 'look' or 'orbit' camera behavior.
inline AZ::Matrix3x3 LookTranslation(const Camera& camera)
{
const AZ::Matrix3x3 orientation = camera.Rotation();
@@ -421,8 +434,8 @@ namespace AzFramework
return AZ::Matrix3x3::CreateFromColumns(basisX, basisY, basisZ);
}
//! TranslationAxes to use while in 'pivot' camera behavior.
inline AZ::Matrix3x3 PivotTranslation(const Camera& camera)
//! Optional TranslationAxes to use while in 'orbit' camera behavior.
inline AZ::Matrix3x3 OrbitTranslation(const Camera& camera)
{
const AZ::Matrix3x3 orientation = camera.Rotation();
@@ -535,11 +548,11 @@ namespace AzFramework
bool m_boost = false; //!< Is the translation speed currently being multiplied/scaled upwards.
};
//! A camera input to handle discrete scroll events that can modify the camera pivot distance.
class PivotDollyScrollCameraInput : public CameraInput
//! A camera input to handle discrete scroll events that can modify the camera offset.
class OrbitDollyScrollCameraInput : public CameraInput
{
public:
PivotDollyScrollCameraInput();
OrbitDollyScrollCameraInput();
// CameraInput overrides ...
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
@@ -548,11 +561,11 @@ namespace AzFramework
AZStd::function<float()> m_scrollSpeedFn;
};
//! A camera input to handle motion deltas that can modify the camera pivot distance.
class PivotDollyMotionCameraInput : public CameraInput
//! A camera input to handle motion deltas that can modify the camera offset.
class OrbitDollyMotionCameraInput : public CameraInput
{
public:
explicit PivotDollyMotionCameraInput(const InputChannelId& dollyChannelId);
explicit OrbitDollyMotionCameraInput(const InputChannelId& dollyChannelId);
// CameraInput overrides ...
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
@@ -569,10 +582,10 @@ namespace AzFramework
};
//! A camera input to handle discrete scroll events that can scroll (translate) the camera along its forward axis.
class ScrollTranslationCameraInput : public CameraInput
class LookScrollTranslationCameraInput : public CameraInput
{
public:
ScrollTranslationCameraInput();
LookScrollTranslationCameraInput();
// CameraInput overrides ...
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
@@ -583,36 +596,36 @@ namespace AzFramework
//! A camera input that doubles as its own set of camera inputs.
//! It is 'exclusive', so does not overlap with other sibling camera inputs - it runs its own set of camera inputs as 'children'.
class PivotCameraInput : public CameraInput
class OrbitCameraInput : public CameraInput
{
public:
using PivotFn = AZStd::function<AZ::Vector3(const AZ::Vector3& position, const AZ::Vector3& direction)>;
explicit PivotCameraInput(const InputChannelId& pivotChannelId);
explicit OrbitCameraInput(const InputChannelId& orbitChannelId);
// CameraInput overrides ...
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
bool Exclusive() const override;
void SetPivotInputChannelId(const InputChannelId& pivotChanneId);
void SetOrbitInputChannelId(const InputChannelId& orbitChanneId);
Cameras m_pivotCameras; //!< The camera inputs to run when this camera input is active (only these will run as it is exclusive).
Cameras m_orbitCameras; //!< The camera inputs to run when this camera input is active (only these will run as it is exclusive).
//! Override the default behavior for how a pivot point is calculated.
void SetPivotFn(PivotFn pivotFn);
private:
InputChannelId m_pivotChannelId; //!< Input channel to begin the pivot camera input.
PivotFn m_pivotFn; //!< The pivot position to use for this pivot camera (how is the pivot point calculated/retrieved).
InputChannelId m_orbitChannelId; //!< Input channel to begin the orbit camera input.
PivotFn m_pivotFn; //!< The pivot position to use for this orbit camera (how is the pivot point calculated/retrieved).
};
inline void PivotCameraInput::SetPivotFn(PivotFn pivotFn)
inline void OrbitCameraInput::SetPivotFn(PivotFn pivotFn)
{
m_pivotFn = AZStd::move(pivotFn);
}
inline bool PivotCameraInput::Exclusive() const
inline bool OrbitCameraInput::Exclusive() const
{
return true;
}
@@ -624,9 +637,9 @@ namespace AzFramework
return AZ::Vector3::CreateZero();
}
//! Callback to use for FocusCameraInput when a pivot camera is being used.
//! Callback to use for FocusCameraInput when a orbit camera is being used.
//! @note This is when offset is non zero.
inline AZ::Vector3 FocusPivot(const float length)
inline AZ::Vector3 FocusOrbit(const float length)
{
return AZ::Vector3::CreateAxisY(-length);
}
@@ -667,7 +680,9 @@ namespace AzFramework
bool HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, float scrollDelta) override;
Camera StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, float scrollDelta, float deltaTime) override;
//! HandleEvents delegates directly to m_handleEventsFn.
AZStd::function<bool(CameraInput&, const InputEvent&, const ScreenVector&, float)> m_handleEventsFn;
//! StepCamera delegates directly to m_stepCameraFn.
AZStd::function<Camera(CameraInput&, const Camera&, const ScreenVector&, float, float)> m_stepCameraFn;
};
@@ -53,31 +53,31 @@ namespace UnitTest
};
m_firstPersonTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
m_translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivot);
m_translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook);
m_pivotCamera = AZStd::make_shared<AzFramework::PivotCameraInput>(m_pivotChannelId);
m_pivotCamera->SetPivotFn(
m_orbitCamera = AZStd::make_shared<AzFramework::OrbitCameraInput>(m_orbitChannelId);
m_orbitCamera->SetPivotFn(
[this](const AZ::Vector3&, const AZ::Vector3&)
{
return m_pivot;
});
auto pivotRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(AzFramework::InputDeviceMouse::Button::Left);
auto orbitRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(AzFramework::InputDeviceMouse::Button::Left);
// set rotate speed to be a value that will scale motion delta (pixels moved) by a thousandth.
pivotRotateCamera->m_rotateSpeedFn = []()
orbitRotateCamera->m_rotateSpeedFn = []()
{
return 0.001f;
};
auto pivotTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
m_translateCameraInputChannelIds, AzFramework::PivotTranslation, AzFramework::TranslateOffset);
auto orbitTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
m_translateCameraInputChannelIds, AzFramework::OrbitTranslation, AzFramework::TranslateOffsetOrbit);
m_pivotCamera->m_pivotCameras.AddCamera(pivotRotateCamera);
m_pivotCamera->m_pivotCameras.AddCamera(pivotTranslateCamera);
m_orbitCamera->m_orbitCameras.AddCamera(orbitRotateCamera);
m_orbitCamera->m_orbitCameras.AddCamera(orbitTranslateCamera);
m_cameraSystem->m_cameras.AddCamera(m_firstPersonRotateCamera);
m_cameraSystem->m_cameras.AddCamera(m_firstPersonTranslateCamera);
m_cameraSystem->m_cameras.AddCamera(m_pivotCamera);
m_cameraSystem->m_cameras.AddCamera(m_orbitCamera);
// these tests rely on using motion delta, not cursor positions (default is true)
AzFramework::ed_cameraSystemUseCursor = false;
@@ -87,7 +87,7 @@ namespace UnitTest
{
AzFramework::ed_cameraSystemUseCursor = true;
m_pivotCamera.reset();
m_orbitCamera.reset();
m_firstPersonRotateCamera.reset();
m_firstPersonTranslateCamera.reset();
@@ -97,11 +97,11 @@ namespace UnitTest
AllocatorsTestFixture::TearDown();
}
AzFramework::InputChannelId m_pivotChannelId = AzFramework::InputChannelId("keyboard_key_modifier_alt_l");
AzFramework::InputChannelId m_orbitChannelId = AzFramework::InputChannelId("keyboard_key_modifier_alt_l");
AzFramework::TranslateCameraInputChannelIds m_translateCameraInputChannelIds;
AZStd::shared_ptr<AzFramework::RotateCameraInput> m_firstPersonRotateCamera;
AZStd::shared_ptr<AzFramework::TranslateCameraInput> m_firstPersonTranslateCamera;
AZStd::shared_ptr<AzFramework::PivotCameraInput> m_pivotCamera;
AZStd::shared_ptr<AzFramework::OrbitCameraInput> m_orbitCamera;
AZ::Vector3 m_pivot = AZ::Vector3::CreateZero();
//! This is approximately Pi/2 * 1000 - this can be used to rotate the camera 90 degrees (pitch or yaw based
@@ -109,17 +109,17 @@ namespace UnitTest
inline static const int PixelMotionDelta = 1570;
};
TEST_F(CameraInputFixture, BeginAndEndPivotCameraInputConsumesCorrectEvents)
TEST_F(CameraInputFixture, BeginAndEndOrbitCameraInputConsumesCorrectEvents)
{
// begin pivot camera
// begin orbit camera
const bool consumed1 = HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceKeyboard::Key::ModifierAltL,
AzFramework::InputChannel::State::Began });
// begin listening for pivot rotate (click detector) - event is not consumed
// begin listening for orbit rotate (click detector) - event is not consumed
const bool consumed2 = HandleEventAndUpdate(
AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began });
// begin pivot rotate (mouse has moved sufficient distance to initiate)
// begin orbit rotate (mouse has moved sufficient distance to initiate)
const bool consumed3 = HandleEventAndUpdate(AzFramework::HorizontalMotionEvent{ 5 });
// end pivot (mouse up) - event is not consumed
// end orbit (mouse up) - event is not consumed
const bool consumed4 = HandleEventAndUpdate(
AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Ended });
@@ -260,10 +260,10 @@ namespace UnitTest
EXPECT_TRUE(activationEnded);
}
TEST_F(CameraInputFixture, PivotCameraInputHandlesLookAtPointAndSelfAtSamePositionWhenPivoting)
TEST_F(CameraInputFixture, OrbitCameraInputHandlesLookAtPointAndSelfAtSamePositionWhenOrbiting)
{
// create pathological lookAtFn that just returns the same position as the camera
m_pivotCamera->SetPivotFn(
m_orbitCamera->SetPivotFn(
[](const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction)
{
return position;
@@ -275,7 +275,7 @@ namespace UnitTest
AZ::Transform::CreateFromQuaternionAndTranslation(
AZ::Quaternion::CreateFromEulerAnglesDegrees(AZ::Vector3(0.0f, 0.0f, 90.0f)), expectedCameraPosition));
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_pivotChannelId, AzFramework::InputChannel::State::Began });
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began });
// verify the camera yaw has not changed and pivot point matches the expected camera position
using ::testing::FloatNear;
@@ -321,14 +321,14 @@ namespace UnitTest
EXPECT_THAT(m_camera.m_offset, IsClose(AZ::Vector3::CreateZero()));
}
TEST_F(CameraInputFixture, PivotRotateCameraInputRotatesPitchOffsetByNinetyDegreesWithRequiredPixelDelta)
TEST_F(CameraInputFixture, OrbitRotateCameraInputRotatesPitchOffsetByNinetyDegreesWithRequiredPixelDelta)
{
const auto cameraStartingPosition = AZ::Vector3::CreateAxisY(-20.0f);
m_targetCamera.m_pivot = cameraStartingPosition;
m_pivot = AZ::Vector3::CreateAxisY(-10.0f);
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_pivotChannelId, AzFramework::InputChannel::State::Began });
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began });
HandleEventAndUpdate(
AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began });
HandleEventAndUpdate(AzFramework::VerticalMotionEvent{ PixelMotionDelta });
@@ -344,14 +344,14 @@ namespace UnitTest
EXPECT_THAT(m_camera.Translation(), IsCloseTolerance(expectedCameraEndingPosition, 0.01f));
}
TEST_F(CameraInputFixture, PivotRotateCameraInputRotatesYawOffsetByNinetyDegreesWithRequiredPixelDelta)
TEST_F(CameraInputFixture, OrbitRotateCameraInputRotatesYawOffsetByNinetyDegreesWithRequiredPixelDelta)
{
const auto cameraStartingPosition = AZ::Vector3(15.0f, -20.0f, 0.0f);
m_targetCamera.m_pivot = cameraStartingPosition;
m_pivot = AZ::Vector3(10.0f, -10.0f, 0.0f);
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_pivotChannelId, AzFramework::InputChannel::State::Began });
HandleEventAndUpdate(AzFramework::DiscreteInputEvent{ m_orbitChannelId, AzFramework::InputChannel::State::Began });
HandleEventAndUpdate(
AzFramework::DiscreteInputEvent{ AzFramework::InputDeviceMouse::Button::Left, AzFramework::InputChannel::State::Began });
HandleEventAndUpdate(AzFramework::HorizontalMotionEvent{ -PixelMotionDelta });
@@ -6,10 +6,11 @@
*
*/
#include <AzQtComponents/AzQtComponents_Traits_Platform.h>
#include <AzQtComponents/Components/Widgets/FileDialog.h>
#include <QMessageBox>
#include <QRegExp>
#include <QRegularExpression>
namespace AzQtComponents
{
@@ -24,7 +25,12 @@ namespace AzQtComponents
// Trigger Qt's save filename dialog
// If filePath isn't empty, it means we are prompting again because the filename was invalid,
// so pass it instead of the directory so the filename is pre-filled in for the user
filePath = QFileDialog::getSaveFileName(parent, caption, (filePath.isEmpty()) ? dir : filePath, filter, selectedFilter, options);
QString localSelectedFilter;
filePath = QFileDialog::getSaveFileName(parent, caption, (filePath.isEmpty()) ? dir : filePath, filter, &localSelectedFilter, options);
if (selectedFilter)
{
*selectedFilter = localSelectedFilter;
}
if (!filePath.isEmpty())
{
@@ -32,15 +38,39 @@ namespace AzQtComponents
QString fileName = fileInfo.fileName();
// Check if the filename has any invalid characters
QRegExp validFileNameRegex("^[a-zA-Z0-9_\\-./]*$");
shouldPromptAgain = !validFileNameRegex.exactMatch(fileName);
QRegularExpression validFileNameRegex("^[a-zA-Z0-9_\\-./]*$");
QRegularExpressionMatch validFileNameMatch = validFileNameRegex.match(fileName);
// If the filename had invalid characters, then show a warning message and then we will re-prompt the save filename dialog
if (shouldPromptAgain)
if (!validFileNameMatch.hasMatch())
{
QMessageBox::warning(parent, QObject::tr("Invalid filename"),
QObject::tr("O3DE assets are restricted to alphanumeric characters, hyphens (-), underscores (_), and dots (.)\n\n%1").arg(fileName));
shouldPromptAgain = true;
continue;
}
else
{
shouldPromptAgain = false;
}
#if AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_APPLY_MISSING_EXTENSION
// If a filter was selected, then make sure that the resulting filename ends with that extension. On systems that use the default QFileDialog,
// the extension is not guaranteed to be set in the resulting filename
if (FileDialog::ApplyMissingExtension(localSelectedFilter, filePath))
{
// If an extension had to be applied, then the file dialog did not handle the case of overwriting existing files.
// We need to check that condition before we proceed
QFileInfo updatedFilePath(filePath);
if (updatedFilePath.exists())
{
QMessageBox::StandardButton overwriteSelection = QMessageBox::question(parent,
QObject::tr("File exists"),
QObject::tr("%1 exists. Do you want to overwrite the existing file?").arg(updatedFilePath.fileName()));
shouldPromptAgain = (overwriteSelection == QMessageBox::No);
}
}
#endif // AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_APPLY_MISSING_EXTENSION
}
else
{
@@ -51,4 +81,56 @@ namespace AzQtComponents
return filePath;
}
bool FileDialog::ApplyMissingExtension(const QString& selectedFilter, QString& filePath)
{
if (selectedFilter.isEmpty())
{
return false;
}
// According to the QT documentation for QFileDialog, the selected filter will come in the form
// <Filter Name> (<filter pattern1> <filter pattern2> .. <filter patternN> )
//
// For example:
// "Images (*.gif *.png *.jpg)"
//
// Extract the contents of the <filter pattern>(s) inside the parenthesis and split them based on a whitespace or comma
const QRegularExpression filterContent(".*\\((?<filters>[^\\)]+)\\)");
QRegularExpressionMatch filterContentMatch = filterContent.match(selectedFilter);
if (!filterContentMatch.hasMatch())
{
return false;
}
QString filterExtensionsString = filterContentMatch.captured("filters");
QStringList filterExtensionsFull = filterExtensionsString.split(" ", Qt::SkipEmptyParts);
if (filterExtensionsFull.length() <= 0)
{
return false;
}
// If there are multiple suffixes in the selected filter, then default to the first one if a suffix needs to be appended
QString defaultSuffix = filterExtensionsFull[0].mid(1);
// Iterate through the filter patterns to see if the current filename matches
QFileInfo fileInfo(filePath);
bool extensionNeeded = true;
for (const QString& filterExtensionFull : filterExtensionsFull)
{
QString wildcardExpression = QRegularExpression::wildcardToRegularExpression(filterExtensionFull);
QRegularExpression filterPattern(wildcardExpression, AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_FILTER_CASE_SENSITIVITY);
QRegularExpressionMatch filterPatternMatch = filterPattern.match(fileInfo.fileName());
if (filterPatternMatch.hasMatch())
{
// The filename matches one of the filter patterns already, the extension does not need to be added to the filename
extensionNeeded = false;
}
}
if (extensionNeeded)
{
// If the current (if any) suffix does not match, automatically add the default suffix for the selected filter
filePath.append(defaultSuffix);
}
return extensionNeeded;
}
} // namespace AzQtComponents
@@ -24,6 +24,12 @@ namespace AzQtComponents
static QString GetSaveFileName(QWidget* parent = nullptr, const QString& caption = QString(),
const QString& dir = QString(), const QString& filter = QString(),
QString* selectedFilter = nullptr, QFileDialog::Options options = QFileDialog::Options());
//! Helper method that parses a selected filter from Qt's QFileDialog::getSaveFileName and applies the
//! selected filter's extension to the filePath if it doesnt already have the extension. This is needed
//! on platforms that do not have a default file dialog (These platforms uses Qt's custom file dialog which will
//! not apply the filter's extension automatically on user entered filenames)
static bool ApplyMissingExtension(const QString& selectedFilter, QString& filePath);
};
} // namespace AzQtComponents
@@ -12,4 +12,6 @@ set(FILES
../../Utilities/QtWindowUtilities_linux.cpp
../../Utilities/ScreenGrabber_linux.cpp
../../../Platform/Linux/AzQtComponents/Components/StyledDockWidget_Linux.cpp
../../../Platform/Linux/AzQtComponents/AzQtComponents_Traits_Linux.h
../../../Platform/Linux/AzQtComponents/AzQtComponents_Traits_Platform.h
)
@@ -12,4 +12,6 @@ set(FILES
../../Utilities/QtWindowUtilities_mac.mm
../../Utilities/ScreenGrabber_mac.mm
../../../Platform/Mac/AzQtComponents/Components/StyledDockWidget_Mac.cpp
../../../Platform/Mac/AzQtComponents/AzQtComponents_Traits_Mac.h
../../../Platform/Mac/AzQtComponents/AzQtComponents_Traits_Platform.h
)
@@ -17,4 +17,6 @@ set(FILES
../../Components/TitleBarOverdrawScreenHandler_win.h
../../Components/TitleBarOverdrawScreenHandler_win.cpp
../../../Platform/Windows/AzQtComponents/Components/StyledDockWidget_Windows.cpp
../../../Platform/Windows/AzQtComponents/AzQtComponents_Traits_Windows.h
../../../Platform/Windows/AzQtComponents/AzQtComponents_Traits_Platform.h
)
@@ -0,0 +1,65 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzTest/AzTest.h>
#include <AzQtComponents/Components/Widgets/FileDialog.h>
#include <QString>
TEST(AzQtComponents, ApplyMissingExtension_UpdateMissingExtension_Success)
{
const QString textFiler{"Text Files (*.txt)"};
QString testPath{"testFile"};
bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath);
EXPECT_TRUE(result);
EXPECT_STRCASEEQ("testFile.txt", testPath.toUtf8().constData());
}
TEST(AzQtComponents, ApplyMissingExtension_NoUpdateExistingExtension_Success)
{
const QString textFiler{"Text Files (*.txt)"};
QString testPath{"testFile.txt"};
bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath);
EXPECT_FALSE(result);
EXPECT_STRCASEEQ("testFile.txt", testPath.toUtf8().constData());
}
TEST(AzQtComponents, ApplyMissingExtension_UpdateMissingExtensionMultipleExtensionFilter_Success)
{
const QString textFiler{"Image Files (*.jpg *.bmp *.png)"};
QString testPath{"testFile"};
bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath);
EXPECT_TRUE(result);
EXPECT_STRCASEEQ("testFile.jpg", testPath.toUtf8().constData());
}
TEST(AzQtComponents, ApplyMissingExtension_NoUpdateMissingExtensionMultipleExtensionFilter_Success)
{
const QString textFiler{"Image Files (*.jpg *.bmp *.png)"};
QString testPath{"testFile.png"};
bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath);
EXPECT_FALSE(result);
EXPECT_STRCASEEQ("testFile.png", testPath.toUtf8().constData());
}
TEST(AzQtComponents, ApplyMissingExtension_NoUpdateMissingExtensionEmptyFilter_Success)
{
const QString textFiler{""};
QString testPath{"testFile"};
bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath);
EXPECT_FALSE(result);
EXPECT_STRCASEEQ("testFile", testPath.toUtf8().constData());
}
TEST(AzQtComponents, ApplyMissingExtension_NoUpdateMissingExtensionInvalidFilter_Success)
{
const QString textFiler{"Bad Filter!!"};
QString testPath{"testFile"};
bool result = AzQtComponents::FileDialog::ApplyMissingExtension(textFiler, testPath);
EXPECT_FALSE(result);
EXPECT_STRCASEEQ("testFile", testPath.toUtf8().constData());
}
@@ -9,6 +9,7 @@
set(FILES
Tests/AzQtComponentTests.cpp
Tests/ColorControllerTests.cpp
Tests/FileDialogTests.cpp
Tests/FloatToStringConversionTests.cpp
Tests/HexParsingTests.cpp
Tests/StyleSheetCacheTests.cpp
@@ -10,6 +10,8 @@ if(NOT PAL_TRAIT_BUILD_HOST_TOOLS)
return()
endif()
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
ly_add_target(
NAME AzQtComponents SHARED
NAMESPACE AZ
@@ -26,6 +28,7 @@ ly_add_target(
AzQtComponents
PUBLIC
.
${pal_dir}
COMPILE_DEFINITIONS
PRIVATE
AZ_QT_COMPONENTS_EXPORT_SYMBOLS
@@ -53,6 +56,7 @@ ly_add_target(
.
AzQtComponents
AzQtComponents/Gallery
${pal_dir}
BUILD_DEPENDENCIES
PRIVATE
3rdParty::Qt::Svg
@@ -86,6 +90,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
PRIVATE
Tests
AzQtComponents
${pal_dir}
BUILD_DEPENDENCIES
PRIVATE
AZ::AzQtComponents
@@ -0,0 +1,11 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_APPLY_MISSING_EXTENSION 1
#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_FILTER_CASE_SENSITIVITY QRegularExpression::NoPatternOption
@@ -0,0 +1,10 @@
/*
* 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 <AzQtComponents/AzQtComponents_Traits_Linux.h>
@@ -0,0 +1,11 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_APPLY_MISSING_EXTENSION 0
#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_FILTER_CASE_SENSITIVITY QRegularExpression::NoPatternOption
@@ -0,0 +1,10 @@
/*
* 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 <AzQtComponents/AzQtComponents_Traits_Mac.h>
@@ -0,0 +1,10 @@
/*
* 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 <AzQtComponents/AzQtComponents_Traits_Windows.h>
@@ -0,0 +1,11 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_APPLY_MISSING_EXTENSION 0
#define AZ_TRAIT_AZQTCOMPONENTS_FILE_DIALOG_FILTER_CASE_SENSITIVITY QRegularExpression::CaseInsensitiveOption
@@ -410,7 +410,7 @@ namespace AzToolsFramework
filter.append(ext);
if (i < n - 1)
{
filter.append(", ");
filter.append(" ");
}
}
filter.append(")");
@@ -224,6 +224,7 @@ namespace AzToolsFramework
return false;
}
AZ::Data::SerializedAssetTracker* assetTracker = settings.m_metadata.Find<AZ::Data::SerializedAssetTracker>();
referencedAssets = AZStd::move(assetTracker->GetTrackedAssets());
@@ -245,6 +246,30 @@ namespace AzToolsFramework
entityIdMapper.SetEntityIdGenerationApproach(InstanceEntityIdMapper::EntityIdGenerationApproach::Random);
}
// some assets may come in from the JSON serialzier with no AssetID, but have an asset hint
// this attempts to fix up the assets using the assetHint field
auto fixUpInvalidAssets = [](AZ::Data::Asset<AZ::Data::AssetData>& asset)
{
if (!asset.GetId().IsValid() && !asset.GetHint().empty())
{
AZ::Data::AssetId assetId;
AZ::Data::AssetCatalogRequestBus::BroadcastResult(
assetId,
&AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath,
asset.GetHint().c_str(),
AZ::Data::s_invalidAssetType,
false);
if (assetId.IsValid())
{
asset.Create(assetId, true);
}
}
};
auto tracker = AZ::Data::SerializedAssetTracker{};
tracker.SetAssetFixUp(fixUpInvalidAssets);
AZ::JsonDeserializerSettings settings;
// The InstanceEntityIdMapper is registered twice because it's used in several places during deserialization where one is
// specific for the InstanceEntityIdMapper and once for the generic JsonEntityIdMapper. Because the Json Serializer's meta
@@ -252,16 +277,17 @@ namespace AzToolsFramework
settings.m_metadata.Add(static_cast<AZ::JsonEntityIdSerializer::JsonEntityIdMapper*>(&entityIdMapper));
settings.m_metadata.Add(&entityIdMapper);
settings.m_metadata.Create<InstanceEntityScrubber>(newlyAddedEntities);
settings.m_metadata.Add(tracker);
AZStd::string scratchBuffer;
auto issueReportingCallback = [&scratchBuffer](
AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
AZStd::string_view message, AZ::JsonSerializationResult::ResultCode result,
AZStd::string_view path) -> AZ::JsonSerializationResult::ResultCode
{
return Internal::JsonIssueReporter(scratchBuffer, message, result, path);
};
settings.m_reporting = AZStd::move(issueReportingCallback);
AZ::JsonSerializationResult::ResultCode result = AZ::JsonSerialization::Load(instance, prefabDom, settings);
AZ::Data::AssetManager::Instance().ResumeAssetRelease();
@@ -1025,7 +1025,7 @@ namespace AzToolsFramework
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/LuaScript.svg")
->Attribute(AZ::Edit::Attributes::PrimaryAssetType, AZ::AzTypeInfo<AZ::ScriptAsset>::Uuid())
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Icons/Components/Viewport/Script.png")
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/lua-script/")
->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/scripting/lua-script/")
->DataElement("AssetRef", &ScriptEditorComponent::m_scriptAsset, "Script", "Which script to use")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &ScriptEditorComponent::ScriptHasChanged)
->Attribute("BrowseIcon", ":/stylesheet/img/UI20/browse-edit-select-files.svg")
@@ -103,10 +103,6 @@ namespace AzToolsFramework
static const char* const ResetEntityTransformDesc = "Reset transform based on manipulator mode";
static const char* const ResetManipulatorTitle = "Reset Manipulator";
static const char* const ResetManipulatorDesc = "Reset the manipulator to recenter it on the selected entity";
static const char* const ResetTransformLocalTitle = "Reset Transform (Local)";
static const char* const ResetTransformLocalDesc = "Reset transform to local space";
static const char* const ResetTransformWorldTitle = "Reset Transform (World)";
static const char* const ResetTransformWorldDesc = "Reset transform to world space";
static const char* const EntityBoxSelectUndoRedoDesc = "Box Select Entities";
static const char* const EntityDeselectUndoRedoDesc = "Deselect Entity";
@@ -2424,45 +2420,9 @@ namespace AzToolsFramework
AddAction(
m_actions, { QKeySequence(Qt::CTRL + Qt::Key_R) }, EditResetManipulator, ResetManipulatorTitle, ResetManipulatorDesc,
AZStd::bind(AZStd::mem_fn(&EditorTransformComponentSelection::DelegateClearManipulatorOverride), this));
AddAction(
m_actions, { QKeySequence(Qt::ALT + Qt::Key_R) }, EditResetLocal, ResetTransformLocalTitle, ResetTransformLocalDesc,
[this]()
[this]
{
switch (m_mode)
{
case Mode::Rotation:
ResetOrientationForSelectedEntitiesLocal();
break;
case Mode::Scale:
CopyScaleToSelectedEntitiesIndividualWorld(1.0f);
break;
case Mode::Translation:
// do nothing
break;
}
});
AddAction(
m_actions, { QKeySequence(Qt::SHIFT + Qt::Key_R) }, EditResetWorld, ResetTransformWorldTitle, ResetTransformWorldDesc,
[this]()
{
switch (m_mode)
{
case Mode::Rotation:
{
// begin an undo batch so operations inside CopyOrientation... and
// DelegateClear... are grouped into a single undo/redo
ScopedUndoBatch undoBatch{ ResetTransformWorldTitle };
CopyOrientationToSelectedEntitiesIndividual(AZ::Quaternion::CreateIdentity());
ClearManipulatorOrientationOverride();
}
break;
case Mode::Scale:
case Mode::Translation:
break;
}
DelegateClearManipulatorOverride();
});
AddAction(
@@ -31,8 +31,6 @@ namespace AzToolsFramework
constexpr inline AZ::Crc32 EditPivot = AZ_CRC_CE("com.o3de.action.editortransform.editpivot");
constexpr inline AZ::Crc32 EditReset = AZ_CRC_CE("com.o3de.action.editortransform.editreset");
constexpr inline AZ::Crc32 EditResetManipulator = AZ_CRC_CE("com.o3de.action.editortransform.editresetmanipulator");
constexpr inline AZ::Crc32 EditResetLocal = AZ_CRC_CE("com.o3de.action.editortransform.editresetlocal");
constexpr inline AZ::Crc32 EditResetWorld = AZ_CRC_CE("com.o3de.action.editortransform.editresetworld");
constexpr inline AZ::Crc32 ViewportUiVisible = AZ_CRC_CE("com.o3de.action.editortransform.viewportuivisible");
//@}
@@ -25,7 +25,7 @@ namespace UnitTest
R"X(Executing RC.EXE: '"E:\lyengine\dev\windows\bin\profile\rc.exe" "E:/Directory/File.tga")X",
R"X(Executing RC.EXE with working directory : '')X",
R"X(ResourceCompiler 64 - bit DEBUG)X",
R"X(Platform support : PC, PowerVR, etc2Comp)X",
R"X(Platform support : PC, PowerVR)X",
R"X(Version 1.1.8.6 Nov 5 2018 13 : 28 : 28)X"
};
+3
View File
@@ -222,6 +222,9 @@ void UpdateFPExceptionsMaskForThreads()
//////////////////////////////////////////////////////////////////////////
int DebugCallStack::handleException(EXCEPTION_POINTERS* exception_pointer)
{
AZ_TracePrintf("Exit", "Exception with exit code: 0x%x", exception_pointer->ExceptionRecord->ExceptionCode);
AZ::Debug::Trace::PrintCallstack("Exit");
if (gEnv == NULL)
{
return EXCEPTION_EXECUTE_HANDLER;
@@ -395,7 +395,7 @@ namespace LUAEditor
void LUAEditorMainWindow::OnLuaDocumentation()
{
QDesktopServices::openUrl(QUrl("http://docs.aws.amazon.com/lumberyard/latest/developerguide/lua-scripting-intro.html"));
QDesktopServices::openUrl(QUrl("https://o3de.org/docs/user-guide/scripting/lua/"));
}
void LUAEditorMainWindow::OnMenuCloseCurrentWindow()
@@ -24,7 +24,7 @@ namespace AWSCore
/**
* Add required SystemComponents to the SystemEntity.
*/
virtual AZ::ComponentTypeList GetRequiredSystemComponents() const override;
AZ::ComponentTypeList GetRequiredSystemComponents() const override;
};
}
@@ -42,7 +42,7 @@ namespace AWSCore
AWSCoreConfiguration();
~AWSCoreConfiguration() = default;
~AWSCoreConfiguration() override = default;
void ActivateConfig();
void DeactivateConfig();
@@ -23,7 +23,7 @@ namespace AWSCore
{
public:
AWSDefaultCredentialHandler();
~AWSDefaultCredentialHandler() = default;
~AWSDefaultCredentialHandler() override = default;
//! Activate handler and its credentials provider, make sure activation
//! invoked after AWSNativeSDK init to avoid memory leak
@@ -15,13 +15,12 @@
namespace AWSCore
{
//! Defines AWSCoreAttributionConsent QT dialog as QT message box.
class AWSCoreAttributionConsentDialog :
public QMessageBox
class AWSCoreAttributionConsentDialog
: public QMessageBox
{
public:
AZ_CLASS_ALLOCATOR(AWSCoreAttributionConsentDialog, AZ::SystemAllocator, 0);
AWSCoreAttributionConsentDialog();
virtual ~AWSCoreAttributionConsentDialog() = default;
~AWSCoreAttributionConsentDialog() override = default;
};
} // namespace AWSCore
@@ -18,4 +18,4 @@ namespace AWSCore
static constexpr char AwsAttributionAttributeKeyActiveAWSGems[] = "aws_gems";
static constexpr char AwsAttributionAttributeKeyTimestamp[] = "timestamp";
} // namespace AWSCOre
} // namespace AWSCore
@@ -34,7 +34,7 @@ namespace AWSCore
"Failed to launch Resource Mapping Tool, please check <a href=\"file:///%s\">logs</a> for details.";
AWSCoreEditorMenu(const QString& text);
~AWSCoreEditorMenu();
~AWSCoreEditorMenu() override;
private:
QAction* AddExternalLinkAction(const AZStd::string& name, const AZStd::string& url, const AZStd::string& icon = "");
@@ -71,7 +71,7 @@ namespace AWSCore
};
AWSResourceMappingManager();
~AWSResourceMappingManager() = default;
~AWSResourceMappingManager() override = default;
void ActivateManager();
void DeactivateManager();
@@ -64,9 +64,6 @@ namespace AWSCore
/// Initialize an AwsApiClientJobConfig object.
///
/// \param DefaultConfigType - the type of the config object from which
/// default values will be taken.
///
/// \param defaultConfig - the config object that provides values when
/// no override has been set in this object. The default is nullptr, which
/// will cause a default value to be used.
@@ -83,10 +80,10 @@ namespace AWSCore
}
}
virtual ~AwsApiClientJobConfig() = default;
~AwsApiClientJobConfig() override = default;
/// Gets a client initialized used currently applied settings. If
/// any settings change after first use, code must call
/// any settings change after first use, code must call
/// ApplySettings before those changes will take effect.
std::shared_ptr<ClientType> GetClient() override
{
@@ -112,7 +109,7 @@ namespace AWSCore
}
else
{
// If no explict credenitals are provided then AWS C++ SDK will perform standard search
// If no explicit credentials are provided then AWS C++ SDK will perform standard search
return std::make_shared<ClientType>(Aws::Auth::AWSCredentials(), GetClientConfiguration());
}
}
@@ -14,14 +14,12 @@
namespace AWSCore
{
/// Base class for all AWS jobs. Primarily exists so that
/// Base class for all AWS jobs. Primarily exists so that
/// AwsApiJob::s_config can be used for settings that apply to
/// all AWS jobs.
class AwsApiJob
: public AZ::Job
{
public:
// To use a different allocator, extend this class and use this macro.
AZ_CLASS_ALLOCATOR(AwsApiJob, AZ::SystemAllocator, 0);
@@ -33,11 +31,10 @@ namespace AWSCore
protected:
AwsApiJob(bool isAutoDelete, IConfig* config = GetDefaultConfig());
virtual ~AwsApiJob();
~AwsApiJob() override = default;
/// Used for error messages.
static const char* COMPONENT_DISPLAY_NAME;
};
} // namespace AWSCore
@@ -96,9 +96,6 @@ namespace AWSCore
/// Initialize an AwsApiClientJobConfig object.
///
/// \param DefaultConfigType - the type of the config object from which
/// default values will be taken.
///
/// \param defaultConfig - the config object that provides values when
/// no override has been set in this object. The default is nullptr, which
/// will cause a default value to be used.
@@ -146,7 +143,7 @@ namespace AWSCore
#endif
Override<Aws::String> caFile;
/// Applys settings changes made after first use.
/// Applies settings changes made after first use.
virtual void ApplySettings();
//////////////////////////////////////////////////////////////////////////
@@ -217,7 +214,7 @@ namespace AWSCore
: protected AWSCoreNotificationsBus::Handler
{
public:
~AwsApiJobConfigHolder()
~AwsApiJobConfigHolder() override
{
AWSCoreNotificationsBus::Handler::BusDisconnect();
}
@@ -145,10 +145,10 @@ namespace AWSCore
AWS_API_REQUEST_TRAITS_TEMPLATE_DEFINITION_HELPER
typename AWS_API_REQUEST_TRAITS_TEMPLATE_INSTANCE_HELPER::AsyncFunctionType AWS_API_REQUEST_TRAITS_TEMPLATE_INSTANCE_HELPER::AsyncFunction = _AsyncFunction;
/// Macro that simplifies the declaration of an AwsRequstJob that has a result.
/// Macro that simplifies the declaration of an AwsRequestJob that has a result.
#define AWS_API_REQUEST_JOB(SERVICE, REQUEST) AWSCore::AwsApiRequestJob<AWS_API_REQUEST_TRAITS(SERVICE, REQUEST)>
/// Macro that simplifies the declaration of an AwsRequstJob that has no result.
/// Macro that simplifies the declaration of an AwsRequestJob that has no result.
#define AWS_API_REQUEST_JOB_NO_RESULT(SERVICE, REQUEST) AWSCore::AwsApiRequestJob<AWS_API_REQUEST_TRAITS_NO_RESULT(SERVICE, REQUEST)>
/// An Az::Job that that executes a specific AWS request.
@@ -257,7 +257,7 @@ namespace AWSCore
/// of request data until your running on the job's worker thread,
/// instead of setting the request data before calling Start.
///
/// \param true if the request should be made.
/// \return true if the request should be made.
virtual bool PrepareRequest()
{
return true;
@@ -39,7 +39,7 @@ namespace AWSCore
: public AZ::ComponentBus
{
public:
virtual ~HttpClientComponentNotifications() {}
~HttpClientComponentNotifications() override = default;
virtual void OnHttpRequestSuccess(int responseCode, AZStd::string responseBody) {}
virtual void OnHttpRequestFailure(int responseCode) {}
};
@@ -55,7 +55,7 @@ namespace AWSCore
{
public:
AZ_COMPONENT(HttpClientComponent, "{23ECDBDF-129A-4670-B9B4-1E0B541ACD61}");
virtual ~HttpClientComponent() = default;
~HttpClientComponent() override = default;
void Init() override;
void Activate() override;
@@ -178,7 +178,7 @@ namespace AWSCore
};
/// Override to process the response to the HTTP request before callbacks are fired.
/// WARNING: This gets called on the job's thread, so observe thread safety precations.
/// WARNING: This gets called on the job's thread, so observe thread safety precautions.
virtual void ProcessResponse(const std::shared_ptr<Aws::Http::HttpResponse>& response)
{
AZ_UNUSED(response);
@@ -29,24 +29,24 @@ namespace AWSCore
Ch Peek() const
{
int c = m_is.peek();
return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
}
Ch Take()
{
int c = m_is.get();
return c == std::char_traits<char>::eof() ? '\0' : (Ch)c;
return c == std::char_traits<char>::eof() ? '\0' : static_cast<Ch>(c);
}
size_t Tell() const
{
return (size_t)m_is.tellg();
return static_cast<size_t>(m_is.tellg());
}
Ch* PutBegin()
{
AZ_Assert(false, "Not Implemented");
return 0;
return nullptr;
}
void Put(Ch)
@@ -161,7 +161,7 @@ namespace AWSCore
}
/// Write JSON format content directly to the writer's output stream.
/// This can be used to efficently output static content.
/// This can be used to efficiently output static content.
bool WriteJson(const Ch* json)
{
if (json)
@@ -182,7 +182,7 @@ namespace AWSCore
}
/// Write an object. The object can implement a WriteJson function
/// or you can provide an GobalWriteJson template function
/// or you can provide an GlobalWriteJson template function
/// specialization.
template<class ObjectType>
bool Object(const ObjectType& obj)
@@ -36,7 +36,7 @@ namespace AWSCore
class RequestBuilder
{
public:
RequestBuilder() = default;
RequestBuilder();
/// Converts the provided object to JSON and sends it as the
/// body of the request. The object can implement the following
@@ -20,7 +20,7 @@ namespace AWSCore
{
public:
virtual const AZStd::string GetServiceUrl() = 0;
virtual AZStd::string GetServiceUrl() = 0;
};
/// Encapsulates what code needs to know about a service in order to
@@ -81,9 +81,6 @@ namespace AWSCore
/// Initialize an ServiceClientJobConfig object.
///
/// \param DefaultConfigType - the type of the config object from which
/// default values will be taken.
///
/// \param defaultConfig - the config object that provides values when
/// no override has been set in this object. The default is nullptr, which
/// will cause a default value to be used.
@@ -102,7 +99,7 @@ namespace AWSCore
/// This implementation assumes the caller will cache this value as
/// needed. See it's use in ServiceRequestJobConfig.
const AZStd::string GetServiceUrl() override
AZStd::string GetServiceUrl() override
{
if (endpointOverride.has_value())
{
@@ -119,7 +119,7 @@ namespace AWSCore
Error error;
/// Determines if the AWS credentials, as supplied by the credentialsProvider from
/// the ServiceReqestJobConfig object (which defaults to the user's credentials),
/// the ServiceRequestJobConfig object (which defaults to the user's credentials),
/// are used to sign the request. The default is true. Override this and return false
/// if calling a public API and want to avoid the overhead of signing requests.
bool UseAWSCredentials() {
@@ -565,13 +565,11 @@ namespace AWSCore
}
AZStd::string requestContent;
AZStd::string responseContent;
std::istreambuf_iterator<AZStd::string::value_type> eos;
std::shared_ptr<Aws::IOStream> requestStream = response->GetOriginatingRequest().GetContentBody();
if (requestStream)
{
std::istreambuf_iterator<AZStd::string::value_type> eos;
requestStream->clear();
requestStream->seekg(0);
requestContent = AZStd::string{ std::istreambuf_iterator<AZStd::string::value_type>(*requestStream.get()),eos };
@@ -584,7 +582,7 @@ namespace AWSCore
Aws::IOStream& responseStream = response->GetResponseBody();
responseStream.clear();
responseStream.seekg(0);
responseContent = AZStd::string{ std::istreambuf_iterator<AZStd::string::value_type>(responseStream),responseEos };
AZStd::string responseContent = AZStd::string{ std::istreambuf_iterator<AZStd::string::value_type>(responseStream), responseEos };
responseContent = EscapePercentCharsInString(responseContent);
responseStream.seekg(0);
@@ -44,9 +44,6 @@ namespace AWSCore
/// Initialize an ServiceRequestJobConfig object.
///
/// \param DefaultConfigType - the type of the config object from which
/// default values will be taken.
///
/// \param defaultConfig - the config object that provides values when
/// no override has been set in this object. The default is nullptr, which
/// will cause a default value to be used.
@@ -79,7 +79,7 @@ namespace AWSCore
QMenuBar* menuBar = mainWindow->menuBar();
QList<QAction*> actionList = menuBar->actions();
QAction* insertPivot = nullptr;
for (QList<QAction*>::iterator itr = actionList.begin(); itr != actionList.end(); itr++)
for (QList<QAction*>::iterator itr = actionList.begin(); itr != actionList.end(); ++itr)
{
if (QString::compare((*itr)->text(), EDITOR_HELP_MENU_TEXT) == 0)
{
@@ -88,7 +88,7 @@ namespace AWSCore
}
}
auto menu = m_awsCoreEditorManager->GetAWSCoreEditorMenu();
const auto menu = m_awsCoreEditorManager->GetAWSCoreEditorMenu();
if (insertPivot)
{
menuBar->insertMenu(insertPivot, menu);
@@ -35,8 +35,7 @@ namespace AWSCore
this->setDefaultButton(QMessageBox::Save);
this->button(QMessageBox::Cancel)->hide();
this->setIcon(QMessageBox::Information);
QGridLayout* layout = (QGridLayout*)this->layout();
if (layout)
if (QGridLayout* layout = static_cast<QGridLayout*>(this->layout()))
{
layout->setVerticalSpacing(20);
layout->setHorizontalSpacing(10);
@@ -68,19 +68,19 @@ namespace AWSCore
AZ_Assert(fileIO, "File IO is not initialized.");
// Resolve path to editor_aws_preferences.setreg
AZStd::string editorAWSPreferencesFilePath =
const AZStd::string editorAWSPreferencesFilePath =
AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName);
AZStd::array<char, AZ::IO::MaxPathLength> resolvedPathAWSPreference{};
if (!fileIO->ResolvePath(editorAWSPreferencesFilePath.c_str(), resolvedPathAWSPreference.data(), resolvedPathAWSPreference.size()))
AZ::IO::FixedMaxPath resolvedPathAWSPreference;
if (!fileIO->ResolvePath(resolvedPathAWSPreference, AZ::IO::PathView(editorAWSPreferencesFilePath)))
{
AZ_Warning("AWSAttributionManager", false, "Error resolving path %s", resolvedPathAWSPreference.data());
AZ_Warning("AWSAttributionManager", false, "Error resolving path %s", resolvedPathAWSPreference.c_str());
return;
}
if (fileIO->Exists(resolvedPathAWSPreference.data()))
if (fileIO->Exists(resolvedPathAWSPreference.c_str()))
{
m_settingsRegistry->MergeSettingsFile(
resolvedPathAWSPreference.data(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "");
resolvedPathAWSPreference.String(), AZ::SettingsRegistryInterface::Format::JsonMergePatch, "");
}
}
@@ -136,8 +136,8 @@ namespace AWSCore
return true;
}
AZStd::chrono::seconds lastSendTimeStamp = AZStd::chrono::seconds(lastSendTimeStampSeconds);
AZStd::chrono::seconds secondsSinceLastSend =
const AZStd::chrono::seconds lastSendTimeStamp = AZStd::chrono::seconds(lastSendTimeStampSeconds);
const AZStd::chrono::seconds secondsSinceLastSend =
AZStd::chrono::duration_cast<AZStd::chrono::seconds>(AZStd::chrono::system_clock::now().time_since_epoch()) - lastSendTimeStamp;
if (static_cast<AZ::u64>(secondsSinceLastSend.count()) >= delayInSeconds)
{
@@ -154,7 +154,7 @@ namespace AWSCore
if (credentialResult.result)
{
std::shared_ptr<Aws::Auth::AWSCredentialsProvider> provider = credentialResult.result;
auto creds = provider->GetAWSCredentials();
const auto creds = provider->GetAWSCredentials();
if (!creds.IsEmpty())
{
return true;
@@ -200,9 +200,13 @@ namespace AWSCore
AZ_Assert(fileIO, "File IO is not initialized.");
// Resolve path to editor_aws_preferences.setreg
AZStd::string editorPreferencesFilePath = AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName);
AZStd::array<char, AZ::IO::MaxPathLength> resolvedPath {};
fileIO->ResolvePath(editorPreferencesFilePath.c_str(), resolvedPath.data(), resolvedPath.size());
const AZStd::string editorPreferencesFilePath = AZStd::string::format("@user@/%s/%s", AZ::SettingsRegistryInterface::RegistryFolder, EditorAWSPreferencesFileName);
AZ::IO::FixedMaxPath resolvedPathAWSPreference;
if (!fileIO->ResolvePath(resolvedPathAWSPreference, AZ::IO::PathView(editorPreferencesFilePath)))
{
AZ_Warning("AWSAttributionManager", false, "Error resolving path %s", editorPreferencesFilePath.c_str());
return;
}
AZ::SettingsRegistryMergeUtils::DumperSettings dumperSettings;
dumperSettings.m_prettifyOutput = true;
@@ -215,14 +219,14 @@ namespace AWSCore
{
AZ_Warning(
"AWSAttributionManager", false, R"(Unable to save changes to the Editor AWS Preferences registry file at "%s"\n)",
resolvedPath.data());
resolvedPathAWSPreference.c_str());
return;
}
bool saved {};
constexpr auto configurationMode =
AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY;
if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPath.data(), configurationMode))
if (AZ::IO::SystemFile outputFile; outputFile.Open(resolvedPathAWSPreference.c_str(), configurationMode))
{
saved = outputFile.Write(stringBuffer.data(), stringBuffer.size()) == stringBuffer.size();
}
@@ -54,7 +54,7 @@ namespace AWSCore
{
if (m_resourceMappingToolWatcher->IsProcessRunning())
{
m_resourceMappingToolWatcher->TerminateProcess(AZ::u32(-1));
m_resourceMappingToolWatcher->TerminateProcess(static_cast<AZ::u32>(-1));
}
m_resourceMappingToolWatcher.reset();
}
@@ -214,7 +214,7 @@ namespace AWSCore
QMenu* AWSCoreEditorMenu::SetAWSFeatureSubMenu(const AZStd::string& menuText)
{
auto actionList = this->actions();
for (QList<QAction*>::iterator itr = actionList.begin(); itr != actionList.end(); itr++)
for (QList<QAction*>::iterator itr = actionList.begin(); itr != actionList.end(); ++itr)
{
if (QString::compare((*itr)->text(), menuText.c_str()) == 0)
{
@@ -22,10 +22,6 @@ namespace AWSCore
{
}
AwsApiJob::~AwsApiJob()
{
}
AwsApiJob::Config* AwsApiJob::GetDefaultConfig()
{
static AwsApiJobConfigHolder<AwsApiJob::Config> s_configHolder{};
@@ -49,7 +49,7 @@ namespace AWSCore
{
m_fileFields.emplace_back(FileField{ std::move(fieldName), std::move(fileName) , AZStd::vector<char>{} });
m_fileFields.back().m_fileData.reserve(length);
m_fileFields.back().m_fileData.assign((const char*)bytes, (const char*)bytes + length);
m_fileFields.back().m_fileData.assign(static_cast<const char*>(bytes), static_cast<const char*>(bytes) + length);
}
void MultipartFormData::SetCustomBoundary(AZStd::string boundary)
@@ -10,6 +10,10 @@
namespace AWSCore
{
RequestBuilder::RequestBuilder()
: m_httpMethod(Aws::Http::HttpMethod::HTTP_GET)
{
}
bool RequestBuilder::SetPathParameterUnescaped(const char* key, const char* value)
{
@@ -26,7 +26,6 @@ namespace AWSCore
: m_status(Status::NotLoaded)
, m_defaultAccountId("")
, m_defaultRegion("")
, m_resourceMappings()
{
}
@@ -164,7 +163,7 @@ namespace AWSCore
m_defaultRegion = jsonDocument.FindMember(ResourceMappingRegionKeyName)->value.GetString();
auto resourceMappings = jsonDocument.FindMember(ResourceMappingResourcesKeyName)->value.GetObject();
for (auto mappingIter = resourceMappings.MemberBegin(); mappingIter != resourceMappings.MemberEnd(); mappingIter++)
for (auto mappingIter = resourceMappings.MemberBegin(); mappingIter != resourceMappings.MemberEnd(); ++mappingIter)
{
auto mappingValue = mappingIter->value.GetObject();
if (mappingValue.MemberCount() != 0)
@@ -71,7 +71,7 @@ namespace AWSCore
[](DynamoDBGetItemRequestJob* job) // OnSuccess handler
{
auto item = job->result.GetItem();
if (item.size() > 0)
if (!item.empty())
{
DynamoDBAttributeValueMap result;
for (const auto& itermPair : item)
@@ -40,7 +40,7 @@ public:
AWSCoreNotificationsBus::Handler::BusConnect();
}
~AWSCoreNotificationsBusMock()
~AWSCoreNotificationsBusMock() override
{
AWSCoreNotificationsBus::Handler::BusDisconnect();
}
@@ -18,7 +18,7 @@ class AWSCVarCredentialHandlerTest
{
public:
AWSCVarCredentialHandlerTest() = default;
virtual ~AWSCVarCredentialHandlerTest() = default;
~AWSCVarCredentialHandlerTest() override = default;
void SetUp() override
{
@@ -36,14 +36,14 @@ public:
m_credentialsProvider.reset();
}
int GetCredentialHandlerOrder() const
int GetCredentialHandlerOrder() const override
{
return 1;
}
std::shared_ptr<Aws::Auth::AWSCredentialsProvider> GetCredentialsProvider()
std::shared_ptr<Aws::Auth::AWSCredentialsProvider> GetCredentialsProvider() override
{
m_handlerCounter++;
++m_handlerCounter;
return m_credentialsProvider;
}
@@ -72,14 +72,14 @@ public:
m_credentialsProvider.reset();
}
int GetCredentialHandlerOrder() const
int GetCredentialHandlerOrder() const override
{
return 2;
}
std::shared_ptr<Aws::Auth::AWSCredentialsProvider> GetCredentialsProvider()
std::shared_ptr<Aws::Auth::AWSCredentialsProvider> GetCredentialsProvider() override
{
m_handlerCounter++;
++m_handlerCounter;
return m_credentialsProvider;
}
@@ -115,10 +115,10 @@ public:
TEST_F(AWSCredentialBusTest, GetCredentialsProvider_CallFromMultithread_GetExpectedCredentialsProviderAndNumberOfCalls)
{
int testThreadNumber = 10;
constexpr int testThreadNumber = 10;
AZStd::atomic<int> actualEbusCalls = 0;
AZStd::vector<AZStd::thread> testThreadPool;
for (int index = 0; index < testThreadNumber; index++)
for (int index = 0; index < testThreadNumber; ++index)
{
testThreadPool.emplace_back(AZStd::thread([&]() {
AWSCredentialResult result;
@@ -49,7 +49,7 @@ class AWSDefaultCredentialHandlerTest
{
public:
AWSDefaultCredentialHandlerTest() = default;
virtual ~AWSDefaultCredentialHandlerTest() = default;
~AWSDefaultCredentialHandlerTest() override = default;
void SetUp() override
{
@@ -23,6 +23,11 @@ class AWSApiClientJobConfigTest
, public AWSCredentialRequestBus::Handler
{
public:
AWSApiClientJobConfigTest()
: m_credentialHandlerCounter(0)
{
}
void SetUp() override
{
AWSNativeSDKInit::InitializationManager::InitAwsApi();
@@ -84,7 +84,7 @@ class ServiceClientJobConfigTest
void ReloadConfigFile(bool reloadConfigFileName = false) override
{
AZ_UNUSED(reloadConfigFileName);
};
}
};
TEST_F(ServiceClientJobConfigTest, GetServiceUrl_CreateServiceWithServiceNameOnly_GetExpectedFeatureServiceUrl)
@@ -217,7 +217,7 @@ TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_Confi
CreateTestConfigFile(TEST_VALID_RESOURCE_MAPPING_CONFIG_FILE);
m_resourceMappingManager->ActivateManager();
int testThreadNumber = 10;
constexpr int testThreadNumber = 10;
AZStd::atomic<int> actualEbusCalls = 0;
AZStd::vector<AZStd::thread> testThreadPool;
for (int index = 0; index < testThreadNumber; index++)
@@ -226,7 +226,7 @@ TEST_F(AWSResourceMappingManagerTest, ActivateManager_ParseValidConfigFile_Confi
AZStd::string actualAccountId;
AWSResourceMappingRequestBus::BroadcastResult(actualAccountId, &AWSResourceMappingRequests::GetDefaultAccountId);
EXPECT_FALSE(actualAccountId.empty());
actualEbusCalls++;
++actualEbusCalls;
}));
}
@@ -44,19 +44,19 @@ TEST_F(AWSResourceMappingUtilsTest, FormatRESTApiUrl_PassingInvalidRESTApiId_Ret
{
auto actualUrl = AWSResourceMappingUtils::FormatRESTApiUrl("", TEST_VALID_RESTAPI_REGION, TEST_VALID_RESTAPI_STAGE);
EXPECT_TRUE(actualUrl == "");
EXPECT_TRUE(actualUrl.empty());
}
TEST_F(AWSResourceMappingUtilsTest, FormatRESTApiUrl_PassingInvalidRESTApiRegion_ReturnEmptyResult)
{
auto actualUrl = AWSResourceMappingUtils::FormatRESTApiUrl(TEST_VALID_RESTAPI_ID, "", TEST_VALID_RESTAPI_STAGE);
EXPECT_TRUE(actualUrl == "");
EXPECT_TRUE(actualUrl.empty());
}
TEST_F(AWSResourceMappingUtilsTest, FormatRESTApiUrl_PassingInvalidRESTApiStage_ReturnEmptyResult)
{
auto actualUrl = AWSResourceMappingUtils::FormatRESTApiUrl(TEST_VALID_RESTAPI_ID, TEST_VALID_RESTAPI_REGION, "");
EXPECT_TRUE(actualUrl == "");
EXPECT_TRUE(actualUrl.empty());
}
@@ -23,7 +23,7 @@ public:
AWSScriptBehaviorDynamoDBNotificationBus::Handler::BusConnect();
}
~AWSScriptBehaviorDynamoDBNotificationBusHandlerMock()
~AWSScriptBehaviorDynamoDBNotificationBusHandlerMock() override
{
AWSScriptBehaviorDynamoDBNotificationBus::Handler::BusDisconnect();
}
@@ -22,7 +22,7 @@ public:
AWSScriptBehaviorLambdaNotificationBus::Handler::BusConnect();
}
~AWSScriptBehaviorLambdaNotificationBusHandlerMock()
~AWSScriptBehaviorLambdaNotificationBusHandlerMock() override
{
AWSScriptBehaviorLambdaNotificationBus::Handler::BusDisconnect();
}
@@ -24,7 +24,7 @@ public:
AWSScriptBehaviorS3NotificationBus::Handler::BusConnect();
}
~AWSScriptBehaviorS3NotificationBusHandlerMock()
~AWSScriptBehaviorS3NotificationBusHandlerMock() override
{
AWSScriptBehaviorS3NotificationBus::Handler::BusDisconnect();
}
@@ -107,8 +107,8 @@ class AWSCoreFixture
: public UnitTest::ScopedAllocatorSetupFixture
{
public:
AWSCoreFixture() {}
virtual ~AWSCoreFixture() = default;
AWSCoreFixture() = default;
~AWSCoreFixture() override = default;
void SetUp() override
{
+10
View File
@@ -64,6 +64,16 @@ To add additional dependencies, for example other CDK libraries, just add
them to your `setup.py` file and rerun the `pip install -r requirements.txt`
command.
## Optional Features
Server access logging is enabled by default. To disable the feature, use the following commands to synthesize and deploy this CDK application.
```
$ cdk synth -c disable_access_log=true --all
$ cdk deploy -c disable_access_log=true --all
```
See https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerLogs.html for more information about server access logging.
## Useful commands
* `cdk ls` list all stacks in the app
+3 -2
View File
@@ -57,8 +57,9 @@ example_stack = ExampleResources(
tags={Constants.O3DE_PROJECT_TAG_NAME: PROJECT_NAME, Constants.O3DE_FEATURE_TAG_NAME: FEATURE_NAME},
env=env
)
#
# Add the common stack as a dependency of the feature stack
# Add the core stack as a dependency of the feature stack since the feature stack
# requires the core stack outputs for deployment.
example_stack.add_dependency(core_construct.common_stack)
app.synth()
+19 -18
View File
@@ -60,17 +60,6 @@ class CoreStack(core.Stack):
type='TAG_FILTERS_1_0')
)
# Create an S3 bucket for Amazon S3 server access logging
# See https://docs.aws.amazon.com/AmazonS3/latest/dev/security-best-practices.html
self._server_access_logs_bucket = s3.Bucket(
self,
f'{self._project_name}-{self._feature_name}-Access-Log-Bucket',
block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
encryption=s3.BucketEncryption.S3_MANAGED,
access_control=s3.BucketAccessControl.LOG_DELIVERY_WRITE
)
self._server_access_logs_bucket.grant_read(self._admin_group)
# Define exports
# Export resource group
self._resource_group_output = core.CfnOutput(
@@ -94,10 +83,22 @@ class CoreStack(core.Stack):
export_name=f"{self._project_name}:AdminGroup",
value=self._admin_group.group_arn)
# Export access log bucket name
self._server_access_logs_bucket_output = core.CfnOutput(
self,
id=f'ServerAccessLogsBucketOutput',
description='Name of the S3 bucket for storing server access logs generated by the sample CDK application(s)',
export_name=f"{self._project_name}:ServerAccessLogsBucket",
value=self._server_access_logs_bucket.bucket_name)
# Create an S3 bucket for Amazon S3 server access logging
# See https://docs.aws.amazon.com/AmazonS3/latest/dev/security-best-practices.html
if self.node.try_get_context('disable_access_log') != 'true':
self._server_access_logs_bucket = s3.Bucket(
self,
f'{self._project_name}-{self._feature_name}-Access-Log-Bucket',
block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
encryption=s3.BucketEncryption.S3_MANAGED,
access_control=s3.BucketAccessControl.LOG_DELIVERY_WRITE
)
self._server_access_logs_bucket.grant_read(self._admin_group)
# Export access log bucket name
self._server_access_logs_bucket_output = core.CfnOutput(
self,
id=f'ServerAccessLogsBucketOutput',
description='Name of the S3 bucket for storing server access logs generated by the sample CDK application(s)',
export_name=f"{self._project_name}:ServerAccessLogsBucket",
value=self._server_access_logs_bucket.bucket_name)
@@ -118,19 +118,23 @@ class ExampleResources(core.Stack):
# https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html
# 3. Enable Amazon S3 server access logging
# https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerLogs.html
server_access_logs_bucket = s3.Bucket.from_bucket_name(
self,
f'{self._project_name}-{self._feature_name}-ImportedAccessLogsBucket',
core.Fn.import_value(f"{self._project_name}:ServerAccessLogsBucket")
)
server_access_logs_bucket = None
if self.node.try_get_context('disable_access_log') != 'true':
server_access_logs_bucket = s3.Bucket.from_bucket_name(
self,
f'{self._project_name}-{self._feature_name}-ImportedAccessLogsBucket',
core.Fn.import_value(f"{self._project_name}:ServerAccessLogsBucket")
)
example_bucket = s3.Bucket(
self,
f'{self._project_name}-{self._feature_name}-Example-S3bucket',
block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
encryption=s3.BucketEncryption.S3_MANAGED,
server_access_logs_bucket=server_access_logs_bucket,
server_access_logs_prefix=f'{self._project_name}-{self._feature_name}-{self.region}-AccessLogs'
server_access_logs_bucket=
server_access_logs_bucket if server_access_logs_bucket else None,
server_access_logs_prefix=
f'{self._project_name}-{self._feature_name}-{self.region}-AccessLogs' if server_access_logs_bucket else None
)
s3_deployment.BucketDeployment(
@@ -74,7 +74,12 @@ namespace AWSMetrics
{
behaviorContext->EBus<AWSMetricsRequestBus>("AWSMetricsRequestBus", "Generate and submit metrics to the metrics analytics pipeline")
->Attribute(AZ::Script::Attributes::Category, "AWSMetrics")
->Event("SubmitMetrics", &AWSMetricsRequestBus::Events::SubmitMetrics)
->Event(
"SubmitMetrics", &AWSMetricsRequestBus::Events::SubmitMetrics,
{ { { "Metrics Attributes list", "The list of metrics attributes to submit." },
{ "Event priority", "Priority of the event. Defaults to 0, which is highest priority." },
{ "Event source override", "Event source used to override the default, 'AWSMetricGem'." },
{ "Buffer metrics", "Whether to buffer metrics and send them in a batch." } } })
->Event("FlushMetrics", &AWSMetricsRequestBus::Events::FlushMetrics)
;
@@ -63,13 +63,10 @@ ly_add_target(
3rdParty::Qt::Widgets
3rdParty::Qt::Gui
3rdParty::astc-encoder
3rdParty::etc2comp
3rdParty::PVRTexTool
3rdParty::squish-ccr
3rdParty::tiff
3rdParty::ISPCTexComp
3rdParty::ilmbase
Legacy::CryCommon
AZ::AzFramework
AZ::AzToolsFramework
AZ::AzQtComponents
@@ -39,16 +39,7 @@ namespace ImageProcessingAtom
ePixelFormat_ASTC_10x8,
ePixelFormat_ASTC_10x10,
ePixelFormat_ASTC_12x10,
ePixelFormat_ASTC_12x12,
//Formats supported by PowerVR GPU. Mainly for ios devices.
ePixelFormat_PVRTC2, //2bpp
ePixelFormat_PVRTC4, //4bpp
//formats for opengl and opengles 3.0 (android devices)
ePixelFormat_EAC_R11, //one channel unsigned data
ePixelFormat_EAC_RG11, //two channel unsigned data
ePixelFormat_ETC2, //Compresses RGB888 data, it taks 4x4 groups of pixel data and compresses each into a 64-bit
ePixelFormat_ETC2a1, //Compresses RGB888A1 data, it taks 4x4 groups of pixel data and compresses each into a 64-bit
ePixelFormat_ETC2a, //Compresses RGBA8888 data with full alpha support
ePixelFormat_ASTC_12x12,
// Standardized Compressed DXGI Formats (DX10+)
// Data in these compressed formats is hardware decodable on all DX10 chips, and manageable with the DX10-API.
@@ -88,7 +79,6 @@ namespace ImageProcessingAtom
};
bool IsASTCFormat(EPixelFormat fmt);
bool IsETCFormat(EPixelFormat fmt);
} // namespace ImageProcessingAtom
namespace AZ
@@ -109,13 +109,6 @@ namespace ImageProcessingAtom
->Value("ASTC_10x10", EPixelFormat::ePixelFormat_ASTC_10x10)
->Value("ASTC_12x10", EPixelFormat::ePixelFormat_ASTC_12x10)
->Value("ASTC_12x12", EPixelFormat::ePixelFormat_ASTC_12x12)
->Value("PVRTC2", EPixelFormat::ePixelFormat_PVRTC2)
->Value("PVRTC4", EPixelFormat::ePixelFormat_PVRTC4)
->Value("EAC_R11", EPixelFormat::ePixelFormat_EAC_R11)
->Value("EAC_RG11", EPixelFormat::ePixelFormat_EAC_RG11)
->Value("ETC2", EPixelFormat::ePixelFormat_ETC2)
->Value("ETC2a1", EPixelFormat::ePixelFormat_ETC2a1)
->Value("ETC2a", EPixelFormat::ePixelFormat_ETC2a)
->Value("BC1", EPixelFormat::ePixelFormat_BC1)
->Value("BC1a", EPixelFormat::ePixelFormat_BC1a)
->Value("BC3", EPixelFormat::ePixelFormat_BC3)

Some files were not shown because too many files have changed in this diff Show More