Merge remote-tracking branch 'upstream/development' into Atom/santorac/MoreShaderHotReloadFixes

This commit is contained in:
santorac
2021-08-26 08:41:42 -07:00
607 changed files with 3264 additions and 63104 deletions
+1
View File
@@ -5,6 +5,7 @@ __pycache__
AssetProcessorTemp/**
[Bb]uild/**
[Oo]ut/**
CMakeUserPresets.json
[Cc]ache/
/install/
Editor/EditorEventLog.xml
+9
View File
@@ -0,0 +1,9 @@
#
# 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
#
#
ly_install_directory(DIRECTORIES .)
@@ -51,8 +51,8 @@ class TestAutomationBase:
cls.asset_processor.teardown()
cls._kill_ly_processes()
def _run_test(self, request, workspace, editor, testcase_module, extra_cmdline_args=[], use_null_renderer=True):
def _run_test(self, request, workspace, editor, testcase_module, extra_cmdline_args=[], batch_mode=True,
autotest_mode=True, use_null_renderer=True):
test_starttime = time.time()
self.logger = logging.getLogger(__name__)
errors = []
@@ -90,9 +90,13 @@ class TestAutomationBase:
editor_starttime = time.time()
self.logger.debug("Running automated test")
testcase_module_filepath = self._get_testcase_module_filepath(testcase_module)
pycmd = ["--runpythontest", testcase_module_filepath, "-BatchMode", "-autotest_mode", f"-pythontestcase={request.node.originalname}"]
pycmd = ["--runpythontest", testcase_module_filepath, f"-pythontestcase={request.node.originalname}"]
if use_null_renderer:
pycmd += ["-rhi=null"]
if batch_mode:
pycmd += ["-BatchMode"]
if autotest_mode:
pycmd += ["-autotest_mode"]
pycmd += extra_cmdline_args
editor.args.extend(pycmd) # args are added to the WinLauncher start command
editor.start(backupFiles = False, launch_ap = False)
@@ -11,22 +11,8 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
NAME AutomatedTesting::EditorTests_Main
TEST_SUITE main
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}
PYTEST_MARKS "SUITE_main and not REQUIRES_gpu"
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
Editor
)
ly_add_pytest(
NAME AutomatedTesting::EditorTests_Periodic
TEST_SUITE periodic
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}
PYTEST_MARKS "SUITE_periodic and not REQUIRES_gpu"
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py
PYTEST_MARKS "not REQUIRES_gpu"
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
@@ -40,8 +26,21 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
TEST_SUITE main
TEST_SERIAL
TEST_REQUIRES gpu
PATH ${CMAKE_CURRENT_LIST_DIR}
PYTEST_MARKS "SUITE_main and REQUIRES_gpu"
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main.py
PYTEST_MARKS "REQUIRES_gpu"
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
Editor
)
ly_add_pytest(
NAME AutomatedTesting::EditorTests_Periodic
TEST_SUITE periodic
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Periodic.py
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
@@ -54,8 +53,7 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
NAME AutomatedTesting::EditorTests_Sandbox
TEST_SUITE sandbox
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}
PYTEST_MARKS "SUITE_sandbox"
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Sandbox.py
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
@@ -63,4 +61,47 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_
COMPONENT
Editor
)
ly_add_pytest(
NAME AutomatedTesting::EditorTests_Main_Optimized
TEST_SUITE main
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
PYTEST_MARKS "not REQUIRES_gpu"
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
Editor
)
ly_add_pytest(
NAME AutomatedTesting::EditorTests_Main_GPU_Optimized
TEST_SUITE main
TEST_SERIAL
TEST_REQUIRES gpu
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Main_Optimized.py
PYTEST_MARKS "REQUIRES_gpu"
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
Editor
)
ly_add_pytest(
NAME AutomatedTesting::EditorTests_Sandbox_Optimized
TEST_SUITE sandbox
TEST_SERIAL
PATH ${CMAKE_CURRENT_LIST_DIR}/TestSuite_Sandbox_Optimized.py
RUNTIME_DEPENDENCIES
Legacy::Editor
AZ::AssetProcessor
AutomatedTesting.Assets
COMPONENT
Editor
)
endif()
@@ -5,30 +5,24 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C13660194 : Asset Browser - Filtering
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.legacy.general as general
import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
import editor_python_test_tools.hydra_editor_utils as hydra
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper
class Tests:
asset_filtered = (
"Asset was filtered to in the Asset Browser",
"Failed to filter to the expected asset"
)
asset_type_filtered = (
"Expected asset type was filtered to in the Asset Browser",
"Failed to filter to the expected asset type"
)
class AssetBrowserSearchFilteringTest(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="AssetBrowser_SearchFiltering", args=["level"])
def AssetBrowser_SearchFiltering():
import editor_python_test_tools.pyside_utils as pyside_utils
@pyside_utils.wrap_async
async def run_test(self):
async def run_test():
"""
Summary:
Asset Browser - Filtering
@@ -60,7 +54,13 @@ class AssetBrowserSearchFilteringTest(EditorTestHelper):
:return: None
"""
self.incorrect_file_found = False
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.legacy.general as general
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
def verify_files_appeared(model, allowed_asset_extentions, parent_index=QtCore.QModelIndex()):
indexes = [parent_index]
@@ -74,25 +74,24 @@ class AssetBrowserSearchFilteringTest(EditorTestHelper):
and (cur_data.lower().split(".")[-1] not in allowed_asset_extentions)
and not cur_data[-1] == ")"
):
print(f"Incorrect file found: {cur_data}")
self.incorrect_file_found = True
indexes = list()
break
Report.info(f"Incorrect file found: {cur_data}")
return False
indexes.append(cur_index)
return True
# 1) Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
# 1) Open level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
# 2) Open Asset Browser
general.close_pane("Asset Browser")
general.open_pane("Asset Browser")
# 2) Open Asset Browser (if not opened already)
editor_window = pyside_utils.get_editor_main_window()
asset_browser_open = general.is_pane_visible("Asset Browser")
if not asset_browser_open:
Report.info("Opening Asset Browser")
action = pyside_utils.get_action_for_menu_path(editor_window, "Tools", "Asset Browser")
action.trigger()
else:
Report.info("Asset Browser is already open")
editor_window = pyside_utils.get_editor_main_window()
app = QtWidgets.QApplication.instance()
@@ -103,10 +102,9 @@ class AssetBrowserSearchFilteringTest(EditorTestHelper):
asset_browser_tree = asset_browser.findChild(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget")
model_index = pyside_utils.find_child_by_pattern(asset_browser_tree, "cedar.fbx")
pyside_utils.item_view_index_mouse_click(asset_browser_tree, model_index)
is_filtered = pyside_utils.wait_for_condition(
is_filtered = await pyside_utils.wait_for_condition(
lambda: asset_browser_tree.indexBelow(asset_browser_tree.currentIndex()) == QtCore.QModelIndex(), 5.0)
if is_filtered:
print("cedar.fbx asset is filtered in Asset Browser")
Report.result(Tests.asset_filtered, is_filtered)
# 4) Click the "X" in the search bar.
clear_search = asset_browser.findChild(QtWidgets.QToolButton, "ClearToolButton")
@@ -122,40 +120,47 @@ class AssetBrowserSearchFilteringTest(EditorTestHelper):
tree.model().setData(animation_model_index, 2, Qt.CheckStateRole)
general.idle_wait(1.0)
# check asset types after clicking on Animation filter
verify_files_appeared(asset_browser_tree.model(), ["i_caf", "fbx", "xml", "animgraph", "motionset"])
print(f"Animation file type(s) is present in the file tree: {not self.incorrect_file_found}")
asset_type_filter = verify_files_appeared(asset_browser_tree.model(), ["i_caf", "fbx", "xml", "animgraph", "motionset"])
Report.result(Tests.asset_type_filtered, asset_type_filter)
# 6) Add additional filter(FileTag) from the filter menu
self.incorrect_file_found = False
line_edit.setText("FileTag")
filetag_model_index = await pyside_utils.wait_for_child_by_pattern(tree, "FileTag")
tree.model().setData(filetag_model_index, 2, Qt.CheckStateRole)
general.idle_wait(1.0)
# check asset types after clicking on FileTag filter
verify_files_appeared(
more_types_filtered = verify_files_appeared(
asset_browser_tree.model(), ["i_caf", "fbx", "xml", "animgraph", "motionset", "filetag"]
)
print(f"FileTag file type(s) and Animation file type(s) is present in the file tree: {not self.incorrect_file_found}")
Report.result(Tests.asset_type_filtered, more_types_filtered)
# 7) Remove one of the filtered asset types from the list of applied filters
self.incorrect_file_found = False
filter_layout = asset_browser.findChild(QtWidgets.QFrame, "filteredLayout")
animation_close_button = filter_layout.children()[1]
first_close_button = animation_close_button.findChild(QtWidgets.QPushButton, "closeTag")
first_close_button.click()
general.idle_wait(1.0)
# check asset types after removing Animation filter
verify_files_appeared(asset_browser_tree.model(), ["filetag"])
print(f"FileTag file type(s) is present in the file tree after removing Animation filter: {not self.incorrect_file_found}")
remove_filtered = verify_files_appeared(asset_browser_tree.model(), ["filetag"])
Report.result(Tests.asset_type_filtered, remove_filtered)
# 8) Remove all of the filter asset types from the list of filters
filetag_close_button = filter_layout.children()[1]
second_close_button = filetag_close_button.findChild(QtWidgets.QPushButton, "closeTag")
second_close_button.click()
# 9) Close the asset browser
asset_browser.close()
# Click off of the Asset Browser filter window to close it
QtTest.QTest.mouseClick(tree, Qt.LeftButton, Qt.NoModifier)
# 9) Restore Asset Browser tool state and
if not asset_browser_open:
Report.info("Closing Asset Browser")
general.close_pane("Asset Browser")
run_test()
test = AssetBrowserSearchFilteringTest()
test.run()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(AssetBrowser_SearchFiltering)
@@ -5,124 +5,119 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C13660195: Asset Browser - File Tree Navigation
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
import azlmbr.legacy.general as general
import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
class Tests:
collapse_expand = (
"Asset Browser hierarchy successfully collapsed/expanded",
"Failed to collapse/expand Asset Browser hierarchy"
)
asset_visible = (
"Expected asset is visible in the Asset Browser hierarchy",
"Failed to find expected asset in the Asset Browser hierarchy"
)
scrollbar_visible = (
"Scrollbar is visible",
"Scrollbar was not found"
)
class AssetBrowserTreeNavigationTest(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="AssetBrowser_TreeNavigation", args=["level"])
def AssetBrowser_TreeNavigation():
"""
Summary:
Verify if we are able to expand a file hierarchy in the Asset Browser and ScrollBar appears
appropriately.
def run_test(self):
"""
Summary:
Verify if we are able to expand a file hierarchy in the Asset Browser and ScrollBar appears
appropriately.
Expected Behavior:
The folder list is expanded to display the children of the selected folder.
A scroll bar appears to allow scrolling up and down through the asset browser.
Assets are present in the Asset Browser.
Expected Behavior:
The folder list is expanded to display the children of the selected folder.
A scroll bar appears to allow scrolling up and down through the asset browser.
Assets are present in the Asset Browser.
Test Steps:
1) Open a simple level
2) Open Asset Browser
3) Collapse all files initially
4) Get all Model Indexes
5) Expand each of the folder and verify if it is opened
6) Verify if the ScrollBar appears after expanding the tree
Test Steps:
1) Open a new level
2) Open Asset Browser
3) Collapse all files initially
4) Get all Model Indexes
5) Expand each of the folder and verify if it is opened
6) Verify if the ScrollBar appears after expanding the tree
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
:return: None
"""
from PySide2 import QtWidgets, QtTest, QtCore
def collapse_expand_and_verify(model_index, hierarchy_level):
tree.collapse(model_index)
collapse_success = not tree.isExpanded(model_index)
self.log(f"Level {hierarchy_level} collapsed: {collapse_success}")
tree.expand(model_index)
expand_success = tree.isExpanded(model_index)
self.log(f"Level {hierarchy_level} expanded: {expand_success}")
return collapse_success and expand_success
import azlmbr.legacy.general as general
# This is the hierarchy we are expanding (4 steps inside)
self.file_path = ("AutomatedTesting", "Assets", "ImageGradients", "image_grad_test_gsi.png")
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
# 1) Open a new level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
def collapse_expand_and_verify(model_index, hierarchy_level):
tree.collapse(model_index)
collapse_success = not tree.isExpanded(model_index)
Report.info(f"Level {hierarchy_level} collapsed: {collapse_success}")
tree.expand(model_index)
expand_success = tree.isExpanded(model_index)
Report.info(f"Level {hierarchy_level} expanded: {expand_success}")
return collapse_success and expand_success
# 2) Open Asset Browser (if not opened already)
editor_window = pyside_utils.get_editor_main_window()
asset_browser_open = general.is_pane_visible("Asset Browser")
if not asset_browser_open:
self.log("Opening Asset Browser")
action = pyside_utils.get_action_for_menu_path(editor_window, "Tools", "Asset Browser")
action.trigger()
else:
self.log("Asset Browser is already open")
# This is the hierarchy we are expanding (4 steps inside)
file_path = ("AutomatedTesting", "Assets", "ImageGradients", "image_grad_test_gsi.png")
# 3) Collapse all files initially
main_window = editor_window.findChild(QtWidgets.QMainWindow)
asset_browser = pyside_utils.find_child_by_hierarchy(main_window, ..., "Asset Browser")
tree = pyside_utils.find_child_by_hierarchy(asset_browser, ..., "m_assetBrowserTreeViewWidget")
scroll_area = tree.findChild(QtWidgets.QWidget, "qt_scrollarea_vcontainer")
scroll_bar = scroll_area.findChild(QtWidgets.QScrollBar)
tree.collapseAll()
# 1) Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
# 4) Get all Model Indexes
model_index_1 = pyside_utils.find_child_by_hierarchy(tree, self.file_path[0])
model_index_2 = pyside_utils.find_child_by_hierarchy(model_index_1, self.file_path[1])
model_index_3 = pyside_utils.find_child_by_hierarchy(model_index_2, self.file_path[2])
model_index_4 = pyside_utils.find_child_by_hierarchy(model_index_3, self.file_path[3])
# 2) Open Asset Browser (if not opened already)
editor_window = pyside_utils.get_editor_main_window()
asset_browser_open = general.is_pane_visible("Asset Browser")
if not asset_browser_open:
Report.info("Opening Asset Browser")
action = pyside_utils.get_action_for_menu_path(editor_window, "Tools", "Asset Browser")
action.trigger()
else:
Report.info("Asset Browser is already open")
# 5) Verify each level of the hierarchy to the file can be collapsed/expanded
self.test_success = collapse_expand_and_verify(model_index_1, 1) and self.test_success
self.test_success = collapse_expand_and_verify(model_index_2, 2) and self.test_success
self.test_success = collapse_expand_and_verify(model_index_3, 3) and self.test_success
self.log(f"Collapse/Expand tests: {self.test_success}")
# 3) Collapse all files initially
main_window = editor_window.findChild(QtWidgets.QMainWindow)
asset_browser = pyside_utils.find_child_by_hierarchy(main_window, ..., "Asset Browser")
tree = pyside_utils.find_child_by_hierarchy(asset_browser, ..., "m_assetBrowserTreeViewWidget")
scroll_area = tree.findChild(QtWidgets.QWidget, "qt_scrollarea_vcontainer")
scroll_bar = scroll_area.findChild(QtWidgets.QScrollBar)
tree.collapseAll()
# Select the asset
tree.scrollTo(model_index_4)
pyside_utils.item_view_index_mouse_click(tree, model_index_4)
# 4) Get all Model Indexes
model_index_1 = pyside_utils.find_child_by_hierarchy(tree, file_path[0])
model_index_2 = pyside_utils.find_child_by_hierarchy(model_index_1, file_path[1])
model_index_3 = pyside_utils.find_child_by_hierarchy(model_index_2, file_path[2])
model_index_4 = pyside_utils.find_child_by_hierarchy(model_index_3, file_path[3])
# Verify if the currently selected item model index is same as the Asset Model index
# to prove that it is visible
asset_visible = tree.currentIndex() == model_index_4
self.test_success = asset_visible and self.test_success
self.log(f"Asset visibility test: {asset_visible}")
# 5) Verify each level of the hierarchy to the file can be collapsed/expanded
Report.result(Tests.collapse_expand, collapse_expand_and_verify(model_index_1, 1) and
collapse_expand_and_verify(model_index_2, 2) and collapse_expand_and_verify(model_index_3, 3))
# 6) Verify if the ScrollBar appears after expanding the tree
scrollbar_visible = scroll_bar.isVisible()
self.test_success = scrollbar_visible and self.test_success
self.log(f"Scrollbar visibility test: {scrollbar_visible}")
# Select the asset
tree.scrollTo(model_index_4)
pyside_utils.item_view_index_mouse_click(tree, model_index_4)
# 7) Restore Asset Browser tool state
if not asset_browser_open:
self.log("Closing Asset Browser")
general.close_pane("Asset Browser")
# Verify if the currently selected item model index is same as the Asset Model index
# to prove that it is visible
Report.result(Tests.asset_visible, tree.currentIndex() == model_index_4)
# 6) Verify if the ScrollBar appears after expanding the tree
Report.result(Tests.scrollbar_visible, scroll_bar.isVisible())
# 7) Restore Asset Browser tool state
if not asset_browser_open:
Report.info("Closing Asset Browser")
general.close_pane("Asset Browser")
test = AssetBrowserTreeNavigationTest()
test.run()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(AssetBrowser_TreeNavigation)
@@ -5,33 +5,13 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C13751579: Asset Picker UI/UX
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
def AssetPicker_UI_UX():
import azlmbr.asset as asset
import azlmbr.bus as bus
import azlmbr.legacy.general as general
import azlmbr.paths
import azlmbr.math as math
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
import editor_python_test_tools.hydra_editor_utils as hydra
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper
class AssetPickerUIUXTest(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="AssetPicker_UI_UX", args=["level"])
import editor_python_test_tools.pyside_utils as pyside_utils
@pyside_utils.wrap_async
async def run_test(self):
async def run_test():
"""
Summary:
Verify the functionality of Asset Picker and UI/UX properties
@@ -45,7 +25,7 @@ class AssetPickerUIUXTest(EditorTestHelper):
The asset picker is closed and the selected asset is assigned to the mesh component.
Test Steps:
1) Open a new level
1) Open a simple level
2) Create entity and add Mesh component
3) Access Entity Inspector
4) Click Asset Picker (Mesh Asset)
@@ -68,10 +48,20 @@ class AssetPickerUIUXTest(EditorTestHelper):
:return: None
"""
self.file_path = ["AutomatedTesting", "Assets", "Objects", "Foliage"]
self.incorrect_file_found = False
self.mesh_asset = "cedar.azmodel"
self.prefix = ""
import os
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.asset as asset
import azlmbr.bus as bus
import azlmbr.legacy.general as general
import azlmbr.math as math
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
file_path = ["AutomatedTesting", "Assets", "Objects", "Foliage"]
def is_asset_assigned(component, interaction_option):
path = os.path.join("assets", "objects", "foliage", "cedar.azmodel")
@@ -80,7 +70,7 @@ class AssetPickerUIUXTest(EditorTestHelper):
result = hydra.get_component_property_value(component, "Controller|Configuration|Mesh Asset")
expected_asset_str = expected_asset_id.invoke("ToString")
result_str = result.invoke("ToString")
print(f"Asset assigned for {interaction_option} option: {expected_asset_str == result_str}")
Report.info(f"Asset assigned for {interaction_option} option: {expected_asset_str == result_str}")
return expected_asset_str == result_str
def move_and_resize_widget(widget):
@@ -89,9 +79,11 @@ class AssetPickerUIUXTest(EditorTestHelper):
x, y = initial_position.x() + 5, initial_position.y() + 5
widget.move(x, y)
curr_position = widget.pos()
move_success = curr_position.x() == x and curr_position.y() == y
self.test_success = move_success and self.test_success
self.log(f"Widget Move Test: {move_success}")
asset_picker_moved = (
"Asset Picker widget moved successfully",
"Failed to move Asset Picker widget"
)
Report.result(asset_picker_moved, curr_position.x() == x and curr_position.y() == y)
# Resize the widget and verify size
width, height = (
@@ -99,9 +91,36 @@ class AssetPickerUIUXTest(EditorTestHelper):
widget.geometry().height() + 10,
)
widget.resize(width, height)
resize_success = widget.geometry().width() == width and widget.geometry().height() == height
self.test_success = resize_success and self.test_success
self.log(f"Widget Resize Test: {resize_success}")
asset_picker_resized = (
"Resized Asset Picker widget successfully",
"Failed to resize Asset Picker widget"
)
Report.result(asset_picker_resized, widget.geometry().width() == width and widget.geometry().height() ==
height)
def verify_expand(model_index, tree):
initially_collapsed = (
"Folder initially collapsed",
"Folder unexpectedly expanded"
)
expanded = (
"Folder expanded successfully",
"Failed to expand folder"
)
# Check initial collapse
Report.result(initially_collapsed, not tree.isExpanded(model_index))
# Expand at the specified index
tree.expand(model_index)
# Verify expansion
Report.result(expanded, tree.isExpanded(model_index))
def verify_collapse(model_index, tree):
collapsed = (
"Folder hierarchy collapsed successfully",
"Failed to collapse folder hierarchy"
)
tree.collapse(model_index)
Report.result(collapsed, not tree.isExpanded(model_index))
def verify_files_appeared(model, allowed_asset_extensions, parent_index=QtCore.QModelIndex()):
indices = [parent_index]
@@ -115,22 +134,20 @@ class AssetPickerUIUXTest(EditorTestHelper):
and (cur_data.lower().split(".")[-1] not in allowed_asset_extensions)
and not cur_data[-1] == ")"
):
print(f"Incorrect file found: {cur_data}")
self.incorrect_file_found = True
indices = list()
break
Report.info(f"Incorrect file found: {cur_data}")
return False
indices.append(cur_index)
self.test_success = not self.incorrect_file_found and self.test_success
return True
def print_message_prefix(message):
print(f"{self.prefix}: {message}")
async def asset_picker(prefix, allowed_asset_extensions, asset, interaction_option):
async def asset_picker(allowed_asset_extensions, asset, interaction_option):
active_modal_widget = await pyside_utils.wait_for_modal_widget()
if active_modal_widget and self.prefix == "":
self.prefix = prefix
if active_modal_widget:
dialog = active_modal_widget.findChildren(QtWidgets.QDialog, "AssetPickerDialogClass")[0]
print_message_prefix(f"Asset Picker title for Mesh: {dialog.windowTitle()}")
asset_picker_title = (
"Asset Picker window is titled as expected",
"Asset Picker window has an unexpected title"
)
Report.result(asset_picker_title, dialog.windowTitle() == "Pick ModelAsset")
tree = dialog.findChildren(QtWidgets.QTreeView, "m_assetBrowserTreeViewWidget")[0]
scroll_area = tree.findChild(QtWidgets.QWidget, "qt_scrollarea_vcontainer")
scroll_bar = scroll_area.findChild(QtWidgets.QScrollBar)
@@ -138,39 +155,42 @@ class AssetPickerUIUXTest(EditorTestHelper):
# a) Collapse all the files initially and verify if scroll bar is not visible
tree.collapseAll()
await pyside_utils.wait_for_condition(lambda: not scroll_bar.isVisible(), 0.5)
print_message_prefix(
f"Scroll Bar is not visible before expanding the tree: {not scroll_bar.isVisible()}"
scroll_bar_hidden = (
"Scroll Bar is not visible before tree expansion",
"Scroll Bar is visible before tree expansion"
)
Report.result(scroll_bar_hidden, not scroll_bar.isVisible())
# Get Model Index of the file paths
model_index_1 = pyside_utils.find_child_by_pattern(tree, self.file_path[0])
print(model_index_1.model())
model_index_2 = pyside_utils.find_child_by_pattern(model_index_1, self.file_path[1])
model_index_1 = pyside_utils.find_child_by_pattern(tree, file_path[0])
model_index_2 = pyside_utils.find_child_by_pattern(model_index_1, file_path[1])
# b) Expand/Verify Top folder of file path
print_message_prefix(f"Top level folder initially collapsed: {not tree.isExpanded(model_index_1)}")
tree.expand(model_index_1)
print_message_prefix(f"Top level folder expanded: {tree.isExpanded(model_index_1)}")
verify_expand(model_index_1, tree)
# c) Expand/Verify Nested folder of file path
print_message_prefix(f"Nested folder initially collapsed: {not tree.isExpanded(model_index_2)}")
tree.expand(model_index_2)
print_message_prefix(f"Nested folder expanded: {tree.isExpanded(model_index_2)}")
verify_expand(model_index_2, tree)
# d) Verify if the ScrollBar appears after expanding folders
tree.expandAll()
await pyside_utils.wait_for_condition(lambda: scroll_bar.isVisible(), 0.5)
print_message_prefix(f"Scroll Bar appeared after expanding tree: {scroll_bar.isVisible()}")
scroll_bar_visible = (
"Scroll Bar is visible after tree expansion",
"Scroll Bar is not visible after tree expansion"
)
Report.result(scroll_bar_visible, scroll_bar.isVisible())
# e) Collapse Nested and Top Level folders and verify if collapsed
tree.collapse(model_index_2)
print_message_prefix(f"Nested folder collapsed: {not tree.isExpanded(model_index_2)}")
tree.collapse(model_index_1)
print_message_prefix(f"Top level folder collapsed: {not tree.isExpanded(model_index_1)}")
verify_collapse(model_index_2, tree)
verify_collapse(model_index_1, tree)
# f) Verify if the correct files are appearing in the Asset Picker
verify_files_appeared(tree.model(), allowed_asset_extensions)
print_message_prefix(f"Expected Assets populated in the file picker: {not self.incorrect_file_found}")
asset_picker_correct_files_appear = (
"Expected assets populated in the file picker",
"Found unexpected assets in the file picker"
)
Report.result(asset_picker_correct_files_appear, verify_files_appeared(tree.model(),
allowed_asset_extensions))
# While we are here we can also check if we can resize and move the widget
move_and_resize_widget(active_modal_widget)
@@ -193,16 +213,10 @@ class AssetPickerUIUXTest(EditorTestHelper):
await pyside_utils.click_button_async(ok_button)
elif interaction_option == "enter":
QtTest.QTest.keyClick(tree, Qt.Key_Enter, Qt.NoModifier)
self.prefix = ""
# 1) Open a new level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
# 1) Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
# 2) Create entity and add Mesh component
entity_position = math.Vector3(125.0, 136.0, 32.0)
@@ -222,7 +236,7 @@ class AssetPickerUIUXTest(EditorTestHelper):
# Assign Mesh Asset via OK button
pyside_utils.click_button_async(attached_button)
await asset_picker("Mesh Asset", ["azmodel", "fbx"], "cedar (ModelAsset)", "ok")
await asset_picker(["azmodel", "fbx"], "cedar (ModelAsset)", "ok")
# 5) Verify if Mesh Asset is assigned
try:
@@ -231,7 +245,11 @@ class AssetPickerUIUXTest(EditorTestHelper):
except pyside_utils.EventLoopTimeoutException as err:
print(err)
mesh_success = False
self.test_success = mesh_success and self.test_success
mesh_asset_assigned_ok = (
"Successfully assigned Mesh asset via OK button",
"Failed to assign Mesh asset via OK button"
)
Report.result(mesh_asset_assigned_ok, mesh_success)
# Clear Mesh Asset
hydra.get_set_test(entity, 0, "Controller|Configuration|Mesh Asset", None)
@@ -242,7 +260,7 @@ class AssetPickerUIUXTest(EditorTestHelper):
# Assign Mesh Asset via Enter
pyside_utils.click_button_async(attached_button)
await asset_picker("Mesh Asset", ["azmodel", "fbx"], "cedar (ModelAsset)", "enter")
await asset_picker(["azmodel", "fbx"], "cedar (ModelAsset)", "enter")
# 5) Verify if Mesh Asset is assigned
try:
@@ -251,8 +269,16 @@ class AssetPickerUIUXTest(EditorTestHelper):
except pyside_utils.EventLoopTimeoutException as err:
print(err)
mesh_success = False
self.test_success = mesh_success and self.test_success
mesh_asset_assigned_enter = (
"Successfully assigned Mesh asset via Enter button",
"Failed to assign Mesh asset via Enter button"
)
Report.result(mesh_asset_assigned_enter, mesh_success)
run_test()
test = AssetPickerUIUXTest()
test.run()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(AssetPicker_UI_UX)
@@ -5,36 +5,44 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C6351273: Create a new level
C6384955: Basic Workflow: Entity Manipulation in the Outliner
C16929880: Add Delete Components
C15167490: Save a level
C15167491: Export a level
"""
import os
import sys
from PySide2 import QtWidgets
import azlmbr.bus as bus
import azlmbr.editor as editor
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'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
import editor_python_test_tools.hydra_editor_utils as hydra
class Tests:
level_created = (
"New level created successfully",
"Failed to create new level"
)
new_entity_created = (
"New entity created successfully",
"Failed to create a new entity"
)
child_entity_created = (
"New child entity created successfully",
"Failed to create new child entity"
)
component_added = (
"Component added to entity successfully",
"Failed to add component to entity"
)
component_updated = (
"Component property updated successfully",
"Failed to update component property"
)
component_removed = (
"Component removed from entity successfully",
"Failed to remove component from entity"
)
level_saved_and_exported = (
"Level saved and exported successfully",
"Failed to save/export level"
)
class TestBasicEditorWorkflows(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="BasicEditorWorkflows_LevelEntityComponent", args=["level"])
def BasicEditorWorkflows_LevelEntityComponentCRUD():
import editor_python_test_tools.pyside_utils as pyside_utils
@pyside_utils.wrap_async
async def run_test(self):
async def run_test():
"""
Summary:
Open O3DE editor and check if basic Editor workflows are completable.
@@ -55,6 +63,18 @@ class TestBasicEditorWorkflows(EditorTestHelper):
:return: None
"""
import os
from PySide2 import QtWidgets
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.math as math
import azlmbr.paths
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.utils import Report
def find_entity_by_name(entity_name):
search_filter = entity.SearchFilter()
search_filter.names = [entity_name]
@@ -64,6 +84,7 @@ class TestBasicEditorWorkflows(EditorTestHelper):
return None
# 1) Create a new level
level = "tmp_level"
editor_window = pyside_utils.get_editor_main_window()
new_level_action = pyside_utils.get_action_for_menu_path(editor_window, "File", "New Level")
pyside_utils.trigger_action_async(new_level_action)
@@ -71,21 +92,17 @@ class TestBasicEditorWorkflows(EditorTestHelper):
new_level_dlg = active_modal_widget.findChild(QtWidgets.QWidget, "CNewLevelDialog")
if new_level_dlg:
if new_level_dlg.windowTitle() == "New Level":
self.log("New Level dialog opened")
Report.info("New Level dialog opened")
grp_box = new_level_dlg.findChild(QtWidgets.QGroupBox, "STATIC_GROUP1")
level_name = grp_box.findChild(QtWidgets.QLineEdit, "LEVEL")
level_name.setText(self.args["level"])
level_name.setText(level)
button_box = new_level_dlg.findChild(QtWidgets.QDialogButtonBox, "buttonBox")
button_box.button(QtWidgets.QDialogButtonBox.Ok).click()
# Verify new level was created successfully
level_create_success = await pyside_utils.wait_for_condition(lambda: editor.EditorToolsApplicationRequestBus(
bus.Broadcast, "GetCurrentLevelName") == self.args["level"], 5.0)
self.test_success = level_create_success
self.log(f"Create and load new level: {level_create_success}")
# Execute EditorTestHelper setup since level was created outside of EditorTestHelper's methods
self.test_success = self.test_success and self.after_level_load()
bus.Broadcast, "GetCurrentLevelName") == level, 5.0)
Report.critical_result(Tests.level_created, level_create_success)
# 2) Delete existing entities, and create and manipulate new entities via Entity Inspector
search_filter = azlmbr.entity.SearchFilter()
@@ -99,8 +116,7 @@ class TestBasicEditorWorkflows(EditorTestHelper):
# Find the new entity
parent_entity_id = find_entity_by_name("Entity1")
parent_entity_success = await pyside_utils.wait_for_condition(lambda: parent_entity_id is not None, 5.0)
self.test_success = self.test_success and parent_entity_success
self.log(f"New entity creation: {parent_entity_success}")
Report.critical_result(Tests.new_entity_created, parent_entity_success)
# TODO: Replace Hydra call to creates child entity and add components with context menu triggering - LYN-3951
# Create a new child entity
@@ -111,29 +127,27 @@ class TestBasicEditorWorkflows(EditorTestHelper):
# Verify entity hierarchy
child_entity.get_parent_info()
self.test_success = self.test_success and child_entity.parent_id == parent_entity_id
self.log(f"Create entity hierarchy: {child_entity.parent_id == parent_entity_id}")
Report.result(Tests.child_entity_created, child_entity.parent_id == parent_entity_id)
# 3) Add/configure a component on an entity
# Add component and verify success
child_entity.add_component("Box Shape")
component_add_success = self.wait_for_condition(lambda: hydra.has_components(child_entity.id, ["Box Shape"]), 5.0)
self.test_success = self.test_success and component_add_success
self.log(f"Add component: {component_add_success}")
component_add_success = await pyside_utils.wait_for_condition(lambda: hydra.has_components(child_entity.id,
["Box Shape"]), 5.0)
Report.result(Tests.component_added, component_add_success)
# Update the component
dimensions_to_set = math.Vector3(16.0, 16.0, 16.0)
child_entity.get_set_test(0, "Box Shape|Box Configuration|Dimensions", dimensions_to_set)
box_shape_dimensions = hydra.get_component_property_value(child_entity.components[0], "Box Shape|Box Configuration|Dimensions")
self.test_success = self.test_success and box_shape_dimensions == dimensions_to_set
self.log(f"Component update: {box_shape_dimensions == dimensions_to_set}")
box_shape_dimensions = hydra.get_component_property_value(child_entity.components[0],
"Box Shape|Box Configuration|Dimensions")
Report.result(Tests.component_updated, box_shape_dimensions == dimensions_to_set)
# Remove the component
child_entity.remove_component("Box Shape")
component_rem_success = self.wait_for_condition(lambda: not hydra.has_components(child_entity.id, ["Box Shape"]),
5.0)
self.test_success = self.test_success and component_rem_success
self.log(f"Remove component: {component_rem_success}")
component_rem_success = await pyside_utils.wait_for_condition(lambda: not hydra.has_components(child_entity.id,
["Box Shape"]), 5.0)
Report.result(Tests.component_removed, component_rem_success)
# 4) Save the level
save_level_action = pyside_utils.get_action_for_menu_path(editor_window, "File", "Save")
@@ -143,12 +157,15 @@ class TestBasicEditorWorkflows(EditorTestHelper):
export_action = pyside_utils.get_action_for_menu_path(editor_window, "Game", "Export to Engine")
pyside_utils.trigger_action_async(export_action)
level_pak_file = os.path.join(
"AutomatedTesting", "Levels", self.args["level"], "level.pak"
"AutomatedTesting", "Levels", level, "level.pak"
)
export_success = self.wait_for_condition(lambda: os.path.exists(level_pak_file), 5.0)
self.test_success = self.test_success and export_success
self.log(f"Save and Export: {export_success}")
export_success = await pyside_utils.wait_for_condition(lambda: os.path.exists(level_pak_file), 5.0)
Report.result(Tests.level_saved_and_exported, export_success)
run_test()
test = TestBasicEditorWorkflows()
test.run()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(BasicEditorWorkflows_LevelEntityComponentCRUD)
@@ -5,37 +5,39 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C16929880: Add Delete Components
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.legacy.general as general
import azlmbr.bus as bus
import azlmbr.editor as editor
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'))
import editor_python_test_tools.hydra_editor_utils as hydra
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper
class Tests:
entity_created = (
"Entity created successfully",
"Failed to create entity"
)
box_component_added = (
"Box Shape component added to entity",
"Failed to add Box Shape component to entity"
)
mesh_component_added = (
"Mesh component added to entity",
"Failed to add Mesh component to entity"
)
mesh_component_deleted = (
"Mesh component removed from entity",
"Failed to remove Mesh component from entity"
)
mesh_component_delete_undo = (
"Mesh component removal was successfully undone",
"Failed to undo Mesh component removal"
)
class AddDeleteComponentsTest(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="ComponentCRUD_Add_Delete_Components", args=["level"])
def ComponentCRUD_Add_Delete_Components():
import editor_python_test_tools.pyside_utils as pyside_utils
@pyside_utils.wrap_async
async def run_test(self):
async def run_test():
"""
Summary:
Add/Delete Components to an entity.
Add/Delete Components to/from an entity.
Expected Behavior:
1) Components can be added to an entity.
@@ -61,36 +63,43 @@ class AddDeleteComponentsTest(EditorTestHelper):
:return: None
"""
from PySide2 import QtWidgets, QtTest, QtCore
from PySide2.QtCore import Qt
import azlmbr.legacy.general as general
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.math as math
import editor_python_test_tools.hydra_editor_utils as hydra
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
async def add_component(component_name):
pyside_utils.click_button_async(add_comp_btn)
popup = await pyside_utils.wait_for_popup_widget()
tree = popup.findChild(QtWidgets.QTreeView, "Tree")
component_index = pyside_utils.find_child_by_pattern(tree, component_name)
if component_index.isValid():
print(f"{component_name} found")
Report.info(f"{component_name} found")
tree.expand(component_index)
tree.setCurrentIndex(component_index)
QtTest.QTest.keyClick(tree, Qt.Key_Enter, Qt.NoModifier)
# 1) Open level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
# 1) Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
# 2) Create entity
entity_position = math.Vector3(125.0, 136.0, 32.0)
entity_id = editor.ToolsApplicationRequestBus(
bus.Broadcast, "CreateNewEntityAtPosition", entity_position, entity.EntityId()
)
if entity_id.IsValid():
print("Entity Created")
Report.critical_result(Tests.entity_created, entity_id.IsValid())
# 3) Select the newly created entity
general.select_object("Entity2")
general.select_object("Entity1")
# Give the Entity Inspector time to fully create its contents
general.idle_wait(0.5)
@@ -100,11 +109,11 @@ class AddDeleteComponentsTest(EditorTestHelper):
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
add_comp_btn = entity_inspector.findChild(QtWidgets.QPushButton, "m_addComponentButton")
await add_component("Box Shape")
print(f"Box Shape Component added: {hydra.has_components(entity_id, ['Box Shape'])}")
Report.result(Tests.box_component_added, hydra.has_components(entity_id, ['Box Shape']))
# 5) Add/verify Mesh component
await add_component("Mesh")
print(f"Mesh Component added: {hydra.has_components(entity_id, ['Mesh'])}")
Report.result(Tests.mesh_component_added, hydra.has_components(entity_id, ['Mesh']))
# 6) Delete Mesh Component
general.idle_wait(0.5)
@@ -116,15 +125,17 @@ class AddDeleteComponentsTest(EditorTestHelper):
QtTest.QTest.mouseClick(mesh_frame, Qt.LeftButton, Qt.NoModifier)
QtTest.QTest.keyClick(mesh_frame, Qt.Key_Delete, Qt.NoModifier)
success = await pyside_utils.wait_for_condition(lambda: not hydra.has_components(entity_id, ['Mesh']), 5.0)
if success:
print(f"Mesh Component deleted: {not hydra.has_components(entity_id, ['Mesh'])}")
Report.result(Tests.mesh_component_deleted, success)
# 7) Undo deletion of component
QtTest.QTest.keyPress(entity_inspector, Qt.Key_Z, Qt.ControlModifier)
success = await pyside_utils.wait_for_condition(lambda: hydra.has_components(entity_id, ['Mesh']), 5.0)
if success:
print(f"Mesh Component deletion undone: {hydra.has_components(entity_id, ['Mesh'])}")
Report.result(Tests.mesh_component_delete_undo, success)
run_test()
test = AddDeleteComponentsTest()
test.run()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(ComponentCRUD_Add_Delete_Components)
@@ -7,27 +7,32 @@ SPDX-License-Identifier: Apache-2.0 OR MIT
C6376081: Basic Function: Docked/Undocked Tools
"""
import os
import sys
from PySide2 import QtWidgets, QtTest, QtCore
import azlmbr.legacy.general as general
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
import azlmbr.paths
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
class Tests:
all_tools_docked = (
"The tools are all docked together in a tabbed widget",
"Failed to dock all tools together"
)
docked_outliner_works = (
"Entity Outliner works when docked, can select an Entity",
"Failed to select an Entity in the Outliner while docked"
)
docked_inspector_works = (
"Entity Inspector works when docked, Entity name changed",
"Failed to change Entity name in the Inspector while docked"
)
docked_console_works = (
"Console works when docked, sent a Console Command",
"Failed to send Console Command in the Console while docked"
)
class TestDockingBasicDockedTools(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="Docking_BasicDockedTools", args=["level"])
def Docking_BasicDockedTools():
import editor_python_test_tools.pyside_utils as pyside_utils
@pyside_utils.wrap_async
async def run_test(self):
async def run_test():
"""
Summary:
Test that tools still work as expected when docked together.
@@ -50,14 +55,19 @@ class TestDockingBasicDockedTools(EditorTestHelper):
:return: None
"""
# Create a level since we are going to be dealing with an Entity.
self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
from PySide2 import QtWidgets, QtTest, QtCore
import azlmbr.legacy.general as general
import azlmbr.bus as bus
import azlmbr.editor as editor
import azlmbr.entity as entity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
# Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
# Make sure the Entity Outliner, Entity Inspector and Console tools are open
general.open_pane("Entity Outliner (PREVIEW)")
@@ -101,12 +111,14 @@ class TestDockingBasicDockedTools(EditorTestHelper):
entity_inspector_parent = entity_inspector.parentWidget()
entity_outliner_parent = entity_outliner.parentWidget()
console_parent = console.parentWidget()
print(f"Entity Inspector parent = {entity_inspector_parent}, Entity Outliner parent = {entity_outliner_parent}, Console parent = {console_parent}")
return isinstance(entity_inspector_parent, QtWidgets.QStackedWidget) and (entity_inspector_parent == entity_outliner_parent) and (entity_outliner_parent == console_parent)
Report.info(f"Entity Inspector parent = {entity_inspector_parent}, Entity Outliner parent = "
f"{entity_outliner_parent}, Console parent = {console_parent}")
return isinstance(entity_inspector_parent, QtWidgets.QStackedWidget) and \
(entity_inspector_parent == entity_outliner_parent) and \
(entity_outliner_parent == console_parent)
success = await pyside_utils.wait_for(check_all_panes_tabbed, timeout=3.0)
if success:
print("The tools are all docked together in a tabbed widget")
Report.result(Tests.all_tools_docked, success)
# 2.1,2) Select an Entity in the Entity Outliner.
entity_inspector = editor_window.findChild(QtWidgets.QDockWidget, "Entity Inspector")
@@ -116,8 +128,7 @@ class TestDockingBasicDockedTools(EditorTestHelper):
test_entity_index = pyside_utils.find_child_by_pattern(object_tree, entity_original_name)
object_tree.clearSelection()
object_tree.setCurrentIndex(test_entity_index)
if object_tree.currentIndex():
print("Entity Outliner works when docked, can select an Entity")
Report.result(Tests.docked_outliner_works, object_tree.currentIndex() == test_entity_index)
# 2.3,4) Change the name of the selected Entity via the Entity Inspector.
entity_inspector_name_field = entity_inspector.findChild(QtWidgets.QLineEdit, "m_entityNameEditor")
@@ -125,14 +136,23 @@ class TestDockingBasicDockedTools(EditorTestHelper):
entity_inspector_name_field.setText(expected_new_name)
QtTest.QTest.keyClick(entity_inspector_name_field, QtCore.Qt.Key_Enter)
entity_new_name = editor.EditorEntityInfoRequestBus(bus.Event, "GetName", entity_id)
if entity_new_name == expected_new_name:
print(f"Entity Inspector works when docked, Entity name changed to {entity_new_name}")
Report.result(Tests.docked_inspector_works, entity_new_name == expected_new_name)
# 2.5,6) Send a console command.
console_line_edit = console.findChild(QtWidgets.QLineEdit, "lineEdit")
console_line_edit.setText("Hello, world!")
console_line_edit.setText("t_Scale 2")
QtTest.QTest.keyClick(console_line_edit, QtCore.Qt.Key_Enter)
general.get_cvar("t_Scale")
Report.result(Tests.docked_console_works, general.get_cvar("t_Scale") == "2")
# Reset the altered cvar
console_line_edit.setText("t_Scale 1")
QtTest.QTest.keyClick(console_line_edit, QtCore.Qt.Key_Enter)
run_test()
test = TestDockingBasicDockedTools()
test.run()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(Docking_BasicDockedTools)
@@ -5,32 +5,36 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C1506881: Adding/Removing Event Groups
"""
import os
import sys
from PySide2 import QtWidgets
class Tests:
asset_editor_opened = (
"Successfully opened the Asset Editor",
"Failed to open the Asset Editor"
)
event_groups_added = (
"Successfully added event groups via +",
"Failed to add event groups"
)
single_event_group_deleted = (
"Successfully deleted an event group",
"Failed to delete event group"
)
all_event_groups_deleted = (
"Successfully deleted all event groups",
"Failed to delete all event groups"
)
asset_editor_closed = (
"Successfully closed the Asset Editor",
"Failed to close the Asset Editor"
)
import azlmbr.legacy.general as general
import azlmbr.bus as bus
import azlmbr.editor as editor
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'))
import editor_python_test_tools.hydra_editor_utils as hydra
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.editor_test_helper import EditorTestHelper
def InputBindings_Add_Remove_Input_Events():
class AddRemoveInputEventsTest(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="InputBindings_Add_Remove_Input_Events", args=["level"])
import editor_python_test_tools.pyside_utils as pyside_utils
@pyside_utils.wrap_async
async def run_test(self):
async def run_test():
"""
Summary:
Verify if we are able add/remove input events in inputbindings file.
@@ -42,7 +46,7 @@ class AddRemoveInputEventsTest(EditorTestHelper):
Test Steps:
1) Open a new level
1) Open an existing level
2) Open Asset Editor
3) Access Asset Editor
4) Create a new .inputbindings file and add event groups
@@ -61,6 +65,13 @@ class AddRemoveInputEventsTest(EditorTestHelper):
:return: None
"""
from PySide2 import QtWidgets
import azlmbr.legacy.general as general
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
def open_asset_editor():
general.open_pane("Asset Editor")
return general.is_pane_visible("Asset Editor")
@@ -69,17 +80,12 @@ class AddRemoveInputEventsTest(EditorTestHelper):
general.close_pane("Asset Editor")
return not general.is_pane_visible("Asset Editor")
# 1) Open a new level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
# 1) Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
# 2) Open Asset Editor
print(f"Asset Editor opened: {open_asset_editor()}")
Report.result(Tests.asset_editor_opened, open_asset_editor())
# 3) Access Asset Editor
editor_window = pyside_utils.get_editor_main_window()
@@ -103,8 +109,7 @@ class AddRemoveInputEventsTest(EditorTestHelper):
# 5) Verify if there are 3 elements in the Input Event Groups label
no_of_elements_label = input_event_groups.findChild(QtWidgets.QLabel, "DefaultLabel")
success = await pyside_utils.wait_for_condition(lambda: "3 elements" in no_of_elements_label.text(), 2.0)
if success:
print("New Event Groups added when + is clicked")
Report.result(Tests.event_groups_added, success)
# 6) Delete one event group
event = asset_editor_widget.findChildren(QtWidgets.QFrame, "<Unspecified Event>")[0]
@@ -121,11 +126,11 @@ class AddRemoveInputEventsTest(EditorTestHelper):
input_event_group = input_event_groups[1]
no_of_elements_label = input_event_group.findChild(QtWidgets.QLabel, "DefaultLabel")
return no_of_elements_label.text()
return ""
return "";
success = await pyside_utils.wait_for_condition(lambda: "2 elements" in get_elements_label_text(asset_editor_widget), 2.0)
if success:
print("Event Group deleted when the Delete button is clicked on an Event Group")
success = await pyside_utils.wait_for_condition(lambda: "2 elements" in
get_elements_label_text(asset_editor_widget), 2.0)
Report.result(Tests.single_event_group_deleted, success)
# 8) Click on Delete button to delete all the Event Groups
# First QToolButton child of active input_event_groups is +, Second QToolButton is Delete
@@ -141,13 +146,17 @@ class AddRemoveInputEventsTest(EditorTestHelper):
yes_button.click()
# 9) Verify if all the elements are deleted
success = await pyside_utils.wait_for_condition(lambda: "0 elements" in get_elements_label_text(asset_editor_widget), 2.0)
if success:
print("All event groups deleted on clicking the Delete button")
success = await pyside_utils.wait_for_condition(lambda: "0 elements" in
get_elements_label_text(asset_editor_widget), 2.0)
Report.result(Tests.all_event_groups_deleted, success)
# 10) Close Asset Editor
print(f"Asset Editor closed: {close_asset_editor()}")
Report.result(Tests.asset_editor_closed, close_asset_editor())
run_test()
test = AddRemoveInputEventsTest()
test.run()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(InputBindings_Add_Remove_Input_Events)
@@ -5,93 +5,78 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C24064529: Base Edit Menu Options
"""
import os
import sys
def Menus_EditMenuOptions_Work():
"""
Summary:
Interact with Edit Menu options and verify if all the options are working.
import azlmbr.paths
Expected Behavior:
The Edit menu functions normally.
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
Test Steps:
1) Open an existing level
2) Interact with Edit Menu options
Note:
- This test file must be called from the O3DE Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
class TestEditMenuOptions(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="Menus_EditMenuOptions", args=["level"])
:return: None
"""
def run_test(self):
"""
Summary:
Interact with Edit Menu options and verify if all the options are working.
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
Expected Behavior:
The Edit menu functions normally.
edit_menu_options = [
("Undo",),
("Redo",),
("Duplicate",),
("Delete",),
("Select All",),
("Invert Selection",),
("Toggle Pivot Location",),
("Reset Entity Transform",),
("Reset Manipulator",),
("Reset Transform (Local)",),
("Reset Transform (World)",),
("Hide Selection",),
("Show All",),
("Modify", "Snap", "Snap angle"),
("Modify", "Transform Mode", "Move"),
("Modify", "Transform Mode", "Rotate"),
("Modify", "Transform Mode", "Scale"),
("Editor Settings", "Global Preferences"),
("Editor Settings", "Editor Settings Manager"),
("Editor Settings", "Keyboard Customization", "Customize Keyboard"),
("Editor Settings", "Keyboard Customization", "Export Keyboard Settings"),
("Editor Settings", "Keyboard Customization", "Import Keyboard Settings"),
]
Test Steps:
1) Create a temp level
2) Interact with Edit Menu options
# 1) Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
Note:
- This test file must be called from the O3DE Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
edit_menu_options = [
("Undo",),
("Redo",),
("Duplicate",),
("Delete",),
("Select All",),
("Invert Selection",),
("Toggle Pivot Location",),
("Reset Entity Transform",),
("Reset Manipulator",),
("Reset Transform (Local)",),
("Reset Transform (World)",),
("Hide Selection",),
("Show All",),
("Modify", "Snap", "Snap angle"),
("Modify", "Transform Mode", "Move"),
("Modify", "Transform Mode", "Rotate"),
("Modify", "Transform Mode", "Scale"),
("Editor Settings", "Global Preferences"),
("Editor Settings", "Editor Settings Manager"),
("Editor Settings", "Keyboard Customization", "Customize Keyboard"),
("Editor Settings", "Keyboard Customization", "Export Keyboard Settings"),
("Editor Settings", "Keyboard Customization", "Import Keyboard Settings"),
]
# 1) Create and open the temp level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
def on_action_triggered(action_name):
print(f"{action_name} Action triggered")
# 2) Interact with Edit Menu options
# 2) Interact with Edit Menu options
editor_window = pyside_utils.get_editor_main_window()
for option in edit_menu_options:
try:
editor_window = pyside_utils.get_editor_main_window()
for option in edit_menu_options:
action = pyside_utils.get_action_for_menu_path(editor_window, "Edit", *option)
trig_func = lambda: on_action_triggered(action.iconText())
action.triggered.connect(trig_func)
action.trigger()
action.triggered.disconnect(trig_func)
action = pyside_utils.get_action_for_menu_path(editor_window, "Edit", *option)
action.trigger()
action_triggered = True
except Exception as e:
self.test_success = False
action_triggered = False
print(e)
menu_action_triggered = (
f"{action.iconText()} action triggered successfully",
f"Failed to trigger {action.iconText()} action"
)
Report.result(menu_action_triggered, action_triggered)
test = TestEditMenuOptions()
test.run()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(Menus_EditMenuOptions_Work)
@@ -5,80 +5,69 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import sys
import azlmbr.paths
def Menus_FileMenuOptions_Work():
"""
Summary:
Interact with File Menu options and verify if all the options are working.
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
Expected Behavior:
The File menu functions normally.
Test Steps:
1) Open level
2) Interact with File Menu options
class TestFileMenuOptions(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="file_menu_options: ", args=["level"])
Note:
- This test file must be called from the O3DE Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
def run_test(self):
"""
Summary:
Interact with File Menu options and verify if all the options are working.
:return: None
"""
Expected Behavior:
The File menu functions normally.
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
Test Steps:
1) Open level
2) Interact with File Menu options
file_menu_options = [
("New Level",),
("Open Level",),
("Import",),
("Save",),
("Save As",),
("Save Level Statistics",),
("Edit Project Settings",),
("Edit Platform Settings",),
("New Project",),
("Open Project",),
("Show Log File",),
("Resave All Slices",),
("Exit",),
]
Note:
- This test file must be called from the O3DE Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
# 1) Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
:return: None
"""
file_menu_options = [
("New Level",),
("Open Level",),
("Import",),
("Save",),
("Save As",),
("Save Level Statistics",),
("Edit Project Settings",),
("Edit Platform Settings",),
("New Project",),
("Open Project",),
("Show Log File",),
("Resave All Slices",),
("Exit",),
]
# 1) Open level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
def on_action_triggered(action_name):
print(f"{action_name} Action triggered")
# 2) Interact with File Menu options
# 2) Interact with File Menu options
editor_window = pyside_utils.get_editor_main_window()
for option in file_menu_options:
try:
editor_window = pyside_utils.get_editor_main_window()
for option in file_menu_options:
action = pyside_utils.get_action_for_menu_path(editor_window, "File", *option)
trig_func = lambda: on_action_triggered(action.iconText())
action.triggered.connect(trig_func)
action.trigger()
action.triggered.disconnect(trig_func)
action = pyside_utils.get_action_for_menu_path(editor_window, "File", *option)
action.trigger()
action_triggered = True
except Exception as e:
self.test_success = False
action_triggered = False
print(e)
menu_action_triggered = (
f"{action.iconText()} action triggered successfully",
f"Failed to trigger {action.iconText()} action"
)
Report.result(menu_action_triggered, action_triggered)
test = TestFileMenuOptions()
test.run()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(Menus_FileMenuOptions_Work)
@@ -5,81 +5,66 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C24064534: The View menu options function normally
"""
import os
import sys
def Menus_ViewMenuOptions_Work():
"""
Summary:
Interact with View Menu options and verify if all the options are working.
import azlmbr.paths
Expected Behavior:
The View menu functions normally.
sys.path.append(os.path.join(azlmbr.paths.devroot, 'AutomatedTesting', 'Gem', 'PythonTests'))
from editor_python_test_tools.editor_test_helper import EditorTestHelper
import editor_python_test_tools.pyside_utils as pyside_utils
Test Steps:
1) Open an existing level
2) Interact with View Menu options
Note:
- This test file must be called from the O3DE Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
class TestViewMenuOptions(EditorTestHelper):
def __init__(self):
EditorTestHelper.__init__(self, log_prefix="Menus_EditMenuOptions", args=["level"])
:return: None
"""
def run_test(self):
"""
Summary:
Interact with View Menu options and verify if all the options are working.
import editor_python_test_tools.pyside_utils as pyside_utils
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
Expected Behavior:
The View menu functions normally.
view_menu_options = [
("Center on Selection",),
("Show Quick Access Bar",),
("Viewport", "Configure Layout"),
("Viewport", "Go to Position"),
("Viewport", "Center on Selection"),
("Viewport", "Go to Location"),
("Viewport", "Remember Location"),
("Viewport", "Switch Camera"),
("Viewport", "Show/Hide Helpers"),
("Refresh Style",),
]
Test Steps:
1) Create a temp level
2) Interact with View Menu options
# 1) Open an existing simple level
helper.init_idle()
helper.open_level("Physics", "Base")
Note:
- This test file must be called from the O3DE Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
view_menu_options = [
("Center on Selection",),
("Show Quick Access Bar",),
("Viewport", "Configure Layout"),
("Viewport", "Go to Position"),
("Viewport", "Center on Selection"),
("Viewport", "Go to Location"),
("Viewport", "Remember Location"),
("Viewport", "Switch Camera"),
("Viewport", "Show/Hide Helpers"),
("Refresh Style",),
]
# 1) Create and open the temp level
self.test_success = self.create_level(
self.args["level"],
heightmap_resolution=1024,
heightmap_meters_per_pixel=1,
terrain_texture_resolution=4096,
use_terrain=False,
)
def on_action_triggered(action_name):
print(f"{action_name} Action triggered")
# 2) Interact with View Menu options
# 2) Interact with View Menu options
editor_window = pyside_utils.get_editor_main_window()
for option in view_menu_options:
try:
editor_window = pyside_utils.get_editor_main_window()
for option in view_menu_options:
action = pyside_utils.get_action_for_menu_path(editor_window, "View", *option)
trig_func = lambda: on_action_triggered(action.iconText())
action.triggered.connect(trig_func)
action.trigger()
action.triggered.disconnect(trig_func)
action = pyside_utils.get_action_for_menu_path(editor_window, "View", *option)
action.trigger()
action_triggered = True
except Exception as e:
self.test_success = False
action_triggered = False
print(e)
menu_action_triggered = (
f"{action.iconText()} action triggered successfully",
f"Failed to trigger {action.iconText()} action"
)
Report.result(menu_action_triggered, action_triggered)
test = TestViewMenuOptions()
test.run()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(Menus_ViewMenuOptions_Work)
@@ -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 sys
import ly_test_tools.environment.file_system as file_system
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
from base import TestAutomationBase
@pytest.fixture
def remove_test_level(request, workspace, project):
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", "tmp_level")], True, True)
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", "tmp_level")], True, True)
request.addfinalizer(teardown)
@pytest.mark.SUITE_main
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(TestAutomationBase):
def test_BasicEditorWorkflows_LevelEntityComponentCRUD(self, request, workspace, editor, launcher_platform,
remove_test_level):
from .EditorScripts import BasicEditorWorkflows_LevelEntityComponentCRUD as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False, autotest_mode=False)
@pytest.mark.REQUIRES_gpu
def test_BasicEditorWorkflows_GPU_LevelEntityComponentCRUD(self, request, workspace, editor, launcher_platform,
remove_test_level):
from .EditorScripts import BasicEditorWorkflows_LevelEntityComponentCRUD as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False, autotest_mode=False,
use_null_renderer=False)
@@ -0,0 +1,75 @@
"""
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 EditorSingleTest, EditorSharedTest, EditorParallelTest, EditorTestSuite
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
@pytest.mark.SUITE_main
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomationNoAutoTestMode(EditorTestSuite):
# Disable -autotest_mode and -BatchMode. Tests cannot run in -BatchMode due to UI interactions, and these tests
# interact with modal dialogs
global_extra_cmdline_args = []
class test_BasicEditorWorkflows_LevelEntityComponentCRUD(EditorSingleTest):
# Custom teardown to remove slice asset created during test
def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "Levels", "tmp_level")],
True, True)
from .EditorScripts import BasicEditorWorkflows_LevelEntityComponentCRUD as test_module
@pytest.mark.REQUIRES_gpu
class test_BasicEditorWorkflows_GPU_LevelEntityComponentCRUD(EditorSingleTest):
# Disable null renderer
use_null_renderer = False
# Custom teardown to remove slice asset created during test
def teardown(self, request, workspace, editor, editor_test_results, launcher_platform):
file_system.delete([os.path.join(workspace.paths.engine_root(), "AutomatedTesting", "Levels", "tmp_level")],
True, True)
from .EditorScripts import BasicEditorWorkflows_LevelEntityComponentCRUD as test_module
class test_InputBindings_Add_Remove_Input_Events(EditorSharedTest):
from .EditorScripts import InputBindings_Add_Remove_Input_Events as test_module
@pytest.mark.skip(reason="Crashes Editor: ATOM-15493")
class test_AssetPicker_UI_UX(EditorSharedTest):
from .EditorScripts import AssetPicker_UI_UX as test_module
@pytest.mark.xfail(reason="Optimized tests are experimental, we will enable xfail and monitor them temporarily.")
@pytest.mark.SUITE_main
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomationAutoTestMode(EditorTestSuite):
# Enable only -autotest_mode for these tests. Tests cannot run in -BatchMode due to UI interactions
global_extra_cmdline_args = ["-autotest_mode"]
class test_AssetBrowser_TreeNavigation(EditorSharedTest):
from .EditorScripts import AssetBrowser_TreeNavigation as test_module
@pytest.mark.skip(reason="Crashes Editor: ATOM-15493")
class test_AssetBrowser_SearchFiltering(EditorSharedTest):
from .EditorScripts import AssetBrowser_SearchFiltering as test_module
class test_ComponentCRUD_Add_Delete_Components(EditorSharedTest):
from .EditorScripts import ComponentCRUD_Add_Delete_Components as test_module
class test_Menus_ViewMenuOptions_Work(EditorSharedTest):
from .EditorScripts import Menus_ViewMenuOptions as test_module
@pytest.mark.skip(reason="Times out due to dialogs failing to dismiss: LYN-4208")
class test_Menus_FileMenuOptions_Work(EditorSharedTest):
from .EditorScripts import Menus_FileMenuOptions as test_module
@@ -0,0 +1,62 @@
"""
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 sys
import ly_test_tools.environment.file_system as file_system
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
from base import TestAutomationBase
@pytest.fixture
def remove_test_level(request, workspace, project):
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", "tmp_level")], True, True)
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", "tmp_level")], True, True)
request.addfinalizer(teardown)
@pytest.mark.SUITE_periodic
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(TestAutomationBase):
def test_AssetBrowser_TreeNavigation(self, request, workspace, editor, launcher_platform):
from .EditorScripts import AssetBrowser_TreeNavigation as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
@pytest.mark.skip(reason="Crashes Editor: ATOM-15493")
def test_AssetBrowser_SearchFiltering(self, request, workspace, editor, launcher_platform):
from .EditorScripts import AssetBrowser_SearchFiltering as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
@pytest.mark.skip(reason="Crashes Editor: ATOM-15493")
def test_AssetPicker_UI_UX(self, request, workspace, editor, launcher_platform):
from .EditorScripts import AssetPicker_UI_UX as test_module
self._run_test(request, workspace, editor, test_module, autotest_mode=False, batch_mode=False)
def test_ComponentCRUD_Add_Delete_Components(self, request, workspace, editor, launcher_platform):
from .EditorScripts import ComponentCRUD_Add_Delete_Components as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
def test_InputBindings_Add_Remove_Input_Events(self, request, workspace, editor, launcher_platform):
from .EditorScripts import InputBindings_Add_Remove_Input_Events as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False, autotest_mode=False)
def test_Menus_ViewMenuOptions_Work(self, request, workspace, editor, launcher_platform):
from .EditorScripts import Menus_ViewMenuOptions as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
@pytest.mark.skip(reason="Times out due to dialogs failing to dismiss: LYN-4208")
def test_Menus_FileMenuOptions_Work(self, request, workspace, editor, launcher_platform):
from .EditorScripts import Menus_FileMenuOptions as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
@@ -0,0 +1,27 @@
"""
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 sys
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../automatedtesting_shared')
from base import TestAutomationBase
@pytest.mark.SUITE_sandbox
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomation(TestAutomationBase):
def test_Menus_EditMenuOptions_Work(self, request, workspace, editor, launcher_platform):
from .EditorScripts import Menus_EditMenuOptions as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
def test_Docking_BasicDockedTools(self, request, workspace, editor, launcher_platform):
from .EditorScripts import Docking_BasicDockedTools as test_module
self._run_test(request, workspace, editor, test_module, batch_mode=False)
@@ -0,0 +1,27 @@
"""
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
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_sandbox
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
@pytest.mark.parametrize("project", ["AutomatedTesting"])
class TestAutomationAutoTestMode(EditorTestSuite):
# Enable only -autotest_mode for these tests. Tests cannot run in -BatchMode due to UI interactions
global_extra_cmdline_args = ["-autotest_mode"]
class test_Docking_BasicDockedTools(EditorSharedTest):
from .EditorScripts import Docking_BasicDockedTools as test_module
class test_Menus_EditMenuOptions_Work(EditorSharedTest):
from .EditorScripts import Menus_EditMenuOptions as test_module
@@ -1,89 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C13660195: Asset Browser - File Tree Navigation
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAssetBrowser(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C13660195")
@pytest.mark.SUITE_periodic
def test_AssetBrowser_TreeNavigation(self, request, editor, level, launcher_platform):
expected_lines = [
"Collapse/Expand tests: True",
"Asset visibility test: True",
"Scrollbar visibility test: True",
"AssetBrowser_TreeNavigation: result=SUCCESS"
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"AssetBrowser_TreeNavigation.py",
expected_lines,
run_python="--runpython",
cfg_args=[level],
timeout=log_monitor_timeout
)
@pytest.mark.test_case_id("C13660194")
@pytest.mark.SUITE_periodic
def test_AssetBrowser_SearchFiltering(self, request, editor, level, launcher_platform):
expected_lines = [
"cedar.fbx asset is filtered in Asset Browser",
"Animation file type(s) is present in the file tree: True",
"FileTag file type(s) and Animation file type(s) is present in the file tree: True",
"FileTag file type(s) is present in the file tree after removing Animation filter: True",
]
unexpected_lines = [
"Asset Browser opened: False",
"Animation file type(s) is present in the file tree: False",
"FileTag file type(s) and Animation file type(s) is present in the file tree: False",
"FileTag file type(s) is present in the file tree after removing Animation filter: False",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"AssetBrowser_SearchFiltering.py",
expected_lines,
unexpected_lines=unexpected_lines,
cfg_args=[level],
auto_test_mode=False,
run_python="--runpython",
timeout=log_monitor_timeout,
)
@@ -1,74 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C13751579: Asset Picker UI/UX
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 90
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestAssetPicker(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C13751579", "C1508814")
@pytest.mark.SUITE_periodic
@pytest.mark.xfail # ATOM-15493
def test_AssetPicker_UI_UX(self, request, editor, level, launcher_platform):
expected_lines = [
"TestEntity Entity successfully created",
"Mesh component was added to entity",
"Entity has a Mesh component",
"Mesh Asset: Asset Picker title for Mesh: Pick ModelAsset",
"Mesh Asset: Scroll Bar is not visible before expanding the tree: True",
"Mesh Asset: Top level folder initially collapsed: True",
"Mesh Asset: Top level folder expanded: True",
"Mesh Asset: Nested folder initially collapsed: True",
"Mesh Asset: Nested folder expanded: True",
"Mesh Asset: Scroll Bar appeared after expanding tree: True",
"Mesh Asset: Nested folder collapsed: True",
"Mesh Asset: Top level folder collapsed: True",
"Mesh Asset: Expected Assets populated in the file picker: True",
"Widget Move Test: True",
"Widget Resize Test: True",
"Asset assigned for ok option: True",
"Asset assigned for enter option: True",
"AssetPicker_UI_UX: result=SUCCESS"
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"AssetPicker_UI_UX.py",
expected_lines,
cfg_args=[level],
run_python="--runpython",
auto_test_mode=False,
timeout=log_monitor_timeout,
)
@@ -1,96 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import ly_test_tools._internal.pytest_plugin as internal_plugin
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestBasicEditorWorkflows(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C6351273", "C6384955", "C16929880", "C15167490", "C15167491")
@pytest.mark.SUITE_main
def test_BasicEditorWorkflows_LevelEntityComponentCRUD(self, request, editor, level, launcher_platform):
# Skip test if running against Debug build
if "debug" in internal_plugin.build_directory:
pytest.skip("Does not execute against debug builds.")
expected_lines = [
"Create and load new level: True",
"New entity creation: True",
"Create entity hierarchy: True",
"Add component: True",
"Component update: True",
"Remove component: True",
"Save and Export: True",
"BasicEditorWorkflows_LevelEntityComponent: result=SUCCESS",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"BasicEditorWorkflows_LevelEntityComponentCRUD.py",
expected_lines,
cfg_args=[level],
timeout=log_monitor_timeout,
auto_test_mode=False
)
@pytest.mark.test_case_id("C6351273", "C6384955", "C16929880", "C15167490", "C15167491")
@pytest.mark.SUITE_main
@pytest.mark.REQUIRES_gpu
def test_BasicEditorWorkflows_GPU_LevelEntityComponentCRUD(self, request, editor, level, launcher_platform):
# Skip test if running against Debug build
if "debug" in internal_plugin.build_directory:
pytest.skip("Does not execute against debug builds.")
expected_lines = [
"Create and load new level: True",
"New entity creation: True",
"Create entity hierarchy: True",
"Add component: True",
"Component update: True",
"Remove component: True",
"Save and Export: True",
"BasicEditorWorkflows_LevelEntityComponent: result=SUCCESS",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"BasicEditorWorkflows_LevelEntityComponentCRUD.py",
expected_lines,
cfg_args=[level],
timeout=log_monitor_timeout,
auto_test_mode=False,
null_renderer=False
)
@@ -1,62 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C16929880: Add Delete Components
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestComponentCRUD(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C16929880", "C16877220")
@pytest.mark.SUITE_periodic
@pytest.mark.BAT
def test_ComponentCRUD_Add_Delete_Components(self, request, editor, level, launcher_platform):
expected_lines = [
"Entity Created",
"Box Shape found",
"Box Shape Component added: True",
"Mesh found",
"Mesh Component added: True",
"Mesh Component deleted: True",
"Mesh Component deletion undone: True",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"ComponentCRUD_Add_Delete_Components.py",
expected_lines,
cfg_args=[level],
auto_test_mode=False,
timeout=log_monitor_timeout
)
@@ -1,55 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
C6376081: Basic Function: Docked/Undocked Tools
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestDocking(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C6376081")
@pytest.mark.SUITE_sandbox
def test_Docking_BasicDockedTools(self, request, editor, level, launcher_platform):
expected_lines = [
"The tools are all docked together in a tabbed widget",
"Entity Outliner works when docked, can select an Entity",
"Entity Inspector works when docked, Entity name changed to DifferentName",
"Hello, world!" # This line verifies the Console is working while docked
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Docking_BasicDockedTools.py",
expected_lines,
cfg_args=[level],
timeout=log_monitor_timeout,
)
@@ -1,66 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
"""
C1506881: Adding/Removing Event Groups
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestInputBindings(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C1506881")
@pytest.mark.SUITE_periodic
def test_InputBindings_Add_Remove_Input_Events(self, request, editor, level, launcher_platform):
expected_lines = [
"Asset Editor opened: True",
"New Event Groups added when + is clicked",
"Event Group deleted when the Delete button is clicked on an Event Group",
"All event groups deleted on clicking the Delete button",
"Asset Editor closed: True",
]
unexpected_lines = [
"Asset Editor opened: False",
"Asset Editor closed: False",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"InputBindings_Add_Remove_Input_Events.py",
expected_lines,
unexpected_lines=unexpected_lines,
cfg_args=[level],
run_python="--runpython",
auto_test_mode=False,
timeout=log_monitor_timeout,
)
@@ -1,132 +0,0 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
import os
import pytest
# Bail on the test if ly_test_tools doesn't exist.
pytest.importorskip('ly_test_tools')
import ly_test_tools.environment.file_system as file_system
import ly_test_tools.environment.process_utils as process_utils
import editor_python_test_tools.hydra_test_utils as hydra
test_directory = os.path.join(os.path.dirname(__file__), "EditorScripts")
log_monitor_timeout = 180
@pytest.mark.parametrize('project', ['AutomatedTesting'])
@pytest.mark.parametrize('level', ['tmp_level'])
@pytest.mark.usefixtures("automatic_process_killer")
@pytest.mark.parametrize("launcher_platform", ['windows_editor'])
class TestMenus(object):
@pytest.fixture(autouse=True)
def setup_teardown(self, request, workspace, project, level):
def teardown():
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
process_utils.kill_processes_named("o3de", ignore_extensions=True) # Kill ProjectManager windows
request.addfinalizer(teardown)
file_system.delete([os.path.join(workspace.paths.engine_root(), project, "Levels", level)], True, True)
@pytest.mark.test_case_id("C16780783", "C2174438")
@pytest.mark.SUITE_sandbox
def test_Menus_EditMenuOptions_Work(self, request, editor, level, launcher_platform):
expected_lines = [
"Undo Action triggered",
"Redo Action triggered",
"Duplicate Action triggered",
"Delete Action triggered",
"Select All Action triggered",
"Invert Selection Action triggered",
"Toggle Pivot Location Action triggered",
"Reset Entity Transform",
"Reset Manipulator",
"Reset Transform (Local) Action triggered",
"Reset Transform (World) Action triggered",
"Hide Selection Action triggered",
"Show All Action triggered",
"Snap angle Action triggered",
"Move Action triggered",
"Rotate Action triggered",
"Scale Action triggered",
"Global Preferences Action triggered",
"Editor Settings Manager Action triggered",
"Customize Keyboard Action triggered",
"Export Keyboard Settings Action triggered",
"Import Keyboard Settings Action triggered",
"Menus_EditMenuOptions: result=SUCCESS"
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Menus_EditMenuOptions.py",
expected_lines,
cfg_args=[level],
run_python="--runpython",
timeout=log_monitor_timeout
)
@pytest.mark.test_case_id("C16780807")
@pytest.mark.SUITE_periodic
def test_Menus_ViewMenuOptions_Work(self, request, editor, level, launcher_platform):
expected_lines = [
"Center on Selection Action triggered",
"Show Quick Access Bar Action triggered",
"Configure Layout Action triggered",
"Go to Position Action triggered",
"Center on Selection Action triggered",
"Go to Location Action triggered",
"Remember Location Action triggered",
"Switch Camera Action triggered",
"Show/Hide Helpers Action triggered",
"Refresh Style Action triggered",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Menus_ViewMenuOptions.py",
expected_lines,
cfg_args=[level],
run_python="--runpython",
timeout=log_monitor_timeout
)
@pytest.mark.test_case_id("C16780778")
@pytest.mark.SUITE_sandbox
@pytest.mark.xfail # LYN-4208
def test_Menus_FileMenuOptions_Work(self, request, editor, level, launcher_platform):
expected_lines = [
"New Level Action triggered",
"Open Level Action triggered",
"Import Action triggered",
"Save Action triggered",
"Save As Action triggered",
"Save Level Statistics Action triggered",
"Edit Project Settings Action triggered",
"Edit Platform Settings Action triggered",
"New Project Action triggered",
"Open Project Action triggered",
"Show Log File Action triggered",
"Resave All Slices Action triggered",
"Exit Action triggered",
]
hydra.launch_and_validate_results(
request,
test_directory,
editor,
"Menus_FileMenuOptions.py",
expected_lines,
cfg_args=[level],
run_python="--runpython",
timeout=log_monitor_timeout
)
+5 -6
View File
@@ -64,14 +64,13 @@ include(cmake/Projects.cmake)
if(NOT INSTALLED_ENGINE)
# Add the rest of the targets
add_subdirectory(Assets)
add_subdirectory(Code)
add_subdirectory(python)
add_subdirectory(Registry)
add_subdirectory(scripts)
# SPEC-1417 will investigate and fix this
if(NOT PAL_PLATFORM_NAME STREQUAL "Mac")
add_subdirectory(Tools/LyTestTools/tests/)
add_subdirectory(Tools/RemoteConsole/ly_remote_console/tests/)
endif()
add_subdirectory(Templates)
add_subdirectory(Tools)
# Add external subdirectories listed in the engine.json. LY_EXTERNAL_SUBDIRS is a cache variable so the user can add extra
# external subdirectories
+1 -1
View File
@@ -628,7 +628,7 @@ void CAnimationContext::GoToFrameCmd(IConsoleCmdArgs* pArgs)
float targetFrame = (float)atof(pArgs->GetArg(1));
if (pSeq->GetTimeRange().start > targetFrame || targetFrame > pSeq->GetTimeRange().end)
{
gEnv->pLog->LogError("GoToFrame: requested time %f is outside the range of sequence %s (%f, %f)", targetFrame, pSeq->GetName(), pSeq->GetTimeRange().start, pSeq->GetTimeRange().end);
gEnv->pLog->LogError("GoToFrame: requested time %f is outside the range of sequence %s (%f, %f)", targetFrame, pSeq->GetName().c_str(), pSeq->GetTimeRange().start, pSeq->GetTimeRange().end);
return;
}
GetIEditor()->GetAnimation()->m_currTime = targetFrame;
+1
View File
@@ -14,6 +14,7 @@
#include <QPoint>
#include <QRect>
#include "Cry_Vector2.h"
#include <AzCore/Casting/numeric_cast.h>
//////////////////////////////////////////////////////////////////////////
class CWndGridHelper
+10 -3
View File
@@ -78,7 +78,6 @@ AZ_POP_DISABLE_WARNING
// CryCommon
#include <CryCommon/ITimer.h>
#include <CryCommon/IPhysics.h>
#include <CryCommon/ILevelSystem.h>
// Editor
@@ -3910,11 +3909,19 @@ void CCryEditApp::OpenLUAEditor(const char* files)
AZStd::string_view exePath;
AZ::ComponentApplicationBus::BroadcastResult(exePath, &AZ::ComponentApplicationRequests::GetExecutableFolder);
AZStd::string process = AZStd::string::format("\"%.*s" AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING "LuaIDE"
#if defined(AZ_PLATFORM_LINUX)
// On Linux platforms, launching a process is not done through a shell and its arguments are passed in
// separately. There is no need to wrap the process path in case of spaces in the path
constexpr const char* argumentQuoteString = "";
#else
constexpr const char* argumentQuoteString = "\"";
#endif
AZStd::string process = AZStd::string::format("%s%.*s" AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING "LuaIDE"
#if defined(AZ_PLATFORM_WINDOWS)
".exe"
#endif
"\"", aznumeric_cast<int>(exePath.size()), exePath.data());
"%s", argumentQuoteString, aznumeric_cast<int>(exePath.size()), exePath.data(), argumentQuoteString);
AZStd::string processArgs = AZStd::string::format("%s -engine-path \"%s\"", args.c_str(), engineRoot);
StartProcessDetached(process.c_str(), processArgs.c_str());
+4 -4
View File
@@ -1047,7 +1047,7 @@ static bool TryRenameFile(const QString& oldPath, const QString& newPath, int re
bool CCryEditDoc::SaveLevel(const QString& filename)
{
AZ_PROFILE_FUNCTION(AzToolsFramework);
AZ_PROFILE_FUNCTION(Editor);
QWaitCursor wait;
CAutoCheckOutDialogEnableForAll enableForAll;
@@ -1067,7 +1067,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
{
AZ_PROFILE_SCOPE(AzToolsFramework, "CCryEditDoc::SaveLevel BackupBeforeSave");
AZ_PROFILE_SCOPE(Editor, "CCryEditDoc::SaveLevel BackupBeforeSave");
BackupBeforeSave();
}
@@ -1178,7 +1178,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
CPakFile pakFile;
{
AZ_PROFILE_SCOPE(AzToolsFramework, "CCryEditDoc::SaveLevel Open PakFile");
AZ_PROFILE_SCOPE(Editor, "CCryEditDoc::SaveLevel Open PakFile");
if (!pakFile.Open(tempSaveFile.toUtf8().data(), false))
{
gEnv->pLog->LogWarning("Unable to open pack file %s for writing", tempSaveFile.toUtf8().data());
@@ -1209,7 +1209,7 @@ bool CCryEditDoc::SaveLevel(const QString& filename)
AZ::IO::ByteContainerStream<AZStd::vector<char>> entitySaveStream(&entitySaveBuffer);
{
AZ_PROFILE_SCOPE(AzToolsFramework, "CCryEditDoc::SaveLevel Save Entities To Stream");
AZ_PROFILE_SCOPE(Editor, "CCryEditDoc::SaveLevel Save Entities To Stream");
EBUS_EVENT_RESULT(
savedEntities, AzToolsFramework::EditorEntityContextRequestBus, SaveToStreamForEditor, entitySaveStream, layerEntities,
instancesInLayers);
-4
View File
@@ -8,8 +8,6 @@
#pragma once
#ifndef CRYINCLUDE_EDITOR_EDITORDEFS_H
#define CRYINCLUDE_EDITOR_EDITORDEFS_H
#include <AzCore/PlatformDef.h>
@@ -186,5 +184,3 @@
#endif
#endif
#endif // CRYINCLUDE_EDITOR_EDITORDEFS_H
@@ -5,6 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "EditorPreferencesPageViewportMovement.h"
@@ -12,44 +13,96 @@
#include <AzQtComponents/Components/StyleManager.h>
// Editor
#include "Settings.h"
#include "EditorViewportSettings.h"
#include "Settings.h"
void CEditorPreferencesPage_ViewportMovement::Reflect(AZ::SerializeContext& serialize)
{
serialize.Class<CameraMovementSettings>()
->Version(1)
->Field("MoveSpeed", &CameraMovementSettings::m_moveSpeed)
->Version(2)
->Field("TranslateSpeed", &CameraMovementSettings::m_translateSpeed)
->Field("RotateSpeed", &CameraMovementSettings::m_rotateSpeed)
->Field("FastMoveSpeed", &CameraMovementSettings::m_fastMoveSpeed)
->Field("WheelZoomSpeed", &CameraMovementSettings::m_wheelZoomSpeed)
->Field("InvertYAxis", &CameraMovementSettings::m_invertYRotation)
->Field("InvertPan", &CameraMovementSettings::m_invertPan);
->Field("BoostMultiplier", &CameraMovementSettings::m_boostMultiplier)
->Field("ScrollSpeed", &CameraMovementSettings::m_scrollSpeed)
->Field("DollySpeed", &CameraMovementSettings::m_dollySpeed)
->Field("PanSpeed", &CameraMovementSettings::m_panSpeed)
->Field("RotateSmoothing", &CameraMovementSettings::m_rotateSmoothing)
->Field("RotateSmoothness", &CameraMovementSettings::m_rotateSmoothness)
->Field("TranslateSmoothing", &CameraMovementSettings::m_translateSmoothing)
->Field("TranslateSmoothness", &CameraMovementSettings::m_translateSmoothness)
->Field("CaptureCursorLook", &CameraMovementSettings::m_captureCursorLook)
->Field("OrbitYawRotationInverted", &CameraMovementSettings::m_orbitYawRotationInverted)
->Field("PanInvertedX", &CameraMovementSettings::m_panInvertedX)
->Field("PanInvertedY", &CameraMovementSettings::m_panInvertedY);
serialize.Class<CEditorPreferencesPage_ViewportMovement>()
->Version(1)
->Field("CameraMovementSettings", &CEditorPreferencesPage_ViewportMovement::m_cameraMovementSettings);
serialize.Class<CEditorPreferencesPage_ViewportMovement>()->Version(1)->Field(
"CameraMovementSettings", &CEditorPreferencesPage_ViewportMovement::m_cameraMovementSettings);
AZ::EditContext* editContext = serialize.GetEditContext();
if (editContext)
if (AZ::EditContext* editContext = serialize.GetEditContext())
{
editContext->Class<CameraMovementSettings>("Camera Movement Settings", "")
->DataElement(AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_moveSpeed, "Camera Movement Speed", "Camera Movement Speed")
->DataElement(AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_rotateSpeed, "Camera Rotation Speed", "Camera Rotation Speed")
->DataElement(AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_fastMoveSpeed, "Fast Movement Scale", "Fast Movement Scale (holding shift")
->DataElement(AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_wheelZoomSpeed, "Wheel Zoom Speed", "Wheel Zoom Speed")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_invertYRotation, "Invert Y Axis", "Invert Y Rotation (holding RMB)")
->DataElement(AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_invertPan, "Invert Pan", "Invert Pan (holding MMB)");
editContext->Class<CameraMovementSettings>("Camera Settings", "")
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_translateSpeed, "Camera Movement Speed", "Camera movement speed")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_rotateSpeed, "Camera Rotation Speed", "Camera rotation speed")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_boostMultiplier, "Camera Boost Multiplier",
"Camera boost multiplier to apply to movement speed")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_scrollSpeed, "Camera Scroll Speed",
"Camera movement speed while using scroll/wheel input")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_dollySpeed, "Camera Dolly Speed",
"Camera movement speed while using mouse motion to move in and out")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_panSpeed, "Camera Pan Speed",
"Camera movement speed while panning using the mouse")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_rotateSmoothing, "Camera Rotate Smoothing",
"Is camera rotation smoothing enabled or disabled")
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_rotateSmoothness, "Camera Rotate Smoothness",
"Amount of camera smoothing to apply while rotating the camera")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->Attribute(AZ::Edit::Attributes::Visibility, &CameraMovementSettings::RotateSmoothingVisibility)
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_translateSmoothing, "Camera Translate Smoothing",
"Is camera translation smoothing enabled or disabled")
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ::Edit::PropertyRefreshLevels::EntireTree)
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_translateSmoothness, "Camera Translate Smoothness",
"Amount of camera smoothing to apply while translating the camera")
->Attribute(AZ::Edit::Attributes::Min, 0.01f)
->Attribute(AZ::Edit::Attributes::Visibility, &CameraMovementSettings::TranslateSmoothingVisibility)
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_orbitYawRotationInverted, "Camera Orbit Yaw Inverted",
"Inverted yaw rotation while orbiting")
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_panInvertedX, "Invert Pan X",
"Invert direction of pan in local X axis")
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_panInvertedY, "Invert Pan Y",
"Invert direction of pan in local Y axis")
->DataElement(
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_captureCursorLook, "Camera Capture Look Cursor",
"Should the cursor be captured (hidden) while performing free look");
editContext->Class<CEditorPreferencesPage_ViewportMovement>("Gizmo Movement Preferences", "Gizmo Movement Preferences")
editContext->Class<CEditorPreferencesPage_ViewportMovement>("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_ViewportMovement::m_cameraMovementSettings, "Camera Movement Settings", "Camera Movement Settings");
->DataElement(
AZ::Edit::UIHandlers::Default, &CEditorPreferencesPage_ViewportMovement::m_cameraMovementSettings,
"Camera Movement Settings", "Camera Movement Settings");
}
}
CEditorPreferencesPage_ViewportMovement::CEditorPreferencesPage_ViewportMovement()
{
InitializeSettings();
@@ -68,21 +121,36 @@ QIcon& CEditorPreferencesPage_ViewportMovement::GetIcon()
void CEditorPreferencesPage_ViewportMovement::OnApply()
{
SandboxEditor::SetCameraTranslateSpeed(m_cameraMovementSettings.m_moveSpeed);
SandboxEditor::SetCameraTranslateSpeed(m_cameraMovementSettings.m_translateSpeed);
SandboxEditor::SetCameraRotateSpeed(m_cameraMovementSettings.m_rotateSpeed);
SandboxEditor::SetCameraBoostMultiplier(m_cameraMovementSettings.m_fastMoveSpeed);
SandboxEditor::SetCameraScrollSpeed(m_cameraMovementSettings.m_wheelZoomSpeed);
SandboxEditor::SetCameraOrbitYawRotationInverted(m_cameraMovementSettings.m_invertYRotation);
SandboxEditor::SetCameraPanInvertedX(m_cameraMovementSettings.m_invertPan);
SandboxEditor::SetCameraPanInvertedY(m_cameraMovementSettings.m_invertPan);
SandboxEditor::SetCameraBoostMultiplier(m_cameraMovementSettings.m_boostMultiplier);
SandboxEditor::SetCameraScrollSpeed(m_cameraMovementSettings.m_scrollSpeed);
SandboxEditor::SetCameraDollyMotionSpeed(m_cameraMovementSettings.m_dollySpeed);
SandboxEditor::SetCameraPanSpeed(m_cameraMovementSettings.m_panSpeed);
SandboxEditor::SetCameraRotateSmoothness(m_cameraMovementSettings.m_rotateSmoothness);
SandboxEditor::SetCameraRotateSmoothingEnabled(m_cameraMovementSettings.m_rotateSmoothing);
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::SetCameraPanInvertedX(m_cameraMovementSettings.m_panInvertedX);
SandboxEditor::SetCameraPanInvertedY(m_cameraMovementSettings.m_panInvertedY);
}
void CEditorPreferencesPage_ViewportMovement::InitializeSettings()
{
m_cameraMovementSettings.m_moveSpeed = SandboxEditor::CameraTranslateSpeed();
m_cameraMovementSettings.m_translateSpeed = SandboxEditor::CameraTranslateSpeed();
m_cameraMovementSettings.m_rotateSpeed = SandboxEditor::CameraRotateSpeed();
m_cameraMovementSettings.m_fastMoveSpeed = SandboxEditor::CameraBoostMultiplier();
m_cameraMovementSettings.m_wheelZoomSpeed = SandboxEditor::CameraScrollSpeed();
m_cameraMovementSettings.m_invertYRotation = SandboxEditor::CameraOrbitYawRotationInverted();
m_cameraMovementSettings.m_invertPan = SandboxEditor::CameraPanInvertedX() && SandboxEditor::CameraPanInvertedY();
m_cameraMovementSettings.m_boostMultiplier = SandboxEditor::CameraBoostMultiplier();
m_cameraMovementSettings.m_scrollSpeed = SandboxEditor::CameraScrollSpeed();
m_cameraMovementSettings.m_dollySpeed = SandboxEditor::CameraDollyMotionSpeed();
m_cameraMovementSettings.m_panSpeed = SandboxEditor::CameraPanSpeed();
m_cameraMovementSettings.m_rotateSmoothness = SandboxEditor::CameraRotateSmoothness();
m_cameraMovementSettings.m_rotateSmoothing = SandboxEditor::CameraRotateSmoothingEnabled();
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_panInvertedX = SandboxEditor::CameraPanInvertedX();
m_cameraMovementSettings.m_panInvertedY = SandboxEditor::CameraPanInvertedY();
}
@@ -5,17 +5,21 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include "Include/IPreferencesPage.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <QIcon>
inline AZ::Crc32 EditorPropertyVisibility(const bool enabled)
{
return enabled ? AZ::Edit::PropertyVisibility::Show : AZ::Edit::PropertyVisibility::Hide;
}
class CEditorPreferencesPage_ViewportMovement
: public IPreferencesPage
class CEditorPreferencesPage_ViewportMovement : public IPreferencesPage
{
public:
AZ_RTTI(CEditorPreferencesPage_ViewportMovement, "{BC593332-7EAF-4171-8A35-1C5DE5B40909}", IPreferencesPage)
@@ -25,12 +29,22 @@ public:
CEditorPreferencesPage_ViewportMovement();
virtual ~CEditorPreferencesPage_ViewportMovement() = default;
virtual const char* GetCategory() override { return "Viewports"; }
virtual const char* GetCategory() override
{
return "Viewports";
}
virtual const char* GetTitle();
virtual QIcon& GetIcon() override;
virtual void OnApply() override;
virtual void OnCancel() override {}
virtual bool OnQueryCancel() override { return true; }
virtual void OnCancel() override
{
}
virtual bool OnQueryCancel() override
{
return true;
}
private:
void InitializeSettings();
@@ -39,16 +53,32 @@ private:
{
AZ_TYPE_INFO(CameraMovementSettings, "{60B8C07E-5F48-4171-A50B-F45558B5CCA1}")
float m_moveSpeed;
float m_translateSpeed;
float m_rotateSpeed;
float m_fastMoveSpeed;
float m_wheelZoomSpeed;
bool m_invertYRotation;
bool m_invertPan;
float m_scrollSpeed;
float m_dollySpeed;
float m_panSpeed;
float m_boostMultiplier;
float m_rotateSmoothness;
bool m_rotateSmoothing;
float m_translateSmoothness;
bool m_translateSmoothing;
bool m_captureCursorLook;
bool m_orbitYawRotationInverted;
bool m_panInvertedX;
bool m_panInvertedY;
AZ::Crc32 RotateSmoothingVisibility() const
{
return EditorPropertyVisibility(m_rotateSmoothing);
}
AZ::Crc32 TranslateSmoothingVisibility() const
{
return EditorPropertyVisibility(m_translateSmoothing);
}
};
CameraMovementSettings m_cameraMovementSettings;
QIcon m_icon;
};
+12 -1
View File
@@ -33,6 +33,7 @@ namespace SandboxEditor
constexpr AZStd::string_view CameraTranslateSmoothnessSetting = "/Amazon/Preferences/Editor/Camera/TranslateSmoothness";
constexpr AZStd::string_view CameraTranslateSmoothingSetting = "/Amazon/Preferences/Editor/Camera/TranslateSmoothing";
constexpr AZStd::string_view CameraRotateSmoothingSetting = "/Amazon/Preferences/Editor/Camera/RotateSmoothing";
constexpr AZStd::string_view CameraCaptureCursorLookSetting = "/Amazon/Preferences/Editor/Camera/CaptureCursorLook";
constexpr AZStd::string_view CameraTranslateForwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateForwardId";
constexpr AZStd::string_view CameraTranslateBackwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateBackwardId";
constexpr AZStd::string_view CameraTranslateLeftIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateLeftId";
@@ -60,7 +61,7 @@ namespace SandboxEditor
AZStd::remove_cvref_t<T> GetRegistry(const AZStd::string_view setting, T&& defaultValue)
{
AZStd::remove_cvref_t<T> value = AZStd::forward<T>(defaultValue);
if (auto* registry = AZ::SettingsRegistry::Get())
if (const auto* registry = AZ::SettingsRegistry::Get())
{
registry->Get(value, setting);
}
@@ -281,6 +282,16 @@ namespace SandboxEditor
SetRegistry(CameraTranslateSmoothingSetting, enabled);
}
bool CameraCaptureCursorForLook()
{
return GetRegistry(CameraCaptureCursorLookSetting, true);
}
void SetCameraCaptureCursorForLook(const bool capture)
{
SetRegistry(CameraCaptureCursorLookSetting, capture);
}
AzFramework::InputChannelId CameraTranslateForwardChannelId()
{
return AzFramework::InputChannelId(
+3
View File
@@ -86,6 +86,9 @@ namespace SandboxEditor
SANDBOX_API bool CameraTranslateSmoothingEnabled();
SANDBOX_API void SetCameraTranslateSmoothingEnabled(bool enabled);
SANDBOX_API bool CameraCaptureCursorForLook();
SANDBOX_API void SetCameraCaptureCursorForLook(bool capture);
SANDBOX_API AzFramework::InputChannelId CameraTranslateForwardChannelId();
SANDBOX_API void SetCameraTranslateForwardChannelId(AZStd::string_view cameraTranslateForwardId);
+24 -90
View File
@@ -54,6 +54,8 @@
// CryCommon
#include <CryCommon/HMDBus.h>
#include <CryCommon/IRenderAuxGeom.h>
#include <CryCommon/physinterface.h>
// AzFramework
#include <AzFramework/Render/IntersectorInterface.h>
@@ -104,7 +106,6 @@
AZ_CVAR(
bool, ed_visibility_logTiming, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Output the timing of the new IVisibilitySystem query");
AZ_CVAR(bool, ed_showCursorCameraLook, true, nullptr, AZ::ConsoleFunctorFlags::Null, "Show the cursor when using free look with the new camera system");
EditorViewportWidget* EditorViewportWidget::m_pPrimaryViewport = nullptr;
@@ -394,8 +395,6 @@ void EditorViewportWidget::UpdateContent(int flags)
//////////////////////////////////////////////////////////////////////////
void EditorViewportWidget::Update()
{
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
if (Editor::EditorQtApplication::instance()->isMovingOrResizing())
{
return;
@@ -742,9 +741,13 @@ void EditorViewportWidget::OnBeginPrepareRender()
RenderAll();
// Draw 2D helpers.
#ifdef LYSHINE_ATOM_TODO
TransformationMatrices backupSceneMatrices;
#endif
m_debugDisplay->DepthTestOff();
//m_renderer->Set2DMode(m_rcClient.right(), m_rcClient.bottom(), backupSceneMatrices);
#ifdef LYSHINE_ATOM_TODO
m_renderer->Set2DMode(m_rcClient.right(), m_rcClient.bottom(), backupSceneMatrices);
#endif
auto prevState = m_debugDisplay->GetState();
m_debugDisplay->SetState(e_Mode3D | e_AlphaBlended | e_FillModeSolid | e_CullModeBack | e_DepthWriteOn | e_DepthTestOn);
@@ -957,15 +960,11 @@ AzFramework::CameraState EditorViewportWidget::GetCameraState()
AZ::Vector3 EditorViewportWidget::PickTerrain(const AzFramework::ScreenPoint& point)
{
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
return LYVec3ToAZVec3(ViewToWorld(AzToolsFramework::ViewportInteraction::QPointFromScreenPoint(point), nullptr, true));
}
AZ::EntityId EditorViewportWidget::PickEntity(const AzFramework::ScreenPoint& point)
{
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
PreWidgetRendering();
AZ::EntityId entityId;
@@ -992,8 +991,6 @@ float EditorViewportWidget::TerrainHeight(const AZ::Vector2& position)
void EditorViewportWidget::FindVisibleEntities(AZStd::vector<AZ::EntityId>& visibleEntitiesOut)
{
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
visibleEntitiesOut.assign(m_entityVisibilityQuery.Begin(), m_entityVisibilityQuery.End());
}
@@ -1079,13 +1076,19 @@ AZStd::shared_ptr<AtomToolsFramework::ModularViewportCameraController> CreateMod
{
const auto hideCursor = [viewportId]
{
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event(
viewportId, &AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::BeginCursorCapture);
if (SandboxEditor::CameraCaptureCursorForLook())
{
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event(
viewportId, &AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::BeginCursorCapture);
}
};
const auto showCursor = [viewportId]
{
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event(
viewportId, &AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::EndCursorCapture);
if (SandboxEditor::CameraCaptureCursorForLook())
{
AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event(
viewportId, &AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::EndCursorCapture);
}
};
auto firstPersonRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(SandboxEditor::CameraFreeLookChannelId());
@@ -1094,12 +1097,10 @@ AZStd::shared_ptr<AtomToolsFramework::ModularViewportCameraController> CreateMod
return SandboxEditor::CameraRotateSpeed();
};
if (!ed_showCursorCameraLook)
{
// default behavior is to hide the cursor but this can be disabled (useful for remote desktop)
firstPersonRotateCamera->SetActivationBeganFn(hideCursor);
firstPersonRotateCamera->SetActivationEndedFn(showCursor);
}
// default behavior is to hide the cursor but this can be disabled (useful for remote desktop)
// note: See CaptureCursorLook in the Settings Registry
firstPersonRotateCamera->SetActivationBeganFn(hideCursor);
firstPersonRotateCamera->SetActivationEndedFn(showCursor);
auto firstPersonPanCamera =
AZStd::make_shared<AzFramework::PanCameraInput>(SandboxEditor::CameraFreePanChannelId(), AzFramework::LookPan);
@@ -1288,7 +1289,7 @@ void EditorViewportWidget::SetViewportId(int id)
m_renderViewport->GetControllerList()->Add(AZStd::make_shared<SandboxEditor::ViewportManipulatorController>());
m_renderViewport->GetControllerList()->Add(CreateModularViewportCameraController(AzFramework::ViewportId(id)));
m_renderViewport->SetViewportSettings(&g_EditorViewportSettings);
UpdateScene();
@@ -1648,7 +1649,7 @@ void EditorViewportWidget::SetViewTM(const Matrix34& camMatrix, bool bMoveOnly)
{
// Should be impossible anyways
AZ_Assert(false, "Internal logic error - view entity Id and view source type out of sync. Please report this as a bug");
return ShouldUpdateObject::No;
return ShouldUpdateObject::No;
}
// Check that the current view is the same view as the view entity view
@@ -2013,73 +2014,6 @@ Vec3 EditorViewportWidget::ViewToWorldNormal(const QPoint& vp, bool onlyTerrain,
return Vec3(0, 0, 1);
}
//////////////////////////////////////////////////////////////////////////
bool EditorViewportWidget::AdjustObjectPosition(const ray_hit& hit, Vec3& outNormal, Vec3& outPos) const
{
Matrix34A objMat, objMatInv;
Matrix33 objRot, objRotInv;
if (hit.pCollider->GetiForeignData() != PHYS_FOREIGN_ID_STATIC)
{
return false;
}
IRenderNode* pNode = (IRenderNode*) hit.pCollider->GetForeignData(PHYS_FOREIGN_ID_STATIC);
if (!pNode || !pNode->GetEntityStatObj())
{
return false;
}
IStatObj* pEntObject = pNode->GetEntityStatObj(hit.partid, 0, &objMat, false);
if (!pEntObject || !pEntObject->GetRenderMesh())
{
return false;
}
objRot = Matrix33(objMat);
objRot.NoScale(); // No scale.
objRotInv = objRot;
objRotInv.Invert();
float fWorldScale = objMat.GetColumn(0).GetLength(); // GetScale
float fWorldScaleInv = 1.0f / fWorldScale;
// transform decal into object space
objMatInv = objMat;
objMatInv.Invert();
// put into normal object space hit direction of projection
Vec3 invhitn = -(hit.n);
Vec3 vOS_HitDir = objRotInv.TransformVector(invhitn).GetNormalized();
// put into position object space hit position
Vec3 vOS_HitPos = objMatInv.TransformPoint(hit.pt);
vOS_HitPos -= vOS_HitDir * RENDER_MESH_TEST_DISTANCE * fWorldScaleInv;
IRenderMesh* pRM = pEntObject->GetRenderMesh();
AABB aabbRNode;
pRM->GetBBox(aabbRNode.min, aabbRNode.max);
Vec3 vOut(0, 0, 0);
if (!Intersect::Ray_AABB(Ray(vOS_HitPos, vOS_HitDir), aabbRNode, vOut))
{
return false;
}
if (!pRM || !pRM->GetVerticesCount())
{
return false;
}
if (RayRenderMeshIntersection(pRM, vOS_HitPos, vOS_HitDir, outPos, outNormal))
{
outNormal = objRot.TransformVector(outNormal).GetNormalized();
outPos = objMat.TransformPoint(outPos);
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool EditorViewportWidget::RayRenderMeshIntersection(IRenderMesh* pRenderMesh, const Vec3& vInPos, const Vec3& vInDir, Vec3& vOutPos, Vec3& vOutNormal) const
{
@@ -2512,7 +2446,7 @@ void EditorViewportWidget::SetViewFromEntityPerspective(const AZ::EntityId& enti
void EditorViewportWidget::SetViewAndMovementLockFromEntityPerspective(const AZ::EntityId& entityId, [[maybe_unused]] bool lockCameraMovement)
{
// This is an editor event, so is only serviced during edit mode, not play game mode
//
//
if (m_playInEditorState != PlayInEditorState::Editor)
{
AZ_Warning("EditorViewportWidget", false,
-1
View File
@@ -220,7 +220,6 @@ private:
// Draw a selected region if it has been selected
void RenderSelectedRegion();
bool AdjustObjectPosition(const ray_hit& hit, Vec3& outNormal, Vec3& outPos) const;
bool RayRenderMeshIntersection(IRenderMesh* pRenderMesh, const Vec3& vInPos, const Vec3& vInDir, Vec3& vOutPos, Vec3& vOutNormal) const;
bool AddCameraMenuItems(QMenu* menu);
+7 -7
View File
@@ -622,7 +622,7 @@ bool CExportManager::ShowFBXExportDialog()
if (pivotObjectNode && !pivotObjectNode->IsGroupNode())
{
m_pivotEntityObject = static_cast<CEntityObject*>(GetIEditor()->GetObjectManager()->FindObject(pivotObjectNode->GetName()));
m_pivotEntityObject = static_cast<CEntityObject*>(GetIEditor()->GetObjectManager()->FindObject(pivotObjectNode->GetName().c_str()));
if (m_pivotEntityObject)
{
@@ -807,7 +807,7 @@ void CExportManager::FillAnimTimeNode(XmlNodeRef writeNode, CTrackViewAnimNode*
if (numAllTracks > 0)
{
XmlNodeRef objNode = writeNode->createNode(CleanXMLText(pObjectNode->GetName()).toUtf8().data());
XmlNodeRef objNode = writeNode->createNode(CleanXMLText(pObjectNode->GetName().c_str()).toUtf8().data());
writeNode->setAttr("time", m_animTimeExportPrimarySequenceCurrentTime);
for (unsigned int trackID = 0; trackID < numAllTracks; ++trackID)
@@ -818,7 +818,7 @@ void CExportManager::FillAnimTimeNode(XmlNodeRef writeNode, CTrackViewAnimNode*
if (trackType == AnimParamType::Animation || trackType == AnimParamType::Sound)
{
QString childName = CleanXMLText(childTrack->GetName());
QString childName = CleanXMLText(childTrack->GetName().c_str());
if (childName.isEmpty())
{
@@ -976,7 +976,7 @@ bool CExportManager::AddObjectsFromSequence(CTrackViewSequence* pSequence, XmlNo
else
{
// In case of exporting animation/sound times data
const QString sequenceName = pSubSequence->GetName();
const QString sequenceName = QString::fromUtf8(pSubSequence->GetName().c_str());
XmlNodeRef subSeqNode2 = seqNode->createNode(sequenceName.toUtf8().data());
if (sequenceName == m_animTimeExportPrimarySequenceName)
@@ -1253,14 +1253,14 @@ void CExportManager::SaveNodeKeysTimeToXML()
m_soundKeyTimeExport = exportDialog.IsSoundExportChecked();
QString filters = "All files (*.xml)";
QString defaultName = QString(pSequence->GetName()) + ".xml";
QString defaultName = QString::fromUtf8(pSequence->GetName().c_str()) + ".xml";
QtUtil::QtMFCScopedHWNDCapture cap;
CAutoDirectoryRestoreFileDialog dlg(QFileDialog::AcceptSave, QFileDialog::AnyFile, "xml", defaultName, filters, {}, {}, cap);
if (dlg.exec())
{
m_animTimeNode = XmlHelpers::CreateXmlNode(pSequence->GetName());
m_animTimeExportPrimarySequenceName = pSequence->GetName();
m_animTimeNode = XmlHelpers::CreateXmlNode(pSequence->GetName().c_str());
m_animTimeExportPrimarySequenceName = QString::fromUtf8(pSequence->GetName().c_str());
m_data.Clear();
m_animTimeExportPrimarySequenceCurrentTime = 0.0;
+3 -4
View File
@@ -6,9 +6,6 @@
*
*/
#ifndef CRYINCLUDE_EDITOR_IEDITOR_H
#define CRYINCLUDE_EDITOR_IEDITOR_H
#pragma once
#ifdef PLUGIN_EXPORTS
@@ -25,6 +22,7 @@
#include <WinWidgetId.h>
#include <AzCore/Component/EntityId.h>
#include <AzCore/Debug/Budget.h>
class QMenu;
@@ -738,4 +736,5 @@ struct IInitializeUIInfo
virtual void SetInfoText(const char* text) = 0;
};
#endif // CRYINCLUDE_EDITOR_IEDITOR_H
AZ_DECLARE_BUDGET(Editor);
-2
View File
@@ -405,8 +405,6 @@ void CEditorImpl::Update()
// Make sure this is not called recursively
m_bUpdates = false;
FUNCTION_PROFILER(GetSystem(), PROFILE_EDITOR);
//@FIXME: Restore this latter.
//if (GetGameEngine() && GetGameEngine()->IsLevelLoaded())
{
-3
View File
@@ -15,9 +15,6 @@
#pragma once
struct IStatObj;
struct IMaterial;
#include "Include/IIconManager.h" // for IIconManager
#include "IEditor.h" // for IDocListener
-4
View File
@@ -6,8 +6,6 @@
*
*/
#pragma once
#ifndef CRYINCLUDE_EDITOR_INCLUDE_IEDITORMATERIAL_H
#define CRYINCLUDE_EDITOR_INCLUDE_IEDITORMATERIAL_H
#include "BaseLibraryItem.h"
@@ -20,5 +18,3 @@ struct IEditorMaterial
virtual _smart_ptr<IMaterial> GetMatInfo(bool bUseExistingEngineMaterial = false) = 0;
virtual void DisableHighlightForFrame() = 0;
};
#endif
@@ -7,6 +7,7 @@
*/
#include <AtomToolsFramework/Viewport/ModularViewportCameraController.h>
#include <AzCore/Settings/SettingsRegistryImpl.h>
#include <AzFramework/Viewport/ViewportControllerList.h>
#include <AzToolsFramework/Input/QtEventToAzInputManager.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
@@ -95,10 +96,16 @@ namespace UnitTest
m_controllerList->RegisterViewportContext(TestViewportId);
m_inputChannelMapper = AZStd::make_unique<AzToolsFramework::QtEventToAzInputMapper>(m_rootWidget.get(), TestViewportId);
m_settingsRegistry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
AZ::SettingsRegistry::Register(m_settingsRegistry.get());
}
void TearDown() override
{
AZ::SettingsRegistry::Unregister(m_settingsRegistry.get());
m_settingsRegistry.reset();
m_inputChannelMapper.reset();
m_controllerList->UnregisterViewportContext(TestViewportId);
@@ -170,7 +177,7 @@ namespace UnitTest
void RepeatDiagonalMouseMovements(const AZStd::function<float()>& deltaTimeFn)
{
// move to the center of the screen
auto start = QPoint(WidgetSize.width() / 2, WidgetSize.height() / 2);
const auto start = QPoint(WidgetSize.width() / 2, WidgetSize.height() / 2);
MouseMove(m_rootWidget.get(), start, QPoint(0, 0));
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTimeFn()), AZ::ScriptTimePoint() });
@@ -204,12 +211,15 @@ namespace UnitTest
::testing::NiceMock<MockWindowRequests> m_mockWindowRequests;
ViewportMouseCursorRequestImpl m_viewportMouseCursorRequests;
AtomToolsFramework::ModularCameraViewportContext* m_cameraViewportContextView = nullptr;
AZStd::unique_ptr<AZ::SettingsRegistryInterface> m_settingsRegistry;
};
const AzFramework::ViewportId ModularViewportCameraControllerFixture::TestViewportId = AzFramework::ViewportId(0);
TEST_F(ModularViewportCameraControllerFixture, MouseMovementDoesNotAccumulateExcessiveDriftInModularViewportCameraWithVaryingDeltaTime)
{
SandboxEditor::SetCameraCaptureCursorForLook(false);
// Given
PrepareCollaborators();
@@ -242,6 +252,8 @@ namespace UnitTest
ModularViewportCameraControllerDeltaTimeParamFixture,
MouseMovementDoesNotAccumulateExcessiveDriftInModularViewportCameraWithFixedDeltaTime)
{
SandboxEditor::SetCameraCaptureCursorForLook(false);
// Given
PrepareCollaborators();
@@ -263,4 +275,92 @@ namespace UnitTest
INSTANTIATE_TEST_CASE_P(
All, ModularViewportCameraControllerDeltaTimeParamFixture, testing::Values(1.0f / 60.0f, 1.0f / 50.0f, 1.0f / 30.0f));
TEST_F(ModularViewportCameraControllerFixture, MouseMovementOrientatesCameraWhenCursorIsCaptured)
{
// Given
PrepareCollaborators();
// ensure cursor is captured
SandboxEditor::SetCameraCaptureCursorForLook(true);
const float deltaTime = 1.0f / 60.0f;
// When
// move to the center of the screen
auto start = QPoint(WidgetSize.width() / 2, WidgetSize.height() / 2);
MouseMove(m_rootWidget.get(), start, QPoint(0, 0));
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() });
const auto mouseDelta = QPoint(5, 0);
// initial movement to begin the camera behavior
MousePressAndMove(m_rootWidget.get(), start, mouseDelta, Qt::MouseButton::RightButton);
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() });
// move the cursor right
for (int i = 0; i < 50; ++i)
{
MousePressAndMove(m_rootWidget.get(), start + mouseDelta, mouseDelta, Qt::MouseButton::RightButton);
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() });
}
// move the cursor left (do an extra iteration moving left to account for the initial dead-zone)
for (int i = 0; i < 51; ++i)
{
MousePressAndMove(m_rootWidget.get(), start + mouseDelta, -mouseDelta, Qt::MouseButton::RightButton);
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() });
}
QTest::mouseRelease(m_rootWidget.get(), Qt::MouseButton::RightButton, Qt::KeyboardModifier::NoModifier, start + mouseDelta);
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() });
// Then
// retrieve the amount of yaw rotation
const AZ::Quaternion cameraRotation = m_cameraViewportContextView->GetCameraTransform().GetRotation();
const auto eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromQuaternion(cameraRotation));
// camera should be back at the center (no yaw)
using ::testing::FloatNear;
EXPECT_THAT(eulerAngles.GetZ(), FloatNear(0.0f, 0.001f));
// Clean-up
HaltCollaborators();
}
TEST_F(ModularViewportCameraControllerFixture, CameraDoesNotContinueToRotateGivenNoInputWhenCaptured)
{
// Given
PrepareCollaborators();
SandboxEditor::SetCameraCaptureCursorForLook(true);
const float deltaTime = 1.0f / 60.0f;
// When
// move to the center of the screen
auto start = QPoint(WidgetSize.width() / 2, WidgetSize.height() / 2);
MouseMove(m_rootWidget.get(), start, QPoint(0, 0));
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() });
// will move a small amount initially
const auto mouseDelta = QPoint(5, 0);
MousePressAndMove(m_rootWidget.get(), start, mouseDelta, Qt::MouseButton::RightButton);
// ensure further updates to not continue to rotate
for (int i = 0; i < 50; ++i)
{
m_controllerList->UpdateViewport({ TestViewportId, AzFramework::FloatSeconds(deltaTime), AZ::ScriptTimePoint() });
}
// Then
// ensure the camera rotation is no longer the identity
const AZ::Quaternion cameraRotation = m_cameraViewportContextView->GetCameraTransform().GetRotation();
const auto eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromQuaternion(cameraRotation));
// initial amount of rotation after first mouse move
using ::testing::FloatNear;
EXPECT_THAT(eulerAngles.GetZ(), FloatNear(-0.025f, 0.001f));
// Clean-up
HaltCollaborators();
}
} // namespace UnitTest
+3 -3
View File
@@ -288,7 +288,7 @@ AZ_POP_DISABLE_WARNING
str += "Version Unknown";
}
}
azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, " %d.%d", OSVerInfo.dwMajorVersion, OSVerInfo.dwMinorVersion);
azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, " %ld.%ld", OSVerInfo.dwMajorVersion, OSVerInfo.dwMinorVersion);
str += szBuffer;
//////////////////////////////////////////////////////////////////////
@@ -338,7 +338,7 @@ AZ_POP_DISABLE_WARNING
str += " ";
azstrdate(szBuffer);
str += szBuffer;
azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, ", system running for %d minutes", GetTickCount() / 60000);
azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, ", system running for %ld minutes", GetTickCount() / 60000);
str += szBuffer;
CryLog("%s", str.toUtf8().data());
#else
@@ -388,7 +388,7 @@ AZ_POP_DISABLE_WARNING
L"(Unknown graphics card)", szLanguageBufferW, sizeof(szLanguageBufferW),
L"system.ini");
AZStd::to_string(szLanguageBuffer, szLanguageBufferW);
azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, "Current display mode is %dx%dx%d, %s",
azsnprintf(szBuffer, MAX_LOGBUFFER_SIZE, "Current display mode is %ldx%ldx%ld, %s",
DisplayConfig.dmPelsWidth, DisplayConfig.dmPelsHeight,
DisplayConfig.dmBitsPerPel, szLanguageBuffer.c_str());
CryLog("%s", szBuffer);
+2 -3
View File
@@ -38,7 +38,6 @@
// To use the Andrew's algorithm in order to make convex hull from the points, this header is needed.
#include "Util/GeometryUtil.h"
namespace {
QColor kLinkColorParent = QColor(0, 255, 255);
QColor kLinkColorChild = QColor(0, 0, 255);
@@ -1928,7 +1927,7 @@ bool CBaseObject::HitTestRectBounds(HitContext& hc, const AABB& box)
//////////////////////////////////////////////////////////////////////////
bool CBaseObject::HitTestRect(HitContext& hc)
{
AZ_PROFILE_FUNCTION(Entity);
AZ_PROFILE_FUNCTION(Editor);
AABB box;
@@ -1965,7 +1964,7 @@ bool CBaseObject::HitHelperTest(HitContext& hc)
//////////////////////////////////////////////////////////////////////////
bool CBaseObject::HitHelperAtTest(HitContext& hc, const Vec3& pos)
{
AZ_PROFILE_FUNCTION(Entity);
AZ_PROFILE_FUNCTION(Editor);
bool bResult = false;
-1
View File
@@ -63,7 +63,6 @@ struct SANDBOX_API DisplayContext
CDisplaySettings* settings;
IDisplayViewport* view;
IRenderer* renderer;
IRenderAuxGeom* pRenderAuxGeom;
IIconManager* pIconManager;
CCamera* camera;
+23 -6
View File
@@ -26,7 +26,6 @@
DisplayContext::DisplayContext()
{
view = 0;
renderer = 0;
flags = 0;
settings = 0;
pIconManager = 0;
@@ -1083,7 +1082,10 @@ void DisplayContext::DrawTerrainLine(Vec3 worldPos1, Vec3 worldPos2)
//////////////////////////////////////////////////////////////////////////
void DisplayContext::DrawTextLabel(const Vec3& pos, float size, const char* text, const bool bCenter, [[maybe_unused]] int srcOffsetX, [[maybe_unused]] int scrOffsetY)
{
ColorF col(m_color4b.r * (1.0f / 255.0f), m_color4b.g * (1.0f / 255.0f), m_color4b.b * (1.0f / 255.0f), m_color4b.a * (1.0f / 255.0f));
AZ_ErrorOnce(nullptr, false, "DisplayContext::DrawTextLabel needs to be removed/ported to use Atom");
#if 0
ColorF col(m_color4b.r * (1.0f / 255.0f), m_color4b.g * (1.0f / 255.0f), m_color4b.b * (1.0f / 255.0f), m_color4b.a * (1.0f / 255.0f));
float fCol[4] = { col.r, col.g, col.b, col.a };
if (flags & DISPLAY_2D)
@@ -1096,13 +1098,28 @@ void DisplayContext::DrawTextLabel(const Vec3& pos, float size, const char* text
{
renderer->DrawLabelEx(pos, size, fCol, true, true, text);
}
#else
AZ_UNUSED(pos);
AZ_UNUSED(size);
AZ_UNUSED(text);
AZ_UNUSED(bCenter);
#endif
}
//////////////////////////////////////////////////////////////////////////
void DisplayContext::Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter)
{
AZ_ErrorOnce(nullptr, false, "DisplayContext::Draw2dTextLabel needs to be removed/ported to use Atom");
#if 0
float col[4] = { m_color4b.r * (1.0f / 255.0f), m_color4b.g * (1.0f / 255.0f), m_color4b.b * (1.0f / 255.0f), m_color4b.a * (1.0f / 255.0f) };
renderer->Draw2dLabel(x, y, size, col, bCenter, "%s", text);
#else
AZ_UNUSED(x);
AZ_UNUSED(y);
AZ_UNUSED(size);
AZ_UNUSED(text);
AZ_UNUSED(bCenter);
#endif
}
//////////////////////////////////////////////////////////////////////////
@@ -1261,10 +1278,6 @@ void DisplayContext::DrawTextureLabel(const Vec3& pos, int nWidth, int nHeight,
//////////////////////////////////////////////////////////////////////////
void DisplayContext::Flush2D()
{
#ifndef PHYSICS_EDITOR
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
#endif
if (m_textureLabels.empty())
{
return;
@@ -1273,6 +1286,9 @@ void DisplayContext::Flush2D()
int rcw, rch;
view->GetDimensions(&rcw, &rch);
AZ_ErrorOnce(nullptr, false, "DisplayContext::Flush2D needs to be removed/ported to use Atom");
#if 0
TransformationMatrices backupSceneMatrices;
renderer->Set2DMode(rcw, rch, backupSceneMatrices, 0.0f, 1.0f);
@@ -1314,6 +1330,7 @@ void DisplayContext::Flush2D()
}
renderer->Unset2DMode(backupSceneMatrices);
#endif
m_textureLabels.clear();
}
+1 -1
View File
@@ -497,7 +497,7 @@ bool CEntityObject::HitTestRect(HitContext& hc)
//////////////////////////////////////////////////////////////////////////
int CEntityObject::MouseCreateCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags)
{
AZ_PROFILE_FUNCTION(Editor);
AZ_PROFILE_FUNCTION(Entity);
if (event == eMouseMove || event == eMouseLDown)
{
-2
View File
@@ -18,8 +18,6 @@
//////////////////////////////////////////////////////////////////////////
void CGizmoManager::Display(DisplayContext& dc)
{
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
AABB bbox;
std::vector<CGizmo*> todelete;
for (Gizmos::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
-1
View File
@@ -37,7 +37,6 @@ 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.
@@ -19,7 +19,6 @@
#include "Objects/ObjectLoader.h"
#include "Objects/SelectionGroup.h"
//////////////////////////////////////////////////////////////////////////
// CUndoBaseObjectNew implementation.
//////////////////////////////////////////////////////////////////////////
+6 -1
View File
@@ -177,11 +177,15 @@ void CTrackGizmo::DrawAxis(DisplayContext& dc, const Vec3& org)
float col[4] = { 1, 1, 1, 1 };
float hcol[4] = { 1, 0, 0, 1 };
Vec3 colX(1, 0, 0), colY(0, 1, 0), colZ(0, 0, 1);
AZ_ErrorOnce(nullptr, false, "CTrackGizmo::DrawAxis needs to be removed/ported to use Atom");
#if 0
dc.renderer->DrawLabelEx(org + x, 1.2f, col, true, true, "X");
dc.renderer->DrawLabelEx(org + y, 1.2f, col, true, true, "Y");
dc.renderer->DrawLabelEx(org + z, 1.2f, col, true, true, "Z");
Vec3 colX(1, 0, 0), colY(0, 1, 0), colZ(0, 0, 1);
if (s_highlightAxis)
{
float col2[4] = { 1, 0, 0, 1 };
@@ -201,6 +205,7 @@ void CTrackGizmo::DrawAxis(DisplayContext& dc, const Vec3& org)
dc.renderer->DrawLabelEx(org + z, 1.2f, col2, true, true, "Z");
}
}
#endif
x = x * 0.8f;
y = y * 0.8f;
+1
View File
@@ -13,6 +13,7 @@
#include "Include/IEditorClassFactory.h"
#include "Util/GuidUtil.h"
#include <map>
//! Derive from this class to decrease the amount of work for creating a new class description
//! Provides standard reference counter implementation for IUnknown
@@ -40,6 +40,7 @@
#include <LmbrCentral/Rendering/MaterialOwnerBus.h>
#include <IDisplayViewport.h>
#include <CryCommon/Cry_GeoIntersect.h>
#include <MathConversion.h>
#include <TrackView/TrackViewAnimNode.h>
#include <ViewManager.h>
@@ -31,6 +31,7 @@
#include <QMessageBox>
#include <QPushButton>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/smart_ptr/make_shared.h>
@@ -13,6 +13,7 @@
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneUI/CommonWidgets/OverlayWidget.h>
#include <SceneAPI/SceneUI/SceneWidgets/ManifestWidget.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Serialization/SerializeContext.h>
ImporterRootDisplay::ImporterRootDisplay(AZ::SerializeContext* serializeContext, QWidget* parent)
+1 -1
View File
@@ -987,7 +987,7 @@ QString CSettingsManager::GenerateContentHash(XmlNodeRef& node, QString sourceNa
return sourceName;
}
uint32 hash = CCrc32::ComputeLowercase(node->getXML(0));
uint32 hash = AZ::Crc32(node->getXML(0));
hashStr = QString::number(hash);
return hashStr;
-2
View File
@@ -148,8 +148,6 @@ void QTopRendererWnd::UpdateContent(int flags)
//////////////////////////////////////////////////////////////////////////
void QTopRendererWnd::Draw([[maybe_unused]] DisplayContext& dc)
{
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
////////////////////////////////////////////////////////////////////////
// Perform the rendering for this window
////////////////////////////////////////////////////////////////////////
@@ -13,6 +13,7 @@
// CryCommon
#include <CryCommon/Maestro/Types/AnimParamType.h>
#include <CryCommon/IFont.h>
// Editor
#include "Settings.h"
+2 -2
View File
@@ -53,7 +53,7 @@ CTVSequenceProps::~CTVSequenceProps()
// CTVSequenceProps message handlers
bool CTVSequenceProps::OnInitDialog()
{
ui->NAME->setText(m_pSequence->GetName());
ui->NAME->setText(m_pSequence->GetName().c_str());
int seqFlags = m_pSequence->GetFlags();
ui->ALWAYS_PLAY->setChecked((seqFlags & IAnimSequence::eSeqFlags_PlayOnReset));
@@ -141,7 +141,7 @@ void CTVSequenceProps::UpdateSequenceProps(const QString& name)
ac->UpdateTimeRange();
}
QString seqName = m_pSequence->GetName();
QString seqName = QString::fromUtf8(m_pSequence->GetName().c_str());
if (name != seqName)
{
// Rename sequence.
+9 -10
View File
@@ -423,7 +423,7 @@ CTrackViewAnimNode* CTrackViewAnimNode::CreateSubNode(
AZStd::string::format(
"Failed to add '%s' to sequence '%s', could not find associated entity. "
"Please try adding the entity associated with '%s'.",
originalNameStr.constData(), director->GetName(), originalNameStr.constData()));
originalNameStr.constData(), director->GetName().c_str(), originalNameStr.constData()));
return nullptr;
}
@@ -472,7 +472,7 @@ CTrackViewAnimNode* CTrackViewAnimNode::CreateSubNode(
{
GetIEditor()->GetMovieSystem()->LogUserNotificationMsg(
AZStd::string::format("'%s' already exists in sequence '%s', skipping...",
originalNameStr.constData(), director2->GetName()));
originalNameStr.constData(), director2->GetName().c_str()));
return nullptr;
}
@@ -488,7 +488,7 @@ CTrackViewAnimNode* CTrackViewAnimNode::CreateSubNode(
if (!newAnimNode)
{
GetIEditor()->GetMovieSystem()->LogUserNotificationMsg(
AZStd::string::format("Failed to add '%s' to sequence '%s'.", nameStr.constData(), director->GetName()));
AZStd::string::format("Failed to add '%s' to sequence '%s'.", nameStr.constData(), director->GetName().c_str()));
return nullptr;
}
@@ -1195,7 +1195,7 @@ CTrackViewAnimNodeBundle CTrackViewAnimNode::GetAnimNodesByName(const char* pNam
{
CTrackViewAnimNodeBundle bundle;
QString nodeName = GetName();
QString nodeName = QString::fromUtf8(GetName().c_str());
if (GetNodeType() == eTVNT_AnimNode && QString::compare(pName, nodeName, Qt::CaseInsensitive) == 0)
{
bundle.AppendAnimNode(this);
@@ -1215,10 +1215,9 @@ CTrackViewAnimNodeBundle CTrackViewAnimNode::GetAnimNodesByName(const char* pNam
}
//////////////////////////////////////////////////////////////////////////
const char* CTrackViewAnimNode::GetParamName(const CAnimParamType& paramType) const
AZStd::string CTrackViewAnimNode::GetParamName(const CAnimParamType& paramType) const
{
const char* pName = m_animNode->GetParamName(paramType);
return pName ? pName : "";
return m_animNode->GetParamName(paramType);
}
//////////////////////////////////////////////////////////////////////////
@@ -1274,7 +1273,7 @@ CTrackViewAnimNodeBundle CTrackViewAnimNode::AddSelectedEntities(const AZStd::ve
if (existingNode->GetDirector() == GetDirector())
{
GetIEditor()->GetMovieSystem()->LogUserNotificationMsg(AZStd::string::format(
"'%s' was already added to '%s', skipping...", entity->GetName().c_str(), GetDirector()->GetName()));
"'%s' was already added to '%s', skipping...", entity->GetName().c_str(), GetDirector()->GetName().c_str()));
continue;
}
@@ -1377,7 +1376,7 @@ void CTrackViewAnimNode::UpdateDynamicParams()
void CTrackViewAnimNode::CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlySelectedKeys, const bool bOnlyFromSelectedTracks)
{
XmlNodeRef childNode = xmlNode->createNode("Node");
childNode->setAttr("name", GetName());
childNode->setAttr("name", GetName().c_str());
childNode->setAttr("type", static_cast<int>(GetType()));
for (auto iter = m_childNodes.begin(); iter != m_childNodes.end(); ++iter)
@@ -1683,7 +1682,7 @@ bool CTrackViewAnimNode::IsValidReparentingTo(CTrackViewAnimNode* pNewParent)
}
// Check if the new parent already contains a node with this name
CTrackViewAnimNodeBundle foundNodes = pNewParent->GetAnimNodesByName(GetName());
CTrackViewAnimNodeBundle foundNodes = pNewParent->GetAnimNodesByName(GetName().c_str());
if (foundNodes.GetCount() > 1 || (foundNodes.GetCount() == 1 && foundNodes.GetNode(0) != this))
{
return false;
+2 -2
View File
@@ -124,7 +124,7 @@ public:
virtual void SetAsViewCamera();
// Name setter/getter
virtual const char* GetName() const override { return m_animNode->GetName(); }
AZStd::string GetName() const override { return m_animNode->GetName(); }
virtual bool SetName(const char* pName) override;
virtual bool CanBeRenamed() const override;
@@ -187,7 +187,7 @@ public:
// Param
unsigned int GetParamCount() const;
CAnimParamType GetParamType(unsigned int index) const;
const char* GetParamName(const CAnimParamType& paramType) const;
AZStd::string GetParamName(const CAnimParamType& paramType) const;
bool IsParamValid(const CAnimParamType& param) const;
IAnimNode::ESupportedParamFlags GetParamFlags(const CAnimParamType& paramType) const;
AnimValueType GetParamValueType(const CAnimParamType& paramType) const;
+3 -3
View File
@@ -1125,7 +1125,7 @@ void CTrackViewDialog::ReloadSequencesComboBox()
{
CTrackViewSequence* sequence = pSequenceManager->GetSequenceByIndex(k);
QString entityIdString = GetEntityIdAsString(sequence->GetSequenceComponentEntityId());
m_sequencesComboBox->addItem(sequence->GetName(), entityIdString);
m_sequencesComboBox->addItem(QString::fromUtf8(sequence->GetName().c_str()), entityIdString);
}
}
@@ -2033,7 +2033,7 @@ void CTrackViewDialog::UpdateTracksToolBar()
continue;
}
name = pAnimNode->GetParamName(paramType);
name = QString::fromUtf8(pAnimNode->GetParamName(paramType).c_str());
QString sToolTipText("Add " + name + " Track");
QIcon hIcon = m_wndNodesCtrl->GetIconForTrack(pTrack);
@@ -2309,7 +2309,7 @@ void CTrackViewDialog::SaveCurrentSequenceToFBX()
return;
}
QString selectedSequenceFBXStr = QString(sequence->GetName()) + ".fbx";
QString selectedSequenceFBXStr = QString::fromUtf8(sequence->GetName().c_str()) + ".fbx";
CExportManager* pExportManager = static_cast<CExportManager*>(GetIEditor()->GetExportManager());
const char szFilters[] = "FBX Files (*.fbx)";
@@ -3453,7 +3453,7 @@ void CTrackViewDopeSheetBase::DrawNodeTrack(CTrackViewAnimNode* animNode, QPaint
const QRect textRect = trackRect.adjusted(4, 0, -4, 0);
QString sAnimNodeName = animNode->GetName();
QString sAnimNodeName = QString::fromUtf8(animNode->GetName().c_str());
const bool hasObsoleteTrack = animNode->HasObsoleteTrack();
if (hasObsoleteTrack)
+2 -2
View File
@@ -626,7 +626,7 @@ bool CTrackViewNode::operator<(const CTrackViewNode& otherNode) const
if (thisTypeOrder == otherTypeOrder)
{
// Same node type, sort by name
return azstricmp(thisAnimNode.GetName(), otherAnimNode.GetName()) < 0;
return thisAnimNode.GetName() < otherAnimNode.GetName();
}
return thisTypeOrder < otherTypeOrder;
@@ -638,7 +638,7 @@ bool CTrackViewNode::operator<(const CTrackViewNode& otherNode) const
if (thisTrack.GetParameterType() == otherTrack.GetParameterType())
{
// Same parameter type, sort by name
return azstricmp(thisTrack.GetName(), otherTrack.GetName()) < 0;
return thisTrack.GetName() < otherTrack.GetName();
}
return thisTrack.GetParameterType() < otherTrack.GetParameterType();
+1 -1
View File
@@ -159,7 +159,7 @@ public:
virtual ~CTrackViewNode() {}
// Name
virtual const char* GetName() const = 0;
virtual AZStd::string GetName() const = 0;
virtual bool SetName([[maybe_unused]] const char* pName) { return false; };
virtual bool CanBeRenamed() const { return false; }
+21 -22
View File
@@ -616,7 +616,7 @@ CTrackViewNodesCtrl::CRecord* CTrackViewNodesCtrl::AddAnimNodeRecord(CRecord* pP
{
CRecord* pNewRecord = new CRecord(animNode);
pNewRecord->setText(0, animNode->GetName());
pNewRecord->setText(0, QString::fromUtf8(animNode->GetName().c_str()));
UpdateAnimNodeRecord(pNewRecord, animNode);
pParentRecord->insertChild(GetInsertPosition(pParentRecord, animNode), pNewRecord);
FillNodesRec(pNewRecord, animNode);
@@ -629,7 +629,7 @@ CTrackViewNodesCtrl::CRecord* CTrackViewNodesCtrl::AddTrackRecord(CRecord* pPare
{
CRecord* pNewTrackRecord = new CRecord(pTrack);
pNewTrackRecord->setSizeHint(0, QSize(30, 18));
pNewTrackRecord->setText(0, pTrack->GetName());
pNewTrackRecord->setText(0, QString::fromUtf8(pTrack->GetName().c_str()));
UpdateTrackRecord(pNewTrackRecord, pTrack);
pParentRecord->insertChild(GetInsertPosition(pParentRecord, pTrack), pNewTrackRecord);
FillNodesRec(pNewTrackRecord, pTrack);
@@ -860,7 +860,7 @@ void CTrackViewNodesCtrl::OnFillItems()
m_nodeToRecordMap.clear();
CRecord* pRootGroupRec = new CRecord(sequence);
pRootGroupRec->setText(0, sequence->GetName());
pRootGroupRec->setText(0, QString::fromUtf8(sequence->GetName().c_str()));
QFont f = font();
f.setBold(true);
pRootGroupRec->setData(0, Qt::FontRole, f);
@@ -1032,8 +1032,8 @@ void CTrackViewNodesCtrl::OnNMRclick(QPoint point)
return;
}
QString file = QString(sequence2->GetName()) + QString(".fbx");
QString selectedSequenceFBXStr = QString(sequence2->GetName()) + ".fbx";
QString file = QString::fromUtf8(sequence2->GetName().c_str()) + QString(".fbx");
QString selectedSequenceFBXStr = QString::fromUtf8(sequence2->GetName().c_str()) + ".fbx";
if (numSelectedNodes > 1)
{
@@ -1041,7 +1041,7 @@ void CTrackViewNodesCtrl::OnNMRclick(QPoint point)
}
else
{
file = QString(selectedNodes.GetNode(0)->GetName()) + QString(".fbx");
file = QString::fromUtf8(selectedNodes.GetNode(0)->GetName().c_str()) + QString(".fbx");
}
QString path = QFileDialog::getSaveFileName(this, tr("Export Selected Nodes To FBX File"), QString(), tr("FBX Files (*.fbx)"));
@@ -1338,7 +1338,7 @@ void CTrackViewNodesCtrl::OnNMRclick(QPoint point)
if (animNode || groupNode)
{
CTrackViewAnimNode* animNode2 = static_cast<CTrackViewAnimNode*>(pNode);
QString oldName = animNode2->GetName();
QString oldName = QString::fromUtf8(animNode2->GetName().c_str());
StringDlg dlg(tr("Rename Node"));
dlg.SetString(oldName);
@@ -1494,7 +1494,7 @@ void CTrackViewNodesCtrl::OnNMRclick(QPoint point)
if (animNode)
{
QString matName;
GetMatNameAndSubMtlIndexFromName(matName, animNode->GetName());
GetMatNameAndSubMtlIndexFromName(matName, animNode->GetName().c_str());
QString newMatName;
newMatName = tr("%1.[%2]").arg(matName).arg(cmd - eMI_SelectSubmaterialBase + 1);
CUndo undo("Rename TrackView node");
@@ -1576,7 +1576,7 @@ CTrackViewTrack* CTrackViewNodesCtrl::GetTrackViewTrack(const Export::EntityAnim
for (unsigned int trackID = 0; trackID < trackBundle.GetCount(); ++trackID)
{
CTrackViewTrack* pTrack = trackBundle.GetTrack(trackID);
const QString bundleTrackName = pTrack->GetAnimNode()->GetName();
const QString bundleTrackName = QString::fromUtf8(pTrack->GetAnimNode()->GetName().c_str());
if (bundleTrackName.compare(nodeName, Qt::CaseInsensitive) != 0)
{
@@ -2164,7 +2164,7 @@ int CTrackViewNodesCtrl::ShowPopupMenuSingleSelection(SContextMenu& contextMenu,
if (bOnNode && !pNode->IsGroupNode())
{
AddMenuSeperatorConditional(contextMenu.main, bAppended);
QString string = QString("%1 Tracks").arg(animNode->GetName());
QString string = QString("%1 Tracks").arg(animNode->GetName().c_str());
contextMenu.main.addAction(string)->setEnabled(false);
bool bAppendedTrackFlag = false;
@@ -2182,7 +2182,7 @@ int CTrackViewNodesCtrl::ShowPopupMenuSingleSelection(SContextMenu& contextMenu,
continue;
}
QAction* a = contextMenu.main.addAction(QString(" %1").arg(pTrack2->GetName()));
QAction* a = contextMenu.main.addAction(QString(" %1").arg(pTrack2->GetName().c_str()));
a->setData(eMI_ShowHideBase + childIndex);
a->setCheckable(true);
a->setChecked(!pTrack2->IsHidden());
@@ -2348,13 +2348,12 @@ bool CTrackViewNodesCtrl::FillAddTrackMenu(STrackMenuTreeNode& menuAddTrack, con
continue;
}
}
name = animNode->GetParamName(paramType);
QStringList splittedName = name.split("/", Qt::SkipEmptyParts);
name = QString::fromUtf8(animNode->GetParamName(paramType).c_str());
QStringList splitName = name.split("/", Qt::SkipEmptyParts);
STrackMenuTreeNode* pCurrentNode = &menuAddTrack;
for (int j = 0; j < splittedName.size() - 1; ++j)
for (const QString& segment : splitName)
{
const QString& segment = splittedName[j];
auto findIter = pCurrentNode->children.find(segment);
if (findIter != pCurrentNode->children.end())
{
@@ -2370,10 +2369,10 @@ bool CTrackViewNodesCtrl::FillAddTrackMenu(STrackMenuTreeNode& menuAddTrack, con
// only add tracks to the that STrackMenuTreeNode tree that haven't already been added
CTrackViewTrackBundle matchedTracks = animNode->GetTracksByParam(paramType);
if (matchedTracks.GetCount() == 0)
if (matchedTracks.GetCount() == 0 && !splitName.isEmpty())
{
STrackMenuTreeNode* pParamNode = new STrackMenuTreeNode;
pCurrentNode->children[splittedName.back()] = std::unique_ptr<STrackMenuTreeNode>(pParamNode);
pCurrentNode->children[splitName.back()] = std::unique_ptr<STrackMenuTreeNode>(pParamNode);
pParamNode->paramType = paramType;
bTracksToAdd = true;
@@ -2464,7 +2463,7 @@ void CTrackViewNodesCtrl::FillAutoCompletionListForFilter()
for (unsigned int i = 0; i < animNodeCount; ++i)
{
strings << animNodes.GetNode(i)->GetName();
strings << QString::fromUtf8(animNodes.GetNode(i)->GetName().c_str());
}
}
else
@@ -2580,10 +2579,10 @@ void CTrackViewNodesCtrl::Update()
{
const CTrackViewAnimNode* track = static_cast<const CTrackViewAnimNode*>(node);
if (track)
{
record->setText(0, track->GetName());
{
record->setText(0, QString::fromUtf8(track->GetName().c_str()));
}
}
}
}
}
}
@@ -2855,7 +2854,7 @@ void CTrackViewNodesCtrl::OnNodeRenamed(CTrackViewNode* pNode, [[maybe_unused]]
if (!m_bIgnoreNotifications)
{
CRecord* pNodeRecord = GetNodeRecord(pNode);
pNodeRecord->setText(0, pNode->GetName());
pNodeRecord->setText(0, QString::fromUtf8(pNode->GetName().c_str()));
update();
}
+1 -1
View File
@@ -66,7 +66,7 @@ public:
CRecord(CTrackViewNode* pNode = nullptr);
CTrackViewNode* GetNode() const { return m_pNode; }
bool IsGroup() const { return m_pNode->GetChildCount() != 0; }
const QString GetName() const { return m_pNode->GetName(); }
const QString GetName() const { return QString::fromUtf8(m_pNode->GetName().c_str()); }
// Workaround: CXTPReportRecord::IsVisible is
// unreliable after the last visible element
@@ -293,8 +293,8 @@ namespace
CTrackViewTrack* pTrack = pNode->GetTrackForParameter(paramType);
if (!pTrack || (paramFlags & IAnimNode::eSupportedParamFlags_MultipleTracks))
{
const char* name = pNode->GetParamName(paramType);
if (_stricmp(name, paramName) == 0)
AZStd::string name = pNode->GetParamName(paramType);
if (name == paramName)
{
CUndo undo("Create track");
if (!pNode->CreateTrack(paramType))
+1 -1
View File
@@ -35,7 +35,7 @@ namespace AzToolsFramework
: public AZ::Component
, public EditorLayerTrackViewRequestBus::Handler
{
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
AZ_POP_DISABLE_DLL_EXPORT_BASECLASS_WARNING
public:
AZ_COMPONENT(TrackViewComponent, "{3CF943CC-6F10-4B19-88FC-CFB697558FFD}")
+3 -3
View File
@@ -894,14 +894,14 @@ bool CTrackViewSequence::SetName(const char* name)
return false;
}
const char* oldName = GetName();
if (0 != strcmp(name, oldName))
AZStd::string oldName = GetName();
if (name != oldName)
{
m_pAnimSequence->SetName(name);
MarkAsModified();
AzToolsFramework::ScopedUndoBatch undoBatch("Rename Sequence");
GetSequence()->OnNodeRenamed(this, oldName);
GetSequence()->OnNodeRenamed(this, oldName.c_str());
undoBatch.MarkEntityDirty(m_pAnimSequence->GetSequenceEntityId());
}
+1 -1
View File
@@ -102,7 +102,7 @@ public:
// ITrackViewNode
virtual ETrackViewNodeType GetNodeType() const override { return eTVNT_Sequence; }
virtual const char* GetName() const override { return m_pAnimSequence->GetName(); }
virtual AZStd::string GetName() const override { return m_pAnimSequence->GetName(); }
virtual bool SetName(const char* pName) override;
virtual bool CanBeRenamed() const override { return true; }
@@ -75,7 +75,7 @@ CTrackViewSequence* CTrackViewSequenceManager::GetSequenceByName(QString name) c
{
CTrackViewSequence* sequence = (*iter).get();
if (sequence->GetName() == name)
if (QString::fromUtf8(sequence->GetName().c_str()) == name)
{
return sequence;
}
@@ -371,8 +371,8 @@ void CTrackViewSequenceManager::SortSequences()
std::stable_sort(m_sequences.begin(), m_sequences.end(),
[](const std::unique_ptr<CTrackViewSequence>& a, const std::unique_ptr<CTrackViewSequence>& b) -> bool
{
QString aName = a.get()->GetName();
QString bName = b.get()->GetName();
QString aName = QString::fromUtf8(a.get()->GetName().c_str());
QString bName = QString::fromUtf8(b.get()->GetName().c_str());
return aName < bName;
});
}
+2 -2
View File
@@ -472,7 +472,7 @@ void CTrackViewTrack::RestoreFromMemento(const CTrackViewTrackMemento& memento)
}
//////////////////////////////////////////////////////////////////////////
const char* CTrackViewTrack::GetName() const
AZStd::string CTrackViewTrack::GetName() const
{
CTrackViewNode* pParentNode = GetParentNode();
@@ -810,7 +810,7 @@ void CTrackViewTrack::CopyKeysToClipboard(XmlNodeRef& xmlNode, const bool bOnlyS
}
XmlNodeRef childNode = xmlNode->newChild("Track");
childNode->setAttr("name", GetName());
childNode->setAttr("name", GetName().c_str());
GetParameterType().SaveToXml(childNode);
childNode->setAttr("valueType", static_cast<int>(GetValueType()));
+1 -1
View File
@@ -80,7 +80,7 @@ public:
CTrackViewAnimNode* GetAnimNode() const;
// Name getter
virtual const char* GetName() const;
AZStd::string GetName() const override;
// CTrackViewNode
virtual ETrackViewNodeType GetNodeType() const override { return eTVNT_Track; }
+1 -1
View File
@@ -75,7 +75,7 @@ CTrackViewTrack* CUndoComponentEntityTrackObject::FindTrack(CTrackViewSequence*
CTrackViewTrack* curTrack = allTracks.GetTrack(trackIndex);
if (curTrack->GetAnimNode() && curTrack->GetAnimNode()->GetComponentId() == m_trackComponentId)
{
if (0 == azstricmp(curTrack->GetName(), m_trackName.c_str()))
if (curTrack->GetName() == m_trackName)
{
CTrackViewAnimNode* parentAnimNode = static_cast<CTrackViewAnimNode*>(curTrack->GetAnimNode()->GetParentNode());
if (parentAnimNode && parentAnimNode->GetAzEntityId() == m_entityId)
+1 -1
View File
@@ -81,7 +81,7 @@ void CTVNewSequenceDialog::OnOK()
for (unsigned int k = 0; k < GetIEditor()->GetSequenceManager()->GetCount(); ++k)
{
CTrackViewSequence* pSequence = GetIEditor()->GetSequenceManager()->GetSequenceByIndex(k);
QString fullname = pSequence->GetName();
QString fullname = QString::fromUtf8(pSequence->GetName().c_str());
if (fullname.compare(m_sequenceName, Qt::CaseInsensitive) == 0)
{
+1 -1
View File
@@ -24,7 +24,7 @@ QColor ColorLinearToGamma(ColorF col)
g = (float)(g <= 0.0031308 ? (12.92 * g) : (1.055 * pow((double)g, 1.0 / 2.4) - 0.055));
b = (float)(b <= 0.0031308 ? (12.92 * b) : (1.055 * pow((double)b, 1.0 / 2.4) - 0.055));
return QColor(FtoI(r * 255.0f), FtoI(g * 255.0f), FtoI(b * 255.0f), FtoI(a * 255.0f));
return QColor(int(r * 255.0f), int(g * 255.0f), int(b * 255.0f), int(a * 255.0f));
}
//////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -205,7 +205,7 @@ QColor ColorLinearToGamma(ColorF col)
g = (float)(g <= 0.0031308 ? (12.92 * g) : (1.055 * pow((double)g, 1.0 / 2.4) - 0.055));
b = (float)(b <= 0.0031308 ? (12.92 * b) : (1.055 * pow((double)b, 1.0 / 2.4) - 0.055));
return QColor(FtoI(r * 255.0f), FtoI(g * 255.0f), FtoI(b * 255.0f), FtoI(a * 255.0f));
return QColor(int(r * 255.0f), int(g * 255.0f), int(b * 255.0f), int(a * 255.0f));
}
//////////////////////////////////////////////////////////////////////////
+2 -4
View File
@@ -1221,15 +1221,14 @@ bool CFileUtil::CreatePath(const QString& strPath)
if (!strDriveLetter.isEmpty())
{
strCurrentDirectoryPath = strDriveLetter;
strCurrentDirectoryPath += "\\";
strCurrentDirectoryPath += AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING;
}
nTotalPathQueueElements = cstrDirectoryQueue.size();
for (nCurrentPathQueue = 0; nCurrentPathQueue < nTotalPathQueueElements; ++nCurrentPathQueue)
{
strCurrentDirectoryPath += cstrDirectoryQueue[static_cast<int>(nCurrentPathQueue)];
strCurrentDirectoryPath += "\\";
strCurrentDirectoryPath += AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING;
// The value which will go out of this loop is the result of the attempt to create the
// last directory, only.
@@ -2158,7 +2157,6 @@ uint32 CFileUtil::GetAttributes(const char* filename, bool bUseSourceControl /*=
return SCC_FILE_ATTRIBUTE_READONLY | SCC_FILE_ATTRIBUTE_INPAK;
}
const char* adjustedFile = file.GetAdjustedFilename();
if (!AZ::IO::SystemFile::Exists(adjustedFile))
{
-4
View File
@@ -41,7 +41,6 @@ struct SPointSorter
//===================================================================
void ConvexHull2DGraham(std::vector<Vec3>& ptsOut, const std::vector<Vec3>& ptsIn)
{
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
const unsigned nPtsIn = ptsIn.size();
if (nPtsIn < 3)
{
@@ -66,7 +65,6 @@ void ConvexHull2DGraham(std::vector<Vec3>& ptsOut, const std::vector<Vec3>& ptsI
std::swap(ptsSorted[0], ptsSorted[iBotRight]);
{
FRAME_PROFILER("SORT Graham", gEnv->pSystem, PROFILE_AI)
std::sort(ptsSorted.begin() + 1, ptsSorted.end(), SPointSorter(ptsSorted[0]));
}
ptsSorted.erase(std::unique(ptsSorted.begin(), ptsSorted.end(), ptEqual), ptsSorted.end());
@@ -196,7 +194,6 @@ inline bool PointSorterAndrew(const Vec3& lhs, const Vec3& rhs)
//===================================================================
SANDBOX_API void ConvexHull2DAndrew(std::vector<Vec3>& ptsOut, const std::vector<Vec3>& ptsIn)
{
FUNCTION_PROFILER(gEnv->pSystem, PROFILE_AI);
const int n = (int)ptsIn.size();
if (n < 3)
{
@@ -206,7 +203,6 @@ SANDBOX_API void ConvexHull2DAndrew(std::vector<Vec3>& ptsOut, const std::vector
std::vector<Vec3> P = ptsIn;
{
FRAME_PROFILER("SORT Andrew", gEnv->pSystem, PROFILE_AI)
std::sort(P.begin(), P.end(), PointSorterAndrew);
}
+2 -2
View File
@@ -48,7 +48,7 @@ inline bool GuidUtil::IsEmpty(REFGUID guid)
inline const char* GuidUtil::ToString(REFGUID guid)
{
static char guidString[64];
sprintf_s(guidString, "{%.8X-%.4X-%.4X-%.2X%.2X-%.2X%.2X%.2X%.2X%.2X%.2X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1],
sprintf_s(guidString, "{%.8" GUID_FORMAT_DATA1 "-%.4X-%.4X-%.2X%.2X-%.2X%.2X%.2X%.2X%.2X%.2X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1],
guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
return guidString;
}
@@ -62,7 +62,7 @@ inline GUID GuidUtil::FromString(const char* guidString)
guid.Data1 = 0;
guid.Data2 = 0;
guid.Data3 = 0;
azsscanf(guidString, "{%8" SCNx32 "-%4hX-%4hX-%2X%2X-%2X%2X%2X%2X%2X%2X}",
azsscanf(guidString, "{%8" GUID_FORMAT_DATA1 "-%4hX-%4hX-%2X%2X-%2X%2X%2X%2X%2X%2X}",
&guid.Data1, &guid.Data2, &guid.Data3, &d[0], &d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7]);
guid.Data4[0] = static_cast<unsigned char>(d[0]);
guid.Data4[1] = static_cast<unsigned char>(d[1]);
+1
View File
@@ -14,6 +14,7 @@
#pragma once
#include <Editor/Util/EditorUtils.h>
#include <CryCommon/Cry_GeoIntersect.h>
//! Half PI
#define PI_HALF (3.1415926535897932384626433832795f / 2.0f)
+1
View File
@@ -9,6 +9,7 @@
#include "StringHelpers.h"
#include "Util.h"
#include <cwctype>
int StringHelpers::CompareIgnoreCase(const AZStd::string& str0, const AZStd::string& str1)
{
-4
View File
@@ -400,7 +400,6 @@ void QtViewport::UpdateContent(int flags)
//////////////////////////////////////////////////////////////////////////
void QtViewport::Update()
{
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
m_viewportUi.Update();
m_bAdvancedSelectMode = false;
@@ -1436,9 +1435,6 @@ bool QtViewport::MouseCallback(EMouseEvent event, const QPoint& point, Qt::Keybo
//////////////////////////////////////////////////////////////////////////
void QtViewport::ProcessRenderLisneters(DisplayContext& rstDisplayContext)
{
FUNCTION_PROFILER(GetIEditor()->GetSystem(), PROFILE_EDITOR);
size_t nCount(0);
size_t nTotal(0);
+14 -6
View File
@@ -12,6 +12,7 @@
#include <AzToolsFramework/ViewportSelection/EditorInteractionSystemViewportSelectionRequestBus.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Buses/Requests/InputSystemCursorRequestBus.h>
#include <AzFramework/Viewport/ScreenGeometry.h>
#include <AzCore/Script/ScriptTimePoint.h>
@@ -112,9 +113,9 @@ namespace SandboxEditor
AzFramework::WindowRequestBus::EventResult(
windowSize, event.m_windowHandle, &AzFramework::WindowRequestBus::Events::GetClientAreaSize);
auto screenPoint = AzFramework::ScreenPoint(
static_cast<int>(position->m_normalizedPosition.GetX() * windowSize.m_width),
static_cast<int>(position->m_normalizedPosition.GetY() * windowSize.m_height));
const auto screenPoint = AzFramework::ScreenPoint(
aznumeric_cast<int>(position->m_normalizedPosition.GetX() * windowSize.m_width),
aznumeric_cast<int>(position->m_normalizedPosition.GetY() * windowSize.m_height));
m_mouseInteraction.m_mousePick.m_screenCoordinates = screenPoint;
AZStd::optional<ProjectedViewportRay> ray;
@@ -207,20 +208,27 @@ namespace SandboxEditor
? &InteractionBus::Events::InternalHandleMouseManipulatorInteraction
: &InteractionBus::Events::InternalHandleMouseViewportInteraction;
const auto mouseInteractionEvent = [mouseInteraction, event = eventType.value(), wheelDelta] {
auto currentCursorState = AzFramework::SystemCursorState::Unknown;
AzFramework::InputSystemCursorRequestBus::EventResult(
currentCursorState, event.m_inputChannel.GetInputDevice().GetInputDeviceId(),
&AzFramework::InputSystemCursorRequestBus::Events::GetSystemCursorState);
const auto mouseInteractionEvent = [mouseInteraction, event = eventType.value(), wheelDelta,
cursorCaptured = currentCursorState == AzFramework::SystemCursorState::ConstrainedAndHidden]
{
switch (event)
{
case MouseEvent::Up:
case MouseEvent::Down:
case MouseEvent::Move:
case MouseEvent::DoubleClick:
return MouseInteractionEvent(AZStd::move(mouseInteraction), event);
return MouseInteractionEvent(AZStd::move(mouseInteraction), event, cursorCaptured);
case MouseEvent::Wheel:
return MouseInteractionEvent(AZStd::move(mouseInteraction), wheelDelta);
}
AZ_Assert(false, "Unhandled MouseEvent");
return MouseInteractionEvent(MouseInteraction{}, MouseEvent::Up);
return MouseInteractionEvent(MouseInteraction{}, MouseEvent::Up, false);
}();
InteractionBus::EventResult(
@@ -10,7 +10,6 @@
// Component includes
#include <AzCore/Asset/AssetManagerComponent.h>
#include <AzCore/Debug/FrameProfilerComponent.h>
#include <AzCore/IO/Streamer/StreamerComponent.h>
#include <AzCore/Jobs/JobManagerComponent.h>
#include <AzCore/Serialization/Json/JsonSystemComponent.h>
@@ -36,7 +35,6 @@ namespace AZ
JsonSystemComponent::CreateDescriptor(),
AssetManagerComponent::CreateDescriptor(),
UserSettingsComponent::CreateDescriptor(),
Debug::FrameProfilerComponent::CreateDescriptor(),
SliceComponent::CreateDescriptor(),
SliceSystemComponent::CreateDescriptor(),
SliceMetadataInfoComponent::CreateDescriptor(),
@@ -51,7 +51,6 @@
#include <AzCore/Driller/Driller.h>
#include <AzCore/Memory/MemoryDriller.h>
#include <AzCore/Debug/TraceMessagesDriller.h>
#include <AzCore/Debug/ProfilerDriller.h>
#include <AzCore/Debug/EventTraceDriller.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/Script/ScriptSystemBus.h>
@@ -546,6 +545,10 @@ namespace AZ
m_entityActivatedEvent.DisconnectAllHandlers();
m_entityDeactivatedEvent.DisconnectAllHandlers();
#if !defined(_RELEASE)
m_budgetTracker.Reset();
#endif
DestroyAllocator();
}
@@ -594,6 +597,10 @@ namespace AZ
CreateOSAllocator();
CreateSystemAllocator();
#if !defined(_RELEASE)
m_budgetTracker.Init();
#endif
// This can be moved to the ComponentApplication constructor if need be
// This is reading the *.setreg files using SystemFile and merging the settings
// to the settings registry.
@@ -625,8 +632,6 @@ namespace AZ
m_eventLogger->Start(outputPath.Native(), baseFileName);
}
CreateDrillers();
Sfmt::Create();
CreateReflectionManager();
@@ -746,12 +751,6 @@ namespace AZ
ComponentApplicationBus::Handler::BusDisconnect();
TickRequestBus::Handler::BusDisconnect();
if (m_drillerManager)
{
Debug::DrillerManager::Destroy(m_drillerManager);
m_drillerManager = nullptr;
}
m_eventLogger->Stop();
// Clear the descriptor to deallocate all strings (owned by ModuleDescriptor)
@@ -899,33 +898,6 @@ namespace AZ
allocatorManager.FinalizeConfiguration();
}
//=========================================================================
// CreateDrillers
// [2/20/2013]
//=========================================================================
void ComponentApplication::CreateDrillers()
{
// Create driller manager and register drillers if requested
if (m_descriptor.m_enableDrilling)
{
m_drillerManager = Debug::DrillerManager::Create();
// Memory driller is responsible for tracking allocations.
// Tracking type and overhead is determined by app configuration.
// Only one MemoryDriller is supported at a time
// Only create the memory driller if there is no handlers connected to the MemoryDrillerBus
if (!Debug::MemoryDrillerBus::HasHandlers())
{
m_drillerManager->Register(aznew Debug::MemoryDriller);
}
// Profiler driller will consume resources only when started.
m_drillerManager->Register(aznew Debug::ProfilerDriller);
// Trace messages driller will consume resources only when started.
m_drillerManager->Register(aznew Debug::TraceMessagesDriller);
m_drillerManager->Register(aznew Debug::EventTraceDriller);
}
}
void ComponentApplication::MergeSettingsToRegistry(SettingsRegistryInterface& registry)
{
SettingsRegistryInterface::Specializations specializations;
@@ -1416,10 +1388,6 @@ namespace AZ
EBUS_EVENT(TickBus, OnTick, m_deltaTime, ScriptTimePoint(now));
}
}
if (m_drillerManager)
{
m_drillerManager->FrameUpdate();
}
}
//=========================================================================
@@ -12,6 +12,7 @@
#include <AzCore/Component/Entity.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Memory/AllocationRecords.h>
#include <AzCore/Debug/BudgetTracker.h>
#include <AzCore/Memory/OSAllocator.h>
#include <AzCore/Module/DynamicModuleHandle.h>
#include <AzCore/Module/ModuleManager.h>
@@ -225,11 +226,6 @@ namespace AZ
/// Returns the path to the folder the executable is in.
const char* GetExecutableFolder() const override { return m_exeDirectory.c_str(); }
/// Returns pointer to the driller manager if it's enabled, otherwise NULL.
Debug::DrillerManager* GetDrillerManager() override { return m_drillerManager; }
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/// TickRequestBus
float GetTickDeltaTime() override;
@@ -324,9 +320,6 @@ namespace AZ
/// Create the system allocator using the data in the m_descriptor
void CreateSystemAllocator();
/// Create the drillers
void CreateDrillers();
virtual void MergeSettingsToRegistry(SettingsRegistryInterface& registry);
//! Sets the specializations that will be used when loading the Settings Registry. Extend this in derived
@@ -402,6 +395,10 @@ namespace AZ
// from the m_console member when it goes out of scope
AZ::SettingsRegistryConsoleUtils::ConsoleFunctorHandle m_settingsRegistryConsoleFunctors;
#if !defined(_RELEASE)
Debug::BudgetTracker m_budgetTracker;
#endif
// this is used when no argV/ArgC is supplied.
// in order to have the same memory semantics (writable, non-const)
// we create a buffer that can be written to (up to AZ_MAX_PATH_LEN) and then
@@ -409,8 +406,6 @@ namespace AZ
char m_commandLineBuffer[AZ_MAX_PATH_LEN];
char* m_commandLineBufferAddress{ m_commandLineBuffer };
Debug::DrillerManager* m_drillerManager{ nullptr };
StartupParameters m_startupParameters;
char** m_argV{ nullptr };
@@ -187,11 +187,6 @@ namespace AZ
//! @return a pointer to the name of the path that contains the application's executable.
virtual const char* GetExecutableFolder() const = 0;
//! Returns a pointer to the driller manager, if driller is enabled.
//! The driller manager manages all active driller sessions and driller factories.
//! @return A pointer to the driller manager. If driller is not enabled, this function returns null.
virtual Debug::DrillerManager* GetDrillerManager() = 0;
//! ResolveModulePath is called whenever LoadDynamicModule wants to resolve a module in order to actually load it.
//! You can override this if you need to load modules from a different path or hijack module loading in some other way.
//! If you do, ensure that you use platform-specific conventions to do so, as this is called by multiple platforms.
@@ -16,6 +16,7 @@
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Debug/Budget.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/EBus/Event.h>
#include <AzCore/std/string/string.h>
@@ -438,3 +439,4 @@ namespace AZ
return component;
}
} // namespace AZ
@@ -0,0 +1,74 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "Budget.h"
#include <AzCore/Module/Environment.h>
#include <AzCore/Math/Crc.h>
#include <AzCore/Memory/SystemAllocator.h>
AZ_DEFINE_BUDGET(Animation);
AZ_DEFINE_BUDGET(Audio);
AZ_DEFINE_BUDGET(AzCore);
AZ_DEFINE_BUDGET(Editor);
AZ_DEFINE_BUDGET(Entity);
AZ_DEFINE_BUDGET(Game);
AZ_DEFINE_BUDGET(System);
AZ_DEFINE_BUDGET(Physics);
namespace AZ::Debug
{
struct BudgetImpl
{
AZ_CLASS_ALLOCATOR(BudgetImpl, AZ::SystemAllocator, 0);
// TODO: Budget implementation for tracking budget wall time per-core, memory, etc.
};
Budget::Budget(const char* name)
: m_name{ name }
, m_crc{ Crc32(name) }
{
}
Budget::Budget(const char* name, uint32_t crc)
: m_name{ name }
, m_crc{ crc }
{
m_impl = aznew BudgetImpl;
}
Budget::~Budget()
{
if (m_impl)
{
delete m_impl;
}
}
// TODO:Budgets Methods below are stubbed pending future work to both update budget data and visualize it
void Budget::PerFrameReset()
{
}
void Budget::BeginProfileRegion()
{
}
void Budget::EndProfileRegion()
{
}
void Budget::TrackAllocation(uint64_t)
{
}
void Budget::UntrackAllocation(uint64_t)
{
}
} // namespace AZ::Debug
@@ -0,0 +1,88 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Debug/BudgetTracker.h>
#include <AzCore/Math/Crc.h>
namespace AZ::Debug
{
// A budget collates per-frame resource utilization and memory for a particular category
class Budget final
{
public:
explicit Budget(const char* name);
Budget(const char* name, uint32_t crc);
~Budget();
void PerFrameReset();
void BeginProfileRegion();
void EndProfileRegion();
void TrackAllocation(uint64_t bytes);
void UntrackAllocation(uint64_t bytes);
const char* Name() const
{
return m_name;
}
uint32_t Crc() const
{
return m_crc;
}
private:
const char* m_name;
const uint32_t m_crc;
struct BudgetImpl* m_impl = nullptr;
};
} // namespace AZ::Debug
// The budget is usable in the same file it was defined without needing an additional declaration.
// If you encounter a linker error complaining that this function is not defined, you have likely forgotten to either
// define or declare the budget used in a profile or memory marker. See AZ_DEFINE_BUDGET and AZ_DECLARE_BUDGET below
// for usage.
#define AZ_BUDGET_GETTER(name) GetAzBudget##name
#if defined(_RELEASE)
#define AZ_DEFINE_BUDGET(name) \
::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \
{ \
return nullptr; \
}
#else
// Usage example:
// In a single C++ source file:
// AZ_DEFINE_BUDGET(AzCore);
//
// Anywhere the budget is used, the budget must be declared (either in a header or in the source file itself)
// AZ_DECLARE_BUDGET(AzCore);
#define AZ_DEFINE_BUDGET(name) \
::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)() \
{ \
constexpr static uint32_t crc = AZ_CRC_CE(#name); \
static ::AZ::Debug::Budget* budget = ::AZ::Debug::BudgetTracker::GetBudgetFromEnvironment(#name, crc); \
return budget; \
}
#endif
// If using a budget defined in a different C++ source file, add AZ_DECLARE_BUDGET(yourBudget); somewhere in your source file at namespace
// scope Alternatively, AZ_DECLARE_BUDGET can be used in a header to declare the budget for use across any users of the header
#define AZ_DECLARE_BUDGET(name) ::AZ::Debug::Budget* AZ_BUDGET_GETTER(name)()
// Declare budgets that are core engine budgets, or may be shared/needed across multiple external gems
// You should NOT need to declare user-space or budgets with isolated usage here. Prefer declaring them local to the module(s) that use
// the budget and defining them within a single module to avoid needing to recompile the entire engine.
AZ_DECLARE_BUDGET(Animation);
AZ_DECLARE_BUDGET(Audio);
AZ_DECLARE_BUDGET(AzCore);
AZ_DECLARE_BUDGET(Editor);
AZ_DECLARE_BUDGET(Entity);
AZ_DECLARE_BUDGET(Game);
AZ_DECLARE_BUDGET(System);
AZ_DECLARE_BUDGET(Physics);
@@ -0,0 +1,72 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Debug/BudgetTracker.h>
#include <AzCore/base.h>
#include <AzCore/Debug/Budget.h>
#include <AzCore/Interface/Interface.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/parallel/scoped_lock.h>
namespace AZ::Debug
{
constexpr static const char* BudgetTrackerEnvName = "budgetTrackerEnv";
struct BudgetTracker::BudgetTrackerImpl
{
AZStd::unordered_map<const char*, Budget> m_budgets;
};
Budget* BudgetTracker::GetBudgetFromEnvironment(const char* budgetName, uint32_t crc)
{
BudgetTracker* tracker = Interface<BudgetTracker>::Get();
if (tracker)
{
return &tracker->GetBudget(budgetName, crc);
}
return nullptr;
}
BudgetTracker::~BudgetTracker()
{
Reset();
}
bool BudgetTracker::Init()
{
if (Interface<BudgetTracker>::Get())
{
return false;
}
Interface<BudgetTracker>::Register(this);
m_impl = new BudgetTrackerImpl;
return true;
}
void BudgetTracker::Reset()
{
if (m_impl)
{
Interface<BudgetTracker>::Unregister(this);
delete m_impl;
m_impl = nullptr;
}
}
Budget& BudgetTracker::GetBudget(const char* budgetName, uint32_t crc)
{
AZStd::scoped_lock lock{ m_mutex };
auto it = m_impl->m_budgets.try_emplace(budgetName, budgetName, crc).first;
return it->second;
}
} // namespace AZ::Debug
@@ -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
*
*/
#pragma once
#include <AzCore/Module/Environment.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/parallel/mutex.h>
namespace AZ::Debug
{
class Budget;
class BudgetTracker
{
public:
AZ_RTTI(BudgetTracker, "{E14A746D-BFFE-4C02-90FB-4699B79864A5}");
static Budget* GetBudgetFromEnvironment(const char* budgetName, uint32_t crc);
~BudgetTracker();
// Returns false if the budget tracker was already present in the environment (initialized already elsewhere)
bool Init();
void Reset();
Budget& GetBudget(const char* budgetName, uint32_t crc);
private:
struct BudgetTrackerImpl;
AZStd::mutex m_mutex;
// The BudgetTracker is likely included in proportionally high number of files throughout the
// engine, so indirection is used here to avoid imposing excessive recompilation in periods
// while the budget system is iterated on.
BudgetTrackerImpl* m_impl = nullptr;
};
} // namespace AZ::Debug
@@ -1,63 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef AZCORE_FRAME_PROFILER_H
#define AZCORE_FRAME_PROFILER_H
#include <AzCore/Driller/DrillerBus.h>
#include <AzCore/std/containers/ring_buffer.h>
#include <AzCore/Debug/Profiler.h>
#include <AzCore/std/parallel/config.h>
#include <AzCore/std/containers/unordered_map.h>
namespace AZ
{
namespace Debug
{
namespace FrameProfiler
{
/**
* This structure is used for frame data history, make sure it's memory efficient.
*/
struct FrameData
{
unsigned int m_frameId; ///< Id of the frame this data belongs to.
union
{
ProfilerRegister::TimeData m_timeData;
ProfilerRegister::ValuesData m_userValues;
};
};
struct RegisterData
{
//////////////////////////////////////////////////////////////////////////
// Profile register snapshot
/// data that doesn't change
const char* m_name; ///< Name of the profiler register.
const char* m_function; ///< Function name in the code.
int m_line; ///< Line number if the code.
AZ::u32 m_systemId; ///< Register system id.
ProfilerRegister::Type m_type;
RegisterData* m_lastParent; ///< Pointer to the last parent register data.
AZStd::ring_buffer<FrameData> m_frames; ///< History of all frame deltas (basically the data you want to display)
};
struct ThreadData
{
typedef AZStd::unordered_map<const ProfilerRegister*, RegisterData> RegistersMap;
AZStd::thread_id m_id; ///< Thread id (same as AZStd::thread::id)
RegistersMap m_registers; ///< Map with all the registers (with history)
};
typedef AZStd::fixed_vector<ThreadData, Profiler::m_maxNumberOfThreads> ThreadDataArray; ///< Array with samplers for all threads
} // namespace FrameProfiler
} // namespace Debug
} // namespace AZ
#endif // AZCORE_FRAME_PROFILER_H
#pragma once
@@ -1,38 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef AZCORE_FRAME_PROFILER_BUS_H
#define AZCORE_FRAME_PROFILER_BUS_H
#include <AzCore/EBus/EBus.h>
#include <AzCore/Debug/FrameProfiler.h>
namespace AZ
{
namespace Debug
{
class FrameProfilerComponent;
/**
* Interface class for frame profiler events.
*/
class FrameProfilerEvents
: public AZ::EBusTraits
{
public:
virtual ~FrameProfilerEvents() {}
/// Called when the frame profiler has computed a new frame (even is there is no new data).
virtual void OnFrameProfilerData(const FrameProfiler::ThreadDataArray& data) = 0;
};
typedef AZ::EBus<FrameProfilerEvents> FrameProfilerBus;
} // namespace Debug
} // namespace AZ
#endif // AZCORE_FRAME_PROFILER_BUS_H
#pragma once
@@ -1,250 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Debug/FrameProfilerComponent.h>
#include <AzCore/Debug/FrameProfilerBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Debug/Profiler.h>
namespace AZ
{
namespace Debug
{
//=========================================================================
// FrameProfilerComponent
// [12/5/2012]
//=========================================================================
FrameProfilerComponent::FrameProfilerComponent()
: m_numFramesStored(2)
, m_frameId(0)
, m_pauseOnFrame(0)
, m_currentThreadData(NULL)
{
}
//=========================================================================
// ~FrameProfilerComponent
// [12/5/2012]
//=========================================================================
FrameProfilerComponent::~FrameProfilerComponent()
{
}
//=========================================================================
// Activate
// [12/5/2012]
//=========================================================================
void FrameProfilerComponent::Activate()
{
if (!Profiler::IsReady())
{
Profiler::Create();
}
Profiler::AddReference();
TickBus::Handler::BusConnect();
AZ_Assert(m_numFramesStored >= 1, "We must have at least one frame to store, otherwise this component is useless!");
}
//=========================================================================
// Deactivate
// [12/5/2012]
//=========================================================================
void FrameProfilerComponent::Deactivate()
{
TickBus::Handler::BusDisconnect();
Profiler::ReleaseReference();
}
//=========================================================================
// OnTick
// [12/5/2012]
//=========================================================================
void FrameProfilerComponent::OnTick(float deltaTime, ScriptTimePoint time)
{
(void)deltaTime;
(void)time;
++m_frameId;
AZ_Error("Profiler", m_frameId != m_pauseOnFrame, "Triggered user pause/error on this frame! Check FrameProfilerComponent pauseOnFrame value!");
if (!Profiler::IsReady())
{
return; // we can't sample registers without profiler
}
// collect data from the profiler
m_currentThreadData = NULL;
Profiler::Instance().ReadRegisterValues(AZStd::bind(&FrameProfilerComponent::ReadProfilerRegisters, this, AZStd::placeholders::_1, AZStd::placeholders::_2));
// process all the resulting data here, not while reading the registers
for (size_t iThread = 0; iThread < m_threads.size(); ++iThread)
{
FrameProfiler::ThreadData& td = m_threads[iThread];
FrameProfiler::ThreadData::RegistersMap::iterator it = td.m_registers.begin();
FrameProfiler::ThreadData::RegistersMap::iterator last = td.m_registers.end();
for (; it != last; ++it)
{
// fix up parents
FrameProfiler::RegisterData& rd = it->second;
if (rd.m_type == ProfilerRegister::PRT_TIME)
{
const FrameProfiler::FrameData& fd = rd.m_frames.back();
if (fd.m_timeData.m_lastParent != nullptr)
{
FrameProfiler::ThreadData::RegistersMap::iterator parentIt = td.m_registers.find(fd.m_timeData.m_lastParent);
AZ_Assert(parentIt != td.m_registers.end(), "We have a parent register that is not in our register map. This should not happen!");
rd.m_lastParent = &parentIt->second;
}
else
{
rd.m_lastParent = NULL;
}
}
}
}
// send an even to whomever cares
EBUS_EVENT(FrameProfilerBus, OnFrameProfilerData, m_threads);
}
int FrameProfilerComponent::GetTickOrder()
{
// Even it's not critical we should tick last to capture the current frame
// so TICK_LAST (since it's not the last int +1 is a valid assumption)
return TICK_LAST + 1;
}
//=========================================================================
// ReadRegisterCallback
// [12/5/2012]
//=========================================================================
bool FrameProfilerComponent::ReadProfilerRegisters(const ProfilerRegister& reg, const AZStd::thread_id& id)
{
if (m_currentThreadData == NULL || m_currentThreadData->m_id != id)
{
m_currentThreadData = NULL;
// find the thread and cache it, as we will received registers thread by thread... so we don't search.
for (size_t i = 0; i < m_threads.size(); ++i)
{
FrameProfiler::ThreadData* td = &m_threads[i];
if (td->m_id == id)
{
m_currentThreadData = td;
break;
}
}
if (m_currentThreadData == NULL)
{
m_threads.push_back();
m_currentThreadData = &m_threads.back();
m_currentThreadData->m_id = id;
}
}
const ProfilerRegister* profReg = &reg;
FrameProfiler::ThreadData::RegistersMap::pair_iter_bool pairIterBool = m_currentThreadData->m_registers.insert_key(profReg);
FrameProfiler::RegisterData& regData = pairIterBool.first->second;
// now update dynamic data with as little as possible computation (we must be fast)
FrameProfiler::FrameData fd; // we can actually move this computation (FrameData and push) for later but we will need to use more memory
fd.m_frameId = m_frameId;
if (pairIterBool.second)
{
// when insert copy the static data only once
regData.m_name = profReg->m_name;
regData.m_function = profReg->m_function;
regData.m_line = profReg->m_line;
regData.m_systemId = profReg->m_systemId;
regData.m_frames.set_capacity(m_numFramesStored);
regData.m_type = static_cast<ProfilerRegister::Type>(profReg->m_type);
}
switch (regData.m_type)
{
case ProfilerRegister::PRT_TIME:
{
fd.m_timeData.m_time = profReg->m_timeData.m_time;
fd.m_timeData.m_childrenTime = profReg->m_timeData.m_childrenTime;
fd.m_timeData.m_calls = profReg->m_timeData.m_calls;
fd.m_timeData.m_childrenCalls = profReg->m_timeData.m_childrenCalls;
fd.m_timeData.m_lastParent = profReg->m_timeData.m_lastParent;
} break;
case ProfilerRegister::PRT_VALUE:
{
fd.m_userValues.m_value1 = profReg->m_userValues.m_value1;
fd.m_userValues.m_value2 = profReg->m_userValues.m_value2;
fd.m_userValues.m_value3 = profReg->m_userValues.m_value3;
fd.m_userValues.m_value4 = profReg->m_userValues.m_value4;
fd.m_userValues.m_value5 = profReg->m_userValues.m_value5;
} break;
}
regData.m_frames.push_back(fd);
return true;
}
//=========================================================================
// GetProvidedServices
//=========================================================================
void FrameProfilerComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("FrameProfilerService", 0x05d1bb90));
}
//=========================================================================
// GetIncompatibleServices
//=========================================================================
void FrameProfilerComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("FrameProfilerService", 0x05d1bb90));
}
//=========================================================================
// GetDependentServices
//=========================================================================
void FrameProfilerComponent::GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent)
{
dependent.push_back(AZ_CRC("MemoryService", 0x5c4d473c));
}
//=========================================================================
// Reflect
//=========================================================================
void FrameProfilerComponent::Reflect(ReflectContext* context)
{
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
{
serializeContext->Class<FrameProfilerComponent, AZ::Component>()
->Version(1)
->Field("numFramesStored", &FrameProfilerComponent::m_numFramesStored)
->Field("pauseOnFrame", &FrameProfilerComponent::m_pauseOnFrame)
;
if (EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<FrameProfilerComponent>(
"Frame Profiler", "Performs per frame profiling (FPS counter, registers, etc.)")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Profiling")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
->DataElement(AZ::Edit::UIHandlers::SpinBox, &FrameProfilerComponent::m_numFramesStored, "Number of Frames", "How many frames we will keep with the RUNTIME buffers.")
->Attribute(AZ::Edit::Attributes::Min, 1)
->DataElement(AZ::Edit::UIHandlers::SpinBox, &FrameProfilerComponent::m_pauseOnFrame, "Pause on frame", "Paused the engine (debug break) on a specific frame. 0 means no pause!")
;
}
}
}
} // namespace Debug
} // namespace AZ
@@ -1,75 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#ifndef AZCORE_FRAME_PROFILER_COMPONENT_H
#define AZCORE_FRAME_PROFILER_COMPONENT_H
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Debug/FrameProfiler.h>
#include <AzCore/std/parallel/threadbus.h>
#include <AzCore/Math/Crc.h>
namespace AZ
{
namespace Debug
{
/**
* Frame profiler component provides a frame profiling information
* (from FPS counter to profiler registers manipulation and so on).
* It's a debug system so it should not be active in release
*/
class FrameProfilerComponent
: public Component
, public AZ::TickBus::Handler
{
public:
AZ_COMPONENT(AZ::Debug::FrameProfilerComponent, "{B81739EF-ED77-4F67-9D05-6ADF94F0431A}")
FrameProfilerComponent();
virtual ~FrameProfilerComponent();
private:
//////////////////////////////////////////////////////////////////////////
// Component base
void Activate() override;
void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Tick bus
void OnTick(float deltaTime, ScriptTimePoint time) override;
int GetTickOrder() override;
//////////////////////////////////////////////////////////////////////////
/// \ref ComponentDescriptor::GetProvidedServices
static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided);
/// \ref ComponentDescriptor::GetIncompatibleServices
static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible);
/// \ref ComponentDescriptor::GetDependentServices
static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent);
/// \red ComponentDescriptor::Reflect
static void Reflect(ReflectContext* reflection);
/// callback for reading profiler registers
bool ReadProfilerRegisters(const ProfilerRegister& reg, const AZStd::thread_id& id);
// Keep in mind memory usage, increases quickly. Prefer remote tools (where the history is kept on the PC) instead of keeping long history
unsigned int m_numFramesStored; ///< Number of frames that we will store in history buffers. >= 1
unsigned int m_frameId; ///< Frame id (it's just counted from the start).
unsigned int m_pauseOnFrame; ///< Allows you to specify a frame the code will pause onto.
FrameProfiler::ThreadDataArray m_threads; ///< Array with samplers for all threads
FrameProfiler::ThreadData* m_currentThreadData; ///< Cached pointer to the last accessed thread data.
};
}
}
#endif // AZCORE_FRAME_PROFILER_COMPONENT_H
#pragma once

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