diff --git a/Assets/Engine/SeedAssetList.seed b/Assets/Engine/SeedAssetList.seed
index 77ec509721..579fd3c444 100644
--- a/Assets/Engine/SeedAssetList.seed
+++ b/Assets/Engine/SeedAssetList.seed
@@ -66,779 +66,75 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -1384,166 +680,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1632,46 +768,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Assets/Engine/exclude.filetag b/Assets/Engine/exclude.filetag
index 52534a87d8..3528454ec4 100644
--- a/Assets/Engine/exclude.filetag
+++ b/Assets/Engine/exclude.filetag
@@ -125,17 +125,6 @@
-
-
-
-
-
-
-
-
-
-
-
@@ -207,27 +196,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/AutomatedTesting/AutomatedTesting_Dependencies.xml b/AutomatedTesting/AutomatedTesting_Dependencies.xml
index 50a5caea73..98e00a2914 100644
--- a/AutomatedTesting/AutomatedTesting_Dependencies.xml
+++ b/AutomatedTesting/AutomatedTesting_Dependencies.xml
@@ -1,5 +1,4 @@
-
\ No newline at end of file
diff --git a/AutomatedTesting/Config/shader_global_build_options.json b/AutomatedTesting/Config/shader_global_build_options.json
index 08e4d7f502..1aacb05575 100644
--- a/AutomatedTesting/Config/shader_global_build_options.json
+++ b/AutomatedTesting/Config/shader_global_build_options.json
@@ -3,9 +3,15 @@
"Version": 1,
"ClassName": "GlobalBuildOptions",
"ClassData": {
- "ShaderCompilerArguments" : {
- "DefaultMatrixOrder" : "Row",
- "AzslcAdditionalFreeArguments" : "--strip-unused-srgs"
+ "ShaderCompilerArguments": {
+ "DefaultMatrixOrder": "Row",
+ "AzslcAdditionalFreeArguments": "--strip-unused-srgs"
+ },
+ "PreprocessorOptions": {
+ "predefinedMacros": [ "AZSL=17" ],
+ "projectIncludePaths": [
+ "Gems/AtomTressFX/Assets/Shaders"
+ ]
}
}
}
\ No newline at end of file
diff --git a/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py b/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py
new file mode 100644
index 0000000000..d5a7acfe91
--- /dev/null
+++ b/AutomatedTesting/Editor/Scripts/scene_mesh_to_prefab.py
@@ -0,0 +1,162 @@
+#
+# 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
+#
+#
+import os, traceback, binascii, sys, json, pathlib
+import azlmbr.math
+import azlmbr.bus
+
+#
+# SceneAPI Processor
+#
+
+
+def log_exception_traceback():
+ exc_type, exc_value, exc_tb = sys.exc_info()
+ data = traceback.format_exception(exc_type, exc_value, exc_tb)
+ print(str(data))
+
+def get_mesh_node_names(sceneGraph):
+ import azlmbr.scene as sceneApi
+ import azlmbr.scene.graph
+ from scene_api import scene_data as sceneData
+
+ meshDataList = []
+ node = sceneGraph.get_root()
+ children = []
+ paths = []
+
+ while node.IsValid():
+ # store children to process after siblings
+ if sceneGraph.has_node_child(node):
+ children.append(sceneGraph.get_node_child(node))
+
+ nodeName = sceneData.SceneGraphName(sceneGraph.get_node_name(node))
+ paths.append(nodeName.get_path())
+
+ # store any node that has mesh data content
+ nodeContent = sceneGraph.get_node_content(node)
+ if nodeContent.CastWithTypeName('MeshData'):
+ if sceneGraph.is_node_end_point(node) is False:
+ if (len(nodeName.get_path())):
+ meshDataList.append(sceneData.SceneGraphName(sceneGraph.get_node_name(node)))
+
+ # advance to next node
+ if sceneGraph.has_node_sibling(node):
+ node = sceneGraph.get_node_sibling(node)
+ elif children:
+ node = children.pop()
+ else:
+ node = azlmbr.scene.graph.NodeIndex()
+
+ return meshDataList, paths
+
+def update_manifest(scene):
+ import json
+ import uuid, os
+ import azlmbr.scene as sceneApi
+ import azlmbr.scene.graph
+ from scene_api import scene_data as sceneData
+
+ graph = sceneData.SceneGraph(scene.graph)
+ # Get a list of all the mesh nodes, as well as all the nodes
+ mesh_name_list, all_node_paths = get_mesh_node_names(graph)
+ scene_manifest = sceneData.SceneManifest()
+
+ clean_filename = scene.sourceFilename.replace('.', '_')
+
+ # Compute the filename of the scene file
+ source_basepath = scene.watchFolder
+ source_relative_path = os.path.dirname(os.path.relpath(clean_filename, source_basepath))
+ source_filename_only = os.path.basename(clean_filename)
+
+ created_entities = []
+
+ # Loop every mesh node in the scene
+ for activeMeshIndex in range(len(mesh_name_list)):
+ mesh_name = mesh_name_list[activeMeshIndex]
+ mesh_path = mesh_name.get_path()
+ # Create a unique mesh group name using the filename + node name
+ mesh_group_name = '{}_{}'.format(source_filename_only, mesh_name.get_name())
+ # Remove forbidden filename characters from the name since this will become a file on disk later
+ mesh_group_name = "".join(char for char in mesh_group_name if char not in "|<>:\"/?*\\")
+ # Add the MeshGroup to the manifest and give it a unique ID
+ mesh_group = scene_manifest.add_mesh_group(mesh_group_name)
+ mesh_group['id'] = '{' + str(uuid.uuid5(uuid.NAMESPACE_DNS, source_filename_only + mesh_path)) + '}'
+ # Set our current node as the only node that is included in this MeshGroup
+ scene_manifest.mesh_group_select_node(mesh_group, mesh_path)
+
+ # Explicitly remove all other nodes to prevent implicit inclusions
+ for node in all_node_paths:
+ if node != mesh_path:
+ scene_manifest.mesh_group_unselect_node(mesh_group, node)
+
+ # Create an editor entity
+ entity_id = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "CreateEditorReadyEntity", mesh_group_name)
+ # Add an EditorMeshComponent to the entity
+ editor_mesh_component = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "GetOrAddComponentByTypeName", entity_id, "AZ::Render::EditorMeshComponent")
+ # Set the ModelAsset assetHint to the relative path of the input asset + the name of the MeshGroup we just created + the azmodel extension
+ # The MeshGroup we created will be output as a product in the asset's path named mesh_group_name.azmodel
+ # The assetHint will be converted to an AssetId later during prefab loading
+ json_update = json.dumps({
+ "Controller": { "Configuration": { "ModelAsset": {
+ "assetHint": os.path.join(source_relative_path, mesh_group_name) + ".azmodel" }}}
+ });
+ # Apply the JSON above to the component we created
+ result = azlmbr.entity.EntityUtilityBus(azlmbr.bus.Broadcast, "UpdateComponentForEntity", entity_id, editor_mesh_component, json_update)
+
+ if not result:
+ raise RuntimeError("UpdateComponentForEntity failed")
+
+ # Keep track of the entity we set up, we'll add them all to the prefab we're creating later
+ created_entities.append(entity_id)
+
+ # Create a prefab with all our entities
+ prefab_filename = source_filename_only + ".prefab"
+ created_template_id = azlmbr.prefab.PrefabSystemScriptingBus(azlmbr.bus.Broadcast, "CreatePrefab", created_entities, prefab_filename)
+
+ if created_template_id == azlmbr.prefab.InvalidTemplateId:
+ raise RuntimeError("CreatePrefab {} failed".format(prefab_filename))
+
+ # Convert the prefab to a JSON string
+ output = azlmbr.prefab.PrefabLoaderScriptingBus(azlmbr.bus.Broadcast, "SaveTemplateToString", created_template_id)
+
+ if output.IsSuccess():
+ jsonString = output.GetValue()
+ uuid = azlmbr.math.Uuid_CreateRandom().ToString()
+ jsonResult = json.loads(jsonString)
+ # Add a PrefabGroup to the manifest and store the JSON on it
+ scene_manifest.add_prefab_group(source_filename_only, uuid, jsonResult)
+ else:
+ raise RuntimeError("SaveTemplateToString failed for template id {}, prefab {}".format(created_template_id, prefab_filename))
+
+ # Convert the manifest to a JSON string and return it
+ new_manifest = scene_manifest.export()
+
+ return new_manifest
+
+sceneJobHandler = None
+
+def on_update_manifest(args):
+ try:
+ scene = args[0]
+ return update_manifest(scene)
+ except RuntimeError as err:
+ print (f'ERROR - {err}')
+ log_exception_traceback()
+
+ global sceneJobHandler
+ sceneJobHandler = None
+
+# try to create SceneAPI handler for processing
+try:
+ import azlmbr.scene as sceneApi
+ if (sceneJobHandler == None):
+ sceneJobHandler = sceneApi.ScriptBuildingNotificationBusHandler()
+ sceneJobHandler.connect()
+ sceneJobHandler.add_callback('OnUpdateManifest', on_update_manifest)
+except:
+ sceneJobHandler = None
diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake
index 112e54d848..84c9e49db5 100644
--- a/AutomatedTesting/Gem/Code/enabled_gems.cmake
+++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake
@@ -21,9 +21,9 @@ set(ENABLED_GEMS
QtForPython
PythonAssetBuilder
Metastream
-
Camera
EMotionFX
+ AtomTressFX
PhysX
CameraFramework
StartingPointMovement
@@ -52,10 +52,7 @@ set(ENABLED_GEMS
AWSCore
AWSClientAuth
AWSMetrics
-
-
-
-
+ PrefabBuilder
AudioSystem
Multiplayer
)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
index 02aaa42597..0d6fe4c8fa 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/Atom/CMakeLists.txt
@@ -65,4 +65,18 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT
COMPONENT
Atom
)
+ ly_add_pytest(
+ NAME AutomatedTesting::Atom_TestSuite_Main_GPU_Optimized
+ TEST_SUITE main
+ TEST_REQUIRES gpu
+ TEST_SERIAL
+ TIMEOUT 1200
+ PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_GPU_Optimized.py
+ RUNTIME_DEPENDENCIES
+ AssetProcessor
+ AutomatedTesting.Assets
+ Editor
+ COMPONENT
+ Atom
+ )
endif()
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
index 249b9c7096..3403d8e9b1 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU.py
@@ -226,9 +226,9 @@ class TestMaterialEditor(object):
self, request, workspace, project, launcher_platform, generic_launcher, exe_file_name, cfg_args):
"""
Tests each valid RHI option (Null RHI excluded) can be launched with the MaterialEditor.
- Checks for the "Finished loading viewport configurtions." success message post lounch.
+ Checks for the "Finished loading viewport configurations." success message post launch.
"""
- expected_lines = ["Finished loading viewport configurtions."]
+ expected_lines = ["Finished loading viewport configurations."]
unexpected_lines = [
# "Trace::Assert",
# "Trace::Error",
@@ -241,7 +241,7 @@ class TestMaterialEditor(object):
generic_launcher,
editor_script="",
run_python="--runpython",
- timeout=30,
+ timeout=60,
expected_lines=expected_lines,
unexpected_lines=unexpected_lines,
halt_on_unexpected=False,
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py
new file mode 100644
index 0000000000..ef572d6e5c
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/TestSuite_Main_GPU_Optimized.py
@@ -0,0 +1,43 @@
+"""
+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
+"""
+import os
+
+import pytest
+
+import ly_test_tools.environment.file_system as file_system
+from ly_test_tools.o3de.editor_test import EditorSharedTest, EditorTestSuite
+from ly_test_tools.image.screenshot_compare_qssim import qssim as compare_screenshots
+from .atom_utils.atom_component_helper import create_screenshots_archive, golden_images_directory
+
+DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots'
+
+
+@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
+@pytest.mark.parametrize("project", ["AutomatedTesting"])
+@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
+class TestAutomation(EditorTestSuite):
+ # Remove -autotest_mode from global_extra_cmdline_args since we need rendering for these tests.
+ global_extra_cmdline_args = ["-BatchMode"] # Default is ["-BatchMode", "-autotest_mode"]
+
+ class AtomGPU_BasicLevelSetup_SetsUpLevel(EditorSharedTest):
+ use_null_renderer = False # Default is True
+ screenshot_name = "AtomBasicLevelSetup.ppm"
+ test_screenshots = [] # Gets set by setup()
+ screenshot_directory = "" # Gets set by setup()
+
+ # Clear existing test screenshots before starting test.
+ def setup(self, workspace):
+ screenshot_directory = os.path.join(workspace.paths.project(), DEFAULT_SUBFOLDER_PATH)
+ test_screenshots = [os.path.join(screenshot_directory, self.screenshot_name)]
+ file_system.delete(test_screenshots, True, True)
+
+ from Atom.tests import hydra_AtomGPU_BasicLevelSetup as test_module
+
+ golden_images = [os.path.join(golden_images_directory(), screenshot_name)]
+ for test_screenshot, golden_screenshot in zip(test_screenshots, golden_images):
+ compare_screenshots(test_screenshot, golden_screenshot)
+ create_screenshots_archive(screenshot_directory)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
index 58b72ef01a..821e0acfdb 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/atom_component_helper.py
@@ -3,13 +3,54 @@ Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright
SPDX-License-Identifier: Apache-2.0 OR MIT
-File to assist with common hydra component functions used across various Atom tests.
"""
+import datetime
import os
+import zipfile
-from editor_python_test_tools.editor_test_helper import EditorTestHelper
-helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")
+def create_screenshots_archive(screenshot_path):
+ """
+ Creates a new zip file archive at archive_path containing all files listed within archive_path.
+ :param screenshot_path: location containing the files to archive, the zip archive file will also be saved here.
+ :return: None, but creates a new zip file archive inside path containing all of the files inside archive_path.
+ """
+ files_to_archive = []
+
+ # Search for .png and .ppm files to add to the zip archive file.
+ for (folder_name, sub_folders, file_names) in os.walk(screenshot_path):
+ for file_name in file_names:
+ if file_name.endswith(".png") or file_name.endswith(".ppm"):
+ file_path = os.path.join(folder_name, file_name)
+ files_to_archive.append(file_path)
+
+ # Setup variables for naming the zip archive file.
+ timestamp = datetime.datetime.now().timestamp()
+ formatted_timestamp = datetime.datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d_%H-%M-%S")
+ screenshots_file = os.path.join(screenshot_path, f'screenshots_{formatted_timestamp}.zip')
+
+ # Write all of the valid .png and .ppm files to the archive file.
+ with zipfile.ZipFile(screenshots_file, 'w', compression=zipfile.ZIP_DEFLATED, allowZip64=True) as zip_archive:
+ for file_path in files_to_archive:
+ file_name = os.path.basename(file_path)
+ zip_archive.write(file_path, file_name)
+
+
+def golden_images_directory():
+ """
+ Uses this file location to return the valid location for golden image files.
+ :return: The path to the golden_images directory, but raises an IOError if the golden_images directory is missing.
+ """
+ current_file_directory = os.path.join(os.path.dirname(__file__))
+ golden_images_dir = os.path.join(current_file_directory, '..', 'golden_images')
+
+ if not os.path.exists(golden_images_dir):
+ raise IOError(
+ f'golden_images" directory was not found at path "{golden_images_dir}"'
+ f'Please add a "golden_images" directory inside: "{current_file_directory}"'
+ )
+
+ return golden_images_dir
def create_basic_atom_level(level_name):
@@ -31,6 +72,9 @@ def create_basic_atom_level(level_name):
import azlmbr.object
import editor_python_test_tools.hydra_editor_utils as hydra
+ from editor_python_test_tools.editor_test_helper import EditorTestHelper
+
+ helper = EditorTestHelper(log_prefix="Atom_EditorTestHelper")
# Create a new level.
new_level_name = level_name
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py
index ef0a592df0..b21c74de19 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/atom_utils/material_editor_utils.py
@@ -211,7 +211,7 @@ class Timeout:
return time.time() > self.die_after
-screenshotsFolder = os.path.join(azlmbr.paths.devroot, "AtomTest", "Cache" "pc", "Screenshots")
+screenshotsFolder = os.path.join(azlmbr.paths.products, "Screenshots")
class ScreenshotHelper:
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py
index 602e7564b3..bbc8463152 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_AddedToEntity.py
@@ -17,7 +17,7 @@ import azlmbr.legacy.general as general
import azlmbr.editor as editor
import azlmbr.render as render
-sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
+sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.utils import TestHelper
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py
index 751f425916..7ecdc6859b 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomEditorComponents_LightComponent.py
@@ -14,7 +14,7 @@ import azlmbr.math as math
import azlmbr.paths
import azlmbr.legacy.general as general
-sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
+sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra
from Atom.atom_utils.atom_constants import LIGHT_TYPES
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py
new file mode 100644
index 0000000000..92c555127a
--- /dev/null
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomGPU_BasicLevelSetup.py
@@ -0,0 +1,292 @@
+"""
+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
+"""
+
+
+# fmt: off
+class Tests :
+ camera_component_added = ("Camera component was added", "Camera component wasn't added")
+ camera_fov_set = ("Camera component FOV property set", "Camera component FOV property wasn't set")
+ directional_light_component_added = ("Directional Light component added", "Directional Light component wasn't added")
+ enter_game_mode = ("Entered game mode", "Failed to enter game mode")
+ exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
+ global_skylight_component_added = ("Global Skylight (IBL) component added", "Global Skylight (IBL) component wasn't added")
+ global_skylight_diffuse_image_set = ("Global Skylight Diffuse Image property set", "Global Skylight Diffuse Image property wasn't set")
+ global_skylight_specular_image_set = ("Global Skylight Specular Image property set", "Global Skylight Specular Image property wasn't set")
+ ground_plane_material_asset_set = ("Ground Plane Material Asset was set", "Ground Plane Material Asset wasn't set")
+ ground_plane_material_component_added = ("Ground Plane Material component added", "Ground Plane Material component wasn't added")
+ ground_plane_mesh_asset_set = ("Ground Plane Mesh Asset property was set", "Ground Plane Mesh Asset property wasn't set")
+ hdri_skybox_component_added = ("HDRi Skybox component added", "HDRi Skybox component wasn't added")
+ hdri_skybox_cubemap_texture_set = ("HDRi Skybox Cubemap Texture property set", "HDRi Skybox Cubemap Texture property wasn't set")
+ mesh_component_added = ("Mesh component added", "Mesh component wasn't added")
+ no_assert_occurred = ("No asserts detected", "Asserts were detected")
+ no_error_occurred = ("No errors detected", "Errors were detected")
+ secondary_grid_spacing = ("Secondary Grid Spacing set", "Secondary Grid Spacing not set")
+ sphere_material_component_added = ("Sphere Material component added", "Sphere Material component wasn't added")
+ sphere_material_set = ("Sphere Material Asset was set", "Sphere Material Asset wasn't set")
+ sphere_mesh_asset_set = ("Sphere Mesh Asset was set", "Sphere Mesh Asset wasn't set")
+ viewport_set = ("Viewport set to correct size", "Viewport not set to correct size")
+# fmt: on
+
+
+def AtomGPU_BasicLevelSetup_SetsUpLevel():
+ """
+ Summary:
+ Sets up a level to match the AtomBasicLevelSetup.ppm golden image then takes a screenshot to verify the setup.
+
+ Test setup:
+ - Wait for Editor idle loop.
+ - Open the "Base" level.
+
+ Expected Behavior:
+ The scene can be setup for a basic level.
+ The test screenshot matches the appearance of the AtomBasicLevelSetup.ppm golden image.
+
+ Test Steps:
+ 1. Close error windows and display helpers then update the viewport size.
+ 2. Create Default Level Entity.
+ 3. Create Grid Entity as a child entity of the Default Level Entity.
+ 4. Add Grid component to Grid Entity and set Secondary Grid Spacing.
+ 5. Create Global Skylight (IBL) Entity as a child entity of the Default Level Entity.
+ 6. Add HDRi Skybox component to the Global Skylight (IBL) Entity.
+ 7. Add Global Skylight (IBL) component to the Global Skylight (IBL) Entity.
+ 8. Set the Cubemap Texture property of the HDRi Skybox component.
+ 9. Set the Diffuse Image property of the Global Skylight (IBL) component.
+ 10. Set the Specular Image property of the Global Skylight (IBL) component.
+ 11. Create a Ground Plane Entity with a Material component that is a child entity of the Default Level Entity.
+ 12. Set the Material Asset property of the Material component for the Ground Plane Entity.
+ 13. Add the Mesh component to the Ground Plane Entity and set the Mesh component Mesh Asset property.
+ 14. Create a Directional Light Entity as a child entity of the Default Level Entity.
+ 15. Add Directional Light component to Directional Light Entity and set entity rotation.
+ 16. Create a Sphere Entity as a child entity of the Default Level Entity then add a Material component.
+ 17. Set the Material Asset property of the Material component for the Sphere Entity.
+ 18. Add Mesh component to Sphere Entity and set the Mesh Asset property for the Mesh component.
+ 19. Create a Camera Entity as a child entity of the Default Level Entity then add a Camera component.
+ 20. Set the Camera Entity rotation value and set the Camera component Field of View value.
+ 21. Enter game mode.
+ 22. Take screenshot.
+ 23. Exit game mode.
+ 24. Look for errors.
+
+ :return: None
+ """
+
+ import os
+ from math import isclose
+
+ import azlmbr.asset as asset
+ import azlmbr.bus as bus
+ import azlmbr.legacy.general as general
+ import azlmbr.math as math
+ import azlmbr.paths
+
+ from editor_python_test_tools.editor_entity_utils import EditorEntity
+ from editor_python_test_tools.utils import Report, Tracer, TestHelper as helper
+
+ from Atom.atom_utils.screenshot_utils import ScreenshotHelper
+
+ MATERIAL_COMPONENT_NAME = "Material"
+ MESH_COMPONENT_NAME = "Mesh"
+ SCREENSHOT_NAME = "AtomBasicLevelSetup"
+ SCREEN_WIDTH = 1280
+ SCREEN_HEIGHT = 720
+ DEGREE_RADIAN_FACTOR = 0.0174533
+
+ def initial_viewport_setup(screen_width, screen_height):
+ general.set_viewport_size(screen_width, screen_height)
+ general.update_viewport()
+ result = isclose(
+ a=general.get_viewport_size().x, b=SCREEN_WIDTH, rel_tol=0.1) and isclose(
+ a=general.get_viewport_size().y, b=SCREEN_HEIGHT, rel_tol=0.1)
+
+ return result
+
+ 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. Close error windows and display helpers then update the viewport size.
+ helper.close_error_windows()
+ helper.close_display_helpers()
+ general.update_viewport()
+ Report.critical_result(Tests.viewport_set, initial_viewport_setup(SCREEN_WIDTH, SCREEN_HEIGHT))
+
+ # 2. Create Default Level Entity.
+ default_level_entity_name = "Default Level"
+ default_level_entity = EditorEntity.create_editor_entity_at(
+ math.Vector3(0.0, 0.0, 0.0), default_level_entity_name)
+
+ # 3. Create Grid Entity as a child entity of the Default Level Entity.
+ grid_name = "Grid"
+ grid_entity = EditorEntity.create_editor_entity(grid_name, default_level_entity.id)
+
+ # 4. Add Grid component to Grid Entity and set Secondary Grid Spacing.
+ grid_component = grid_entity.add_component(grid_name)
+ secondary_grid_spacing_property = "Controller|Configuration|Secondary Grid Spacing"
+ secondary_grid_spacing_value = 1.0
+ grid_component.set_component_property_value(secondary_grid_spacing_property, secondary_grid_spacing_value)
+ secondary_grid_spacing_set = grid_component.get_component_property_value(
+ secondary_grid_spacing_property) == secondary_grid_spacing_value
+ Report.result(Tests.secondary_grid_spacing, secondary_grid_spacing_set)
+
+ # 5. Create Global Skylight (IBL) Entity as a child entity of the Default Level Entity.
+ global_skylight_name = "Global Skylight (IBL)"
+ global_skylight_entity = EditorEntity.create_editor_entity(global_skylight_name, default_level_entity.id)
+
+ # 6. Add HDRi Skybox component to the Global Skylight (IBL) Entity.
+ hdri_skybox_name = "HDRi Skybox"
+ hdri_skybox_component = global_skylight_entity.add_component(hdri_skybox_name)
+ Report.result(Tests.hdri_skybox_component_added, global_skylight_entity.has_component(hdri_skybox_name))
+
+ # 7. Add Global Skylight (IBL) component to the Global Skylight (IBL) Entity.
+ global_skylight_component = global_skylight_entity.add_component(global_skylight_name)
+ Report.result(Tests.global_skylight_component_added, global_skylight_entity.has_component(global_skylight_name))
+
+ # 8. Set the Cubemap Texture property of the HDRi Skybox component.
+ global_skylight_image_asset_path = os.path.join(
+ "LightingPresets", "greenwich_park_02_4k_iblskyboxcm_iblspecular.exr.streamingimage")
+ global_skylight_image_asset = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", global_skylight_image_asset_path, math.Uuid(), False)
+ hdri_skybox_cubemap_texture_property = "Controller|Configuration|Cubemap Texture"
+ hdri_skybox_component.set_component_property_value(
+ hdri_skybox_cubemap_texture_property, global_skylight_image_asset)
+ Report.result(
+ Tests.hdri_skybox_cubemap_texture_set,
+ hdri_skybox_component.get_component_property_value(
+ hdri_skybox_cubemap_texture_property) == global_skylight_image_asset)
+
+ # 9. Set the Diffuse Image property of the Global Skylight (IBL) component.
+ # Re-use the same image that was used in the previous test step.
+ global_skylight_diffuse_image_property = "Controller|Configuration|Diffuse Image"
+ global_skylight_component.set_component_property_value(
+ global_skylight_diffuse_image_property, global_skylight_image_asset)
+ Report.result(
+ Tests.global_skylight_diffuse_image_set,
+ global_skylight_component.get_component_property_value(
+ global_skylight_diffuse_image_property) == global_skylight_image_asset)
+
+ # 10. Set the Specular Image property of the Global Skylight (IBL) component.
+ # Re-use the same image that was used in the previous test step.
+ global_skylight_specular_image_property = "Controller|Configuration|Specular Image"
+ global_skylight_component.set_component_property_value(
+ global_skylight_specular_image_property, global_skylight_image_asset)
+ global_skylight_specular_image_set = global_skylight_component.get_component_property_value(
+ global_skylight_specular_image_property)
+ Report.result(
+ Tests.global_skylight_specular_image_set, global_skylight_specular_image_set == global_skylight_image_asset)
+
+ # 11. Create a Ground Plane Entity with a Material component that is a child entity of the Default Level Entity.
+ ground_plane_name = "Ground Plane"
+ ground_plane_entity = EditorEntity.create_editor_entity(ground_plane_name, default_level_entity.id)
+ ground_plane_material_component = ground_plane_entity.add_component(MATERIAL_COMPONENT_NAME)
+ Report.result(
+ Tests.ground_plane_material_component_added, ground_plane_entity.has_component(MATERIAL_COMPONENT_NAME))
+
+ # 12. Set the Material Asset property of the Material component for the Ground Plane Entity.
+ ground_plane_entity.set_local_uniform_scale(32.0)
+ ground_plane_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_chrome.azmaterial")
+ ground_plane_material_asset = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", ground_plane_material_asset_path, math.Uuid(), False)
+ ground_plane_material_asset_property = "Default Material|Material Asset"
+ ground_plane_material_component.set_component_property_value(
+ ground_plane_material_asset_property, ground_plane_material_asset)
+ Report.result(
+ Tests.ground_plane_material_asset_set,
+ ground_plane_material_component.get_component_property_value(
+ ground_plane_material_asset_property) == ground_plane_material_asset)
+
+ # 13. Add the Mesh component to the Ground Plane Entity and set the Mesh component Mesh Asset property.
+ ground_plane_mesh_component = ground_plane_entity.add_component(MESH_COMPONENT_NAME)
+ Report.result(Tests.mesh_component_added, ground_plane_entity.has_component(MESH_COMPONENT_NAME))
+ ground_plane_mesh_asset_path = os.path.join("Objects", "plane.azmodel")
+ ground_plane_mesh_asset = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", ground_plane_mesh_asset_path, math.Uuid(), False)
+ ground_plane_mesh_asset_property = "Controller|Configuration|Mesh Asset"
+ ground_plane_mesh_component.set_component_property_value(
+ ground_plane_mesh_asset_property, ground_plane_mesh_asset)
+ Report.result(
+ Tests.ground_plane_mesh_asset_set,
+ ground_plane_mesh_component.get_component_property_value(
+ ground_plane_mesh_asset_property) == ground_plane_mesh_asset)
+
+ # 14. Create a Directional Light Entity as a child entity of the Default Level Entity.
+ directional_light_name = "Directional Light"
+ directional_light_entity = EditorEntity.create_editor_entity_at(
+ math.Vector3(0.0, 0.0, 10.0), directional_light_name, default_level_entity.id)
+
+ # 15. Add Directional Light component to Directional Light Entity and set entity rotation.
+ directional_light_entity.add_component(directional_light_name)
+ directional_light_entity_rotation = math.Vector3(DEGREE_RADIAN_FACTOR * -90.0, 0.0, 0.0)
+ directional_light_entity.set_local_rotation(directional_light_entity_rotation)
+ Report.result(
+ Tests.directional_light_component_added, directional_light_entity.has_component(directional_light_name))
+
+ # 16. Create a Sphere Entity as a child entity of the Default Level Entity then add a Material component.
+ sphere_entity = EditorEntity.create_editor_entity_at(
+ math.Vector3(0.0, 0.0, 1.0), "Sphere", default_level_entity.id)
+ sphere_material_component = sphere_entity.add_component(MATERIAL_COMPONENT_NAME)
+ Report.result(Tests.sphere_material_component_added, sphere_entity.has_component(MATERIAL_COMPONENT_NAME))
+
+ # 17. Set the Material Asset property of the Material component for the Sphere Entity.
+ sphere_material_asset_path = os.path.join("Materials", "Presets", "PBR", "metal_brass_polished.azmaterial")
+ sphere_material_asset = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", sphere_material_asset_path, math.Uuid(), False)
+ sphere_material_asset_property = "Default Material|Material Asset"
+ sphere_material_component.set_component_property_value(sphere_material_asset_property, sphere_material_asset)
+ Report.result(Tests.sphere_material_set, sphere_material_component.get_component_property_value(
+ sphere_material_asset_property) == sphere_material_asset)
+
+ # 18. Add Mesh component to Sphere Entity and set the Mesh Asset property for the Mesh component.
+ sphere_mesh_component = sphere_entity.add_component(MESH_COMPONENT_NAME)
+ sphere_mesh_asset_path = os.path.join("Models", "sphere.azmodel")
+ sphere_mesh_asset = asset.AssetCatalogRequestBus(
+ bus.Broadcast, "GetAssetIdByPath", sphere_mesh_asset_path, math.Uuid(), False)
+ sphere_mesh_asset_property = "Controller|Configuration|Mesh Asset"
+ sphere_mesh_component.set_component_property_value(sphere_mesh_asset_property, sphere_mesh_asset)
+ Report.result(Tests.sphere_mesh_asset_set, sphere_mesh_component.get_component_property_value(
+ sphere_mesh_asset_property) == sphere_mesh_asset)
+
+ # 19. Create a Camera Entity as a child entity of the Default Level Entity then add a Camera component.
+ camera_name = "Camera"
+ camera_entity = EditorEntity.create_editor_entity_at(
+ math.Vector3(5.5, -12.0, 9.0), camera_name, default_level_entity.id)
+ camera_component = camera_entity.add_component(camera_name)
+ Report.result(Tests.camera_component_added, camera_entity.has_component(camera_name))
+
+ # 20. Set the Camera Entity rotation value and set the Camera component Field of View value.
+ camera_entity_rotation = math.Vector3(
+ DEGREE_RADIAN_FACTOR * -27.0, DEGREE_RADIAN_FACTOR * -12.0, DEGREE_RADIAN_FACTOR * 25.0)
+ camera_entity.set_local_rotation(camera_entity_rotation)
+ camera_fov_property = "Controller|Configuration|Field of view"
+ camera_fov_value = 60.0
+ camera_component.set_component_property_value(camera_fov_property, camera_fov_value)
+ azlmbr.camera.EditorCameraViewRequestBus(azlmbr.bus.Event, "ToggleCameraAsActiveView", camera_entity.id)
+ Report.result(Tests.camera_fov_set, camera_component.get_component_property_value(
+ camera_fov_property) == camera_fov_value)
+
+ # 21. Enter game mode.
+ helper.enter_game_mode(Tests.enter_game_mode)
+ helper.wait_for_condition(function=lambda: general.is_in_game_mode(), timeout_in_seconds=4.0)
+
+ # 22. Take screenshot.
+ ScreenshotHelper(general.idle_wait_frames).capture_screenshot_blocking(f"{SCREENSHOT_NAME}.ppm")
+
+ # 23. Exit game mode.
+ helper.exit_game_mode(Tests.exit_game_mode)
+ helper.wait_for_condition(function=lambda: not general.is_in_game_mode(), timeout_in_seconds=4.0)
+
+ # 24. Look for errors.
+ helper.wait_for_condition(lambda: error_tracer.has_errors or error_tracer.has_asserts, 1.0)
+ Report.result(Tests.no_assert_occurred, not error_tracer.has_asserts)
+ Report.result(Tests.no_error_occurred, not error_tracer.has_errors)
+
+
+if __name__ == "__main__":
+ from editor_python_test_tools.utils import Report
+ Report.start_test(AtomGPU_BasicLevelSetup_SetsUpLevel)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py
index 88a1ef4c7b..9f8f6c44b2 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_AtomMaterialEditor_BasicTests.py
@@ -16,7 +16,7 @@ import time
import azlmbr.math as math
import azlmbr.paths
-sys.path.append(os.path.join(azlmbr.paths.devassets, "Gem", "PythonTests"))
+sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
import Atom.atom_utils.material_editor_utils as material_editor
@@ -27,10 +27,10 @@ TEST_MATERIAL_1 = "001_DefaultWhite.material"
TEST_MATERIAL_2 = "002_BaseColorLerp.material"
TEST_MATERIAL_3 = "003_MetalMatte.material"
TEST_DATA_PATH = os.path.join(
- azlmbr.paths.devroot, "Gems", "Atom", "TestData", "TestData", "Materials", "StandardPbrTestCases"
+ azlmbr.paths.engroot, "Gems", "Atom", "TestData", "TestData", "Materials", "StandardPbrTestCases"
)
MATERIAL_TYPE_PATH = os.path.join(
- azlmbr.paths.devroot, "Gems", "Atom", "Feature", "Common", "Assets",
+ azlmbr.paths.engroot, "Gems", "Atom", "Feature", "Common", "Assets",
"Materials", "Types", "StandardPBR.materialtype",
)
CACHE_FILE_EXTENSION = ".azmaterial"
@@ -61,7 +61,7 @@ def run():
print(f"Material opened: {material_editor.is_open(document_id)}")
# Verify if the test material exists initially
- target_path = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL)
+ target_path = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL)
print(f"Test asset doesn't exist initially: {not os.path.exists(target_path)}")
# 2) Test Case: Creating a New Material Using Existing One
@@ -109,10 +109,10 @@ def run():
# Assign new color to the material file and save the document as copy
expected_color_1 = math.Color(0.5, 0.5, 0.5, 1.0)
material_editor.set_property(document_id, property_name, expected_color_1)
- target_path_1 = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL_1)
+ target_path_1 = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL_1)
cache_file_name_1 = os.path.splitext(NEW_MATERIAL_1) # Example output: ('test_material_1', '.material')
cache_file_1 = f"{cache_file_name_1[0]}{CACHE_FILE_EXTENSION}"
- target_path_1_cache = os.path.join(azlmbr.paths.devassets, "Cache", "pc", "materials", cache_file_1)
+ target_path_1_cache = os.path.join(azlmbr.paths.products, "materials", cache_file_1)
material_editor.save_document_as_copy(document_id, target_path_1)
material_editor.wait_for_condition(lambda: os.path.exists(target_path_1_cache), 4.0)
@@ -120,10 +120,10 @@ def run():
# Assign new color to the material file save the document as child
expected_color_2 = math.Color(0.75, 0.75, 0.75, 1.0)
material_editor.set_property(document_id, property_name, expected_color_2)
- target_path_2 = os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Materials", NEW_MATERIAL_2)
+ target_path_2 = os.path.join(azlmbr.paths.projectroot, "Materials", NEW_MATERIAL_2)
cache_file_name_2 = os.path.splitext(NEW_MATERIAL_1) # Example output: ('test_material_2', '.material')
cache_file_2 = f"{cache_file_name_2[0]}{CACHE_FILE_EXTENSION}"
- target_path_2_cache = os.path.join(azlmbr.paths.devassets, "Cache", "pc", "materials", cache_file_2)
+ target_path_2_cache = os.path.join(azlmbr.paths.products, "materials", cache_file_2)
material_editor.save_document_as_child(document_id, target_path_2)
material_editor.wait_for_condition(lambda: os.path.exists(target_path_2_cache), 4.0)
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
index 4f7edeba75..92199bf196 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_AtomFeatureIntegrationBenchmark.py
@@ -10,7 +10,7 @@ import sys
import azlmbr.legacy.general as general
-sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
+sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.editor_test_helper import EditorTestHelper
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
index 62a122a723..ac28e67fa1 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_BasicLevelSetup.py
@@ -17,7 +17,7 @@ import azlmbr.math as math
import azlmbr.paths
import azlmbr.editor as editor
-sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
+sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.editor_test_helper import EditorTestHelper
diff --git a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py
index 4a3ae8c85d..1c3e6226c1 100644
--- a/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py
+++ b/AutomatedTesting/Gem/PythonTests/Atom/tests/hydra_GPUTest_LightComponent.py
@@ -14,7 +14,7 @@ import azlmbr.math as math
import azlmbr.paths
import azlmbr.legacy.general as general
-sys.path.append(os.path.join(azlmbr.paths.devroot, "AutomatedTesting", "Gem", "PythonTests"))
+sys.path.append(os.path.join(azlmbr.paths.projectroot, "Gem", "PythonTests"))
import editor_python_test_tools.hydra_editor_utils as hydra
from Atom.atom_utils import atom_component_helper, atom_constants, screenshot_utils
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py
index 1d3ca11618..fcce6eab37 100755
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test.py
@@ -42,7 +42,6 @@ class TestEditorAutomation(object):
"editor command line arg bar",
"editor command line arg baz",
"editor engroot set",
- "editor devroot set",
"path resolved worked"
]
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py
index bd8791fad6..c6ae65612f 100755
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorCommandLine_test_case.py
@@ -20,12 +20,6 @@ if (engroot is not None and len(engroot) is not 0):
print ('engroot is {}'.format(engroot))
print ('editor engroot set')
-# make sure the @devroot@ exists as a azlmbr.paths property
-devroot = azlmbr.paths.devroot
-if (devroot is not None and len(devroot) != 0):
- print ('devroot is {}'.format(devroot))
- print ('editor devroot set')
-
# resolving a basic path
path = azlmbr.paths.resolve_path('@engroot@/engineassets/texturemsg/defaultsolids.mtl')
if (len(path) != 0 and path.find('@engroot@') == -1):
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py
index 5b7f2f42c1..c5ca4de603 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/EditorScripts/ComponentUpdateListProperty_test_case.py
@@ -16,7 +16,7 @@ import azlmbr.entity as entity
import azlmbr.math as math
import azlmbr.paths
-sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
+sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests'))
from automatedtesting_shared.editor_test_helper import EditorTestHelper
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg
index 3adc32d20a..ccc605cec9 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/LevelComponentCommands.cfg
@@ -1,2 +1,2 @@
# this file is copied to $/dev/editor_autoexec.cfg so the the Editor automation runs for this Hydra test
-pyRunFile @devroot@/Tests/hydra/LevelComponentCommands_test_case.py exit_when_done
\ No newline at end of file
+pyRunFile @engroot@/Tests/hydra/LevelComponentCommands_test_case.py exit_when_done
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg
index 6230dfe0fa..3cbd84c1b5 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonBindings/ViewportTitleDlgCommands.cfg
@@ -1,2 +1,2 @@
# this file is copied to $/dev/editor_autoexec.cfg so the the Editor automation runs for this Hydra test
-pyRunFile @devroot@/Tests/hydra/ViewportTitleDlgCommands_test_case.py
\ No newline at end of file
+pyRunFile @engroot@/Tests/hydra/ViewportTitleDlgCommands_test_case.py
\ No newline at end of file
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py
index 154b5730d7..783f71e06c 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/editor_entity_utils.py
@@ -361,3 +361,19 @@ class EditorEntity:
:return: True if "isVisible" is enabled, False otherwise.
"""
return editor.EditorEntityInfoRequestBus(bus.Event, "IsVisible", self.id)
+
+ def set_local_uniform_scale(self, scale_float) -> None:
+ """
+ Sets the "SetLocalUniformScale" value on the entity.
+ :param scale_float: value for "SetLocalUniformScale" to set to.
+ :return: None
+ """
+ azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalUniformScale", self.id, scale_float)
+
+ def set_local_rotation(self, vector3_rotation) -> None:
+ """
+ Sets the "SetLocalRotation" value on the entity.
+ :param vector3_rotation: The math.Vector3 value to use for rotation on the entity (uses radians).
+ :return: None
+ """
+ azlmbr.components.TransformBus(azlmbr.bus.Event, "SetLocalRotation", self.id, vector3_rotation)
diff --git a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py
index cc217f81da..ef3048d8d4 100644
--- a/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py
+++ b/AutomatedTesting/Gem/PythonTests/EditorPythonTestTools/editor_python_test_tools/utils.py
@@ -4,18 +4,18 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
+
+import json
+import math
import os
import time
-import math
+import traceback
+from typing import Callable, Tuple
import azlmbr
import azlmbr.legacy.general as general
import azlmbr.debug
-import json
-import traceback
-
-from typing import Callable, Tuple
class FailFast(Exception):
"""
@@ -127,6 +127,31 @@ class TestHelper:
if ret:
return True
+ @staticmethod
+ def close_error_windows():
+ """
+ Closes Error Report and Error Log windows that block focus if they are visible.
+ :return: None
+ """
+ if general.is_pane_visible("Error Report"):
+ general.close_pane("Error Report")
+ if general.is_pane_visible("Error Log"):
+ general.close_pane("Error Log")
+
+ @staticmethod
+ def close_display_helpers():
+ """
+ Closes helper gizmos, anti-aliasing, and FPS meters.
+ :return: None
+ """
+ if general.is_helpers_shown():
+ general.toggle_helpers()
+ general.idle_wait(1.0)
+ general.idle_wait(1.0)
+ general.run_console("r_displayInfo=0")
+ general.run_console("r_antialiasingmode=0")
+ general.idle_wait(1.0)
+
class Timeout:
# type: (float) -> None
@@ -149,6 +174,7 @@ class Timeout:
def timed_out(self):
return time.time() > self.die_after
+
class Report:
_results = []
_exception = None
@@ -290,8 +316,8 @@ class Report:
Report.info(" x: {:.2f}, y: {:.2f}, z: {:.2f}".format(vector3.x, vector3.y, vector3.z))
if magnitude is not None:
Report.info(" magnitude: {:.2f}".format(magnitude))
-
-
+
+
'''
Utility for scope tracing errors and warnings.
Usage:
@@ -303,7 +329,7 @@ Usage:
Report.result(Tests.warnings_not_found_in_section, not section_tracer.has_warnings)
-'''
+'''
class Tracer:
def __init__(self):
self.warnings = []
@@ -349,10 +375,10 @@ class Tracer:
self.line = args[1]
self.function = args[2]
self.message = args[3]
-
+
def __str__(self):
return f"Assert: [{self.filename}:{self.function}:{self.line}]: {self.message}"
-
+
def __repr__(self):
return f"[Assert: {self.message}]"
@@ -360,21 +386,21 @@ class Tracer:
def __init__(self, args):
self.window = args[0]
self.message = args[1]
-
+
def _on_warning(self, args):
warningInfo = Tracer.WarningInfo(args)
self.warnings.append(warningInfo)
Report.info("Tracer caught Warning: %s" % warningInfo.message)
self.has_warnings = True
return False
-
+
def _on_error(self, args):
errorInfo = Tracer.ErrorInfo(args)
self.errors.append(errorInfo)
Report.info("Tracer caught Error: %s" % errorInfo.message)
self.has_errors = True
return False
-
+
def _on_assert(self, args):
assertInfo = Tracer.AssertInfo(args)
self.asserts.append(assertInfo)
@@ -436,6 +462,7 @@ class AngleHelper:
def vector3_str(vector3):
return "(x: {:.2f}, y: {:.2f}, z: {:.2f})".format(vector3.x, vector3.y, vector3.z)
-
+
+
def aabb_str(aabb):
return "[Min: %s, Max: %s]" % (vector3_str(aabb.min), vector3_str(aabb.max))
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt
index f1299ddc2d..d5c7fd5109 100644
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/CMakeLists.txt
@@ -96,19 +96,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
## GradientSignal ##
- ly_add_pytest(
- NAME AutomatedTesting::GradientSignalTests_Periodic
- TEST_SERIAL
- TEST_SUITE periodic
- PATH ${CMAKE_CURRENT_LIST_DIR}/gradient_signal/TestSuite_Periodic.py
- RUNTIME_DEPENDENCIES
- AZ::AssetProcessor
- Legacy::Editor
- AutomatedTesting.Assets
- COMPONENT
- LargeWorlds
- )
-
ly_add_pytest(
NAME AutomatedTesting::GradientSignalTests_Periodic_Optimized
TEST_SERIAL
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py
index e51be58ec6..84c661873c 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_Embedded_E2E.py
@@ -109,7 +109,7 @@ def DynamicSliceInstanceSpawner_Embedded_E2E():
# 6) Save and export to engine
general.save_level()
general.export_to_engine()
- pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
+ pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak")
Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py
index 7a0abdd969..de2554034f 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/DynamicSliceInstanceSpawner_External_E2E.py
@@ -131,7 +131,7 @@ def DynamicSliceInstanceSpawner_External_E2E():
# 6) Save and export to engine
general.save_level()
general.export_to_engine()
- pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
+ pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak")
Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py
index f56c0b836e..bf6501f469 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/dyn_veg/EditorScripts/LayerBlender_E2E_Editor.py
@@ -155,7 +155,7 @@ def LayerBlender_E2E_Editor():
# 6) Save and export to engine
general.save_level()
general.export_to_engine()
- pak_path = os.path.join(paths.devroot, "AutomatedTesting", "cache", "pc", "levels", lvl_name, "level.pak")
+ pak_path = os.path.join(paths.products, "levels", lvl_name, "level.pak")
Report.result(Tests.saved_and_exported, os.path.exists(pak_path))
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py
index f996a1f8c3..514504d324 100644
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/gradient_signal/TestSuite_Periodic_Optimized.py
@@ -10,7 +10,6 @@ import pytest
from ly_test_tools.o3de.editor_test import EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite
-@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
@pytest.mark.SUITE_periodic
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
diff --git a/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py b/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py
index 65ebf8e59e..957536fffb 100755
--- a/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py
+++ b/AutomatedTesting/Gem/PythonTests/largeworlds/large_worlds_utils/editor_dynveg_test_helper.py
@@ -17,7 +17,7 @@ import azlmbr.vegetation as vegetation
import azlmbr.areasystem as areasystem
import azlmbr.paths
-sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
+sys.path.append(os.path.join(azlmbr.paths.projectroot, 'Gem', 'PythonTests'))
import editor_python_test_tools.hydra_editor_utils as hydra
@@ -25,7 +25,7 @@ def create_surface_entity(name, center_point, box_size_x, box_size_y, box_size_z
# Create a "flat surface" entity to use as a plantable vegetation surface
surface_entity = hydra.Entity(name)
surface_entity.create_entity(
- center_point,
+ center_point,
["Box Shape", "Shape Surface Tag Emitter"]
)
if surface_entity.id.IsValid():
@@ -56,7 +56,7 @@ def create_vegetation_area(name, center_point, box_size_x, box_size_y, box_size_
# Create a vegetation area entity to use as our test vegetation spawner
spawner_entity = hydra.Entity(name)
spawner_entity.create_entity(
- center_point,
+ center_point,
["Vegetation Layer Spawner", "Box Shape", "Vegetation Asset List"]
)
if spawner_entity.id.IsValid():
diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py
index 14a1ab62f0..9b4d2d1393 100644
--- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py
+++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab.py
@@ -25,28 +25,39 @@ import prefab.Prefab_Test_Utils as prefab_test_utils
# This is a helper class which contains some of the useful information about a prefab instance.
class PrefabInstance:
- def __init__(self, name: str=None, prefab_file_name: str=None, container_entity: EditorEntity=EntityId()):
- self.name = name
+ def __init__(self, prefab_file_name: str=None, container_entity: EditorEntity=EntityId()):
self.prefab_file_name: str = prefab_file_name
self.container_entity: EditorEntity = container_entity
+ def __eq__(self, other):
+ return other and self.container_entity.id == other.container_entity.id
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __hash__(self):
+ return hash(self.container_entity.id)
+
"""
See if this instance is valid to be used with other prefab operations.
:return: Whether the target instance is valid or not.
"""
def is_valid() -> bool:
- return self.container_entity.id.IsValid() and self.name is not None and self.prefab_file_name in Prefab.existing_prefabs
+ return self.container_entity.id.IsValid() and self.prefab_file_name in Prefab.existing_prefabs
-
"""
Reparent this instance to target parent entity.
The function will also check pop up dialog ui in editor to see if there's prefab cyclical dependency error while reparenting prefabs.
:param parent_entity_id: The id of the entity this instance should be a child of in the transform hierarchy next.
"""
async def ui_reparent_prefab_instance(self, parent_entity_id: EntityId):
- container_entity_name = self.container_entity.get_name()
- current_children_entity_ids_having_prefab_name = prefab_test_utils.get_children_ids_by_name(parent_entity_id, container_entity_name)
- Report.info(f'current_children_entity_ids_having_prefab_name: {current_children_entity_ids_having_prefab_name}')
+ container_entity_id_before_reparent = self.container_entity.id
+
+ original_parent = EditorEntity(self.container_entity.get_parent_id())
+ original_parent_before_reparent_children_ids = set(original_parent.get_children_ids())
+
+ new_parent = EditorEntity(parent_entity_id)
+ new_parent_before_reparent_children_ids = set(new_parent.get_children_ids())
pyside_utils.run_soon(lambda: self.container_entity.set_parent_entity(parent_entity_id))
pyside_utils.run_soon(lambda: prefab_test_utils.wait_for_propagation())
@@ -60,18 +71,23 @@ class PrefabInstance:
except pyside_utils.EventLoopTimeoutException:
pass
- updated_children_entity_ids_having_prefab_name = prefab_test_utils.get_children_ids_by_name(parent_entity_id, container_entity_name)
- Report.info(f'updated_children_entity_ids_having_prefab_name: {updated_children_entity_ids_having_prefab_name}')
- new_child_with_reparented_prefab_name_added = len(updated_children_entity_ids_having_prefab_name) == len(current_children_entity_ids_having_prefab_name) + 1
- assert new_child_with_reparented_prefab_name_added, "No entity with reparented prefab name become a child of target parent entity"
+ original_parent_after_reparent_children_ids = set(original_parent.get_children_ids())
+ assert len(original_parent_after_reparent_children_ids) == len(original_parent_before_reparent_children_ids) - 1, \
+ "The children count of the Prefab Instance's original parent should be decreased by 1."
+ assert not container_entity_id_before_reparent in original_parent_after_reparent_children_ids, \
+ "This Prefab Instance is still a child entity of its original parent entity."
+
+ new_parent_after_reparent_children_ids = set(new_parent.get_children_ids())
+ assert len(new_parent_after_reparent_children_ids) == len(new_parent_before_reparent_children_ids) + 1, \
+ "The children count of the Prefab Instance's new parent should be increased by 1."
- updated_container_entity_id = set(updated_children_entity_ids_having_prefab_name).difference(current_children_entity_ids_having_prefab_name).pop()
- updated_container_entity = EditorEntity(updated_container_entity_id)
- updated_container_entity_parent_id = updated_container_entity.get_parent_id()
- has_correct_parent = updated_container_entity_parent_id.ToString() == parent_entity_id.ToString()
- assert has_correct_parent, "Prefab reparented is *not* under the expected parent entity"
+ container_entity_id_after_reparent = set(new_parent_after_reparent_children_ids).difference(new_parent_before_reparent_children_ids).pop()
+ reparented_container_entity = EditorEntity(container_entity_id_after_reparent)
+ reparented_container_entity_parent_id = reparented_container_entity.get_parent_id()
+ has_correct_parent = reparented_container_entity_parent_id.ToString() == parent_entity_id.ToString()
+ assert has_correct_parent, "Prefab Instance reparented is *not* under the expected parent entity"
- self.container_entity = EditorEntity(updated_container_entity_id)
+ self.container_entity = reparented_container_entity
# This is a helper class which contains some of the useful information about a prefab template.
class Prefab:
@@ -81,7 +97,7 @@ class Prefab:
def __init__(self, file_name: str):
self.file_name:str = file_name
self.file_path: str = prefab_test_utils.get_prefab_file_path(file_name)
- self.instances: dict = {}
+ self.instances: set[PrefabInstance] = set()
"""
Check if a prefab is ready to be used to generate its instances.
@@ -122,10 +138,10 @@ class Prefab:
:param entities: The entities that should form the new prefab (along with their descendants).
:param file_name: A unique file name of new prefab.
:param prefab_instance_name: A name for the very first instance generated while prefab creation. The default instance name is the same as file_name.
- :return: An outcome object with an entityId of the new prefab's container entity; on failure, it comes with an error message detailing the cause of the error.
+ :return: Created Prefab object and the very first PrefabInstance object owned by the prefab.
"""
@classmethod
- def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> Prefab:
+ def create_prefab(cls, entities: list[EditorEntity], file_name: str, prefab_instance_name: str=None) -> (Prefab, PrefabInstance):
assert not Prefab.is_prefab_loaded(file_name), f"Can't create Prefab '{file_name}' since the prefab already exists"
new_prefab = Prefab(file_name)
@@ -133,18 +149,18 @@ class Prefab:
create_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'CreatePrefabInMemory', entity_ids, new_prefab.file_path)
assert create_prefab_result.IsSuccess(), f"Prefab operation 'CreatePrefab' failed. Error: {create_prefab_result.GetError()}"
- container_entity = EditorEntity(create_prefab_result.GetValue())
+ container_entity_id = create_prefab_result.GetValue()
+ container_entity = EditorEntity(container_entity_id)
if prefab_instance_name:
container_entity.set_name(prefab_instance_name)
- else:
- prefab_instance_name = file_name
prefab_test_utils.wait_for_propagation()
- container_entity_id = prefab_test_utils.find_entity_by_unique_name(prefab_instance_name)
- new_prefab.instances[prefab_instance_name] = PrefabInstance(prefab_instance_name, file_name, EditorEntity(container_entity_id))
+
+ new_prefab_instance = PrefabInstance(file_name, EditorEntity(container_entity_id))
+ new_prefab.instances.add(new_prefab_instance)
Prefab.existing_prefabs[file_name] = new_prefab
- return new_prefab
+ return new_prefab, new_prefab_instance
"""
Remove target prefab instances.
@@ -152,22 +168,15 @@ class Prefab:
"""
@classmethod
def remove_prefabs(cls, prefab_instances: list[PrefabInstance]):
- instances_to_remove_name_counts = Counter()
- instances_removed_expected_name_counts = Counter()
-
- entities_to_remove = [prefab_instance.container_entity for prefab_instance in prefab_instances]
- while entities_to_remove:
- entity = entities_to_remove.pop(-1)
- entity_name = entity.get_name()
- instances_to_remove_name_counts[entity_name] += 1
-
+ entity_ids_to_remove = []
+ entity_id_queue = [prefab_instance.container_entity for prefab_instance in prefab_instances]
+ while entity_id_queue:
+ entity = entity_id_queue.pop(0)
children_entity_ids = entity.get_children_ids()
for child_entity_id in children_entity_ids:
- entities_to_remove.append(EditorEntity(child_entity_id))
+ entity_id_queue.append(EditorEntity(child_entity_id))
- for entity_name, entity_count in instances_to_remove_name_counts.items():
- entities = prefab_test_utils.find_entities_by_name(entity_name)
- instances_removed_expected_name_counts[entity_name] = len(entities) - entity_count
+ entity_ids_to_remove.append(entity.id)
container_entity_ids = [prefab_instance.container_entity.id for prefab_instance in prefab_instances]
delete_prefab_result = prefab.PrefabPublicRequestBus(bus.Broadcast, 'DeleteEntitiesAndAllDescendantsInInstance', container_entity_ids)
@@ -175,28 +184,24 @@ class Prefab:
prefab_test_utils.wait_for_propagation()
- prefab_entities_deleted = True
- for entity_name, expected_entity_count in instances_removed_expected_name_counts.items():
- actual_entity_count = len(prefab_test_utils.find_entities_by_name(entity_name))
- if actual_entity_count is not expected_entity_count:
- prefab_entities_deleted = False
- break
-
- assert prefab_entities_deleted, "Not all entities and descendants in target prefabs are deleted."
+ entity_ids_after_delete = set(prefab_test_utils.get_all_entities())
+ for entity_id_removed in entity_ids_to_remove:
+ if entity_id_removed in entity_ids_after_delete:
+ assert prefab_entities_deleted, "Not all entities and descendants in target prefabs are deleted."
for instance in prefab_instances:
instance_deleted_prefab = Prefab.get_prefab(instance.prefab_file_name)
- instance_deleted_prefab.instances.pop(instance.name)
+ instance_deleted_prefab.instances.remove(instance)
instance = PrefabInstance()
"""
Instantiate an instance of this prefab.
- :param name: A name for newly instantiated prefab instance. The default instance name is the same as this prefab's file name.
:param parent_entity: The entity the prefab should be a child of in the transform hierarchy.
+ :param name: A name for newly instantiated prefab instance. The default instance name is the same as this prefab's file name.
:param prefab_position: The position in world space the prefab should be instantiated in.
- :return: An outcome object with an entityId of the new prefab's container entity; on failure, it comes with an error message detailing the cause of the error.
+ :return: Instantiated PrefabInstance object owned by this prefab.
"""
- def instantiate(self, name: str=None, parent_entity: EditorEntity=None, prefab_position: Vector3=Vector3()) -> PrefabInstance:
+ def instantiate(self, parent_entity: EditorEntity=None, name: str=None, prefab_position: Vector3=Vector3()) -> PrefabInstance:
parent_entity_id = parent_entity.id if parent_entity is not None else EntityId()
instantiate_prefab_result = prefab.PrefabPublicRequestBus(
@@ -209,13 +214,13 @@ class Prefab:
if name:
container_entity.set_name(name)
- else:
- name = self.file_name
prefab_test_utils.wait_for_propagation()
- container_entity_id = prefab_test_utils.find_entity_by_unique_name(name)
- self.instances[name] = PrefabInstance(name, self.file_name, EditorEntity(container_entity_id))
+
+ new_prefab_instance = PrefabInstance(self.file_name, EditorEntity(container_entity_id))
+ assert not new_prefab_instance in self.instances, "This prefab instance is already existed before this instantiation."
+ self.instances.add(new_prefab_instance)
prefab_test_utils.check_entity_at_position(container_entity_id, prefab_position)
- return container_entity_id
+ return new_prefab_instance
diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py
index c6e0daa4dd..f3fbcfa6ad 100644
--- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py
+++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndDeletePrefab.py
@@ -22,11 +22,10 @@ def Prefab_BasicWorkflow_CreateAndDeletePrefab():
car_prefab_entities = [car_entity]
# Checks for prefab creation passed or not
- car_prefab = Prefab.create_prefab(
+ _, car = Prefab.create_prefab(
car_prefab_entities, CAR_PREFAB_FILE_NAME)
# Checks for prefab deletion passed or not
- car = car_prefab.instances[CAR_PREFAB_FILE_NAME]
Prefab.remove_prefabs([car])
if __name__ == "__main__":
diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py
index 04f7b97628..e5a9d9930a 100644
--- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py
+++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_CreateAndReparentPrefab.py
@@ -28,7 +28,7 @@ def Prefab_BasicWorkflow_CreateAndReparentPrefab():
car_prefab_entities = [car_entity]
# Checks for prefab creation passed or not
- car_prefab = Prefab.create_prefab(
+ _, car = Prefab.create_prefab(
car_prefab_entities, CAR_PREFAB_FILE_NAME)
# Creates another new Entity at the root level
@@ -36,12 +36,10 @@ def Prefab_BasicWorkflow_CreateAndReparentPrefab():
wheel_prefab_entities = [wheel_entity]
# Checks for wheel prefab creation passed or not
- wheel_prefab = Prefab.create_prefab(
+ _, wheel = Prefab.create_prefab(
wheel_prefab_entities, WHEEL_PREFAB_FILE_NAME)
# Checks for prefab reparenting passed or not
- car = car_prefab.instances[CAR_PREFAB_FILE_NAME]
- wheel = wheel_prefab.instances[WHEEL_PREFAB_FILE_NAME]
await wheel.ui_reparent_prefab_instance(car.container_entity.id)
run_test()
diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py
index b9015ab556..46be669697 100644
--- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py
+++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_BasicWorkflow_InstantiatePrefab.py
@@ -22,11 +22,11 @@ def Prefab_BasicWorkflow_InstantiatePrefab():
# Checks for prefab instantiation passed or not
test_prefab = Prefab.get_prefab(EXISTING_TEST_PREFAB_FILE_NAME)
- instantiated_test_container_entity_id = test_prefab.instantiate(
+ test_instance = test_prefab.instantiate(
prefab_position=INSTANTIATED_TEST_PREFAB_POSITION)
prefab_test_utils.check_entity_children_count(
- instantiated_test_container_entity_id,
+ test_instance.container_entity.id,
EXPECTED_TEST_PREFAB_CHILDREN_COUNT)
if __name__ == "__main__":
diff --git a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py
index 8cd59ed077..3e19911449 100644
--- a/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py
+++ b/AutomatedTesting/Gem/PythonTests/prefab/Prefab_Test_Utils.py
@@ -29,20 +29,8 @@ def find_entities_by_name(entity_name):
searchFilter.names = [entity_name]
return entity.SearchBus(bus.Broadcast, 'SearchEntities', searchFilter)
-def find_entity_by_unique_name(entity_name):
- unique_name_entity_found_result = (
- "Entity with a unique name found",
- "Entity with a unique name *not* found")
-
- entities = find_entities_by_name(entity_name)
- unique_name_entity_found = len(entities) == 1
- Report.result(unique_name_entity_found_result, unique_name_entity_found)
-
- if unique_name_entity_found:
- return entities[0]
- else:
- Report.info(f"{len(entities)} entities with name '{entity_name}' found")
- return EntityId()
+def get_all_entities():
+ return entity.SearchBus(bus.Broadcast, 'SearchEntities', entity.SearchFilter())
def check_entity_at_position(entity_id, expected_entity_position):
entity_at_expected_position_result = (
diff --git a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py
index 0862e03a79..b2001e6825 100755
--- a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py
+++ b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py
@@ -122,6 +122,7 @@ class TestAutomation(TestAutomationBase):
from . import Debugger_HappyPath_TargetMultipleEntities as test_module
self._run_test(request, workspace, editor, test_module)
+ @pytest.mark.xfail(reason="Test fails to find expected lines, it needs to be fixed.")
def test_EditMenu_Default_UndoRedo(self, request, workspace, editor, launcher_platform, project):
from . import EditMenu_Default_UndoRedo as test_module
self._run_test(request, workspace, editor, test_module)
@@ -181,6 +182,7 @@ class TestAutomation(TestAutomationBase):
from . import NodePalette_SearchText_Deletion as test_module
self._run_test(request, workspace, editor, test_module)
+ @pytest.mark.xfail(reason="Test fails to find expected lines, it needs to be fixed.")
def test_VariableManager_UnpinVariableType_Works(self, request, workspace, editor, launcher_platform):
from . import VariableManager_UnpinVariableType_Works as test_module
self._run_test(request, workspace, editor, test_module)
diff --git a/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace b/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace
index 188fee9f05..05140f340b 100644
--- a/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace
+++ b/AutomatedTesting/Levels/Physics/Material_DefaultLibraryConsistentOnAllFeatures/cowboy.emfxworkspace
@@ -1,3 +1,3 @@
[General]
version=1
-startScript="ImportActor -filename \"@assets@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\n"
+startScript="ImportActor -filename \"@products@/characters/cowboy/actor/cowboy_01.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\n"
diff --git a/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace b/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace
index e429d74a57..870b9a8579 100644
--- a/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace
+++ b/AutomatedTesting/Levels/Physics/Material_DefaultMaterialLibraryChangesWork/ws.emfxworkspace
@@ -1,3 +1,3 @@
[General]
version=1
-startScript="ImportActor -filename \"@assets@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_skeleton_newgeo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@assets@/Levels/Physics/C15096734_PhysxMaterials_DefaultMaterialLibrary/custom_motionset.motionset\"\nLoadAnimGraph -filename \"@assets@/Levels/Physics/C15096734_PhysxMaterials_DefaultMaterialLibrary/rin_physics.animgraph\"\n"
+startScript="ImportActor -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_skeleton_newgeo.actor\"\nCreateActorInstance -actorID %LASTRESULT% -xPos 0.000000 -yPos 0.000000 -zPos 0.000000 -xScale 1.000000 -yScale 1.000000 -zScale 1.000000 -rot 0.00000000,0.00000000,0.00000000,1.00000000\nLoadMotionSet -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/custom_motionset.motionset\"\nLoadAnimGraph -filename \"@products@/levels/physics/c15096734_physxmaterials_defaultmateriallibrary/rin_physics.animgraph\"\n"
diff --git a/AutomatedTesting/Registry/assets_scan_folders.setreg b/AutomatedTesting/Registry/assets_scan_folders.setreg
index 91061f3337..c74ba6703e 100644
--- a/AutomatedTesting/Registry/assets_scan_folders.setreg
+++ b/AutomatedTesting/Registry/assets_scan_folders.setreg
@@ -51,6 +51,14 @@
[
"Gems/UiBasics"
]
+ },
+ "Hair":
+ {
+ "SourcePaths":
+ [
+ "Gems/AtomTressFX/Assets",
+ "Gems/AtomTressFX/Assets/Passes"
+ ]
}
}
}
diff --git a/AutomatedTesting/Registry/physx_overrides/Collider_AddingNewGroupWorks.setreg_override b/AutomatedTesting/Registry/physx_overrides/Collider_AddingNewGroupWorks.setreg_override
index 7065f0dfeb..209e9a9feb 100644
--- a/AutomatedTesting/Registry/physx_overrides/Collider_AddingNewGroupWorks.setreg_override
+++ b/AutomatedTesting/Registry/physx_overrides/Collider_AddingNewGroupWorks.setreg_override
@@ -109,7 +109,7 @@
},
"MaterialLibrary": {
"assetId": {
- "guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
+ "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
},
"loadBehavior": "QueueLoad",
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
diff --git a/AutomatedTesting/Registry/physx_overrides/Collider_CollisionGroupsWorkflow.setreg_override b/AutomatedTesting/Registry/physx_overrides/Collider_CollisionGroupsWorkflow.setreg_override
index b82acaf0ae..65f15f8554 100644
--- a/AutomatedTesting/Registry/physx_overrides/Collider_CollisionGroupsWorkflow.setreg_override
+++ b/AutomatedTesting/Registry/physx_overrides/Collider_CollisionGroupsWorkflow.setreg_override
@@ -121,7 +121,7 @@
},
"MaterialLibrary": {
"assetId": {
- "guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
+ "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
},
"loadBehavior": "QueueLoad",
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
diff --git a/AutomatedTesting/Registry/physx_overrides/Collider_DiffCollisionGroupDiffCollidingLayersNotCollide.setreg_override b/AutomatedTesting/Registry/physx_overrides/Collider_DiffCollisionGroupDiffCollidingLayersNotCollide.setreg_override
index b82acaf0ae..65f15f8554 100644
--- a/AutomatedTesting/Registry/physx_overrides/Collider_DiffCollisionGroupDiffCollidingLayersNotCollide.setreg_override
+++ b/AutomatedTesting/Registry/physx_overrides/Collider_DiffCollisionGroupDiffCollidingLayersNotCollide.setreg_override
@@ -121,7 +121,7 @@
},
"MaterialLibrary": {
"assetId": {
- "guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
+ "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
},
"loadBehavior": "QueueLoad",
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
diff --git a/AutomatedTesting/Registry/physx_overrides/Collider_NoneCollisionGroupSameLayerNotCollide.setreg_override b/AutomatedTesting/Registry/physx_overrides/Collider_NoneCollisionGroupSameLayerNotCollide.setreg_override
index b82acaf0ae..65f15f8554 100644
--- a/AutomatedTesting/Registry/physx_overrides/Collider_NoneCollisionGroupSameLayerNotCollide.setreg_override
+++ b/AutomatedTesting/Registry/physx_overrides/Collider_NoneCollisionGroupSameLayerNotCollide.setreg_override
@@ -121,7 +121,7 @@
},
"MaterialLibrary": {
"assetId": {
- "guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
+ "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
},
"loadBehavior": "QueueLoad",
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
diff --git a/AutomatedTesting/Registry/physx_overrides/Collider_SameCollisionGroupSameCustomLayerCollide.setreg_override b/AutomatedTesting/Registry/physx_overrides/Collider_SameCollisionGroupSameCustomLayerCollide.setreg_override
index b82acaf0ae..65f15f8554 100644
--- a/AutomatedTesting/Registry/physx_overrides/Collider_SameCollisionGroupSameCustomLayerCollide.setreg_override
+++ b/AutomatedTesting/Registry/physx_overrides/Collider_SameCollisionGroupSameCustomLayerCollide.setreg_override
@@ -121,7 +121,7 @@
},
"MaterialLibrary": {
"assetId": {
- "guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
+ "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
},
"loadBehavior": "QueueLoad",
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
diff --git a/AutomatedTesting/Registry/physxsystemconfiguration.setreg b/AutomatedTesting/Registry/physxsystemconfiguration.setreg
index 83aad307a6..2ade83d769 100644
--- a/AutomatedTesting/Registry/physxsystemconfiguration.setreg
+++ b/AutomatedTesting/Registry/physxsystemconfiguration.setreg
@@ -103,7 +103,7 @@
},
"MaterialLibrary": {
"assetId": {
- "guid": "{62446378-67F8-5E49-AC31-761DD5942695}"
+ "guid": "{7CDF49C3-91A2-5C4E-B642-6D1AEC80E70E}"
},
"loadBehavior": "QueueLoad",
"assetHint": "assets/physics/surfacetypemateriallibrary.physmaterial"
diff --git a/AutomatedTesting/multiple_mesh_one_material/FBXTestTexture.png b/AutomatedTesting/multiple_mesh_one_material/FBXTestTexture.png
new file mode 100644
index 0000000000..4f52364cb3
--- /dev/null
+++ b/AutomatedTesting/multiple_mesh_one_material/FBXTestTexture.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:827a63985273229050bf4f63030bcc666f045091fe81cf8157a9ca23b40074b6
+size 3214
diff --git a/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx b/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx
new file mode 100644
index 0000000000..d9deb899f0
--- /dev/null
+++ b/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:d8d24963e6e8765205bc79cbe2304fc39f1245ee75249e2834a71c96c3cab824
+size 22700
diff --git a/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx.assetinfo b/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx.assetinfo
new file mode 100644
index 0000000000..fe18a16cb5
--- /dev/null
+++ b/AutomatedTesting/multiple_mesh_one_material/multiple_mesh_one_material.fbx.assetinfo
@@ -0,0 +1,8 @@
+{
+ "values": [
+ {
+ "$type": "ScriptProcessorRule",
+ "scriptFilename": "Editor/Scripts/scene_mesh_to_prefab.py"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Code/Editor/AssetEditor/AssetEditorRequestsHandler.h b/Code/Editor/AssetEditor/AssetEditorRequestsHandler.h
index ebfa84249d..bbe55e216a 100644
--- a/Code/Editor/AssetEditor/AssetEditorRequestsHandler.h
+++ b/Code/Editor/AssetEditor/AssetEditorRequestsHandler.h
@@ -7,7 +7,6 @@
*/
#pragma once
-#include
#include
#include
diff --git a/Code/Editor/AssetEditor/AssetEditorWindow.h b/Code/Editor/AssetEditor/AssetEditorWindow.h
index 2cf73ac282..63347d6ff3 100644
--- a/Code/Editor/AssetEditor/AssetEditorWindow.h
+++ b/Code/Editor/AssetEditor/AssetEditorWindow.h
@@ -9,7 +9,6 @@
#if !defined(Q_MOC_RUN)
#include
-#include
#include
#include
#include
diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp
index 18946c7874..9fe4cfd0d2 100644
--- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp
+++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.cpp
@@ -141,6 +141,10 @@ AzAssetBrowserWindow::AzAssetBrowserWindow(QWidget* parent)
m_ui->m_assetBrowserTreeViewWidget, &AzAssetBrowser::AssetBrowserTreeView::ClearTypeFilter, m_ui->m_searchWidget,
&AzAssetBrowser::SearchWidget::ClearTypeFilter);
+ connect(
+ this, &AzAssetBrowserWindow::SizeChangedSignal, m_ui->m_assetBrowserTableViewWidget,
+ &AzAssetBrowser::AssetBrowserTableView::UpdateSizeSlot);
+
m_ui->m_assetBrowserTreeViewWidget->SetName("AssetBrowserTreeView_main");
}
@@ -164,6 +168,25 @@ QObject* AzAssetBrowserWindow::createListenerForShowAssetEditorEvent(QObject* pa
return listener;
}
+void AzAssetBrowserWindow::resizeEvent(QResizeEvent* resizeEvent)
+{
+ // leftLayout is the parent of the tableView
+ // rightLayout is the parent of the preview window.
+ // Workaround: When docking windows this event keeps holding the old size of the widgets instead of the new one
+ // but the resizeEvent holds the new size of the whole widget
+ // So we have to save the proportions somehow
+ const QWidget* leftLayout = m_ui->m_leftLayout;
+ const QVBoxLayout* rightLayout = m_ui->m_rightLayout;
+
+ const float oldLeftLayoutWidth = aznumeric_cast(leftLayout->geometry().width());
+ const float oldWidth = aznumeric_cast(leftLayout->geometry().width() + rightLayout->geometry().width());
+
+ const float newWidth = oldLeftLayoutWidth * aznumeric_cast(resizeEvent->size().width()) / oldWidth;
+
+ emit SizeChangedSignal(aznumeric_cast(newWidth));
+ QWidget::resizeEvent(resizeEvent);
+}
+
void AzAssetBrowserWindow::OnInitViewToggleButton()
{
CreateSwitchViewMenu();
diff --git a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h
index bf742b0cf2..753f000300 100644
--- a/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h
+++ b/Code/Editor/AzAssetBrowser/AzAssetBrowserWindow.h
@@ -53,9 +53,17 @@ public:
static QObject* createListenerForShowAssetEditorEvent(QObject* parent);
+
+Q_SIGNALS:
+ void SizeChangedSignal(int newWidth);
+
+protected:
+ void resizeEvent(QResizeEvent* resizeEvent) override;
+
private:
void OnInitViewToggleButton();
void UpdateDisplayInfo();
+
protected slots:
void CreateSwitchViewMenu();
void SetExpandedAssetBrowserMode();
diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt
index 5884795413..2ea0aa1a74 100644
--- a/Code/Editor/CMakeLists.txt
+++ b/Code/Editor/CMakeLists.txt
@@ -33,7 +33,6 @@ ly_add_target(
BUILD_DEPENDENCIES
PRIVATE
Legacy::CryCommon
- 3rdParty::zlib
PUBLIC
3rdParty::Qt::Core
3rdParty::Qt::Gui
@@ -105,7 +104,6 @@ ly_add_target(
3rdParty::Qt::Concurrent
3rdParty::tiff
3rdParty::squish-ccr
- 3rdParty::zlib
3rdParty::AWSNativeSDK::STS
Legacy::CryCommon
Legacy::EditorCommon
diff --git a/Code/Editor/Controls/FolderTreeCtrl.cpp b/Code/Editor/Controls/FolderTreeCtrl.cpp
index b1cbb9414e..4088ab976f 100644
--- a/Code/Editor/Controls/FolderTreeCtrl.cpp
+++ b/Code/Editor/Controls/FolderTreeCtrl.cpp
@@ -278,17 +278,16 @@ void CFolderTreeCtrl::LoadTreeRec(const QString& currentFolder)
void CFolderTreeCtrl::AddItem(const QString& path)
{
- QString folder;
- QString fileNameWithoutExtension;
- QString ext;
-
- Path::Split(path, folder, fileNameWithoutExtension, ext);
+ AZ::IO::FixedMaxPath folder{ AZ::IO::PathView(path.toUtf8().constData()) };
+ AZ::IO::FixedMaxPath fileNameWithoutExtension = folder.Extension();
+ folder = folder.ParentPath();
auto regex = QRegExp(m_fileNameSpec, Qt::CaseInsensitive, QRegExp::Wildcard);
if (regex.exactMatch(path))
{
- CTreeItem* folderTreeItem = CreateFolderItems(folder);
- folderTreeItem->AddChild(fileNameWithoutExtension, path, eTreeImage_File);
+ CTreeItem* folderTreeItem = CreateFolderItems(QString::fromUtf8(folder.c_str(), static_cast(folder.Native().size())));
+ folderTreeItem->AddChild(QString::fromUtf8(fileNameWithoutExtension.c_str(),
+ static_cast(fileNameWithoutExtension.Native().size())), path, eTreeImage_File);
}
}
diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp
index 40ea71f577..1151137bfc 100644
--- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp
+++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.cpp
@@ -26,6 +26,9 @@
#include
#include
+//AzCore
+#include
+
// Editor
#include "Clipboard.h"
diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h
index 64a4341096..ed5d1915ac 100644
--- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h
+++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedPropertyCtrl.h
@@ -12,7 +12,6 @@
#if !defined(Q_MOC_RUN)
#include
-#include
#include
#include "Include/EditorCoreAPI.h"
#include "ReflectedPropertyItem.h"
diff --git a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h
index a15f8326d1..7c38465c5e 100644
--- a/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h
+++ b/Code/Editor/Controls/ReflectedPropertyControl/ReflectedVar.h
@@ -10,10 +10,10 @@
#define CRYINCLUDE_EDITOR_UTILS_REFLECTEDVAR_H
#pragma once
-#include
#include
#include
#include "Util/VariablePropertyType.h"
+#include
#include
#include
#include
diff --git a/Code/Editor/Core/QtEditorApplication.cpp b/Code/Editor/Core/QtEditorApplication.cpp
index 66ed42af8f..a4aab24be4 100644
--- a/Code/Editor/Core/QtEditorApplication.cpp
+++ b/Code/Editor/Core/QtEditorApplication.cpp
@@ -44,7 +44,7 @@ enum
{
// in milliseconds
GameModeIdleFrequency = 0,
- EditorModeIdleFrequency = 0,
+ EditorModeIdleFrequency = 1,
InactiveModeFrequency = 10,
UninitializedFrequency = 9999,
};
diff --git a/Code/Editor/Core/Tests/test_Main.cpp b/Code/Editor/Core/Tests/test_Main.cpp
index 3d3e286f18..16b0aa92cf 100644
--- a/Code/Editor/Core/Tests/test_Main.cpp
+++ b/Code/Editor/Core/Tests/test_Main.cpp
@@ -33,6 +33,7 @@ public:
protected:
void SetupEnvironment() override
{
+ AttachEditorCoreAZEnvironment(AZ::Environment::GetInstance());
m_allocatorScope.ActivateAllocators();
m_cryPak = new NiceMock();
@@ -49,6 +50,7 @@ protected:
{
delete m_cryPak;
m_allocatorScope.DeactivateAllocators();
+ DetachEditorCoreAZEnvironment();
}
private:
diff --git a/Code/Editor/Core/Tests/test_PathUtil.cpp b/Code/Editor/Core/Tests/test_PathUtil.cpp
index 83e50a5947..cade19eb81 100644
--- a/Code/Editor/Core/Tests/test_PathUtil.cpp
+++ b/Code/Editor/Core/Tests/test_PathUtil.cpp
@@ -5,22 +5,29 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
-#include "EditorDefs.h"
-#include
-#include "Util/PathUtil.h"
-#include
-
-TEST(PathUtil, GamePathToFullPath_DoesNotBufferOverflow)
+#include
+#include
+namespace UnitTest
{
- // There are no test assertions in this test because the purpose is just to verify that the test runs without crashing
- QString pngExtension(".png");
+ class PathUtil
+ : public ScopedAllocatorSetupFixture
+ {
+ };
+
+ TEST_F(PathUtil, GamePathToFullPath_DoesNotBufferOverflow)
+ {
+ // There are no test assertions in this test because the purpose is just to verify that the test runs without crashing
+ QString pngExtension(".png");
- // Create a string of lenth AZ_MAX_PATH_LEN that ends in .png
- QString longStringMaxPath(AZ_MAX_PATH_LEN, 'x');
- longStringMaxPath.replace(longStringMaxPath.length() - pngExtension.length(), longStringMaxPath.length(), pngExtension);
- Path::GamePathToFullPath(longStringMaxPath);
+ // Create a string of length AZ_MAX_PATH_LEN that ends in .png
+ QString longStringMaxPath(AZ_MAX_PATH_LEN, 'x');
+ longStringMaxPath.replace(longStringMaxPath.length() - pngExtension.length(), longStringMaxPath.length(), pngExtension);
+ AZ_TEST_START_TRACE_SUPPRESSION;
+ Path::GamePathToFullPath(longStringMaxPath);
+ AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
- QString longStringMaxPathPlusOne(AZ_MAX_PATH_LEN + 1, 'x');
- longStringMaxPathPlusOne.replace(longStringMaxPathPlusOne.length() - pngExtension.length(), longStringMaxPathPlusOne.length(), pngExtension);
- Path::GamePathToFullPath(longStringMaxPathPlusOne);
+ QString longStringMaxPathPlusOne(AZ_MAX_PATH_LEN + 1, 'x');
+ longStringMaxPathPlusOne.replace(longStringMaxPathPlusOne.length() - pngExtension.length(), longStringMaxPathPlusOne.length(), pngExtension);
+ Path::GamePathToFullPath(longStringMaxPathPlusOne);
+ }
}
diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp
index b5eb4229df..4aa3d22114 100644
--- a/Code/Editor/CryEdit.cpp
+++ b/Code/Editor/CryEdit.cpp
@@ -2642,7 +2642,7 @@ void CCryEditApp::OnFileResaveSlices()
sliceAssetInfos.reserve(5000);
AZ::Data::AssetCatalogRequests::AssetEnumerationCB sliceCountCb = [&sliceAssetInfos]([[maybe_unused]] const AZ::Data::AssetId id, const AZ::Data::AssetInfo& info)
{
- // Only add slices and nothing that has been temporarily added to the catalog with a macro in it (ie @devroot@)
+ // Only add slices and nothing that has been temporarily added to the catalog with a macro in it (ie @engroot@)
if (info.m_assetType == azrtti_typeid() && info.m_relativePath[0] != '@')
{
sliceAssetInfos.push_back(info);
diff --git a/Code/Editor/CryEditDoc.cpp b/Code/Editor/CryEditDoc.cpp
index 07d946c609..75bd0ad270 100644
--- a/Code/Editor/CryEditDoc.cpp
+++ b/Code/Editor/CryEditDoc.cpp
@@ -1108,7 +1108,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
if (QFileInfo(filename).isRelative())
{
// Resolving the path through resolvepath would normalize and lowcase it, and in this case, we don't want that.
- fullPathName = Path::ToUnixPath(QDir(QString::fromUtf8(gEnv->pFileIO->GetAlias("@devassets@"))).absoluteFilePath(fullPathName));
+ fullPathName = Path::ToUnixPath(QDir(QString::fromUtf8(gEnv->pFileIO->GetAlias("@projectroot@"))).absoluteFilePath(fullPathName));
}
if (!CFileUtil::OverwriteFile(fullPathName))
@@ -2159,7 +2159,7 @@ bool CCryEditDoc::LoadXmlArchiveArray(TDocMultiArchive& arrXmlAr, const QString&
xmlAr.bLoading = true;
// bound to the level folder, as if it were the assets folder.
- // this mounts (whateverlevelname.ly) as @assets@/Levels/whateverlevelname/ and thus it works...
+ // this mounts (whateverlevelname.ly) as @products@/Levels/whateverlevelname/ and thus it works...
bool openLevelPakFileSuccess = pIPak->OpenPack(levelPath.toUtf8().data(), absoluteLevelPath.toUtf8().data());
if (!openLevelPakFileSuccess)
{
diff --git a/Code/Editor/Dialogs/PythonScriptsDialog.cpp b/Code/Editor/Dialogs/PythonScriptsDialog.cpp
index e95fb90c0a..35047947ac 100644
--- a/Code/Editor/Dialogs/PythonScriptsDialog.cpp
+++ b/Code/Editor/Dialogs/PythonScriptsDialog.cpp
@@ -91,7 +91,7 @@ CPythonScriptsDialog::CPythonScriptsDialog(QWidget* parent)
{
AZ::IO::Path newSourcePath = jsonSourcePathPointer;
// Resolve any file aliases first - Do not use ResolvePath() as that assumes
- // any relative path is underneath the @assets@ alias
+ // any relative path is underneath the @products@ alias
if (auto fileIoBase = AZ::IO::FileIOBase::GetInstance(); fileIoBase != nullptr)
{
AZ::IO::FixedMaxPath replacedAliasPath;
diff --git a/Code/Editor/EditorFileMonitor.cpp b/Code/Editor/EditorFileMonitor.cpp
index 7feb9d32a8..311c42befa 100644
--- a/Code/Editor/EditorFileMonitor.cpp
+++ b/Code/Editor/EditorFileMonitor.cpp
@@ -14,6 +14,8 @@
// Editor
#include "CryEdit.h"
+#include
+
//////////////////////////////////////////////////////////////////////////
CEditorFileMonitor::CEditorFileMonitor()
{
@@ -177,26 +179,14 @@ void CEditorFileMonitor::OnFileMonitorChange(const SFileChangeInfo& rChange)
// Make file relative to PrimaryCD folder.
QString filename = rChange.filename;
- // Remove game directory if present in path.
- const QString rootPath =
- QDir::fromNativeSeparators(QString::fromLatin1(Path::GetEditingRootFolder().c_str()));
- if (filename.startsWith(rootPath, Qt::CaseInsensitive))
- {
- filename = filename.right(filename.length() - rootPath.length());
- }
-
- // Make sure there is no leading slash
- if (!filename.isEmpty() && (filename[0] == '\\' || filename[0] == '/'))
- {
- filename = filename.mid(1);
- }
+ // Make path relative to the the project directory
+ AZ::IO::Path projectPath{ AZ::Utils::GetProjectPath() };
+ AZ::IO::FixedMaxPath projectRelativeFilePath = AZ::IO::PathView(filename.toUtf8().constData()).LexicallyProximate(
+ projectPath);
- if (!filename.isEmpty())
+ if (!projectRelativeFilePath.empty())
{
- //remove game name. Make it relative to the game folder
- const QString filenameRelGame = RemoveGameName(filename);
- const int extIndex = filename.lastIndexOf('.');
- const QString ext = filename.right(filename.length() - 1 - extIndex);
+ AZ::IO::PathView ext = projectRelativeFilePath.Extension();
// Check for File Monitor callback
std::vector::iterator iter;
@@ -207,15 +197,11 @@ void CEditorFileMonitor::OnFileMonitorChange(const SFileChangeInfo& rChange)
// We compare against length of callback string, so we get directory matches as well as full filenames
if (sCallback.pListener)
{
- if (sCallback.extension == "*" || ext.compare(sCallback.extension, Qt::CaseInsensitive) == 0)
+ if (sCallback.extension == "*" || AZ::IO::PathView(sCallback.extension.toUtf8().constData()) == ext)
{
- if (filenameRelGame.compare(sCallback.item, Qt::CaseInsensitive) == 0)
- {
- sCallback.pListener->OnFileChange(qPrintable(filenameRelGame), IFileChangeListener::EChangeType(rChange.changeType));
- }
- else if (filename.compare(sCallback.item, Qt::CaseInsensitive) == 0)
+ if (AZ::IO::PathView(sCallback.item.toUtf8().constData()) == projectRelativeFilePath)
{
- sCallback.pListener->OnFileChange(qPrintable(filename), IFileChangeListener::EChangeType(rChange.changeType));
+ sCallback.pListener->OnFileChange(qPrintable(projectRelativeFilePath.c_str()), IFileChangeListener::EChangeType(rChange.changeType));
}
}
}
diff --git a/Code/Editor/EditorModularViewportCameraComposer.cpp b/Code/Editor/EditorModularViewportCameraComposer.cpp
index e375e98fb6..c492010336 100644
--- a/Code/Editor/EditorModularViewportCameraComposer.cpp
+++ b/Code/Editor/EditorModularViewportCameraComposer.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
namespace SandboxEditor
@@ -94,7 +95,8 @@ namespace SandboxEditor
cameras.AddCamera(m_firstPersonPanCamera);
cameras.AddCamera(m_firstPersonTranslateCamera);
cameras.AddCamera(m_firstPersonScrollCamera);
- cameras.AddCamera(m_orbitCamera);
+ cameras.AddCamera(m_firstPersonFocusCamera);
+ cameras.AddCamera(m_pivotCamera);
});
return controller;
@@ -110,6 +112,7 @@ namespace SandboxEditor
viewportId, &AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::BeginCursorCapture);
}
};
+
const auto showCursor = [viewportId = m_viewportId]
{
if (SandboxEditor::CameraCaptureCursorForLook())
@@ -131,8 +134,8 @@ namespace SandboxEditor
m_firstPersonRotateCamera->SetActivationBeganFn(hideCursor);
m_firstPersonRotateCamera->SetActivationEndedFn(showCursor);
- m_firstPersonPanCamera =
- AZStd::make_shared(SandboxEditor::CameraFreePanChannelId(), AzFramework::LookPan);
+ m_firstPersonPanCamera = AZStd::make_shared(
+ SandboxEditor::CameraFreePanChannelId(), AzFramework::LookPan, AzFramework::TranslatePivot);
m_firstPersonPanCamera->m_panSpeedFn = []
{
@@ -151,8 +154,8 @@ namespace SandboxEditor
const auto translateCameraInputChannelIds = BuildTranslateCameraInputChannelIds();
- m_firstPersonTranslateCamera =
- AZStd::make_shared(AzFramework::LookTranslation, translateCameraInputChannelIds);
+ m_firstPersonTranslateCamera = AZStd::make_shared(
+ translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivot);
m_firstPersonTranslateCamera->m_translateSpeedFn = []
{
@@ -171,120 +174,120 @@ namespace SandboxEditor
return SandboxEditor::CameraScrollSpeed();
};
- m_orbitCamera = AZStd::make_shared(SandboxEditor::CameraOrbitChannelId());
+ const auto pivotFn = []
+ {
+ // use the manipulator transform as the pivot point
+ AZStd::optional entityPivot;
+ AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
+ entityPivot, AzToolsFramework::GetEntityContextId(),
+ &AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
- m_orbitCamera->SetLookAtFn(
- [viewportId = m_viewportId](const AZ::Vector3& position, const AZ::Vector3& direction) -> AZStd::optional
+ if (entityPivot.has_value())
{
- AZStd::optional lookAtAfterInterpolation;
- AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
- lookAtAfterInterpolation, viewportId,
- &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::LookAtAfterInterpolation);
+ return entityPivot->GetTranslation();
+ }
- // initially attempt to use the last set look at point after an interpolation has finished
- if (lookAtAfterInterpolation.has_value())
- {
- return *lookAtAfterInterpolation;
- }
-
- const float RayDistance = 1000.0f;
- AzFramework::RenderGeometry::RayRequest ray;
- ray.m_startWorldPosition = position;
- ray.m_endWorldPosition = position + direction * RayDistance;
- ray.m_onlyVisible = true;
-
- AzFramework::RenderGeometry::RayResult renderGeometryIntersectionResult;
- AzFramework::RenderGeometry::IntersectorBus::EventResult(
- renderGeometryIntersectionResult, AzToolsFramework::GetEntityContextId(),
- &AzFramework::RenderGeometry::IntersectorBus::Events::RayIntersect, ray);
-
- // attempt a ray intersection with any visible mesh and return the intersection position if successful
- if (renderGeometryIntersectionResult)
- {
- return renderGeometryIntersectionResult.m_worldPosition;
- }
+ // otherwise just use the identity
+ return AZ::Vector3::CreateZero();
+ };
+
+ m_firstPersonFocusCamera =
+ AZStd::make_shared(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusLook);
- // if there is no selection or no intersection, fallback to default camera orbit behavior (ground plane
- // intersection)
- return {};
+ m_firstPersonFocusCamera->SetPivotFn(pivotFn);
+
+ m_pivotCamera = AZStd::make_shared(SandboxEditor::CameraPivotChannelId());
+
+ m_pivotCamera->SetPivotFn(
+ [pivotFn]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction)
+ {
+ return pivotFn();
});
- m_orbitRotateCamera = AZStd::make_shared(SandboxEditor::CameraOrbitLookChannelId());
+ m_pivotRotateCamera = AZStd::make_shared(SandboxEditor::CameraPivotLookChannelId());
- m_orbitRotateCamera->m_rotateSpeedFn = []
+ m_pivotRotateCamera->m_rotateSpeedFn = []
{
return SandboxEditor::CameraRotateSpeed();
};
- m_orbitRotateCamera->m_invertYawFn = []
+ m_pivotRotateCamera->m_invertYawFn = []
{
- return SandboxEditor::CameraOrbitYawRotationInverted();
+ return SandboxEditor::CameraPivotYawRotationInverted();
};
- m_orbitTranslateCamera =
- AZStd::make_shared(AzFramework::OrbitTranslation, translateCameraInputChannelIds);
+ m_pivotTranslateCamera = AZStd::make_shared(
+ translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslateOffset);
- m_orbitTranslateCamera->m_translateSpeedFn = []
+ m_pivotTranslateCamera->m_translateSpeedFn = []
{
return SandboxEditor::CameraTranslateSpeed();
};
- m_orbitTranslateCamera->m_boostMultiplierFn = []
+ m_pivotTranslateCamera->m_boostMultiplierFn = []
{
return SandboxEditor::CameraBoostMultiplier();
};
- m_orbitDollyScrollCamera = AZStd::make_shared();
+ m_pivotDollyScrollCamera = AZStd::make_shared();
- m_orbitDollyScrollCamera->m_scrollSpeedFn = []
+ m_pivotDollyScrollCamera->m_scrollSpeedFn = []
{
return SandboxEditor::CameraScrollSpeed();
};
- m_orbitDollyMoveCamera =
- AZStd::make_shared(SandboxEditor::CameraOrbitDollyChannelId());
+ m_pivotDollyMoveCamera = AZStd::make_shared(SandboxEditor::CameraPivotDollyChannelId());
- m_orbitDollyMoveCamera->m_cursorSpeedFn = []
+ m_pivotDollyMoveCamera->m_motionSpeedFn = []
{
return SandboxEditor::CameraDollyMotionSpeed();
};
- m_orbitPanCamera = AZStd::make_shared(SandboxEditor::CameraOrbitPanChannelId(), AzFramework::OrbitPan);
+ m_pivotPanCamera = AZStd::make_shared(
+ SandboxEditor::CameraPivotPanChannelId(), AzFramework::LookPan, AzFramework::TranslateOffset);
- m_orbitPanCamera->m_panSpeedFn = []
+ m_pivotPanCamera->m_panSpeedFn = []
{
return SandboxEditor::CameraPanSpeed();
};
- m_orbitPanCamera->m_invertPanXFn = []
+ m_pivotPanCamera->m_invertPanXFn = []
{
return SandboxEditor::CameraPanInvertedX();
};
- m_orbitPanCamera->m_invertPanYFn = []
+ m_pivotPanCamera->m_invertPanYFn = []
{
return SandboxEditor::CameraPanInvertedY();
};
- 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_pivotFocusCamera =
+ AZStd::make_shared(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusPivot);
+
+ m_pivotFocusCamera->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);
}
void EditorModularViewportCameraComposer::OnEditorModularViewportCameraComposerSettingsChanged()
{
const auto translateCameraInputChannelIds = BuildTranslateCameraInputChannelIds();
m_firstPersonTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds);
- m_orbitTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds);
-
m_firstPersonPanCamera->SetPanInputChannelId(SandboxEditor::CameraFreePanChannelId());
- m_orbitPanCamera->SetPanInputChannelId(SandboxEditor::CameraOrbitPanChannelId());
m_firstPersonRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraFreeLookChannelId());
- m_orbitRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraOrbitLookChannelId());
- m_orbitCamera->SetOrbitInputChannelId(SandboxEditor::CameraOrbitChannelId());
- m_orbitDollyMoveCamera->SetDollyInputChannelId(SandboxEditor::CameraOrbitDollyChannelId());
+ 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());
}
void EditorModularViewportCameraComposer::OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId)
@@ -295,8 +298,7 @@ namespace SandboxEditor
AZ::TransformBus::EventResult(worldFromLocal, viewEntityId, &AZ::TransformBus::Events::GetWorldTM);
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
- m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame,
- worldFromLocal);
+ m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetReferenceFrame, worldFromLocal);
}
else
{
diff --git a/Code/Editor/EditorModularViewportCameraComposer.h b/Code/Editor/EditorModularViewportCameraComposer.h
index e6e71c976c..90103dba43 100644
--- a/Code/Editor/EditorModularViewportCameraComposer.h
+++ b/Code/Editor/EditorModularViewportCameraComposer.h
@@ -42,12 +42,14 @@ namespace SandboxEditor
AZStd::shared_ptr m_firstPersonPanCamera;
AZStd::shared_ptr m_firstPersonTranslateCamera;
AZStd::shared_ptr m_firstPersonScrollCamera;
- AZStd::shared_ptr m_orbitCamera;
- AZStd::shared_ptr m_orbitRotateCamera;
- AZStd::shared_ptr m_orbitTranslateCamera;
- AZStd::shared_ptr m_orbitDollyScrollCamera;
- AZStd::shared_ptr m_orbitDollyMoveCamera;
- AZStd::shared_ptr m_orbitPanCamera;
+ AZStd::shared_ptr m_firstPersonFocusCamera;
+ AZStd::shared_ptr m_pivotCamera;
+ AZStd::shared_ptr m_pivotRotateCamera;
+ AZStd::shared_ptr m_pivotTranslateCamera;
+ AZStd::shared_ptr m_pivotDollyScrollCamera;
+ AZStd::shared_ptr m_pivotDollyMoveCamera;
+ AZStd::shared_ptr m_pivotPanCamera;
+ AZStd::shared_ptr m_pivotFocusCamera;
AzFramework::ViewportId m_viewportId;
};
diff --git a/Code/Editor/EditorPreferencesPageViewportCamera.cpp b/Code/Editor/EditorPreferencesPageViewportCamera.cpp
index 368d2769f8..b632163186 100644
--- a/Code/Editor/EditorPreferencesPageViewportCamera.cpp
+++ b/Code/Editor/EditorPreferencesPageViewportCamera.cpp
@@ -61,7 +61,7 @@ static AZStd::vector GetEditorInputNames()
void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serialize)
{
serialize.Class()
- ->Version(2)
+ ->Version(3)
->Field("TranslateSpeed", &CameraMovementSettings::m_translateSpeed)
->Field("RotateSpeed", &CameraMovementSettings::m_rotateSpeed)
->Field("BoostMultiplier", &CameraMovementSettings::m_boostMultiplier)
@@ -73,12 +73,12 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial
->Field("TranslateSmoothing", &CameraMovementSettings::m_translateSmoothing)
->Field("TranslateSmoothness", &CameraMovementSettings::m_translateSmoothness)
->Field("CaptureCursorLook", &CameraMovementSettings::m_captureCursorLook)
- ->Field("OrbitYawRotationInverted", &CameraMovementSettings::m_orbitYawRotationInverted)
+ ->Field("PivotYawRotationInverted", &CameraMovementSettings::m_pivotYawRotationInverted)
->Field("PanInvertedX", &CameraMovementSettings::m_panInvertedX)
->Field("PanInvertedY", &CameraMovementSettings::m_panInvertedY);
serialize.Class()
- ->Version(1)
+ ->Version(2)
->Field("TranslateForward", &CameraInputSettings::m_translateForwardChannelId)
->Field("TranslateBackward", &CameraInputSettings::m_translateBackwardChannelId)
->Field("TranslateLeft", &CameraInputSettings::m_translateLeftChannelId)
@@ -86,12 +86,13 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial
->Field("TranslateUp", &CameraInputSettings::m_translateUpChannelId)
->Field("TranslateDown", &CameraInputSettings::m_translateDownChannelId)
->Field("Boost", &CameraInputSettings::m_boostChannelId)
- ->Field("Orbit", &CameraInputSettings::m_orbitChannelId)
+ ->Field("Pivot", &CameraInputSettings::m_pivotChannelId)
->Field("FreeLook", &CameraInputSettings::m_freeLookChannelId)
->Field("FreePan", &CameraInputSettings::m_freePanChannelId)
- ->Field("OrbitLook", &CameraInputSettings::m_orbitLookChannelId)
- ->Field("OrbitDolly", &CameraInputSettings::m_orbitDollyChannelId)
- ->Field("OrbitPan", &CameraInputSettings::m_orbitPanChannelId);
+ ->Field("PivotLook", &CameraInputSettings::m_pivotLookChannelId)
+ ->Field("PivotDolly", &CameraInputSettings::m_pivotDollyChannelId)
+ ->Field("PivotPan", &CameraInputSettings::m_pivotPanChannelId)
+ ->Field("Focus", &CameraInputSettings::m_focusChannelId);
serialize.Class()
->Version(1)
@@ -143,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_orbitYawRotationInverted, "Camera Orbit Yaw Inverted",
- "Inverted yaw rotation while orbiting")
+ AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_pivotYawRotationInverted, "Camera Pivot Yaw Inverted",
+ "Inverted yaw rotation while pivoting")
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_panInvertedX, "Invert Pan X",
"Invert direction of pan in local X axis")
@@ -185,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_orbitChannelId, "Orbit",
- "Key/button to begin the camera orbit behavior")
+ AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotChannelId, "Pivot",
+ "Key/button to begin the camera pivot behavior")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames)
->DataElement(
AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_freeLookChannelId, "Free Look",
@@ -196,24 +197,27 @@ 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_orbitLookChannelId, "Orbit Look",
- "Key/button to begin camera orbit look")
+ AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotLookChannelId, "Pivot Look",
+ "Key/button to begin camera pivot look")
+ ->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames)
+ ->DataElement(
+ AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotDollyChannelId, "Pivot Dolly",
+ "Key/button to begin camera pivot dolly")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames)
->DataElement(
- AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitDollyChannelId, "Orbit Dolly",
- "Key/button to begin camera orbit dolly")
+ AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_pivotPanChannelId, "Pivot Pan",
+ "Key/button to begin camera pivot pan")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames)
->DataElement(
- AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_orbitPanChannelId, "Orbit Pan",
- "Key/button to begin camera orbit pan")
+ AZ::Edit::UIHandlers::ComboBox, &CameraInputSettings::m_focusChannelId, "Focus", "Key/button to focus camera pivot")
->Attribute(AZ::Edit::Attributes::StringList, &GetEditorInputNames);
editContext->Class("Viewport Preferences", "Viewport Preferences")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Visibility, AZ_CRC("PropertyVisibility_ShowChildrenOnly", 0xef428f20))
->DataElement(
- AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportCamera::m_cameraMovementSettings,
- "Camera Movement Settings", "Camera Movement Settings")
+ AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportCamera::m_cameraMovementSettings, "Camera Movement Settings",
+ "Camera Movement Settings")
->DataElement(
AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportCamera::m_cameraInputSettings, "Camera Input Settings",
"Camera Input Settings");
@@ -264,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::SetCameraOrbitYawRotationInverted(m_cameraMovementSettings.m_orbitYawRotationInverted);
+ SandboxEditor::SetCameraPivotYawRotationInverted(m_cameraMovementSettings.m_pivotYawRotationInverted);
SandboxEditor::SetCameraPanInvertedX(m_cameraMovementSettings.m_panInvertedX);
SandboxEditor::SetCameraPanInvertedY(m_cameraMovementSettings.m_panInvertedY);
@@ -275,12 +279,13 @@ void CEditorPreferencesPage_ViewportCamera::OnApply()
SandboxEditor::SetCameraTranslateUpChannelId(m_cameraInputSettings.m_translateUpChannelId);
SandboxEditor::SetCameraTranslateDownChannelId(m_cameraInputSettings.m_translateDownChannelId);
SandboxEditor::SetCameraTranslateBoostChannelId(m_cameraInputSettings.m_boostChannelId);
- SandboxEditor::SetCameraOrbitChannelId(m_cameraInputSettings.m_orbitChannelId);
+ SandboxEditor::SetCameraPivotChannelId(m_cameraInputSettings.m_pivotChannelId);
SandboxEditor::SetCameraFreeLookChannelId(m_cameraInputSettings.m_freeLookChannelId);
SandboxEditor::SetCameraFreePanChannelId(m_cameraInputSettings.m_freePanChannelId);
- SandboxEditor::SetCameraOrbitLookChannelId(m_cameraInputSettings.m_orbitLookChannelId);
- SandboxEditor::SetCameraOrbitDollyChannelId(m_cameraInputSettings.m_orbitDollyChannelId);
- SandboxEditor::SetCameraOrbitPanChannelId(m_cameraInputSettings.m_orbitPanChannelId);
+ SandboxEditor::SetCameraPivotLookChannelId(m_cameraInputSettings.m_pivotLookChannelId);
+ SandboxEditor::SetCameraPivotDollyChannelId(m_cameraInputSettings.m_pivotDollyChannelId);
+ SandboxEditor::SetCameraPivotPanChannelId(m_cameraInputSettings.m_pivotPanChannelId);
+ SandboxEditor::SetCameraFocusChannelId(m_cameraInputSettings.m_focusChannelId);
SandboxEditor::EditorModularViewportCameraComposerNotificationBus::Broadcast(
&SandboxEditor::EditorModularViewportCameraComposerNotificationBus::Events::OnEditorModularViewportCameraComposerSettingsChanged);
@@ -299,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_orbitYawRotationInverted = SandboxEditor::CameraOrbitYawRotationInverted();
+ m_cameraMovementSettings.m_pivotYawRotationInverted = SandboxEditor::CameraPivotYawRotationInverted();
m_cameraMovementSettings.m_panInvertedX = SandboxEditor::CameraPanInvertedX();
m_cameraMovementSettings.m_panInvertedY = SandboxEditor::CameraPanInvertedY();
@@ -310,10 +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_orbitChannelId = SandboxEditor::CameraOrbitChannelId().GetName();
+ m_cameraInputSettings.m_pivotChannelId = SandboxEditor::CameraPivotChannelId().GetName();
m_cameraInputSettings.m_freeLookChannelId = SandboxEditor::CameraFreeLookChannelId().GetName();
m_cameraInputSettings.m_freePanChannelId = SandboxEditor::CameraFreePanChannelId().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_pivotLookChannelId = SandboxEditor::CameraPivotLookChannelId().GetName();
+ m_cameraInputSettings.m_pivotDollyChannelId = SandboxEditor::CameraPivotDollyChannelId().GetName();
+ m_cameraInputSettings.m_pivotPanChannelId = SandboxEditor::CameraPivotPanChannelId().GetName();
+ m_cameraInputSettings.m_focusChannelId = SandboxEditor::CameraFocusChannelId().GetName();
}
diff --git a/Code/Editor/EditorPreferencesPageViewportCamera.h b/Code/Editor/EditorPreferencesPageViewportCamera.h
index 31a728599f..cd31141c4a 100644
--- a/Code/Editor/EditorPreferencesPageViewportCamera.h
+++ b/Code/Editor/EditorPreferencesPageViewportCamera.h
@@ -54,7 +54,7 @@ private:
float m_translateSmoothness;
bool m_translateSmoothing;
bool m_captureCursorLook;
- bool m_orbitYawRotationInverted;
+ bool m_pivotYawRotationInverted;
bool m_panInvertedX;
bool m_panInvertedY;
@@ -80,12 +80,13 @@ private:
AZStd::string m_translateUpChannelId;
AZStd::string m_translateDownChannelId;
AZStd::string m_boostChannelId;
- AZStd::string m_orbitChannelId;
+ AZStd::string m_pivotChannelId;
AZStd::string m_freeLookChannelId;
AZStd::string m_freePanChannelId;
- AZStd::string m_orbitLookChannelId;
- AZStd::string m_orbitDollyChannelId;
- AZStd::string m_orbitPanChannelId;
+ AZStd::string m_pivotLookChannelId;
+ AZStd::string m_pivotDollyChannelId;
+ AZStd::string m_pivotPanChannelId;
+ AZStd::string m_focusChannelId;
};
CameraMovementSettings m_cameraMovementSettings;
diff --git a/Code/Editor/EditorPreferencesTreeWidgetItem.cpp b/Code/Editor/EditorPreferencesTreeWidgetItem.cpp
index 7adc298c2c..09578e72ee 100644
--- a/Code/Editor/EditorPreferencesTreeWidgetItem.cpp
+++ b/Code/Editor/EditorPreferencesTreeWidgetItem.cpp
@@ -9,6 +9,9 @@
#include "EditorPreferencesTreeWidgetItem.h"
+// AzCore
+#include
+
// AzToolsFramework
#include
diff --git a/Code/Editor/EditorViewportCamera.cpp b/Code/Editor/EditorViewportCamera.cpp
index 0c7a1559d1..b25e7072ff 100644
--- a/Code/Editor/EditorViewportCamera.cpp
+++ b/Code/Editor/EditorViewportCamera.cpp
@@ -48,7 +48,7 @@ namespace SandboxEditor
{
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
viewportContext->GetId(), &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform,
- AZ::Transform::CreateFromQuaternionAndTranslation(CameraRotation(pitch, yaw), position), 0.0f);
+ AZ::Transform::CreateFromQuaternionAndTranslation(CameraRotation(pitch, yaw), position));
}
}
diff --git a/Code/Editor/EditorViewportSettings.cpp b/Code/Editor/EditorViewportSettings.cpp
index 063ec125ba..c2539b008c 100644
--- a/Code/Editor/EditorViewportSettings.cpp
+++ b/Code/Editor/EditorViewportSettings.cpp
@@ -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 CameraOrbitYawRotationInvertedSetting = "/Amazon/Preferences/Editor/Camera/YawRotationInverted";
+ constexpr AZStd::string_view CameraPivotYawRotationInvertedSetting = "/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,13 @@ 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 CameraOrbitIdSetting = "/Amazon/Preferences/Editor/Camera/OrbitId";
+ constexpr AZStd::string_view CameraPivotIdSetting = "/Amazon/Preferences/Editor/Camera/PivotId";
constexpr AZStd::string_view CameraFreeLookIdSetting = "/Amazon/Preferences/Editor/Camera/FreeLookId";
constexpr AZStd::string_view CameraFreePanIdSetting = "/Amazon/Preferences/Editor/Camera/FreePanId";
- 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 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 CameraFocusIdSetting = "/Amazon/Preferences/Editor/Camera/FocusId";
template
void SetRegistry(const AZStd::string_view setting, T&& value)
@@ -239,14 +240,14 @@ namespace SandboxEditor
SetRegistry(CameraDollyMotionSpeedSetting, speed);
}
- bool CameraOrbitYawRotationInverted()
+ bool CameraPivotYawRotationInverted()
{
- return GetRegistry(CameraOrbitYawRotationInvertedSetting, false);
+ return GetRegistry(CameraPivotYawRotationInvertedSetting, false);
}
- void SetCameraOrbitYawRotationInverted(const bool inverted)
+ void SetCameraPivotYawRotationInverted(const bool inverted)
{
- SetRegistry(CameraOrbitYawRotationInvertedSetting, inverted);
+ SetRegistry(CameraPivotYawRotationInvertedSetting, inverted);
}
bool CameraPanInvertedX()
@@ -403,14 +404,14 @@ namespace SandboxEditor
SetRegistry(CameraTranslateBoostIdSetting, cameraTranslateBoostId);
}
- AzFramework::InputChannelId CameraOrbitChannelId()
+ AzFramework::InputChannelId CameraPivotChannelId()
{
- return AzFramework::InputChannelId(GetRegistry(CameraOrbitIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str());
+ return AzFramework::InputChannelId(GetRegistry(CameraPivotIdSetting, AZStd::string("keyboard_key_modifier_alt_l")).c_str());
}
- void SetCameraOrbitChannelId(AZStd::string_view cameraOrbitId)
+ void SetCameraPivotChannelId(AZStd::string_view cameraPivotId)
{
- SetRegistry(CameraOrbitIdSetting, cameraOrbitId);
+ SetRegistry(CameraPivotIdSetting, cameraPivotId);
}
AzFramework::InputChannelId CameraFreeLookChannelId()
@@ -433,33 +434,43 @@ namespace SandboxEditor
SetRegistry(CameraFreePanIdSetting, cameraFreePanId);
}
- AzFramework::InputChannelId CameraOrbitLookChannelId()
+ AzFramework::InputChannelId CameraPivotLookChannelId()
{
- return AzFramework::InputChannelId(GetRegistry(CameraOrbitLookIdSetting, AZStd::string("mouse_button_left")).c_str());
+ return AzFramework::InputChannelId(GetRegistry(CameraPivotLookIdSetting, AZStd::string("mouse_button_left")).c_str());
}
- void SetCameraOrbitLookChannelId(AZStd::string_view cameraOrbitLookId)
+ void SetCameraPivotLookChannelId(AZStd::string_view cameraPivotLookId)
{
- SetRegistry(CameraOrbitLookIdSetting, cameraOrbitLookId);
+ SetRegistry(CameraPivotLookIdSetting, cameraPivotLookId);
}
- AzFramework::InputChannelId CameraOrbitDollyChannelId()
+ AzFramework::InputChannelId CameraPivotDollyChannelId()
{
- return AzFramework::InputChannelId(GetRegistry(CameraOrbitDollyIdSetting, AZStd::string("mouse_button_right")).c_str());
+ return AzFramework::InputChannelId(GetRegistry(CameraPivotDollyIdSetting, AZStd::string("mouse_button_right")).c_str());
}
- void SetCameraOrbitDollyChannelId(AZStd::string_view cameraOrbitDollyId)
+ void SetCameraPivotDollyChannelId(AZStd::string_view cameraPivotDollyId)
{
- SetRegistry(CameraOrbitDollyIdSetting, cameraOrbitDollyId);
+ SetRegistry(CameraPivotDollyIdSetting, cameraPivotDollyId);
}
- AzFramework::InputChannelId CameraOrbitPanChannelId()
+ AzFramework::InputChannelId CameraPivotPanChannelId()
{
- return AzFramework::InputChannelId(GetRegistry(CameraOrbitPanIdSetting, AZStd::string("mouse_button_middle")).c_str());
+ return AzFramework::InputChannelId(GetRegistry(CameraPivotPanIdSetting, AZStd::string("mouse_button_middle")).c_str());
}
- void SetCameraOrbitPanChannelId(AZStd::string_view cameraOrbitPanId)
+ void SetCameraPivotPanChannelId(AZStd::string_view cameraPivotPanId)
{
- SetRegistry(CameraOrbitPanIdSetting, cameraOrbitPanId);
+ SetRegistry(CameraPivotPanIdSetting, cameraPivotPanId);
+ }
+
+ AzFramework::InputChannelId CameraFocusChannelId()
+ {
+ return AzFramework::InputChannelId(GetRegistry(CameraFocusIdSetting, AZStd::string("keyboard_key_alphanumeric_X")).c_str());
+ }
+
+ void SetCameraFocusChannelId(AZStd::string_view cameraFocusId)
+ {
+ SetRegistry(CameraFocusIdSetting, cameraFocusId);
}
} // namespace SandboxEditor
diff --git a/Code/Editor/EditorViewportSettings.h b/Code/Editor/EditorViewportSettings.h
index 20d397a29e..0253b01621 100644
--- a/Code/Editor/EditorViewportSettings.h
+++ b/Code/Editor/EditorViewportSettings.h
@@ -71,8 +71,8 @@ namespace SandboxEditor
SANDBOX_API float CameraDollyMotionSpeed();
SANDBOX_API void SetCameraDollyMotionSpeed(float speed);
- SANDBOX_API bool CameraOrbitYawRotationInverted();
- SANDBOX_API void SetCameraOrbitYawRotationInverted(bool inverted);
+ SANDBOX_API bool CameraPivotYawRotationInverted();
+ SANDBOX_API void SetCameraPivotYawRotationInverted(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 CameraOrbitChannelId();
- SANDBOX_API void SetCameraOrbitChannelId(AZStd::string_view cameraOrbitId);
+ SANDBOX_API AzFramework::InputChannelId CameraPivotChannelId();
+ SANDBOX_API void SetCameraPivotChannelId(AZStd::string_view cameraPivotId);
SANDBOX_API AzFramework::InputChannelId CameraFreeLookChannelId();
SANDBOX_API void SetCameraFreeLookChannelId(AZStd::string_view cameraFreeLookId);
@@ -128,12 +128,15 @@ namespace SandboxEditor
SANDBOX_API AzFramework::InputChannelId CameraFreePanChannelId();
SANDBOX_API void SetCameraFreePanChannelId(AZStd::string_view cameraFreePanId);
- SANDBOX_API AzFramework::InputChannelId CameraOrbitLookChannelId();
- SANDBOX_API void SetCameraOrbitLookChannelId(AZStd::string_view cameraOrbitLookId);
+ SANDBOX_API AzFramework::InputChannelId CameraPivotLookChannelId();
+ SANDBOX_API void SetCameraPivotLookChannelId(AZStd::string_view cameraPivotLookId);
- SANDBOX_API AzFramework::InputChannelId CameraOrbitDollyChannelId();
- SANDBOX_API void SetCameraOrbitDollyChannelId(AZStd::string_view cameraOrbitDollyId);
+ SANDBOX_API AzFramework::InputChannelId CameraPivotDollyChannelId();
+ SANDBOX_API void SetCameraPivotDollyChannelId(AZStd::string_view cameraPivotDollyId);
- SANDBOX_API AzFramework::InputChannelId CameraOrbitPanChannelId();
- SANDBOX_API void SetCameraOrbitPanChannelId(AZStd::string_view cameraOrbitPanId);
+ SANDBOX_API AzFramework::InputChannelId CameraPivotPanChannelId();
+ SANDBOX_API void SetCameraPivotPanChannelId(AZStd::string_view cameraPivotPanId);
+
+ SANDBOX_API AzFramework::InputChannelId CameraFocusChannelId();
+ SANDBOX_API void SetCameraFocusChannelId(AZStd::string_view cameraFocusId);
} // namespace SandboxEditor
diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp
index 5b5b52d28f..dad6734428 100644
--- a/Code/Editor/EditorViewportWidget.cpp
+++ b/Code/Editor/EditorViewportWidget.cpp
@@ -2428,7 +2428,7 @@ void EditorViewportWidget::RestoreViewportAfterGameMode()
}
else
{
- AZ_Error("CryLegacy", false, "Not restoring the editor viewport camera is currently unsupported");
+ AZ_Warning("CryLegacy", false, "Not restoring the editor viewport camera is currently unsupported");
SetViewTM(preGameModeViewTM);
}
}
diff --git a/Code/Editor/Include/IDisplayViewport.h b/Code/Editor/Include/IDisplayViewport.h
index 813c54355b..c7dff33e50 100644
--- a/Code/Editor/Include/IDisplayViewport.h
+++ b/Code/Editor/Include/IDisplayViewport.h
@@ -35,8 +35,6 @@ struct IDisplayViewport
*/
virtual float GetDistanceToLine(const Vec3& lineP1, const Vec3& lineP2, const QPoint& point) const = 0;
- virtual CBaseObjectsCache* GetVisibleObjectsCache() = 0;
-
enum EAxis
{
AXIS_NONE,
diff --git a/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp b/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp
index affe5794cc..1a44d43370 100644
--- a/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp
+++ b/Code/Editor/Lib/Tests/Camera/test_EditorCamera.cpp
@@ -167,7 +167,7 @@ namespace UnitTest
AZ::Quaternion::CreateRotationZ(AZ::DegToRad(90.0f)), AZ::Vector3(20.0f, 40.0f, 60.0f));
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform,
- transformToInterpolateTo, 0.0f);
+ transformToInterpolateTo);
// simulate interpolation
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
@@ -193,7 +193,7 @@ namespace UnitTest
// When
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
TestViewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform,
- transformToInterpolateTo, 0.0f);
+ transformToInterpolateTo);
// simulate interpolation
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(0.5f), AZ::ScriptTimePoint() });
diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp
index beb338b732..05477bb0c7 100644
--- a/Code/Editor/MainWindow.cpp
+++ b/Code/Editor/MainWindow.cpp
@@ -27,10 +27,11 @@ AZ_POP_DISABLE_WARNING
#endif
// AzCore
-#include
#include
-#include
#include
+#include
+#include
+#include
#include
// AzFramework
diff --git a/Code/Editor/Objects/ObjectManager.cpp b/Code/Editor/Objects/ObjectManager.cpp
index 06aa8866b3..f67cf24553 100644
--- a/Code/Editor/Objects/ObjectManager.cpp
+++ b/Code/Editor/Objects/ObjectManager.cpp
@@ -33,10 +33,6 @@
AZ_CVAR_EXTERNED(bool, ed_visibility_logTiming);
-AZ_CVAR(
- bool, ed_visibility_use, true, nullptr, AZ::ConsoleFunctorFlags::Null,
- "Enable/disable using the new IVisibilitySystem for Entity visibility determination");
-
/*!
* Class Description used for object templates.
* This description filled from Xml template files.
@@ -76,17 +72,6 @@ public:
int GameCreationOrder() override { return superType->GameCreationOrder(); };
};
-void CBaseObjectsCache::AddObject(CBaseObject* object)
-{
- m_objects.push_back(object);
- if (object->GetType() == OBJTYPE_AZENTITY)
- {
- auto componentEntityObject = static_cast(object);
- m_entityIds.push_back(componentEntityObject->GetAssociatedEntityId());
- }
-}
-
-
//////////////////////////////////////////////////////////////////////////
// CObjectManager implementation.
//////////////////////////////////////////////////////////////////////////
@@ -1267,25 +1252,8 @@ void CObjectManager::Display(DisplayContext& dc)
UpdateVisibilityList();
}
- bool viewIsDirty = dc.settings->IsDisplayHelpers(); // displaying helpers require computing all the bound boxes and things anyway.
-
- if (!viewIsDirty)
+ if (dc.settings->IsDisplayHelpers())
{
- if (CBaseObjectsCache* cache = dc.view->GetVisibleObjectsCache())
- {
- // if the current rendering viewport has an out-of-date cache serial number, it needs to be refreshed too.
- // views set their cache empty when they indicate they need to force a refresh.
- if ((cache->GetObjectCount() == 0) || (cache->GetSerialNumber() != m_visibilitySerialNumber))
- {
- viewIsDirty = true;
- }
- }
- }
-
- if (viewIsDirty)
- {
- FindDisplayableObjects(dc, true); // this also actually draws the helpers.
-
// Also broadcast for anyone else that needs to draw global debug to do so now
AzFramework::DebugDisplayEventBus::Broadcast(&AzFramework::DebugDisplayEvents::DrawGlobalDebugInfo);
}
@@ -1296,94 +1264,14 @@ void CObjectManager::Display(DisplayContext& dc)
}
}
-void CObjectManager::ForceUpdateVisibleObjectCache(DisplayContext& dc)
+void CObjectManager::ForceUpdateVisibleObjectCache([[maybe_unused]] DisplayContext& dc)
{
- FindDisplayableObjects(dc, false);
+ AZ_Assert(false, "CObjectManager::ForceUpdateVisibleObjectCache is legacy/deprecated and should not be used.");
}
-void CObjectManager::FindDisplayableObjects(DisplayContext& dc, [[maybe_unused]] bool bDisplay)
+void CObjectManager::FindDisplayableObjects([[maybe_unused]] DisplayContext& dc, [[maybe_unused]] bool bDisplay)
{
- // if the new IVisibilitySystem is being used, do not run this logic
- if (ed_visibility_use)
- {
- return;
- }
-
- AZ_PROFILE_FUNCTION(Editor);
-
- auto start = std::chrono::steady_clock::now();
- CBaseObjectsCache* pDispayedViewObjects = dc.view->GetVisibleObjectsCache();
- if (!pDispayedViewObjects)
- {
- return;
- }
-
- pDispayedViewObjects->SetSerialNumber(m_visibilitySerialNumber); // update viewport to be latest serial number
-
- AABB bbox;
- bbox.min.zero();
- bbox.max.zero();
-
- pDispayedViewObjects->ClearObjects();
- pDispayedViewObjects->Reserve(static_cast(m_visibleObjects.size()));
-
- if (dc.flags & DISPLAY_2D)
- {
- int numVis = static_cast(m_visibleObjects.size());
- for (int i = 0; i < numVis; i++)
- {
- CBaseObject* obj = m_visibleObjects[i];
-
- obj->GetBoundBox(bbox);
- if (dc.box.IsIntersectBox(bbox))
- {
- pDispayedViewObjects->AddObject(obj);
- }
- }
- }
- else
- {
- CSelectionGroup* pSelection = GetSelection();
- if (pSelection && pSelection->GetCount() > 1)
- {
- AABB mergedAABB;
- mergedAABB.Reset();
- for (int i = 0, iCount(pSelection->GetCount()); i < iCount; ++i)
- {
- CBaseObject* pObj(pSelection->GetObject(i));
- if (pObj == nullptr)
- {
- continue;
- }
- AABB aabb;
- pObj->GetBoundBox(aabb);
- mergedAABB.Add(aabb);
- }
-
- pSelection->GetObject(0)->CBaseObject::DrawDimensions(dc, &mergedAABB);
- }
-
- int numVis = static_cast(m_visibleObjects.size());
- for (int i = 0; i < numVis; i++)
- {
- CBaseObject* obj = m_visibleObjects[i];
-
- if (obj)
- {
- if ((dc.flags & DISPLAY_SELECTION_HELPERS) || obj->IsSelected())
- {
- pDispayedViewObjects->AddObject(obj);
- }
- }
- }
- }
-
- if (ed_visibility_logTiming && !ed_visibility_use)
- {
- auto stop = std::chrono::steady_clock::now();
- std::chrono::duration diff = stop - start;
- AZ_Printf("Visibility", "FindDisplayableObjects (old) - Duration: %f", diff);
- }
+ AZ_Assert(false, "CObjectManager::FindDisplayableObjects is legacy/deprecated and should not be used.");
}
void CObjectManager::BeginEditParams(CBaseObject* obj, int flags)
@@ -1630,214 +1518,24 @@ bool CObjectManager::HitTestObject(CBaseObject* obj, HitContext& hc)
return (bSelectionHelperHit || obj->HitTest(hc));
}
-
//////////////////////////////////////////////////////////////////////////
-bool CObjectManager::HitTest(HitContext& hitInfo)
+bool CObjectManager::HitTest([[maybe_unused]] HitContext& hitInfo)
{
- AZ_PROFILE_FUNCTION(Editor);
-
- hitInfo.object = nullptr;
- hitInfo.dist = FLT_MAX;
- hitInfo.axis = 0;
- hitInfo.manipulatorMode = 0;
-
- HitContext hcOrg = hitInfo;
- if (hcOrg.view)
- {
- hcOrg.view->GetPerpendicularAxis(nullptr, &hcOrg.b2DViewport);
- }
- hcOrg.rayDir = hcOrg.rayDir.GetNormalized();
-
- HitContext hc = hcOrg;
-
- float mindist = FLT_MAX;
-
- if (!hitInfo.bIgnoreAxis && !hc.bUseSelectionHelpers)
- {
- // Test gizmos.
- if (m_gizmoManager->HitTest(hc))
- {
- if (hc.axis != 0)
- {
- hitInfo.object = hc.object;
- hitInfo.gizmo = hc.gizmo;
- hitInfo.axis = hc.axis;
- hitInfo.manipulatorMode = hc.manipulatorMode;
- hitInfo.dist = hc.dist;
- return true;
- }
- }
- }
-
- if (hitInfo.bOnlyGizmo)
- {
- return false;
- }
-
- // Only HitTest objects, that where previously Displayed.
- CBaseObjectsCache* pDispayedViewObjects = hitInfo.view->GetVisibleObjectsCache();
-
- const bool iconsPrioritized = true; // Force icons to always be prioritized over other things you hit. Can change to be a configurable option in the future.
-
- CBaseObject* selected = nullptr;
- const char* name = nullptr;
- bool iconHit = false;
- int numVis = pDispayedViewObjects->GetObjectCount();
- for (int i = 0; i < numVis; i++)
- {
- CBaseObject* obj = pDispayedViewObjects->GetObject(i);
-
- if (obj == hitInfo.pExcludedObject)
- {
- continue;
- }
-
- if (HitTestObject(obj, hc))
- {
- if (m_selectCallback && !m_selectCallback->CanSelectObject(obj))
- {
- continue;
- }
-
- // Check if this object is nearest.
- if (hc.axis != 0)
- {
- hitInfo.object = obj;
- hitInfo.axis = hc.axis;
- hitInfo.dist = hc.dist;
- return true;
- }
-
- // When prioritizing icons, we don't allow non-icon hits to beat icon hits
- if (iconsPrioritized && iconHit && !hc.iconHit)
- {
- continue;
- }
-
- if (hc.dist < mindist || (!iconHit && hc.iconHit))
- {
- if (hc.iconHit)
- {
- iconHit = true;
- }
-
- mindist = hc.dist;
- name = hc.name;
- selected = obj;
- }
-
- // Clear the object pointer if an object was hit, not just if the collision
- // was closer than any previous. Not all paths from HitTestObject set the object pointer and so you could get
- // an object from a previous (rejected) result but with collision information about a closer hit.
- hc.object = nullptr;
- hc.iconHit = false;
-
- // If use deep selection
- if (hitInfo.pDeepSelection)
- {
- hitInfo.pDeepSelection->AddObject(hc.dist, obj);
- }
- }
- }
-
- if (selected)
- {
- hitInfo.object = selected;
- hitInfo.dist = mindist;
- hitInfo.name = name;
- hitInfo.iconHit = iconHit;
- return true;
- }
+ AZ_Assert(false, "CObjectManager::HitTest is legacy/deprecated and should not be used.");
return false;
}
-void CObjectManager::FindObjectsInRect(CViewport* view, const QRect& rect, std::vector& guids)
-{
- AZ_PROFILE_FUNCTION(Editor);
-
- if (rect.width() < 1 || rect.height() < 1)
- {
- return;
- }
-
- HitContext hc;
- hc.view = view;
- hc.b2DViewport = view->GetType() != ET_ViewportCamera;
- hc.rect = rect;
- hc.bUseSelectionHelpers = view->GetAdvancedSelectModeFlag();
-
- guids.clear();
- CBaseObjectsCache* pDispayedViewObjects = view->GetVisibleObjectsCache();
-
- int numVis = pDispayedViewObjects->GetObjectCount();
- for (int i = 0; i < numVis; ++i)
- {
- CBaseObject* pObj = pDispayedViewObjects->GetObject(i);
-
- HitTestObjectAgainstRect(pObj, view, hc, guids);
- }
+void CObjectManager::FindObjectsInRect(
+ [[maybe_unused]] CViewport* view, [[maybe_unused]] const QRect& rect, [[maybe_unused]] std::vector& guids)
+{
+ AZ_Assert(false, "CObjectManager::FindObjectsInRect is legacy/deprecated and should not be used.");
}
//////////////////////////////////////////////////////////////////////////
-void CObjectManager::SelectObjectsInRect(CViewport* view, const QRect& rect, bool bSelect)
+void CObjectManager::SelectObjectsInRect(
+ [[maybe_unused]] CViewport* view, [[maybe_unused]] const QRect& rect, [[maybe_unused]] bool bSelect)
{
- AZ_PROFILE_FUNCTION(Editor);
-
- // Ignore too small rectangles.
- if (rect.width() < 1 || rect.height() < 1)
- {
- return;
- }
-
- CUndo undo("Select Object(s)");
-
- HitContext hc;
- hc.view = view;
- hc.b2DViewport = view->GetType() != ET_ViewportCamera;
- hc.rect = rect;
- hc.bUseSelectionHelpers = view->GetAdvancedSelectModeFlag();
-
- bool isUndoRecording = GetIEditor()->IsUndoRecording();
- if (isUndoRecording)
- {
- m_processingBulkSelect = true;
- }
-
- CBaseObjectsCache* displayedViewObjects = view->GetVisibleObjectsCache();
- int numVis = displayedViewObjects->GetObjectCount();
-
- // Tracking the previous selection allows proper undo/redo functionality of additional
- // selections (CTRL + drag select)
- AZStd::unordered_set previousSelection;
-
- for (int i = 0; i < numVis; ++i)
- {
- CBaseObject* object = displayedViewObjects->GetObject(i);
-
- if (object->IsSelected())
- {
- previousSelection.insert(object);
- }
- else
- {
- // This will update m_currSelection
- SelectObjectInRect(object, view, hc, bSelect);
-
- // Legacy undo/redo does not go through the Ebus system and must be done individually
- if (isUndoRecording && object->GetType() != OBJTYPE_AZENTITY)
- {
- GetIEditor()->RecordUndo(new CUndoBaseObjectSelect(object, true));
- }
- }
- }
-
- if (isUndoRecording && m_currSelection)
- {
- // Component Entities can handle undo/redo in bulk due to Ebuses
- GetIEditor()->RecordUndo(new CUndoBaseObjectBulkSelect(previousSelection, *m_currSelection));
- }
-
- m_processingBulkSelect = false;
+ AZ_Assert(false, "CObjectManager::SelectObjectsInRect is legacy/deprecated and should not be used.");
}
//////////////////////////////////////////////////////////////////////////
@@ -3011,6 +2709,4 @@ namespace AzToolsFramework
}
}
-}
-
-
+} // namespace AzToolsFramework
diff --git a/Code/Editor/Objects/ObjectManager.h b/Code/Editor/Objects/ObjectManager.h
index 4ffa5e9a07..0ad5d8323e 100644
--- a/Code/Editor/Objects/ObjectManager.h
+++ b/Code/Editor/Objects/ObjectManager.h
@@ -52,40 +52,6 @@ public:
}
};
-//////////////////////////////////////////////////////////////////////////
-// Array of editor objects.
-//////////////////////////////////////////////////////////////////////////
-class CBaseObjectsCache
-{
-public:
- int GetObjectCount() const { return static_cast(m_objects.size()); }
- CBaseObject* GetObject(int nIndex) const { return m_objects[nIndex]; }
- void AddObject(CBaseObject* object);
-
- void ClearObjects()
- {
- m_objects.clear();
- m_entityIds.clear();
- }
-
- void Reserve(int nCount)
- {
- m_objects.reserve(nCount);
- m_entityIds.reserve(nCount);
- }
-
- const AZStd::vector& GetEntityIdCache() const { return m_entityIds; }
-
- /// Checksum is used as a dirty flag.
- unsigned int GetSerialNumber() { return m_serialNumber; }
- void SetSerialNumber(unsigned int serialNumber) { m_serialNumber = serialNumber; }
-private:
- //! List of objects that was displayed at last frame.
- std::vector<_smart_ptr > m_objects;
- AZStd::vector m_entityIds;
- unsigned int m_serialNumber = 0;
-};
-
/*!
* CObjectManager is a singleton object that
* manages global set of objects in level.
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp
index 47bd214b8d..41e950a058 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp
@@ -142,8 +142,7 @@ void GetSelectedEntitiesSetWithFlattenedHierarchy(AzToolsFramework::EntityIdSet&
}
SandboxIntegrationManager::SandboxIntegrationManager()
- : m_inObjectPickMode(false)
- , m_startedUndoRecordingNestingLevel(0)
+ : m_startedUndoRecordingNestingLevel(0)
, m_dc(nullptr)
, m_notificationWindowManager(new AzToolsFramework::SliceOverridesNotificationWindowManager())
{
@@ -1000,62 +999,6 @@ void SandboxIntegrationManager::SetupSliceContextMenu_Modify(QMenu* menu, const
revertAction->setEnabled(canRevert);
}
-void SandboxIntegrationManager::HandleObjectModeSelection(const AZ::Vector2& point, [[maybe_unused]] int flags, bool& handled)
-{
- // Todo - Use a custom "edit tool". This will eliminate the need for this bus message entirely, which technically
- // makes this feature less intrusive on Sandbox.
- // UPDATE: This is now provided by EditorPickEntitySelection when the new Viewport Interaction Model changes are enabled.
- if (m_inObjectPickMode)
- {
- CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport();
- const QPoint viewPoint(static_cast(point.GetX()), static_cast(point.GetY()));
-
- HitContext hitInfo;
- hitInfo.view = view;
- if (view->HitTest(viewPoint, hitInfo))
- {
- if (hitInfo.object && (hitInfo.object->GetType() == OBJTYPE_AZENTITY))
- {
- CComponentEntityObject* entityObject = static_cast(hitInfo.object);
- AzToolsFramework::EditorPickModeRequestBus::Broadcast(
- &AzToolsFramework::EditorPickModeRequests::PickModeSelectEntity, entityObject->GetAssociatedEntityId());
- }
- }
-
- AzToolsFramework::EditorPickModeRequestBus::Broadcast(
- &AzToolsFramework::EditorPickModeRequests::StopEntityPickMode);
-
- handled = true;
- }
-}
-
-void SandboxIntegrationManager::UpdateObjectModeCursor(AZ::u32& cursorId, AZStd::string& cursorStr)
-{
- if (m_inObjectPickMode)
- {
- cursorId = static_cast(STD_CURSOR_HAND);
- cursorStr = "Pick an entity...";
- }
-}
-
-void SandboxIntegrationManager::OnEntityPickModeStarted()
-{
- m_inObjectPickMode = true;
-
- // Currently this object pick mode is activated only via PropertyEntityIdCtrl picker.
- // When the picker button is clicked, we transfer focus to the viewport so the
- // spacebar can still be used to activate selection helpers.
- if (CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport())
- {
- view->SetFocus();
- }
-}
-
-void SandboxIntegrationManager::OnEntityPickModeStopped()
-{
- m_inObjectPickMode = false;
-}
-
void SandboxIntegrationManager::CreateEditorRepresentation(AZ::Entity* entity)
{
IEditor* editor = GetIEditor();
@@ -1739,8 +1682,7 @@ void SandboxIntegrationManager::GoToEntitiesInViewports(const AzToolsFramework::
AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
viewportContext->GetId(),
- &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform,
- distanceToLookAt);
+ &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform);
}
}
}
@@ -1953,7 +1895,7 @@ void SandboxIntegrationManager::MakeSliceFromEntities(const AzToolsFramework::En
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(entitiesAndDescendants,
&AzToolsFramework::ToolsApplicationRequestBus::Events::GatherEntitiesAndAllDescendents, entities);
- const AZStd::string slicesAssetsPath = "@devassets@/Slices";
+ const AZStd::string slicesAssetsPath = "@projectroot@/Slices";
if (!gEnv->pFileIO->Exists(slicesAssetsPath.c_str()))
{
diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h
index 617c5cb2c8..40962409a3 100644
--- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h
+++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h
@@ -93,7 +93,6 @@ namespace AzToolsFramework
class SandboxIntegrationManager
: private AzToolsFramework::ToolsApplicationEvents::Bus::Handler
, private AzToolsFramework::EditorRequests::Bus::Handler
- , private AzToolsFramework::EditorPickModeNotificationBus::Handler
, private AzToolsFramework::EditorContextMenuBus::Handler
, private AzToolsFramework::EditorWindowRequests::Bus::Handler
, private AzFramework::AssetCatalogEventBus::Handler
@@ -140,8 +139,6 @@ private:
QDockWidget* InstanceViewPane(const char* paneName) override;
void CloseViewPane(const char* paneName) override;
void BrowseForAssets(AzToolsFramework::AssetBrowser::AssetSelectionModel& selection) override;
- void HandleObjectModeSelection(const AZ::Vector2& point, int flags, bool& handled) override;
- void UpdateObjectModeCursor(AZ::u32& cursorId, AZStd::string& cursorStr) override;
void CreateEditorRepresentation(AZ::Entity* entity) override;
bool DestroyEditorRepresentation(AZ::EntityId entityId, bool deleteAZEntity) override;
void CloneSelection(bool& handled) override;
@@ -175,10 +172,6 @@ private:
QWidget* GetAppMainWindow() override;
//////////////////////////////////////////////////////////////////////////
- // EditorPickModeNotificationBus
- void OnEntityPickModeStarted() override;
- void OnEntityPickModeStopped() override;
-
//////////////////////////////////////////////////////////////////////////
// AzToolsFramework::EditorContextMenu::Bus::Handler overrides
void PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags) override;
@@ -281,7 +274,6 @@ private:
private:
AZ::Vector2 m_contextMenuViewPoint;
- int m_inObjectPickMode;
short m_startedUndoRecordingNestingLevel; // used in OnBegin/EndUndo to ensure we only accept undo's we started recording
AzToolsFramework::SliceOverridesNotificationWindowManager* m_notificationWindowManager;
diff --git a/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp b/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp
index 98bf228391..0ff9467f33 100644
--- a/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp
+++ b/Code/Editor/Plugins/EditorAssetImporter/AssetImporterWindow.cpp
@@ -30,6 +30,7 @@ class CXTPDockingPaneLayout; // Needed for settings.h
#include
#include
#include
+#include
#include
#include
#include
@@ -47,41 +48,6 @@ class CXTPDockingPaneLayout; // Needed for settings.h
const char* AssetImporterWindow::s_documentationWebAddress = "http://docs.aws.amazon.com/lumberyard/latest/userguide/char-fbx-importer.html";
const AZ::Uuid AssetImporterWindow::s_browseTag = AZ::Uuid::CreateString("{C240D2E1-BFD2-4FFA-BB5B-CC0FA389A5D3}");
-void MakeUserFriendlySourceAssetPath(QString& out, const QString& sourcePath)
-{
- char devAssetsRoot[AZ_MAX_PATH_LEN] = { 0 };
- if (!gEnv->pFileIO->ResolvePath("@devroot@", devAssetsRoot, AZ_MAX_PATH_LEN))
- {
- out = sourcePath;
- return;
- }
-
- AZStd::replace(devAssetsRoot, devAssetsRoot + AZ_MAX_PATH_LEN- 1, AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR);
-
- // Find if the sourcePathArray is a sub directory of the devAssets folder
- // Keep reference to sourcePathArray long enough to use in PathView
- QByteArray sourcePathArray = sourcePath.toUtf8();
- AZ::IO::PathView sourcePathRootView(sourcePathArray.data());
- AZ::IO::PathView devAssetsRootView(devAssetsRoot);
- auto [sourcePathIter, devAssetsIter] = AZStd::mismatch(sourcePathRootView.begin(), sourcePathRootView.end(),
- devAssetsRootView.begin(), devAssetsRootView.end());
- // If the devAssets path iterator is not equal to the end, then there was a mismistch while comparing it
- // against the source path indicating that the source path is not a sub-directory
- if (devAssetsIter != devAssetsRootView.end())
- {
- out = sourcePath;
- return;
- }
-
- int offset = aznumeric_cast(strlen(devAssetsRoot));
- if (sourcePath.at(offset) == AZ_CORRECT_FILESYSTEM_SEPARATOR)
- {
- ++offset;
- }
- out = sourcePath.right(sourcePath.length() - offset);
-
-}
-
AssetImporterWindow::AssetImporterWindow()
: AssetImporterWindow(nullptr)
{
@@ -102,7 +68,7 @@ AssetImporterWindow::AssetImporterWindow(QWidget* parent)
AssetImporterWindow::~AssetImporterWindow()
{
- AZ_Assert(m_processingOverlayIndex == AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex,
+ AZ_Assert(m_processingOverlayIndex == AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex,
"Processing overlay (and potentially background thread) still active at destruction.");
AZ_Assert(!m_processingOverlay, "Processing overlay (and potentially background thread) still active at destruction.");
}
@@ -133,7 +99,7 @@ void AssetImporterWindow::OpenFile(const AZStd::string& filePath)
QMessageBox::warning(this, "In progress", "Unable to close one or more windows at this time.");
return;
}
-
+
OpenFileInternal(filePath);
}
@@ -146,7 +112,7 @@ void AssetImporterWindow::closeEvent(QCloseEvent* ev)
if (m_processingOverlay)
{
- AZ_Assert(m_processingOverlayIndex != AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex,
+ AZ_Assert(m_processingOverlayIndex != AZ::SceneAPI::UI::OverlayWidget::s_invalidOverlayIndex,
"Processing overlay present, but not the index in the overlay for it.");
if (m_processingOverlay->HasProcessingCompleted())
{
@@ -157,7 +123,7 @@ void AssetImporterWindow::closeEvent(QCloseEvent* ev)
}
else
{
- QMessageBox::critical(this, "Processing In Progress", "Unable to close the result window at this time.",
+ QMessageBox::critical(this, "Processing In Progress", "Unable to close the result window at this time.",
QMessageBox::Ok, QMessageBox::Ok);
ev->ignore();
return;
@@ -165,7 +131,7 @@ void AssetImporterWindow::closeEvent(QCloseEvent* ev)
}
else
{
- QMessageBox::critical(this, "Processing In Progress", "Please wait until processing has completed to try again.",
+ QMessageBox::critical(this, "Processing In Progress", "Please wait until processing has completed to try again.",
QMessageBox::Ok, QMessageBox::Ok);
ev->ignore();
return;
@@ -199,7 +165,9 @@ void AssetImporterWindow::Init()
// Load the style sheets
AzQtComponents::StylesheetPreprocessor styleSheetProcessor(nullptr);
- AZStd::string mainWindowQSSPath = Path::GetEditingRootFolder() + "\\Editor\\Styles\\AssetImporterWindow.qss";
+ auto mainWindowQSSPath = AZ::IO::Path(AZ::Utils::GetEnginePath()) / "Assets";
+ mainWindowQSSPath /= "Editor/Styles/AssetImporterWindow.qss";
+ mainWindowQSSPath.MakePreferred();
QFile mainWindowStyleSheetFile(mainWindowQSSPath.c_str());
if (mainWindowStyleSheetFile.open(QFile::ReadOnly))
{
@@ -212,7 +180,7 @@ void AssetImporterWindow::Init()
{
ui->m_actionInspect->setVisible(false);
}
-
+
ResetMenuAccess(WindowState::InitialNothingLoaded);
// Setup the overlay system, and set the root to be the root display. The root display has the browse,
@@ -220,7 +188,7 @@ void AssetImporterWindow::Init()
m_overlay.reset(aznew AZ::SceneAPI::UI::OverlayWidget(this));
m_rootDisplay.reset(aznew ImporterRootDisplay(m_serializeContext));
connect(m_rootDisplay.data(), &ImporterRootDisplay::UpdateClicked, this, &AssetImporterWindow::UpdateClicked);
-
+
connect(m_overlay.data(), &AZ::SceneAPI::UI::OverlayWidget::LayerAdded, this, &AssetImporterWindow::OverlayLayerAdded);
connect(m_overlay.data(), &AZ::SceneAPI::UI::OverlayWidget::LayerRemoved, this, &AssetImporterWindow::OverlayLayerRemoved);
@@ -242,7 +210,7 @@ void AssetImporterWindow::Init()
AZStd::string joinedExtensions;
AzFramework::StringFunc::Join(joinedExtensions, extensions.begin(), extensions.end(), " or ");
- AZStd::string firstLineText =
+ AZStd::string firstLineText =
AZStd::string::format(
"%s files are available for use after placing them in any folder within your game project. "
"These files will automatically be processed and may be accessed via the Asset Browser. Learn more...",
@@ -250,13 +218,13 @@ void AssetImporterWindow::Init()
ui->m_initialPromptFirstLine->setText(firstLineText.c_str());
- AZStd::string secondLineText =
+ AZStd::string secondLineText =
AZStd::string::format("To adjust the %s settings, right-click the file in the Asset Browser and select \"Edit Settings\" from the context menu.", joinedExtensions.c_str());
ui->m_initialPromptSecondLine->setText(secondLineText.c_str());
}
else
{
- AZStd::string firstLineText =
+ AZStd::string firstLineText =
AZStd::string::format(
"Files are available for use after placing them in any folder within your game project. "
"These files will automatically be processed and may be accessed via the Asset Browser. Learn more...", s_documentationWebAddress);
@@ -282,12 +250,12 @@ void AssetImporterWindow::OpenFileInternal(const AZStd::string& filePath)
auto asyncLoadHandler = AZStd::make_shared(
s_browseTag,
[this, filePath]()
- {
- m_assetImporterDocument->LoadScene(filePath);
+ {
+ m_assetImporterDocument->LoadScene(filePath);
},
[this]()
{
- HandleAssetLoadingCompleted();
+ HandleAssetLoadingCompleted();
}, this);
m_processingOverlay.reset(new ProcessingOverlayWidget(m_overlay.data(), ProcessingOverlayWidget::Layout::Loading, s_browseTag));
@@ -304,7 +272,7 @@ bool AssetImporterWindow::IsAllowedToChangeSourceFile()
return true;
}
- QMessageBox messageBox(QMessageBox::Icon::NoIcon, "Unsaved changes",
+ QMessageBox messageBox(QMessageBox::Icon::NoIcon, "Unsaved changes",
"You have unsaved changes. Do you want to discard those changes?",
QMessageBox::StandardButton::Discard | QMessageBox::StandardButton::Cancel, this);
messageBox.exec();
@@ -406,7 +374,7 @@ void AssetImporterWindow::OnSceneResetRequested()
else
{
m_assetImporterDocument->ClearScene();
- AZ_TracePrintf(ErrorWindow, "Manifest reset returned in '%s'",
+ AZ_TracePrintf(ErrorWindow, "Manifest reset returned in '%s'",
result.GetResult() == ProcessingResult::Failure ? "Failure" : "Ignored");
}
},
@@ -456,7 +424,7 @@ void AssetImporterWindow::OnInspect()
// make sure the inspector doesn't outlive the AssetImporterWindow, since we own the data it will be inspecting.
auto* theInspectWidget = aznew AZ::SceneAPI::UI::SceneGraphInspectWidget(*m_assetImporterDocument->GetScene());
QObject::connect(this, &QObject::destroyed, theInspectWidget, [theInspectWidget]() { theInspectWidget->window()->close(); } );
-
+
m_overlay->PushLayer(label, theInspectWidget, "Scene Inspector", buttons);
}
@@ -483,7 +451,7 @@ void AssetImporterWindow::OverlayLayerRemoved()
else
{
ResetMenuAccess(WindowState::InitialNothingLoaded);
-
+
ui->m_initialBrowseContainer->show();
m_rootDisplay->hide();
}
@@ -533,8 +501,9 @@ void AssetImporterWindow::HandleAssetLoadingCompleted()
m_fullSourcePath = m_assetImporterDocument->GetScene()->GetSourceFilename();
SetTitle(m_fullSourcePath.c_str());
- QString userFriendlyFileName;
- MakeUserFriendlySourceAssetPath(userFriendlyFileName, m_fullSourcePath.c_str());
+ AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
+ AZ::IO::FixedMaxPath relativeSourcePath = AZ::IO::PathView(m_fullSourcePath).LexicallyProximate(projectPath);
+ auto userFriendlyFileName = QString::fromUtf8(relativeSourcePath.c_str(), static_cast(relativeSourcePath.Native().size()));
m_rootDisplay->SetSceneDisplay(userFriendlyFileName, m_assetImporterDocument->GetScene());
// Once we've browsed to something successfully, we need to hide the initial browse button layer and
diff --git a/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp b/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp
index b1d07af41c..5ee54667b9 100644
--- a/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp
+++ b/Code/Editor/Plugins/EditorAssetImporter/SceneSerializationHandler.cpp
@@ -7,9 +7,11 @@
*/
#include
+#include
#include
#include
#include
+#include
#include
#include
#include
@@ -50,22 +52,15 @@ namespace AZ
return nullptr;
}
- AZStd::string cleanPath = filePath;
- if (AzFramework::StringFunc::Path::IsRelative(filePath.c_str()))
+ AZ::IO::Path enginePath;
+ if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
- const char* absolutePath = nullptr;
- AzToolsFramework::AssetSystemRequestBus::BroadcastResult(absolutePath,
- &AzToolsFramework::AssetSystemRequestBus::Events::GetAbsoluteDevRootFolderPath);
- AZ_Assert(absolutePath, "Unable to retrieve the dev folder path");
- AzFramework::StringFunc::Path::Join(absolutePath, cleanPath.c_str(), cleanPath);
- }
- else
- {
- // Normalizing is not needed if the path is relative as Join(...) will also normalize.
- AzFramework::StringFunc::Path::Normalize(cleanPath);
+ settingsRegistry->Get(enginePath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder);
}
- auto sceneIt = m_scenes.find(cleanPath);
+ AZ::IO::Path cleanPath = (enginePath / filePath).LexicallyNormal();
+
+ auto sceneIt = m_scenes.find(cleanPath.Native());
if (sceneIt != m_scenes.end())
{
AZStd::shared_ptr scene = sceneIt->second.lock();
@@ -98,14 +93,14 @@ namespace AZ
}
AZStd::shared_ptr scene =
- AssetImportRequest::LoadSceneFromVerifiedPath(cleanPath, sceneSourceGuid, AssetImportRequest::RequestingApplication::Editor, SceneAPI::SceneCore::LoadingComponent::TYPEINFO_Uuid());
+ AssetImportRequest::LoadSceneFromVerifiedPath(cleanPath.Native(), sceneSourceGuid, AssetImportRequest::RequestingApplication::Editor, SceneAPI::SceneCore::LoadingComponent::TYPEINFO_Uuid());
if (!scene)
{
AZ_TracePrintf(Utilities::ErrorWindow, "Failed to load the requested scene.");
return nullptr;
}
- m_scenes.emplace(AZStd::move(cleanPath), scene);
+ m_scenes.emplace(AZStd::move(cleanPath.Native()), scene);
return scene;
}
diff --git a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
index cd9f2e79c7..609482b581 100644
--- a/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
+++ b/Code/Editor/Plugins/EditorCommon/CMakeLists.txt
@@ -39,7 +39,6 @@ ly_add_target(
EDITOR_COMMON_IMPORTS
BUILD_DEPENDENCIES
PRIVATE
- 3rdParty::zlib
3rdParty::Qt::Core
3rdParty::Qt::Widgets
Legacy::CryCommon
diff --git a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp
index 6b454474be..a53ce966c4 100644
--- a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp
+++ b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.cpp
@@ -46,7 +46,6 @@ namespace ProjectSettingsTool
, LastPathBus::Handler()
, m_ui(new Ui::ProjectSettingsToolWidget())
, m_reconfigureProcess()
- , m_devRoot(GetDevRoot())
, m_projectRoot(GetProjectRoot())
, m_projectName(GetProjectName())
, m_plistsInitVector(
diff --git a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h
index 1c9aa4b1bf..daa5bea27c 100644
--- a/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h
+++ b/Code/Editor/Plugins/ProjectSettingsTool/ProjectSettingsToolWindow.h
@@ -147,7 +147,6 @@ namespace ProjectSettingsTool
// The process used to reconfigure settings
QProcess m_reconfigureProcess;
- AZStd::string m_devRoot;
AZStd::string m_projectRoot;
AZStd::string m_projectName;
diff --git a/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp b/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp
index 0e171adf04..d5b94469cc 100644
--- a/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp
+++ b/Code/Editor/Plugins/ProjectSettingsTool/Utils.cpp
@@ -27,37 +27,31 @@ namespace
}
template
- StringType GetAbsoluteDevRoot()
+ StringType GetAbsoluteEngineRoot()
{
- const char* devRoot = nullptr;
- AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
- devRoot,
- &AzToolsFramework::AssetSystemRequestBus::Handler::GetAbsoluteDevRootFolderPath);
+ AZ::IO::FixedMaxPath engineRoot = AZ::Utils::GetEnginePath();
- if (!devRoot)
+ if (engineRoot.empty())
{
return "";
}
- StringType devRootString(devRoot);
- ToUnixPath(devRootString);
- return devRootString;
+ StringType engineRootString(engineRoot.c_str());
+ ToUnixPath(engineRootString);
+ return engineRootString;
}
template
StringType GetAbsoluteProjectRoot()
{
- const char* projectRoot = nullptr;
- AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
- projectRoot,
- &AzToolsFramework::AssetSystemRequestBus::Handler::GetAbsoluteDevGameFolderPath);
+ AZ::IO::FixedMaxPath projectRoot = AZ::Utils::GetProjectPath();
- if (!projectRoot)
+ if (projectRoot.empty())
{
return "";
}
- StringType projectRootString(projectRoot);
+ StringType projectRootString(projectRoot.c_str());
ToUnixPath(projectRootString);
return projectRootString;
}
@@ -87,9 +81,9 @@ namespace ProjectSettingsTool
return reinterpret_cast(func);
}
- AZStd::string GetDevRoot()
+ AZStd::string GetEngineRoot()
{
- return GetAbsoluteDevRoot();
+ return GetAbsoluteEngineRoot();
}
AZStd::string GetProjectRoot()
{
@@ -104,7 +98,7 @@ namespace ProjectSettingsTool
QString SelectXmlFromFileDialog(const QString& currentFile)
{
// The selected file must be relative to this path
- QString defaultPath = GetAbsoluteDevRoot();
+ QString defaultPath = GetAbsoluteEngineRoot();
QString startPath;
// Choose the starting path for file dialog
@@ -139,7 +133,7 @@ namespace ProjectSettingsTool
QString SelectImageFromFileDialog(const QString& currentFile)
{
- QString defaultPath = QStringLiteral("%1Code%2/Resources/").arg(GetAbsoluteDevRoot(), ::GetProjectName());
+ QString defaultPath = QStringLiteral("%1Code%2/Resources/").arg(GetAbsoluteEngineRoot(), ::GetProjectName());
QString startPath;
@@ -188,7 +182,7 @@ namespace ProjectSettingsTool
// Android
if (group <= ImageGroup::AndroidPortrait)
{
- root = GetDevRoot() + "/Code/Tools/Android/ProjectBuilder/app_";
+ root = GetEngineRoot() + "/Code/Tools/Android/ProjectBuilder/app_";
}
//Ios
else
diff --git a/Code/Editor/Plugins/ProjectSettingsTool/Utils.h b/Code/Editor/Plugins/ProjectSettingsTool/Utils.h
index 4226d534a6..050fb3b85b 100644
--- a/Code/Editor/Plugins/ProjectSettingsTool/Utils.h
+++ b/Code/Editor/Plugins/ProjectSettingsTool/Utils.h
@@ -17,7 +17,7 @@
namespace ProjectSettingsTool
{
void* ConvertFunctorToVoid(AZStd::pair(*func)(const QString&));
- AZStd::string GetDevRoot();
+ AZStd::string GetEngineRoot();
AZStd::string GetProjectRoot();
AZStd::string GetProjectName();
diff --git a/Code/Editor/PythonEditorFuncs.cpp b/Code/Editor/PythonEditorFuncs.cpp
index 455cdfa17d..1b731a3d5f 100644
--- a/Code/Editor/PythonEditorFuncs.cpp
+++ b/Code/Editor/PythonEditorFuncs.cpp
@@ -18,6 +18,7 @@
#include
// AzToolsFramework
+#include
#include
#include
diff --git a/Code/Editor/Settings.cpp b/Code/Editor/Settings.cpp
index 05a6960695..47743d1c42 100644
--- a/Code/Editor/Settings.cpp
+++ b/Code/Editor/Settings.cpp
@@ -935,8 +935,9 @@ void SEditorSettings::LoadDefaultGamePaths()
searchPaths[EDITOR_PATH_MATERIALS].push_back((Path::GetEditingGameDataFolder() + "/Materials").c_str());
}
- AZStd::string iconsPath;
- AZ::StringFunc::Path::Join(Path::GetEditingRootFolder().c_str(), "Editor/UI/Icons", iconsPath);
+ auto iconsPath = AZ::IO::Path(AZ::Utils::GetEnginePath()) / "Assets";
+ iconsPath /= "Editor/UI/Icons";
+ iconsPath.MakePreferred();
searchPaths[EDITOR_PATH_UI_ICONS].push_back(iconsPath.c_str());
}
diff --git a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp
index 6b3f1c2633..d7901e338a 100644
--- a/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp
+++ b/Code/Editor/TrackView/SequenceBatchRenderDialog.cpp
@@ -36,9 +36,6 @@
#include "CryEdit.h"
#include "Viewport.h"
-// Atom Renderer
-#include
-
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
#include
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
@@ -272,7 +269,7 @@ void CSequenceBatchRenderDialog::OnRenderItemSelChange()
// Enable/disable the 'remove'/'update' button properly.
bool bNoSelection = !m_ui->m_renderList->selectionModel()->hasSelection();
m_ui->BATCH_RENDER_REMOVE_SEQ->setEnabled(bNoSelection ? false : true);
-
+
CheckForEnableUpdateButton();
if (bNoSelection)
@@ -363,7 +360,7 @@ void CSequenceBatchRenderDialog::OnRenderItemSelChange()
cvarsText += item.cvars[static_cast(i)];
cvarsText += "\r\n";
}
- m_ui->m_cvarsEdit->setPlainText(cvarsText);
+ m_ui->m_cvarsEdit->setPlainText(cvarsText);
}
void CSequenceBatchRenderDialog::CheckForEnableUpdateButton()
@@ -497,7 +494,7 @@ void CSequenceBatchRenderDialog::OnSavePreset()
}
void CSequenceBatchRenderDialog::stashActiveViewportResolution()
-{
+{
// stash active resolution in global vars
activeViewportWidth = resolutions[0][0];
activeViewportHeight = resolutions[0][1];
@@ -505,7 +502,7 @@ void CSequenceBatchRenderDialog::stashActiveViewportResolution()
if (activeViewport)
{
activeViewport->GetDimensions(&activeViewportWidth, &activeViewportHeight);
- }
+ }
}
void CSequenceBatchRenderDialog::OnGo()
@@ -643,7 +640,7 @@ void CSequenceBatchRenderDialog::OnResolutionSelected()
int defaultH;
const QString currentCustomResText = m_ui->m_resolutionCombo->currentText();
GetResolutionFromCustomResText(currentCustomResText.toStdString().c_str(), defaultW, defaultH);
-
+
CCustomResolutionDlg resDlg(defaultW, defaultH, this);
if (resDlg.exec() == QDialog::Accepted)
{
@@ -755,7 +752,7 @@ bool CSequenceBatchRenderDialog::LoadOutputOptions(const QString& pathname)
{
const QString customResText = resolutionNode->getContent();
m_ui->m_resolutionCombo->setItemText(curSel, customResText);
-
+
GetResolutionFromCustomResText(customResText.toStdString().c_str(), m_customResW, m_customResH);
}
m_ui->m_resolutionCombo->setCurrentIndex(curSel);
@@ -910,12 +907,12 @@ void CSequenceBatchRenderDialog::CaptureItemStart()
folder += "/";
folder += itemText;
- // If this is a relative path, prepend the @assets@ folder to match where the Renderer is going
+ // If this is a relative path, prepend the @products@ folder to match where the Renderer is going
// to dump the frame buffer image captures.
if (AzFramework::StringFunc::Path::IsRelative(folder.toUtf8().data()))
{
AZStd::string absolutePath;
- AZStd::string assetsRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@assets@");
+ AZStd::string assetsRoot = AZ::IO::FileIOBase::GetInstance()->GetAlias("@products@");
AzFramework::StringFunc::Path::Join(assetsRoot.c_str(), folder.toUtf8().data(), absolutePath);
folder = absolutePath.c_str();
}
@@ -965,7 +962,7 @@ void CSequenceBatchRenderDialog::CaptureItemStart()
m_renderContext.cvarDisplayInfoBU = cvarDebugInfo->GetIVal();
if (renderItem.disableDebugInfo && cvarDebugInfo->GetIVal())
{
- const int DISPLAY_INFO_OFF = 0;
+ const int DISPLAY_INFO_OFF = 0;
cvarDebugInfo->Set(DISPLAY_INFO_OFF);
}
}
@@ -1103,13 +1100,13 @@ void CSequenceBatchRenderDialog::OnUpdateEnd(IAnimSequence* sequence)
sequence->SetActiveDirector(m_renderContext.pActiveDirectorBU);
const auto imageFormat = m_ui->m_imageFormatCombo->currentText();
-
+
SRenderItem renderItem = m_renderItems[m_renderContext.currentItemIndex];
if (m_bFFMPEGCommandAvailable && renderItem.bCreateVideo)
{
// Create a video using the ffmpeg plug-in from captured images.
m_renderContext.processingFFMPEG = true;
-
+
AZStd::string outputFolder = m_renderContext.captureOptions.folder;
auto future = QtConcurrent::run(
[renderItem, outputFolder, imageFormat]
@@ -1237,18 +1234,11 @@ void CSequenceBatchRenderDialog::OnKickIdleTimout()
{
componentApplication->TickSystem();
}
-
- // Directly tick the renderer, as it's no longer part of the system tick
- if (auto rpiSystem = AZ::RPI::RPISystemInterface::Get())
- {
- rpiSystem->SimulationTick();
- rpiSystem->RenderTick();
- }
}
}
void CSequenceBatchRenderDialog::OnKickIdle()
-{
+{
if (m_renderContext.captureState == CaptureState::WarmingUpAfterResChange)
{
OnUpdateWarmingUpAfterResChange();
@@ -1264,7 +1254,7 @@ void CSequenceBatchRenderDialog::OnKickIdle()
else if (m_renderContext.captureState == CaptureState::Capturing)
{
OnUpdateCapturing();
- }
+ }
else if (m_renderContext.captureState == CaptureState::End)
{
OnUpdateEnd(m_renderContext.endingSequence);
diff --git a/Code/Editor/TrackView/TrackViewPythonFuncs.cpp b/Code/Editor/TrackView/TrackViewPythonFuncs.cpp
index 72da1e0b18..dc55411f80 100644
--- a/Code/Editor/TrackView/TrackViewPythonFuncs.cpp
+++ b/Code/Editor/TrackView/TrackViewPythonFuncs.cpp
@@ -19,6 +19,7 @@
// Editor
#include "AnimationContext.h"
+#include
namespace
{
diff --git a/Code/Editor/UndoDropDown.cpp b/Code/Editor/UndoDropDown.cpp
index 6bf807ebf4..4f346b57dd 100644
--- a/Code/Editor/UndoDropDown.cpp
+++ b/Code/Editor/UndoDropDown.cpp
@@ -101,13 +101,13 @@ public:
if (fresh.size() < m_stackNames.size())
{
- beginRemoveRows(createIndex(-1, -1), static_cast(fresh.size()), static_cast(m_stackNames.size() - 1));
+ beginRemoveRows(QModelIndex(), static_cast(fresh.size()), static_cast(m_stackNames.size() - 1));
m_stackNames = fresh;
endRemoveRows();
}
else
{
- beginInsertRows(createIndex(-1, -1), static_cast(m_stackNames.size()), static_cast(fresh.size() - 1));
+ beginInsertRows(QModelIndex(), static_cast(m_stackNames.size()), static_cast(fresh.size() - 1));
m_stackNames = fresh;
endInsertRows();
}
diff --git a/Code/Editor/Util/PathUtil.cpp b/Code/Editor/Util/PathUtil.cpp
index c9e6823824..ca3481ddae 100644
--- a/Code/Editor/Util/PathUtil.cpp
+++ b/Code/Editor/Util/PathUtil.cpp
@@ -11,9 +11,9 @@
#include "PathUtil.h"
-#include // for AZ_MAX_PATH_LEN
+#include
+#include
#include // for ebus events
-#include
#include
#include
#include
@@ -179,7 +179,7 @@ namespace Path
EBUS_EVENT_RESULT(engineRoot, AzFramework::ApplicationRequests::Bus, GetEngineRoot);
return QString(engineRoot);
}
-
+
//////////////////////////////////////////////////////////////////////////
QString& ReplaceFilename(const QString& strFilepath, const QString& strFilename, QString& strOutputFilename, bool bCallCaselessPath)
{
@@ -216,30 +216,21 @@ namespace Path
//////////////////////////////////////////////////////////////////////////
QString GetResolvedUserSandboxFolder()
{
- char resolvedPath[AZ_MAX_PATH_LEN] = { 0 };
- gEnv->pFileIO->ResolvePath(GetUserSandboxFolder().toUtf8().data(), resolvedPath, AZ_MAX_PATH_LEN);
- return QString::fromLatin1(resolvedPath);
+ AZ::IO::FixedMaxPath userSandboxFolderPath;
+ gEnv->pFileIO->ResolvePath(userSandboxFolderPath, GetUserSandboxFolder().toUtf8().constData());
+ return QString::fromUtf8(userSandboxFolderPath.c_str(), static_cast(userSandboxFolderPath.Native().size()));
}
// internal function, you should use GetEditingGameDataFolder instead.
AZStd::string GetGameAssetsFolder()
{
- const char* resultValue = nullptr;
- EBUS_EVENT_RESULT(resultValue, AzToolsFramework::AssetSystemRequestBus, GetAbsoluteDevGameFolderPath);
- if (!resultValue)
- {
- if ((gEnv) && (gEnv->pFileIO))
- {
- resultValue = gEnv->pFileIO->GetAlias("@devassets@");
- }
- }
-
- if (!resultValue)
+ AZ::IO::Path projectPath;
+ if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
- resultValue = ".";
+ settingsRegistry->Get(projectPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath);
}
- return resultValue;
+ return projectPath.Native();
}
/// Get the data folder
@@ -258,26 +249,6 @@ namespace Path
return str;
}
- //! Get the root folder (in source control or other writable assets) where you should save root data.
- AZStd::string GetEditingRootFolder()
- {
- const char* resultValue = nullptr;
- EBUS_EVENT_RESULT(resultValue, AzToolsFramework::AssetSystemRequestBus, GetAbsoluteDevRootFolderPath);
-
- if (!resultValue)
- {
- if ((gEnv) && (gEnv->pFileIO))
- {
- resultValue = gEnv->pFileIO->GetAlias("@devassets@");
- }
- }
- if (!resultValue)
- {
- resultValue = ".";
- }
- return resultValue;
- }
-
AZStd::string MakeModPathFromGamePath(const char* relGamePath)
{
@@ -335,165 +306,60 @@ namespace Path
return "";
}
- bool relPathfound = false;
+ bool relPathFound = false;
AZStd::string relativePath;
AZStd::string fullAssetPath(fullPath.toUtf8().data());
- EBUS_EVENT_RESULT(relPathfound, AzToolsFramework::AssetSystemRequestBus, GetRelativeProductPathFromFullSourceOrProductPath, fullAssetPath, relativePath);
+ EBUS_EVENT_RESULT(relPathFound, AzToolsFramework::AssetSystemRequestBus, GetRelativeProductPathFromFullSourceOrProductPath, fullAssetPath, relativePath);
- if (relPathfound)
+ if (relPathFound)
{
// do not normalize this path, it will already be an appropriate asset ID.
return CaselessPaths(relativePath.c_str());
}
- char rootpath[_MAX_PATH] = { 0 };
- azstrcpy(rootpath, _MAX_PATH, Path::GetEditingRootFolder().c_str());
-
- if (bRelativeToGameFolder)
- {
- azstrcpy(rootpath, _MAX_PATH, Path::GetEditingGameDataFolder().c_str());
- }
-
- QString rootPathNormalized(rootpath);
- QString srcPathNormalized(fullPath);
-
-#if defined(AZ_PLATFORM_WINDOWS)
- // avoid confusing PathRelativePathTo
- rootPathNormalized.replace('/', '\\');
- srcPathNormalized.replace('/', '\\');
-#endif
+ AZ::IO::FixedMaxPath rootPath = bRelativeToGameFolder ? AZ::Utils::GetProjectPath() : AZ::Utils::GetEnginePath();
+ AZ::IO::FixedMaxPath resolvedFullPath;
+ AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(resolvedFullPath, fullPath.toUtf8().constData());
// Create relative path
- char resolvedSrcPath[AZ_MAX_PATH_LEN] = { 0 };
- AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(srcPathNormalized.toUtf8().data(), resolvedSrcPath, AZ_MAX_PATH_LEN);
- QByteArray path = QDir(rootPathNormalized).relativeFilePath(resolvedSrcPath).toUtf8();
- if (path.isEmpty())
- {
- return fullPath;
- }
- // The following code is required because the windows PathRelativePathTo function will always return "./SomePath" instead of just "SomePath"
- // Only remove single dot (.) and slash parts of a path, never the double dot (..)
- const char* pBuffer = path.data();
- bool bHasDot = false;
- while (*pBuffer && pBuffer != path.end())
- {
- switch (*pBuffer)
- {
- case '.':
- if (bHasDot)
- {
- // Found a double dot, rewind and stop removing
- pBuffer--;
- break;
- }
- // Fall through intended
- case '/':
- case '\\':
- bHasDot = (*pBuffer == '.');
- pBuffer++;
- continue;
- }
- break;
- }
-
- QString relPath = pBuffer;
- return CaselessPaths(relPath);
+ return CaselessPaths(resolvedFullPath.LexicallyProximate(rootPath).MakePreferred().c_str());
}
QString GamePathToFullPath(const QString& path)
{
using namespace AzToolsFramework;
- AZ_Warning("GamePathToFullPath", path.size() <= AZ_MAX_PATH_LEN, "Path exceeds maximum path length of %d", AZ_MAX_PATH_LEN);
- if ((gEnv) && (gEnv->pFileIO) && gEnv->pCryPak && path.size() <= AZ_MAX_PATH_LEN)
+ AZ_Warning("GamePathToFullPath", path.size() <= AZ::IO::MaxPathLength, "Path exceeds maximum path length of %zu", AZ::IO::MaxPathLength);
+ if (path.size() <= AZ::IO::MaxPathLength)
{
// first, adjust the file name for mods:
- bool fullPathfound = false;
- AZStd::string assetFullPath;
- AZStd::string adjustedFilePath = path.toUtf8().data();
- AssetSystemRequestBus::BroadcastResult(fullPathfound, &AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath, adjustedFilePath, assetFullPath);
- if (fullPathfound)
+ bool fullPathFound = false;
+ AZ::IO::Path assetFullPath;
+ AZ::IO::Path adjustedFilePath = path.toUtf8().constData();
+ AssetSystemRequestBus::BroadcastResult(fullPathFound, &AssetSystemRequestBus::Events::GetFullSourcePathFromRelativeProductPath,
+ adjustedFilePath.Native(), assetFullPath.Native());
+ if (fullPathFound)
{
- //if the bus message succeeds than normalize and lowercase the path
- AzFramework::StringFunc::Path::Normalize(assetFullPath);
- return assetFullPath.c_str();
+ //if the bus message succeeds than normalize
+ return assetFullPath.LexicallyNormal().c_str();
}
- // if the bus message didn't succeed, 'guess' the source assets:
+ // if the bus message didn't succeed, check if he path exist as a resolved path
else
{
// Not all systems have been converted to use local paths. Some editor files save XML files directly, and a full or correctly aliased path is already passed in.
// If the path passed in exists already, then return the resolved filepath
if (AZ::IO::FileIOBase::GetDirectInstance()->Exists(adjustedFilePath.c_str()))
{
- char resolvedPath[AZ_MAX_PATH_LEN + PathUtil::maxAliasLength] = { 0 };
- AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(adjustedFilePath.c_str(), resolvedPath, AZ_MAX_PATH_LEN + PathUtil::maxAliasLength);
- return QString::fromUtf8(resolvedPath);
+ AZ::IO::FixedMaxPath resolvedPath;
+ AZ::IO::FileIOBase::GetDirectInstance()->ResolvePath(resolvedPath, adjustedFilePath);
+ return QString::fromUtf8(resolvedPath.c_str(), static_cast(resolvedPath.Native().size()));
}
- // if we get here it means that the Asset Processor does not know about this file. most of the time we should never get here
- // the rest of this code just does a bunch of heuristic guesses in case of missing files or if the user has hand-edited
- // the asset cache by moving files in via some other means or external process.
- if (adjustedFilePath[0] != '@')
- {
- const char* prefix = (adjustedFilePath[0] == '/' || adjustedFilePath[0] == '\\') ? "@devassets@" : "@devassets@/";
- adjustedFilePath = prefix + adjustedFilePath;
- }
-
- char szAdjustedFile[AZ_MAX_PATH_LEN + PathUtil::maxAliasLength] = { 0 };
- gEnv->pFileIO->ResolvePath(adjustedFilePath.c_str(), szAdjustedFile, AZ_ARRAY_SIZE(szAdjustedFile));
-
- if ((azstrnicmp(szAdjustedFile, "@devassets@", 11) == 0) && ((szAdjustedFile[11] == '/') || (szAdjustedFile[11] == '\\')))
- {
- if (!gEnv->pCryPak->IsFileExist(szAdjustedFile))
- {
- AZStd::string newName(szAdjustedFile);
- AzFramework::StringFunc::Replace(newName, "@devassets@", "@devroot@/engine", false);
-
- if (gEnv->pCryPak->IsFileExist(newName.c_str()))
- {
- azstrcpy(szAdjustedFile, AZ_ARRAY_SIZE(szAdjustedFile), newName.c_str());
- }
- else
- {
- // getting tricky here, try @devroot@ alone, in case its 'editor'
- AzFramework::StringFunc::Replace(newName, "@devassets@", "@devroot@", false);
- if (gEnv->pCryPak->IsFileExist(szAdjustedFile))
- {
- azstrcpy(szAdjustedFile, AZ_ARRAY_SIZE(szAdjustedFile), newName.c_str());
- }
- // give up, best guess is just @devassets@
- }
- }
- }
-
- // we should very rarely actually get to this point in the code.
-
- // szAdjustedFile may contain an alias at this point. (@assets@/blah.whatever)
- // there is a case in which the loose asset exists only within a pak file for some reason
- // this is not recommended but it is possible.in that case, we want to return the original szAdjustedFile
- // without touching it or resolving it so that crypak can open it successfully.
- char adjustedPath[AZ_MAX_PATH_LEN + PathUtil::maxAliasLength] = { 0 };
- if (gEnv->pFileIO->ResolvePath(szAdjustedFile, adjustedPath, AZ_MAX_PATH_LEN + PathUtil::maxAliasLength)) // resolve to full path
- {
- if ((gEnv->pCryPak->IsFileExist(adjustedPath)) || (!gEnv->pCryPak->IsFileExist(szAdjustedFile)))
- {
- // note that if we get here, then EITHER
- // the file exists as a loose asset in the actual adjusted path
- // OR the file does not exist in the original passed-in aliased name (like '@assets@/whatever')
- // in which case we may as well just resolve the path to a full path and return it.
- assetFullPath = adjustedPath;
- AzFramework::StringFunc::Path::Normalize(assetFullPath);
- azstrcpy(szAdjustedFile, AZ_MAX_PATH_LEN + PathUtil::maxAliasLength, assetFullPath.c_str());
- }
- // if the above case succeeded then it means that the file does NOT exist loose
- // but DOES exist in a pak, in which case we leave szAdjustedFile with the alias on the front of it, meaning
- // fopens via crypak will actually succeed.
- }
- return szAdjustedFile;
+ return path;
}
}
else
{
- return "";
+ return QString{};
}
}
diff --git a/Code/Editor/Util/PathUtil.h b/Code/Editor/Util/PathUtil.h
index 2c49031155..163d74e358 100644
--- a/Code/Editor/Util/PathUtil.h
+++ b/Code/Editor/Util/PathUtil.h
@@ -44,9 +44,6 @@ namespace Path
//! always returns a full path
EDITOR_CORE_API AZStd::string GetEditingGameDataFolder();
- //! Get the root folder (in source control or other writable assets) where you should save root data.
- EDITOR_CORE_API AZStd::string GetEditingRootFolder();
-
//! Set the current mod NAME for editing purposes. After doing this the above functions will take this into account
//! name only, please!
EDITOR_CORE_API void SetModName(const char* input);
@@ -69,93 +66,6 @@ namespace Path
return strPath;
}
- //! Split full file name to path and filename
- //! @param filepath [IN] Full file name inclusing path.
- //! @param path [OUT] Extracted file path.
- //! @param file [OUT] Extracted file (with extension).
- inline void Split(const QString& filepath, QString& path, QString& file)
- {
- char path_buffer[_MAX_PATH];
- char drive[_MAX_DRIVE];
- char dir[_MAX_DIR];
- char fname[_MAX_FNAME];
- char ext[_MAX_EXT];
-#ifdef AZ_COMPILER_MSVC
- _splitpath_s(filepath.toUtf8().data(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), fname, AZ_ARRAY_SIZE(fname), ext, AZ_ARRAY_SIZE(ext));
- _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0);
- path = path_buffer;
- _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), 0, 0, fname, ext);
-#else
- _splitpath(filepath.toUtf8().data(), drive, dir, fname, ext);
- _makepath(path_buffer, drive, dir, 0, 0);
- path = path_buffer;
- _makepath(path_buffer, 0, 0, fname, ext);
-#endif
- file = path_buffer;
- }
- inline void Split(const AZStd::string& filepath, AZStd::string& path, AZStd::string& file)
- {
- char path_buffer[_MAX_PATH];
- char drive[_MAX_DRIVE];
- char dir[_MAX_DIR];
- char fname[_MAX_FNAME];
- char ext[_MAX_EXT];
-#ifdef AZ_COMPILER_MSVC
- _splitpath_s(filepath.c_str(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), 0, 0, 0, 0);
- _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0);
- path = path_buffer;
- _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), 0, 0, fname, ext);
-#else
- _splitpath(filepath.c_str(), drive, dir, fname, ext);
- _makepath(path_buffer, drive, dir, 0, 0);
- path = path_buffer;
- _makepath(path_buffer, 0, 0, fname, ext);
-#endif
- file = path_buffer;
- }
-
- //! Split full file name to path and filename
- //! @param filepath [IN] Full file name inclusing path.
- //! @param path [OUT] Extracted file path.
- //! @param filename [OUT] Extracted file (without extension).
- //! @param ext [OUT] Extracted files extension.
- inline void Split(const QString& filepath, QString& path, QString& filename, QString& fext)
- {
- char path_buffer[_MAX_PATH];
- char drive[_MAX_DRIVE];
- char dir[_MAX_DIR];
- char fname[_MAX_FNAME];
- char ext[_MAX_EXT];
-#ifdef AZ_COMPILER_MSVC
- _splitpath_s(filepath.toUtf8().data(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), fname, AZ_ARRAY_SIZE(fname), ext, AZ_ARRAY_SIZE(ext));
- _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0);
-#else
- _splitpath(filepath.toUtf8().data(), drive, dir, fname, ext);
- _makepath(path_buffer, drive, dir, 0, 0);
-#endif
- path = path_buffer;
- filename = fname;
- fext = ext;
- }
- inline void Split(const AZStd::string& filepath, AZStd::string& path, AZStd::string& filename, AZStd::string& fext)
- {
- char path_buffer[_MAX_PATH];
- char drive[_MAX_DRIVE];
- char dir[_MAX_DIR];
- char fname[_MAX_FNAME];
- char ext[_MAX_EXT];
-#ifdef AZ_COMPILER_MSVC
- _splitpath_s(filepath.c_str(), drive, AZ_ARRAY_SIZE(drive), dir, AZ_ARRAY_SIZE(dir), fname, AZ_ARRAY_SIZE(fname), ext, AZ_ARRAY_SIZE(ext));
- _makepath_s(path_buffer, AZ_ARRAY_SIZE(path_buffer), drive, dir, 0, 0);
-#else
- _splitpath(filepath.c_str(), drive, dir, fname, ext);
- _makepath(path_buffer, drive, dir, 0, 0);
-#endif
- path = path_buffer;
- filename = fname;
- fext = ext;
- }
-
//! Split path into segments
//! @param filepath [IN] path
inline QStringList SplitIntoSegments(const QString& path)
diff --git a/Code/Editor/Viewport.cpp b/Code/Editor/Viewport.cpp
index 2d41538d92..5b4f4a4df3 100644
--- a/Code/Editor/Viewport.cpp
+++ b/Code/Editor/Viewport.cpp
@@ -173,8 +173,6 @@ QtViewport::QtViewport(QWidget* parent)
m_bAdvancedSelectMode = false;
- m_pVisibleObjectsCache = new CBaseObjectsCache;
-
m_constructionPlane.SetPlane(Vec3_OneZ, Vec3_Zero);
m_constructionPlaneAxisX = Vec3_Zero;
m_constructionPlaneAxisY = Vec3_Zero;
@@ -204,8 +202,6 @@ QtViewport::QtViewport(QWidget* parent)
//////////////////////////////////////////////////////////////////////////
QtViewport::~QtViewport()
{
- delete m_pVisibleObjectsCache;
-
GetIEditor()->GetViewManager()->UnregisterViewport(this);
}
@@ -376,11 +372,6 @@ void QtViewport::OnDeactivate()
void QtViewport::ResetContent()
{
m_pMouseOverObject = nullptr;
-
- // Need to clear visual object cache.
- // Right after loading new level, some code(e.g. OnMouseMove) access invalid
- // previous level object before cache updated.
- GetVisibleObjectsCache()->ClearObjects();
}
//////////////////////////////////////////////////////////////////////////
@@ -398,11 +389,8 @@ void QtViewport::Update()
m_viewportUi.Update();
m_bAdvancedSelectMode = false;
- bool bSpaceClick = false;
- {
- bSpaceClick = CheckVirtualKey(Qt::Key_Space) & !CheckVirtualKey(Qt::Key_Shift) /*& !CheckVirtualKey(Qt::Key_Control)*/;
- }
- if (bSpaceClick && hasFocus())
+
+ if (CheckVirtualKey(Qt::Key_Space) && !CheckVirtualKey(Qt::Key_Shift) && hasFocus())
{
m_bAdvancedSelectMode = true;
}
diff --git a/Code/Editor/Viewport.h b/Code/Editor/Viewport.h
index 60c1306420..7f8ccc4c4f 100644
--- a/Code/Editor/Viewport.h
+++ b/Code/Editor/Viewport.h
@@ -157,7 +157,7 @@ public:
virtual Vec3 SnapToGrid(const Vec3& vec) = 0;
- //! Get selection procision tolerance.
+ //! Get selection precision tolerance.
virtual float GetSelectionTolerance() const = 0;
//////////////////////////////////////////////////////////////////////////
@@ -491,10 +491,6 @@ public:
void ResetCursor() override;
void SetSupplementaryCursorStr(const QString& str) override;
- //////////////////////////////////////////////////////////////////////////
- // Return visble objects cache.
- CBaseObjectsCache* GetVisibleObjectsCache() override { return m_pVisibleObjectsCache; };
-
void RegisterRenderListener(IRenderListener* piListener) override;
bool UnregisterRenderListener(IRenderListener* piListener) override;
bool IsRenderListenerRegistered(IRenderListener* piListener) override;
@@ -612,8 +608,6 @@ protected:
int m_nLastUpdateFrame;
int m_nLastMouseMoveFrame;
- CBaseObjectsCache* m_pVisibleObjectsCache;
-
QRect m_rcClient;
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
diff --git a/Code/Editor/ViewportTitleDlg.cpp b/Code/Editor/ViewportTitleDlg.cpp
index 65d6de8944..75d16e9a40 100644
--- a/Code/Editor/ViewportTitleDlg.cpp
+++ b/Code/Editor/ViewportTitleDlg.cpp
@@ -15,6 +15,7 @@
#include "ViewportTitleDlg.h"
// Qt
+#include
#include
#include
@@ -36,8 +37,10 @@
#include "MathConversion.h"
#include "EditorViewportSettings.h"
-#include
+#include
#include
+#include
+#include
#include
#include
@@ -145,6 +148,11 @@ CViewportTitleDlg::~CViewportTitleDlg()
AZ::VR::VREventBus::Handler::BusDisconnect();
GetISystem()->GetISystemEventDispatcher()->RemoveListener(this);
GetIEditor()->UnregisterNotifyListener(this);
+
+ if (m_prefabViewportFocusPathHandler)
+ {
+ delete m_prefabViewportFocusPathHandler;
+ }
}
void CViewportTitleDlg::SetupCameraDropdownMenu()
@@ -292,8 +300,6 @@ void CViewportTitleDlg::SetViewPane(CLayoutViewPane* pViewPane)
//////////////////////////////////////////////////////////////////////////
void CViewportTitleDlg::OnInitDialog()
{
- m_ui->m_titleBtn->setText(m_title);
-
// Add a child parented to us that listens for r_displayInfo changes.
auto displayInfoHelper = new CViewportTitleDlgDisplayInfoHelper(this);
connect(displayInfoHelper, &CViewportTitleDlgDisplayInfoHelper::ViewportInfoStatusUpdated, this, &CViewportTitleDlg::UpdateDisplayInfo);
@@ -314,13 +320,28 @@ void CViewportTitleDlg::OnInitDialog()
m_cameraSpeed->setFixedWidth(width);
+ bool isPrefabSystemEnabled = false;
+ AzFramework::ApplicationRequests::Bus::BroadcastResult(isPrefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
+
+ if (isPrefabSystemEnabled)
+ {
+ m_prefabViewportFocusPathHandler = new AzToolsFramework::Prefab::PrefabViewportFocusPathHandler();
+ m_prefabViewportFocusPathHandler->Initialize(m_ui->m_prefabFocusPath, m_ui->m_prefabFocusBackButton);
+ }
+ else
+ {
+ m_ui->m_prefabFocusPath->setEnabled(false);
+ m_ui->m_prefabFocusBackButton->setEnabled(false);
+ m_ui->m_prefabFocusPath->hide();
+ m_ui->m_prefabFocusBackButton->hide();
+ }
+
}
//////////////////////////////////////////////////////////////////////////
void CViewportTitleDlg::SetTitle(const QString& title)
{
m_title = title;
- m_ui->m_titleBtn->setText(m_title);
}
//////////////////////////////////////////////////////////////////////////
diff --git a/Code/Editor/ViewportTitleDlg.h b/Code/Editor/ViewportTitleDlg.h
index 4a2a454907..6996fe7750 100644
--- a/Code/Editor/ViewportTitleDlg.h
+++ b/Code/Editor/ViewportTitleDlg.h
@@ -19,6 +19,7 @@
#include
#include
+#include
#include
#include
@@ -176,6 +177,8 @@ protected:
QWidgetAction* m_gridSizeActionWidget = nullptr;
QWidgetAction* m_angleSizeActionWidget = nullptr;
+ AzToolsFramework::Prefab::PrefabViewportFocusPathHandler* m_prefabViewportFocusPathHandler = nullptr;
+
QScopedPointer m_ui;
};
diff --git a/Code/Editor/ViewportTitleDlg.ui b/Code/Editor/ViewportTitleDlg.ui
index f0679dd2a1..7ba6361cf9 100644
--- a/Code/Editor/ViewportTitleDlg.ui
+++ b/Code/Editor/ViewportTitleDlg.ui
@@ -28,7 +28,7 @@
29
-
+
10
@@ -42,102 +42,112 @@
0
-
-
+
+
+ Up one level
+
+
+
+ :/Breadcrumb/img/UI20/Breadcrumb/arrow_left-default.svg:/Breadcrumb/img/UI20/Breadcrumb/arrow_left-default.svg
+
+
+
+ -
+
0
0
-
- Qt::NoContextMenu
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
-
- Static
+
+
+ -
+
+
+ Camera settings
-
- 11
+
+
+ :/Menu/camera.svg:/Menu/camera.svg
-
-
-
-
- :/Menu/camera.svg:/Menu/camera.svg
-
-
-
- Camera settings
-
-
-
- -
-
-
- Debug information
-
-
-
- :/Menu/debug.svg:/Menu/debug.svg
-
-
-
- true
-
-
-
+
+
+ Debug information
+
+
+
+ :/Menu/debug.svg:/Menu/debug.svg
+
+
+ true
+
+
+
-
-
-
- Toggle viewport helpers
-
-
-
- :/Menu/helpers.svg:/Menu/helpers.svg
-
-
-
- true
-
-
-
+
+
+ Toggle viewport helpers
+
+
+
+ :/Menu/helpers.svg:/Menu/helpers.svg
+
+
+ true
+
+
+
-
-
-
- Viewport resolution
-
-
-
- :/Menu/resolution.svg:/Menu/resolution.svg
-
-
-
+
+
+ Viewport resolution
+
+
+
+ :/Menu/resolution.svg:/Menu/resolution.svg
+
+
-
-
-
- Other settings
-
-
-
- :/Menu/menu.svg:/Menu/menu.svg
-
-
-
+
+
+ Other settings
+
+
+
+ :/Menu/menu.svg:/Menu/menu.svg
+
+
- AzQtComponents::ButtonDivider
+ AzQtComponents::BreadCrumbs
QWidget
- AzQtComponents/Components/ButtonDivider.h
+ AzQtComponents/Components/Widgets/BreadCrumbs.h
1
-
-
-
-
+
+
+
+
diff --git a/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h b/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h
index 33fc93c0f5..6b07d12e9c 100644
--- a/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h
+++ b/Code/Framework/AtomCore/AtomCore/Instance/InstanceData.h
@@ -89,6 +89,9 @@ namespace AZ
// Tracks the asset type used to create the instance.
AssetType m_assetType;
+
+ // Boolean to indicate if the instance has been orphaned from the instance database
+ bool m_isOrphaned = false;
};
/// @cond EXCLUDE_DOCS
diff --git a/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h b/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h
index ac97af3629..4b4ad572c2 100644
--- a/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h
+++ b/Code/Framework/AtomCore/AtomCore/Instance/InstanceDatabase.h
@@ -203,6 +203,16 @@ namespace AZ
//! Calls FindOrCreate using a random InstanceId
Data::Instance Create(const Asset& asset, const AZStd::any* param = nullptr);
+ /**
+ * Removes the instance data from the database. Does not release it.
+ * References to existing instances will remain valid, but new calls to Create/FindOrCreate will create a new instance
+ * This function is temporary, to provide functionality needed for Model hot-reloading, but will be removed
+ * once the Model class does not need it anymore.
+ *
+ * @param id The id of the instance to remove
+ */
+ void TEMPOrphan(const InstanceId& id);
+
private:
InstanceDatabase(const AssetType& assetType);
~InstanceDatabase();
@@ -356,6 +366,20 @@ namespace AZ
return FindOrCreate(Data::InstanceId::CreateRandom(), asset, param);
}
+ template
+ void InstanceDatabase::TEMPOrphan(const InstanceId& id)
+ {
+ AZStd::scoped_lock lock(m_databaseMutex);
+ // Check if the instance is still in the database, in case it was orphaned twice
+ auto instanceItr = m_database.find(id);
+ if (instanceItr != m_database.end())
+ {
+ // Mark the instance as orphaned, and remove it from the database
+ instanceItr->second->m_isOrphaned = true;
+ m_database.erase(instanceItr);
+ }
+ }
+
template
void InstanceDatabase::ReleaseInstance(InstanceData* instance, const InstanceId& instanceId)
{
@@ -374,6 +398,12 @@ namespace AZ
m_database.erase(instance->GetId());
m_instanceHandler.m_deleteFunction(static_cast(instance));
}
+ else if (instance->m_isOrphaned && instance->m_useCount.compare_exchange_strong(expectedRefCount, -1))
+ {
+ // If the instance was orphaned, it has already been removed from the database,
+ // but still needs to be deleted when the refcount drops to 0
+ m_instanceHandler.m_deleteFunction(static_cast(instance));
+ }
}
template
diff --git a/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp b/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp
index 5d1edc5a09..6a5c65ac7a 100644
--- a/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp
+++ b/Code/Framework/AtomCore/Tests/InstanceDatabase.cpp
@@ -181,7 +181,76 @@ namespace UnitTest
EXPECT_EQ(instance, instance3);
}
- void ParallelInstanceCreateHelper(size_t threadCountMax, size_t assetIdCount, size_t durationSeconds)
+ TEST_F(InstanceDatabaseTest, InstanceOrphan)
+ {
+ auto& assetManager = AssetManager::Instance();
+ auto& instanceDatabase = InstanceDatabase::Instance();
+
+ Asset someAsset = assetManager.CreateAsset(s_assetId0, AZ::Data::AssetLoadBehavior::Default);
+
+ Instance orphanedInstance = instanceDatabase.FindOrCreate(s_instanceId0, someAsset);
+ EXPECT_NE(orphanedInstance, nullptr);
+
+ instanceDatabase.TEMPOrphan(s_instanceId0);
+ // After orphan, the instance should not be found in the database, but it should still be valid
+ EXPECT_EQ(instanceDatabase.Find(s_instanceId0), nullptr);
+ EXPECT_NE(orphanedInstance, nullptr);
+
+ instanceDatabase.TEMPOrphan(s_instanceId0);
+ // Orphaning twice should be a no-op
+ EXPECT_EQ(instanceDatabase.Find(s_instanceId0), nullptr);
+ EXPECT_NE(orphanedInstance, nullptr);
+
+ Instance instance2 = instanceDatabase.FindOrCreate(s_instanceId0, someAsset);
+ // Creating another instance with the same id should return a different instance than the one that was orphaned
+ EXPECT_NE(orphanedInstance, instance2);
+ }
+
+ enum class ParallelInstanceTestCases
+ {
+ Create,
+ CreateAndDeferRemoval,
+ CreateAndOrphan,
+ CreateDeferRemovalAndOrphan
+ };
+
+ enum class ParralleInstanceCurrentAction
+ {
+ Create,
+ DeferredRemoval,
+ Orphan
+ };
+
+ ParralleInstanceCurrentAction ParallelInstanceGetCurrentAction(ParallelInstanceTestCases testCase)
+ {
+ switch (testCase)
+ {
+ case ParallelInstanceTestCases::CreateAndDeferRemoval:
+ switch (rand() % 2)
+ {
+ case 0: return ParralleInstanceCurrentAction::Create;
+ case 1: return ParralleInstanceCurrentAction::DeferredRemoval;
+ }
+ case ParallelInstanceTestCases::CreateAndOrphan:
+ switch (rand() % 2)
+ {
+ case 0: return ParralleInstanceCurrentAction::Create;
+ case 1: return ParralleInstanceCurrentAction::Orphan;
+ }
+ case ParallelInstanceTestCases::CreateDeferRemovalAndOrphan:
+ switch (rand() % 3)
+ {
+ case 0: return ParralleInstanceCurrentAction::Create;
+ case 1: return ParralleInstanceCurrentAction::DeferredRemoval;
+ case 2: return ParralleInstanceCurrentAction::Orphan;
+ }
+ case ParallelInstanceTestCases::Create:
+ default:
+ return ParralleInstanceCurrentAction::Create;
+ }
+ }
+
+ void ParallelInstanceCreateHelper(size_t threadCountMax, size_t assetIdCount, float durationSeconds, ParallelInstanceTestCases testCase)
{
printf("Testing threads=%zu assetIds=%zu ... ", threadCountMax, assetIdCount);
@@ -192,6 +261,7 @@ namespace UnitTest
auto& instanceManager = InstanceDatabase::Instance();
AZStd::vector guids;
+ AZStd::vector> instances;
AZStd::vector> assets;
for (size_t i = 0; i < assetIdCount; ++i)
@@ -199,6 +269,7 @@ namespace UnitTest
Uuid guid = Uuid::CreateRandom();
guids.emplace_back(guid);
+ instances.emplace_back(nullptr);
// Pre-create asset so we don't attempt to load it from the catalog.
assets.emplace_back(assetManager.CreateAsset(guid, AZ::Data::AssetLoadBehavior::Default));
@@ -206,6 +277,7 @@ namespace UnitTest
AZStd::vector threads;
AZStd::mutex mutex;
+ AZStd::mutex referenceTableMutex;
AZStd::atomic threadCount((int)threadCountMax);
AZStd::condition_variable cv;
AZStd::atomic_bool keepDispatching(true);
@@ -225,11 +297,15 @@ namespace UnitTest
for (size_t i = 0; i < threadCountMax; ++i)
{
threads.emplace_back(
- [&instanceManager, &threadCount, &cv, &guids, &assets, &durationSeconds]()
+ [&instanceManager, &threadCount, &cv, &guids, &instances, &assets, &durationSeconds, &testCase, &referenceTableMutex]()
{
AZ::Debug::Timer timer;
timer.Stamp();
+ bool deferRemoval = testCase == ParallelInstanceTestCases::CreateAndDeferRemoval ||
+ testCase == ParallelInstanceTestCases::CreateDeferRemovalAndOrphan
+ ? true : false;
+
while (timer.GetDeltaTimeInSeconds() < durationSeconds)
{
const size_t index = rand() % guids.size();
@@ -237,11 +313,36 @@ namespace UnitTest
const InstanceId instanceId{ uuid };
const AssetId assetId{ uuid };
- Instance instance =
- instanceManager.FindOrCreate(instanceId, Asset(assetId, azrtti_typeid()));
- EXPECT_NE(instance, nullptr);
- EXPECT_EQ(instance->GetId(), instanceId);
- EXPECT_EQ(instance->m_asset, assets[index]);
+ ParralleInstanceCurrentAction currentAction = ParallelInstanceGetCurrentAction(testCase);
+
+ if (currentAction == ParralleInstanceCurrentAction::Orphan)
+ {
+ // Orphan the instance, but don't decrease its refcount
+ instanceManager.TEMPOrphan(instanceId);
+ }
+ else if (currentAction == ParralleInstanceCurrentAction::DeferredRemoval)
+ {
+ // Drop the refcount to zero so the instance will be released
+ referenceTableMutex.lock();
+ instances[index] = nullptr;
+ referenceTableMutex.unlock();
+ }
+ else
+ {
+ // Otherwise, add a new instance
+ Instance instance = instanceManager.FindOrCreate(instanceId, assets[index]);
+ EXPECT_NE(instance, nullptr);
+ EXPECT_EQ(instance->GetId(), instanceId);
+ EXPECT_EQ(instance->m_asset, assets[index]);
+
+ if (deferRemoval)
+ {
+ // Keep a reference to the instance alive so it can be removed later
+ referenceTableMutex.lock();
+ instances[index] = instance;
+ referenceTableMutex.unlock();
+ }
+ }
}
threadCount--;
@@ -254,10 +355,12 @@ namespace UnitTest
// Used to detect a deadlock. If we wait for more than 10 seconds, it's likely a deadlock has occurred
while (threadCount > 0 && !timedOut)
{
+ size_t durationSecondsRoundedUp = static_cast(std::ceil(durationSeconds));
+
AZStd::unique_lock lock(mutex);
timedOut =
(AZStd::cv_status::timeout ==
- cv.wait_until(lock, AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(durationSeconds * 2)));
+ cv.wait_until(lock, AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(durationSecondsRoundedUp * 2)));
}
EXPECT_TRUE(threadCount == 0) << "One or more threads appear to be deadlocked at " << timer.GetDeltaTimeInSeconds() << " seconds";
@@ -273,11 +376,11 @@ namespace UnitTest
printf("Took %f seconds\n", timer.GetDeltaTimeInSeconds());
}
- TEST_F(InstanceDatabaseTest, ParallelInstanceCreate)
+ void ParallelCreateTest(ParallelInstanceTestCases testCase)
{
// This is the original test scenario from when InstanceDatabase was first implemented
// threads, AssetIds, seconds
- ParallelInstanceCreateHelper(8, 100, 5);
+ ParallelInstanceCreateHelper(8, 100, 5, testCase);
// This value is checked in as 1 so this test doesn't take too much time, but can be increased locally to soak the test.
const size_t attempts = 1;
@@ -289,11 +392,11 @@ namespace UnitTest
// The idea behind this series of tests is that there are two threads sharing one Instance, and both threads try to
// create or release that instance at the same time.
// At the time, this set of scenarios has something like a 10% failure rate.
- const size_t duration = 2;
+ const float duration = 2.0f;
// threads, AssetIds, seconds
- ParallelInstanceCreateHelper(2, 1, duration);
- ParallelInstanceCreateHelper(4, 1, duration);
- ParallelInstanceCreateHelper(8, 1, duration);
+ ParallelInstanceCreateHelper(2, 1, duration, testCase);
+ ParallelInstanceCreateHelper(4, 1, duration, testCase);
+ ParallelInstanceCreateHelper(8, 1, duration, testCase);
}
for (size_t i = 0; i < attempts; ++i)
@@ -301,19 +404,39 @@ namespace UnitTest
printf("Attempt %zu of %zu... \n", i, attempts);
// Here we try a bunch of different threadCount:assetCount ratios to be thorough
- const size_t duration = 2;
+ const float duration = 2.0f;
// threads, AssetIds, seconds
- ParallelInstanceCreateHelper(2, 1, duration);
- ParallelInstanceCreateHelper(4, 1, duration);
- ParallelInstanceCreateHelper(4, 2, duration);
- ParallelInstanceCreateHelper(4, 4, duration);
- ParallelInstanceCreateHelper(8, 1, duration);
- ParallelInstanceCreateHelper(8, 2, duration);
- ParallelInstanceCreateHelper(8, 3, duration);
- ParallelInstanceCreateHelper(8, 4, duration);
+ ParallelInstanceCreateHelper(2, 1, duration, testCase);
+ ParallelInstanceCreateHelper(4, 1, duration, testCase);
+ ParallelInstanceCreateHelper(4, 2, duration, testCase);
+ ParallelInstanceCreateHelper(4, 4, duration, testCase);
+ ParallelInstanceCreateHelper(8, 1, duration, testCase);
+ ParallelInstanceCreateHelper(8, 2, duration, testCase);
+ ParallelInstanceCreateHelper(8, 3, duration, testCase);
+ ParallelInstanceCreateHelper(8, 4, duration, testCase);
}
}
+ TEST_F(InstanceDatabaseTest, ParallelInstanceCreate)
+ {
+ ParallelCreateTest(ParallelInstanceTestCases::Create);
+ }
+
+ TEST_F(InstanceDatabaseTest, ParallelInstanceCreateAndDeferRemoval)
+ {
+ ParallelCreateTest(ParallelInstanceTestCases::CreateAndDeferRemoval);
+ }
+
+ TEST_F(InstanceDatabaseTest, ParallelInstanceCreateAndOrphan)
+ {
+ ParallelCreateTest(ParallelInstanceTestCases::CreateAndOrphan);
+ }
+
+ TEST_F(InstanceDatabaseTest, ParallelInstanceCreateDeferRemovalAndOrphan)
+ {
+ ParallelCreateTest(ParallelInstanceTestCases::CreateDeferRemovalAndOrphan);
+ }
+
TEST_F(InstanceDatabaseTest, InstanceCreateNoDatabase)
{
bool m_deleted = false;
diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp
index 98182a9568..06bb0b0cac 100644
--- a/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp
+++ b/Code/Framework/AzCore/AzCore/Asset/AssetManager.cpp
@@ -340,6 +340,14 @@ namespace AZ
// (Load jobs will attempt to reuse blocked threads before spinning off new job threads)
ProcessLoadJob();
}
+
+ // Pump the AssetBus function queue once more after the load has completed in case additional
+ // functions have been queued between the last call to DispatchEvents and the completion
+ // of the current load job
+ if (m_shouldDispatchEvents)
+ {
+ AssetManager::Instance().DispatchEvents();
+ }
}
void Finish()
@@ -543,8 +551,6 @@ namespace AZ
{
PrepareShutDown();
- DispatchEvents();
-
// Acquire the asset lock to make sure nobody else is trying to do anything fancy with assets
AZStd::scoped_lock assetLock(m_assetMutex);
@@ -567,7 +573,10 @@ namespace AZ
{
AZ_PROFILE_FUNCTION(AzCore);
AssetManagerNotificationBus::Broadcast(&AssetManagerNotificationBus::Events::OnAssetEventsDispatchBegin);
- AssetBus::ExecuteQueuedEvents();
+ while (AssetBus::QueuedEventCount())
+ {
+ AssetBus::ExecuteQueuedEvents();
+ }
AssetManagerNotificationBus::Broadcast(&AssetManagerNotificationBus::Events::OnAssetEventsDispatchEnd);
}
diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetManagerComponent.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetManagerComponent.cpp
index 93315c9c81..b40c36bc6b 100644
--- a/Code/Framework/AzCore/AzCore/Asset/AssetManagerComponent.cpp
+++ b/Code/Framework/AzCore/AzCore/Asset/AssetManagerComponent.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/Code/Framework/AzCore/AzCore/Asset/AssetSerializer.cpp b/Code/Framework/AzCore/AzCore/Asset/AssetSerializer.cpp
index ee594c585b..b5cc6c5df4 100644
--- a/Code/Framework/AzCore/AzCore/Asset/AssetSerializer.cpp
+++ b/Code/Framework/AzCore/AzCore/Asset/AssetSerializer.cpp
@@ -8,6 +8,7 @@
#include
#include
+#include
#include
namespace AZ {
diff --git a/Code/Framework/AzCore/AzCore/AzCoreModule.cpp b/Code/Framework/AzCore/AzCore/AzCoreModule.cpp
index c60ea1bd72..67123ed826 100644
--- a/Code/Framework/AzCore/AzCore/AzCoreModule.cpp
+++ b/Code/Framework/AzCore/AzCore/AzCoreModule.cpp
@@ -22,6 +22,8 @@
#include
#include
#include
+#include
+#include
namespace AZ
{
@@ -41,6 +43,11 @@ namespace AZ
TimeSystemComponent::CreateDescriptor(),
LoggerSystemComponent::CreateDescriptor(),
EventSchedulerSystemComponent::CreateDescriptor(),
+ TaskGraphSystemComponent::CreateDescriptor(),
+
+#if !defined(_RELEASE)
+ Statistics::StatisticalProfilerProxySystemComponent::CreateDescriptor(),
+#endif
#if !defined(AZCORE_EXCLUDE_LUA)
ScriptSystemComponent::CreateDescriptor(),
@@ -55,6 +62,11 @@ namespace AZ
azrtti_typeid(),
azrtti_typeid(),
azrtti_typeid(),
+ azrtti_typeid(),
+
+#if !defined(_RELEASE)
+ azrtti_typeid(),
+#endif
};
}
}
diff --git a/Code/Framework/AzCore/AzCore/Component/Component.h b/Code/Framework/AzCore/AzCore/Component/Component.h
index 3cbb9b5a86..677517d896 100644
--- a/Code/Framework/AzCore/AzCore/Component/Component.h
+++ b/Code/Framework/AzCore/AzCore/Component/Component.h
@@ -22,6 +22,7 @@
#include
#include // Used as the allocator for most components.
#include
+#include
namespace AZ
{
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
index a13f11c007..7e9accffd7 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.cpp
@@ -74,8 +74,6 @@
#include
#include
-AZ_CVAR(float, g_simulation_tick_rate, 0, nullptr, AZ::ConsoleFunctorFlags::Null, "The rate at which the game simulation tick loop runs, or 0 for as fast as possible");
-
static void PrintEntityName(const AZ::ConsoleCommandContainer& arguments)
{
if (arguments.empty())
@@ -1369,9 +1367,6 @@ namespace AZ
#endif
}
- //=========================================================================
- // Tick
- //=========================================================================
void ComponentApplication::Tick(float deltaOverride /*= -1.f*/)
{
{
@@ -1396,29 +1391,9 @@ namespace AZ
AZ_PROFILE_SCOPE(AzCore, "ComponentApplication::Tick:OnTick");
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
}
-
- // If tick rate limiting is on, ensure (1 / g_simulation_tick_rate) ms has elapsed since the last frame,
- // sleeping if there's still time remaining.
- if (g_simulation_tick_rate > 0.f)
- {
- now = AZStd::chrono::system_clock::now();
-
- // Work in microsecond durations here as that's the native measurement time for time_point
- constexpr float microsecondsPerSecond = 1000.f * 1000.f;
- const AZStd::chrono::microseconds timeBudgetPerTick(static_cast(microsecondsPerSecond / g_simulation_tick_rate));
- AZStd::chrono::microseconds timeUntilNextTick = m_currentTime + timeBudgetPerTick - now;
-
- if (timeUntilNextTick.count() > 0)
- {
- AZStd::this_thread::sleep_for(timeUntilNextTick);
- }
- }
}
}
- //=========================================================================
- // Tick
- //=========================================================================
void ComponentApplication::TickSystem()
{
AZ_PROFILE_SCOPE(System, "Component application tick");
@@ -1566,5 +1541,4 @@ namespace AZ
AZ::SettingsRegistryScriptUtils::ReflectSettingsRegistryToBehaviorContext(*behaviorContext);
}
}
-
} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
index bfc541ca09..8e95ff5fa3 100644
--- a/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
+++ b/Code/Framework/AzCore/AzCore/Component/ComponentApplication.h
@@ -5,6 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
+
#pragma once
#include
diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.cpp b/Code/Framework/AzCore/AzCore/Component/Entity.cpp
index 2e92873238..0fe201d448 100644
--- a/Code/Framework/AzCore/AzCore/Component/Entity.cpp
+++ b/Code/Framework/AzCore/AzCore/Component/Entity.cpp
@@ -649,6 +649,16 @@ namespace AZ
m_stateEvent.Signal(oldState, m_state);
}
+ void Entity::SetSpawnTicketId(u32 spawnTicketId)
+ {
+ m_spawnTicketId = spawnTicketId;
+ }
+
+ u32 Entity::GetSpawnTicketId() const
+ {
+ return m_spawnTicketId;
+ }
+
void Entity::OnNameChanged() const
{
EBUS_EVENT_ID(GetId(), EntityBus, OnEntityNameChanged, m_name);
diff --git a/Code/Framework/AzCore/AzCore/Component/Entity.h b/Code/Framework/AzCore/AzCore/Component/Entity.h
index 356533f268..c2bde375bb 100644
--- a/Code/Framework/AzCore/AzCore/Component/Entity.h
+++ b/Code/Framework/AzCore/AzCore/Component/Entity.h
@@ -133,6 +133,14 @@ namespace AZ
//! @return The state of the entity. For example, the entity has been initialized, the entity is active, and so on.
State GetState() const { return m_state; }
+ //! Gets the ticket id used to spawn the entity.
+ //! @return the ticket id used to spawn the entity. If entity is not spawned, the id will be 0.
+ u32 GetSpawnTicketId() const;
+
+ //! Sets the ticket id used to spawn the entity. The ticket id in the entity will remain 0 unless it's set using this function.
+ //! @param spawnTicketId the ticket id used to spawn the entity.
+ void SetSpawnTicketId(u32 spawnTicketId);
+
//! Connects an entity state event handler to the entity.
//! All state changes will be signaled through this event.
//! @param handler reference to the EntityStateEvent handler to attach to the entities state event.
@@ -410,6 +418,8 @@ namespace AZ
//! A user-friendly name for the entity. This makes error messages easier to read.
AZStd::string m_name;
+ u32 m_spawnTicketId = 0;
+
//! The state of the entity.
State m_state;
diff --git a/Code/Framework/AzCore/AzCore/Component/EntityUtils.h b/Code/Framework/AzCore/AzCore/Component/EntityUtils.h
index ce258bc637..5c02a3fe74 100644
--- a/Code/Framework/AzCore/AzCore/Component/EntityUtils.h
+++ b/Code/Framework/AzCore/AzCore/Component/EntityUtils.h
@@ -5,8 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
-#ifndef AZCORE_ENTITY_UTILS_H
-#define AZCORE_ENTITY_UTILS_H
+#pragma once
#include
#include
@@ -217,6 +216,3 @@ namespace AZ
} // namespace EntityUtils
} // namespace AZ
-
-#endif // AZCORE_ENTITY_UTILS_H
-#pragma once
diff --git a/Code/Framework/AzCore/AzCore/Component/TickBus.h b/Code/Framework/AzCore/AzCore/Component/TickBus.h
index 966a3c303e..e65efb93f2 100644
--- a/Code/Framework/AzCore/AzCore/Component/TickBus.h
+++ b/Code/Framework/AzCore/AzCore/Component/TickBus.h
@@ -46,8 +46,6 @@ namespace AZ
TICK_PRE_RENDER = 750, ///< Suggested tick handler position to update render-related data.
- TICK_RENDER = 800, ///< Suggested tick handler position for rendering.
-
TICK_DEFAULT = 1000, ///< Default tick handler position when the handler is constructed.
TICK_UI = 2000, ///< Suggested tick handler position for UI components.
diff --git a/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h b/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h
index 5c3c835271..615634c05a 100644
--- a/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h
+++ b/Code/Framework/AzCore/AzCore/Debug/AssetTracking.h
@@ -8,6 +8,7 @@
#pragma once
+#include
#include
#include
diff --git a/Code/Framework/AzCore/AzCore/Debug/Budget.cpp b/Code/Framework/AzCore/AzCore/Debug/Budget.cpp
index f9fe7e462a..4a6f3ed114 100644
--- a/Code/Framework/AzCore/AzCore/Debug/Budget.cpp
+++ b/Code/Framework/AzCore/AzCore/Debug/Budget.cpp
@@ -11,6 +11,7 @@
#include
#include
#include
+#include